CSS*

Разработка → 120 dpi и шрифты в em

Delka 20 октября 2008 в 16:41 8,7k
шрифт в em

Шрифты в Em/% хороши всем — возможностью пользователей IE увеличивать кегль, заботой о пользователях, что предпочитают увеличивать размер шрифта браузера по-умолчанию, чтоб лучше видеть текст, да и просто являются нормой для профессиональных верстальщиков.

Минусы: … их вроде как нет, но!
А что если у пользователя разрешение экрана выставлено не в стандартное 96 dpi, а в 120?
Сайт с увеличенными шрифтами смотрится уже не так красиво, как нарисовал дизайнер — ведь масштабируются только шрифты, а не весь сайт! А разрешение 120dpi становится всё популярней, особенно на ноутбуках! Что же делать? Возвращаться к px?

Нет!

В Opera больше нет этого бага, а resolution она просто игнорирует. Зато в IE9 при наличии кода из статьи возникают баги с уменьшенным шрифтом по всему сайту. Не используйте 120dpi fix для всех браузеров, оставьте код только для IE6/7.

ВНИМАНИЕ! По состоянию на 2013 год это статья устарела и её информация полезна лишь для теоретических знаний. Не используйте код из неё на продакшене! Он более не нужен.
* В Opera больше нет этого бага и вообще она скоро будет на другом движке (Webkit).
* IE6 и 7 — уже достояние истории и их почти никто не поддерживает.
* Да и вообще сейчас мало кто верстает в EM, большинство снова использует PX ради независимости стилей (BEM-метод) в вёрстке.


Итак, конкретизируем проблему:

В Windows при разрешении экрана больше 96 dpi браузеры IE≤7 и Opera пропорционально увеличивают величину шрифта по умолчанию.


Это может вызывать неприятное искажение дизайна, как правило, на сайтах с фиксированной шириной.
Firefox и Safari/Сhrome игнорируют экранное dpi.

Резина — как задумал дизайнер:
Fluid design 96dpi

Резина – 120dpi:
Fluid design 120dpi

Фиксированная ширина — как задумал дизайнер:
Fixed design 96dpi

Фиксированная ширина – 120dpi:
Fixed design 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.deviceXDPI2 – фактическое dpi экрана в браузере.
screen.logicalXDPI3 – стандартное dpi экрана (как выставлено в винде, обычно =96)
Как правило screen.deviceXDPI == screen.logicalXDPI. Но бывают исключения, о них ниже.

IE6/7 могут пропорционально увеличивать масштаб на экранах с высоким разрешением.


За это отвечает свойство HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\
UseHR = dword:00000001

MSDN4 как бы говорит нам, что изготовители мониторов с высоким разрешением могут выставлять этот параметр.

Выглядеть это должно так:

IE с включенным увеличением масштаба (UseHR = 1):
IE с включенным увеличением масштаба
IE с выключенным увеличением масштаба (UseHR = 0):
IE с выключенным увеличением масштаба

Мне не удалось добиться масштабирования путём включением этой опции, тем не менее, я перестраховываюсь и проверяю коэффициент масштаба IE и только если он равен 1 (т.е. масштабирование выключено) пропорционально изменяю кегль для body:
document.body.style.fontSize = 1/(screen.logicalYDPI/96) +'em'
Изменение размера шрифта для body автоматически (по каскаду) изменяет кегль всех остальных шрифтов.

IE 5, к сожалению, не поддерживает screen.deviceXDPI/screen.logicalYDPI, поэтому в нём этот код не сработает.

Что насчёт IE8?


В IE8 всё сделано очень красиво и элегантно: браузер увеличивает всё содержимое страницы пропорционально экранному dpi5.
Fluid design IE8 120dpi
96dpi 120dpi 144dpi
IE8 dpi scaling at 96dpi IE8 dpi scaling at 120dpi IE8 dpi scaling at 144dpi
Т.е. автоматически включается Full-page zoom.

Лирическое отступление про 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:
Full page zoom IE7
IE8 Full-page zoom (Adaptive Zoom):
Full page zoom IE8

Горизонтальный скролл теперь появляется только если колонки имеет фиксированную ширину, переносы строк вставляются в новые места (после масштабирования), в общем очень похоже на то как это происходит в 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:
CSS zoom in IE6/7 at 120dpi

Это не тоже самое что 125% full-page-zoom IE7:
125% full-page zoom in IE7

Full-page Zoom в IE7 увеличивает весь html (за счёт чего и появляется горизонтальный скролл), а через css мы можем задать css zoom только для body.

При css-zoom не возникает горизонтального скрола, который есть в IE7 при full-page-zoom, но появляются проблемы с флеш-объектами: они могут исчезать и проявляться частично при наведении курсора мыши, отрисовываться «скомканными».
Flash breaks at CSS zoom in IE6/7

Если у вас не используются объекты типа flash – вы можете использовать такой способ.

Любопытно, это редкий случай применения css свойства zoom по-назначению, а не для задания Layout.


Как насчёт Firefox 3.1, который понимает CSS3 Media Queries?


Для уменьшения кегля на 120dpi мы используем CSS3-свойство min-resolution.
Firefox 3.1 будет понимать и применять его. Но при этом он не увеличивает размер шрифта. Значит шрифт в нём будет меньше чем надо:
small font-size at FF3.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.


Примечания:
  1. Павел Корнилов: Тонкий CSS для Internet Explorer (expression)
  2. MSDN: deviceYDPI Property
  3. MSDN: logicalYDPI Property
  4. MSDN: Adjusting Scale for Higher DPI Screens
  5. MSDN: Making the Web Bigger: DPI Scaling and Internet Explorer 8
  6. MSDN: Internet Explorer 8 and Adaptive Zoom
  7. Cогласно спецификации CSS2 браузер обязан игнорировать стиль, если в селекторе встречается что-то незнакомое
  8. MSDN: About Conditional Comments
Подробнее про то, что такое dpi:
  1. Ководство: § 70. Разрешение экранов. И немного о происхождении 72 точек на дюйм
Проголосовать:
+143
Сохранить: