Шрифты в Em/% хороши всем — возможностью пользователей IE увеличивать кегль, заботой о пользователях, что предпочитают увеличивать размер шрифта браузера по-умолчанию, чтоб лучше видеть текст, да и просто являются нормой для профессиональных верстальщиков.
Минусы: … их вроде как нет, но!
А что если у пользователя разрешение экрана выставлено не в стандартное 96 dpi, а в 120?
Сайт с увеличенными шрифтами смотрится уже не так красиво, как нарисовал дизайнер — ведь масштабируются только шрифты, а не весь сайт! А разрешение 120dpi становится всё популярней, особенно на ноутбуках! Что же делать? Возвращаться к px?
Нет!
ВНИМАНИЕ! По состоянию на 2013 год это статья устарела и её информация полезна лишь для теоретических знаний. Не используйте код из неё на продакшене! Он более не нужен.
* В Opera больше нет этого бага и вообще она скоро будет на другом движке (Webkit).
* IE6 и 7 — уже достояние истории и их почти никто не поддерживает.
* Да и вообще сейчас мало кто верстает в EM, большинство снова использует PX ради независимости стилей (BEM-метод) в вёрстке.
Итак, конкретизируем проблему:
В Windows при разрешении экрана больше 96 dpi браузеры IE≤7 и Opera пропорционально увеличивают величину шрифта по умолчанию.
Это может вызывать неприятное искажение дизайна, как правило, на сайтах с фиксированной шириной.
Firefox и Safari/Сhrome игнорируют экранное dpi.
Резина — как задумал дизайнер:
Резина – 120dpi:
Фиксированная ширина — как задумал дизайнер:
Фиксированная ширина – 120dpi:
На резиновых макетах увеличенный кегль как правило не вызывает проблем, но на сайтах с фиксированной шириной, увеличенные буквы могут просто не вписываться в отведённые им узкие колонки. Большой кегль может смотрется некрасиво рядом с оставшейся неувеличенной графикой.
Что происходит при увеличении размера шрифта:
Как правило, увеличивается только шрифт. Ещё могут увеличиваться блоки, на которые разделён сайт (если их размеры тоже заданы в em/%), но графика не увеличивается!
Это не значит что мы должны отказаться от изменяемых размеров шрифтов!
Ведь на действительно больших мониторах, 120 dpi – не прихоть, а необходимость – плохо видно мелкий шрифт. Да и пользователь может просто захотеть увеличить размер шрифта – как на данной конкретной странице, так и вообще в настройках браузера – чтоб на всех сайтах он был крупнее.
Мы не должныобламывать людям кайфуменьшать удобство пользования сайтом. Но и сайт должен выглядеть красиво, как задумал дизайнер, ведь встречают по-одёжке.
С помощью CSS мы можем проверять разрешение пользователя и пропорционально уменьшать размер шрифта!
html {font-size: 68.75%} /* базовый шрифт 11px */
@media all and (min-resolution: 120dpi) {
html {font-size: 55%} /* пропорционально уменьшаем кегль: 68.75/(120/96) */
}
Для IE6/7 нужен такой код:
#header {
scrollbar-track-color:expression(
this.runtimeStyle.scrollbarTrackColor = "#fff",
((screen.deviceXDPI/screen.logicalXDPI) == 1) ? (document.body.style.fontSize = 1/(screen.logicalYDPI/96) +'em') : false
);
}
Это одноразовый 1 expression, он изменяет базовый кегль пропорционально dpi экрана.Разберём его поподробнее:
#header
– здесь может быть id любого существующего в верстке блока. Он нам нужен только чтоб «зацепиться», сам expression изменяет стили для body.scrollbar-track-color
– любое свойство которое «не жалко». Я использую проприентарное свойство IE, из семейства задающих цвет полос прокрутки. Если у элемента нет полос прокрутки (т.е. значение overflow — visible (по умолчанию) или hidden), то это свойство никак не влияет на отображение блока.screen.deviceXDPI
2 – фактическое dpi экрана в браузере.screen.logicalXDPI
3 – стандартное dpi экрана (как выставлено в винде, обычно =96)Как правило screen.deviceXDPI == screen.logicalXDPI. Но бывают исключения, о них ниже.
IE6/7 могут пропорционально увеличивать масштаб на экранах с высоким разрешением.
За это отвечает свойство
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\
UseHR = dword:00000001
MSDN4 как бы говорит нам, что изготовители мониторов с высоким разрешением могут выставлять этот параметр.
Выглядеть это должно так:
IE с включенным увеличением масштаба (UseHR = 1):IE с выключенным увеличением масштаба (UseHR = 0):
Мне не удалось добиться масштабирования путём включением этой опции, тем не менее, я перестраховываюсь и проверяю коэффициент масштаба IE и только если он равен 1 (т.е. масштабирование выключено) пропорционально изменяю кегль для body:
document.body.style.fontSize = 1/(screen.logicalYDPI/96) +'em'
Изменение размера шрифта для body автоматически (по каскаду) изменяет кегль всех остальных шрифтов.
IE 5, к сожалению, не поддерживает screen.deviceXDPI/screen.logicalYDPI, поэтому в нём этот код не сработает.
Что насчёт IE8?
В IE8 всё сделано очень красиво и элегантно: браузер увеличивает всё содержимое страницы пропорционально экранному dpi5.
96dpi | 120dpi | 144dpi |
---|---|---|
Лирическое отступление про screen.deviceXDPI, screen.logicalXDPI и Page zoom
В IE8 при включении Full-page zoom меняется значение screen.deviceXDPI. При 125% zoom оно = 120, при 150% — 144. При 100% (без масштабирования) screen.deviceXDPI возвращается к 96. При этом не имеет значения какое dpi стоит в винде.
Вот для чего нужна проверка что (screen.deviceXDPI == screen.logicalXDPI)!
Это случай — когда юзер в правом нижнем углу IE8, кликает на select Page zoom и меняет его.
А вот screen.logicalYDPI в 8-ке видимо постоянное число, у меня в тестах оно всегда было 96.
В 7-ке же и 6-ке, оба эти значения, при тестах, менялись только в зависимости от настроек винды. Page zoom в IE7 не менял значения ни того, ни другого свойства.
Я случайно обнаружил это через год после написания статьи, когда писал костыль к древнему сайту :)
Кстати Page zoom в IE8 лучше чем в IE7:
IE7 Full-page zoom:
IE8 Full-page zoom (Adaptive Zoom):
Горизонтальный скролл теперь появляется только если колонки имеет фиксированную ширину, переносы строк вставляются в новые места (после масштабирования), в общем очень похоже на то как это происходит в FF и Opera.
Механизм называется Adaptive Zoom, подробнее о нём можно почитать в блоге разработчиков IE6.
В IE6/7 похожего поведения можно добиться так:
div#header {
scrollbar-track-color:expression(
this.runtimeStyle.scrolbarTrackColor = "#fff",
(((screen.deviceXDPI/screen.logicalXDPI) == 1) && (screen.deviceYDPI > 96)) ?
(
document.body.style.fontSize = 1/(screen.logicalYDPI/96) +'em',
document.body.style.zoom = screen.logicalYDPI/96
) : false
);
}
120 dpi css-zoom IE6/7:
Это не тоже самое что 125% full-page-zoom IE7:
Full-page Zoom в IE7 увеличивает весь html (за счёт чего и появляется горизонтальный скролл), а через css мы можем задать css zoom только для body.
При css-zoom не возникает горизонтального скрола, который есть в IE7 при full-page-zoom, но появляются проблемы с флеш-объектами: они могут исчезать и проявляться частично при наведении курсора мыши, отрисовываться «скомканными».
Если у вас не используются объекты типа flash – вы можете использовать такой способ.
Любопытно, это редкий случай применения css свойства zoom по-назначению, а не для задания Layout.
Как насчёт Firefox 3.1, который понимает CSS3 Media Queries?
Для уменьшения кегля на 120dpi мы используем CSS3-свойство
min-resolution
.Firefox 3.1 будет понимать и применять его. Но при этом он не увеличивает размер шрифта. Значит шрифт в нём будет меньше чем надо:
Исправляем:
html {font-size: 68.75%} /* базовый кегль 11px==1em, все остальные наследуют значение = 11px x Xem */
@media all and (min-resolution: 120dpi) {
html {font-size: 55%}
html, x:-moz-any-link {font-size: 68.75%}
}
x:-moz-any-link
– это выбор несуществующего элемента x с псевдоклассом -moz-any-link. Такой псевдокласс понимает только Gecko-браузеры, остальные проигнорируют всю строчку7.
Необычный глюк в Opera 9 (<9.6)
После того, как мы добавили фикс для FF3.1, Opera стала игнорировать css-объявление, следующее сразу за правилом для min-resolution: 120dpi.Т.е. имеем следующий код:
html {font-size: 68.75%}
@media all and (min-resolution: 120dpi) {
html {font-size: 55%}
html, x:-moz-any-link {font-size: 68.75%}
}
body,table,input,label,textarea,button,select {color: #000; font: normal 1em/1.3 Tahoma, Geneva, sans-serif}
Правило, начинающееся с body
будет проигнорировано в Opera 9.Причём в Opera 8 и 9.6 — всё отлично.
Исправляем:
html {font-size: 68.75%} /* базовый кегль 11px==1em, все остальные наследуют значение = 11px x Xem */
@media all and (min-resolution: 120dpi) {
html {font-size: 55%}
html, x:-moz-any-link {font-size: 68.75%}
}
#for-opera927 {/* dont' remove! */}
Приводить или нет внешний вид сайта на 120dpi к 96 – решать вам
Повторюсь — речь о стартовом виде сайта.Пользователь с экранным разрешением 120dpi видит большинство сайтов точно так же как и на 96 (т.к. большинство свёрстанно с фиксированными размерами). А свёрстанный в em — увидит сразу увеличенным. Причём увеличенным там будет только размер шрифта, а графика останется такой же как и была. Согласитесь — сайт будет не так красив, как его изначально задумал дизайнер.
Так почему бы не показать его пользователю таким, каким он был задумал?
Увеличить размер шрифта на нём он может в любую секунду.
Кстати не факт, что пользователь сам выставил 120dpi.
Он мог просто купить ноутбук, где такие настройки по-умолчанию.
А если пользователь увеличил базовый размер шрифта в FF или Safari (которые игнорирует dpi), чтоб лучше видеть?
Без фикса сайт с em будет иметь огромный шрифт.
И только в IE8 сайт будет красиво и корректно отмасштабирован.
Как насчёт future proof? Не будет ли проблем с будущими версиями браузеров?
В ближайшее время возникновение проблем маловероятно.
Исправления потребуются только в следующих случаях:
- Safari начнёт понимать CSS3 свойство min-resolution, но не будет увеличивать кегль в зависимости от экранного dpi.
В это случае мы дополним код правилом аналогичным тому, что мы написали для FF3.1.
- Internet Explorer 9 начнёт понимать min-resolution, сохранив ту же модель масштабирования (adaptive full-page zoom) что и в IE8.
Это исправляется фиксом для IE≥9 через conditional comments8.
- Opera, вместо увеличения размера шрифта на высоких dpi, начнёт применять full-page zoom.
Лечится правилом аналогичным тому, что мы написали для FF3.1.
Итак вот готовое решение:
html {font-size: 68.75%} /* сюда пишем размер вашего шрифта по-умочанию */
@media all and (min-resolution: 120dpi) {
html {font-size: 55%} /* пропорционально уменьшаем кегль: 68.75/(120/96) */
html, x:-moz-any-link {font-size: 68.75%} /* тут должен быть размер по-умолчанию */
}
#for-opera927 {/* dont' remove! */}
Для IE6/7:
#header {
scrollbar-track-color:expression(
this.runtimeStyle.scrollbarTrackColor = "#fff",
((screen.deviceXDPI/screen.logicalXDPI) == 1) ? (document.body.style.fontSize = 1/(screen.logicalYDPI/96) +'em') : false
);
}
UPD: Opera 10.5+ почему-то не реагирует на правило
@media all and (min-resolution: 120dpi) { ... }
хотя в доках наоборот — написано что только в presto 2.5 появилась его поддержка, а раньше не было (как же работало тогда раньше?). Я пробовал разные варианты, гуглил, искал на форуме Opera, но ничего не нашёл/не помогло.Судя по спеке — в моём коде всё верно.Обсудив с pepelsbey пришли к выводу что это глюк, баг-репорт отправлен. Теперь остаётся ждать пока Opera исправит. К счастью, на западе, где проблема 120dpi распространена, почти нет Opera, а у нас, где Opera популярна, почти нет проблемы 120dpi :)UPD2: Со слов pepelsbey Opera более не поддерживает min-resolution так что код внутри основного css стоит просто выключить. Можно оставить код для IE6/7.
Примечания:
- Павел Корнилов: Тонкий CSS для Internet Explorer (expression)
- MSDN: deviceYDPI Property
- MSDN: logicalYDPI Property
- MSDN: Adjusting Scale for Higher DPI Screens
- MSDN: Making the Web Bigger: DPI Scaling and Internet Explorer 8
- MSDN: Internet Explorer 8 and Adaptive Zoom
- Cогласно спецификации CSS2 браузер обязан игнорировать стиль, если в селекторе встречается что-то незнакомое
- MSDN: About Conditional Comments
Подробнее про то, что такое dpi: