Pull to refresh

Слово в защиту пиксельных значений media queries

Reading time 8 min
Views 36K
Я покажу тебе, глубока ли кроличья нора.Читая публикации о верстке для вэба, вы не раз натыкались на рекомендацию не использовать пикселы в media queries. Например, вот цитата из совсем недавней статьи на Хабре:

Вместо использования фиксированных размеров, лучше использовать относительные единицы для определения breakpoints. На хабре уже многократно была раскрыта тема использования относительных размеров в верстке. Вот неполный список статей: здесь, здесь, здесь. Приведу лишь самый главный довод — это позволит браузерам изменять дизайн в зависимости от уровня установленного размера зума пользователем, в результате чего пользователь увидит более приятный, более доступный для просмотра сайт.

Что, если я скажу вам, что использование пикселов в media queries не только не причиняет никакого вреда верстке, но и имеет преимущества над использованием em'ов?



В статье используется термин «breakpoint». Программистам он режет слух, так как в мире программирования означает совсем другое. Уверяю вас, что в англоязычном мире фронтенд-разработки это устоявшийся и однозначный термин. Он означает ширину окна браузера, при превышении которой компоновка страницы меняется. Коверкать его на русский язык я не стал, как и термин «media query».

 

Media queries с пиксельными значениями не мешают зуму


Начнем с «самого главного довода» против пикселов: якобы, при увеличении страницы в старом браузере пиксельные значения media queries не срабатывают. Это просто-напросто ложь. Пиксельные media queries нормально срабатывают при зуме во всех сколько-нибудь популярных браузерах. Даже в Internet Explorer 8!

Да, IE 8 не поддерживает media queries. Но если вы воспользуетесь в вашем проекте замечательным полифиллом Respond.js, то IE 8 будет отображать его с полной поддержкой media queries. И знаете, что? Они корректно срабатывают при зуме даже в нем. Крутите колесико мыши с зажатым Ctrl — компоновка страницы перстраивается. К примеру, на сайте, анимация зума которого в IE показана справа, я использовал media queries следующего вида:

@media (min-width: 401px) {
  #header-first {
    float: left;
    width: 47.82609%;
    margin-right: 4.34783%; }}

Более древнего IE под рукой не оказалось, но это и не важно — доля IE7 составляет в России всего 0.7%, IE6 — 0.1%, и то, по большей части, за счет госучреждений.

Итак, проблема, называемая в качестве главной причины отказа от пикселов в media queries, просто не существует. По всей видимости, это просто легенда, которая слепо передается из уст в уста, регулярно попадает даже в публикации влиятельных изданий и блоги гуру фронтенда, и никто не удосуживается просто взять и проверить, а так ли это.

UPD 2013-10-31: я обнаружил, что в Safari media queries при зуме не срабатыват. Но они не срабатывают независимо от того, какая единица измерения в них используется. KrylCW помог подтвердить, что это справедливо и для Safari 7. Кроме того, по его данным, media queries не срабатывают при зуме в Яндекс.Браузрере под MacOS (актуальная версия 1.7.1364.22074 (0b6c012)), но срабатывают, если после зума сделать обновление страницы.

Я попробовал Яндекс.Браузер под виндой (актуальная версия 13.10.1500.8765 (e504cce)). Там всё наоборот: пиксельные media queries зумятся корректно, а относительные — нет! Вы зумите страницу, media query срабатывает правильно. Скажем, это происходит на шаге 175%→200%. Потом вы зумите в обратную сторону, и media query на шаге 200%→175% не срабатывает, но срабатывает на шаге 100%→90%. Причем если зумить туда-сюда, то разрыв с каждым циклом увеличивается!

Для желающих попробовать самим наклепал тест: пикселы, em'ы.
 

Изменение базового размера шрифта приводит к «съезжанию» всех breakpiont'ов, если они заданы в em'ах


Представьте такую ситуацию. Звонит вам шеф или клиент и говорит: «А чего у нас на сайте шрифт такой мелкий? Моя жена ничего не может прочитать, сделайте покрупнее». Спорить бесполезно. Вы грустно вдыхаете, бросаете виноватый взгляд на дверь отдела дизайна, открываете CSS-код и увеличиваете базовый размер шрифта с 13px до 16px (да, базовый размер шрифта все равно задается в пикселах, как ни крути).

Что при этом происходит? Все breakpoint'ы, заданные в em'ах, смещаются. Теперь на планшетах сайт отображается в одну колонку: так, как раньше выглядел только на телефоне. Выглядит это примерно так (сделайте ширину окна менее 900px и ужаснитесь). Вы этому рады? Готов спорить, что окажись вы в такой ситуации, вы будете, матерясь вполголоса, спешно переписывать все media queries… или в полный голос, если в проекте не используется препроцессор.

Да, я в курсе про идеологию Content First, в соответствии с которой breakpoint'ы и должны смещаться, подчиняясь комфортному для потребления масштабу контента. Это позволяет уйти от необходимости учитывать в CSS-коде дуриллион разнокалиберных устройств, имеющих браузер. Вместо этого вы ставите breakpoint'ы в единицах, относительных размеру шрифта, и заставляете сайт перестраиваться тогда, когда контенту становится слишком тесно или слишком просторно.

Но не врите себе. Выполняя любой коммерческий проект, вы хотите (или ваш клиент хочет) строго определенную компоновку на наиболее популярных устройствах. Например, чтобы превьюшки, которые на мобильнике отображаются в один столбец, на iPad'е в портретном режиме превращалась в сетку с тремя столбцами. Вы не хотите, чтобы при изменении размера шрифта это сломалось. Если ваш дизайнер решил, что на iPad в ландшафтном режиме должен быть сайдбар, то должен быть там независимо от того, шрифт какого размера используется на сайте. Если шрифт для узкого сайдбара окажется слишком велик, то вы скорее уменьшете шрифт, чем избавитесь от сайдбара.

Да, для контент-ориентированных сайтов ширина колонки текста не должна выходить за комфортные пределы. Но, во-первых, эта ширина имеет достаточно широкий диапазон. Мне известна рекомендация в 45—75 знаков, то есть ширина колонки может безболезненно меняться на величину вплоть до 66 процентных пунктов. Во-вторых, почему именно такая ширина считается стандартом? Откройте любой глянцевый журнал, там сплошь и рядом попадаются колонки текста шириной по 15 знаков, и никому не приходит в голову, что это плохо. Мне, например, очень удобно свернуть журнал трубочкой, когда я пытаюсь читать его в битком набитом вагоне метро. А на Хабре ширина колонки текста — от 75 до примерно 115 знаков, причем подавляющее большинство посетителей Хабра видят текст шириной именно 115 знаков.

Кстати, вы не заметили тут подмену понятий? Сделать оптимальную ширину текста можно и с использованием пиксельных media queries.

И наконец, часто ли вам приходится менять размер всех шрифтов на уже выполненном проекте, причем без переоформления всего остального? А если у вас все шрифты в em'ах, а клиент потребовал увеличить шрифт только основного текста? Простите, последний вопрос к теме статьи не относится.

 

Смежные media queries, заданные в em'ах, отображаются внахлест


Я называю пару media queries «смежными», когда максимальная ширина одного совпадает с минимальной шириной другого. Приведу взятый с потолка пример:

.container {
  color: black;
  background-color: white; }}

@media (max-width: 40em) {
  .container { color: red; }}

@media (min-width: 40em) {
  .container { background-color: red; }}

Отгадаете, что увидит посетитель, которому «повезет» открыть этот сайт в браузере шириной точно 40em?

Величина перекрытия составляет всего один пиксел, но она есть. Если у посетителя сайта вдруг окажется именно такая ширина экрана, то и компоновка страницы, и оформление могут оказаться покорежены, вплоть до полной нечитаемости.

При использовании пикселов проблема решается элементарным и совершенно надежным способом:

@media (max-width: 600px) { /* ... */ }
@media (min-width: 601px) { /* ... */ }

Когда я, слепо подчиняясь мнению большинства, писал media queries на em'ах и обнаружил перекрытие, я попробвал решить проблему аналогичным способом: (min-width: 20,1em). Нахлест сменился зазором: на определенной ширине окна не применяется ни тот, ни другой media query. Я попробовал 20,01, потом 20,001… Методом артиллерийской вилки мне удалось найти нужное значение остатка после запятой.

Я быстро понял, что один раз подобрать этот остаток недостаточно. Для каждого базового размера шрифта остаток будет другим, иначе обязательно будет иметь место либо зазор, либо нахлест. Но я не растерялся, ведь я хорошо владею SASS и могу написать mixin, побирающий правильный остаток для любого значения в em'ах. Берем на входе сколько-то em'ов, умножаем на базовый размер шрифта, прибавляем единичку, делим обратно на базовый размер шрифта — и вуаля, получаем на выходе безопасное значение.

У вас на этом месте должно возникнуть смутное ощущение, что этот путь какой-то… неправильный. По крайней мере, у меня оно возникло. Я попытался посмотреть на ситуацию со стороны и задался вопросом: чем я, собственно, занимаюсь?

И это подводит нас к следующему аргументу:

 

Em'ы в media queries — это посредник между двумя пиксельными величинами: базовым размером шрифта и шириной окна браузера


Как уже упоминалось выше, базовый размер шрифта всегда задается в пикселах. В противном случае браузер просто не знает, какой размер шрифта считать равным одному em'у. Если базовый размер шрифта не указан, любой нормальный браузер примет его за 16 пикселов. Если он указан в em'ах, то браузер помножит его на те же 16 пикселов. То же касается и других относительных единиц: 1 pt принимается 4/3 px, а количество пикселов в сантиметре прописано в ОС.

Min-width и max-width в media queries сопоставляются с шириной окна, которая у любого браузера задана целым числом виртуальных пикселов. К примеру, для iPhone по четвертый включительно, она составляет 320×480, а для iPhone 5 — 320x568.

Задавая media queries в em'ах, вы сначала производите в уме преобразование из пикселов в em, а потом из em обратно в пикселы, чтобы понять, а в какую ширину экрана вы этим breakpoint'ом, собственно, попадаете.

Незачем так себя мучить. Просто используйте пикселы.

 

Использование пиксельных media queries не означает отказ от подхода «content first»


То, что вы используете пикселы в media queries, не лишает вас возможности исходить из контента при проектирвоании media queries.

Статей о том, как грамотно делать media queries, в интернетах великое множество, и эта тема выходит за рамки данной статьи. Поэтому я ограничусь несколькими рекомендациями, которыми постараюсь подкрепить тезис в подзаголовке.

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

Во-первых, не используйте по отдельному CSS-файлу для каждой ширины экрана (поддержку IE можно обеспечить полифиллом). Структурируйте код по используемым на страницах сайта модулям и расставляйте media queries индивидуально для каждого модуля. Это облегчит контроль над каждым модулем и упростит поддержку кода.

Во-вторых, при проектировании responsive layout отталкивайтесь от контента. Способ очень простой (и придуман не мной). Сначала сверстайте модуль, ориентируясь на минимальную ширину экрана. Разумеется, модуль должен быть «резиновым». Затем растягивайте окно браузера до тех пор, пока модуль не станет выглядеть паршиво. В этом месте ставьте breakpoint и переверстывайте под эту ширину. Повторяйте до тех пор, пока не упретесь max-width вашего сайта.

Кстати, не ограничивайте максимальную ширину сайта узкой колонкой в 980 пикселов. Если у вас большой монитор, посмотрите, как роскошно может выглядеть сайт на ширине 1920 пикселов. Если у вас монитор меньше, то, ради бога, наскребите пять тысяч рублей и купите себе большой. Это же ваш профессиональный инструмент!

В-третьих, используйте препроцессор. Внедрить препроцессор в проект — непросто, особенно для новичка, но он сэкономит вам колоссальное количество возни.

Подойдет любой препроцессор, но я горячо рекомендую Sass. Не потому, что сам язык Sass чем-то лучше — они все более или менее равны по возможностям, а потому, что он имеет цельную экосистему библиотек. Библиотеки, которые принято называть «расширениями Compass», очень богаты функционально и эффективно взаимодействуют друг с другом.

В четвертых, чтобы не оказаться погребенным под кучей разнокалиберных media queries…

 

Нарезайте шкалу размеров экрана на дольки


Для того, чтобы облегчить задачу работы с media queries, я смастерил расширение Breakpoint Slicer (которое, в свою очередь, использует Breakpoint — очень мощное и универсальное расширение для работы с media queries).

Идея Breakpoint Slicer очень проста. Вы расставляете breakpoint'ы через небольшие промежутки, например: 400px, 600px, 800px, 1050px. Модуль пронумеровывает эти промежутки по порядку:

  1. 0—400
  2. 401—600
  3. 601—800
  4. 801—1050
  5. 1051—∞

А затем в Sass-коде вы просто говорите, с какого по какой промежуток надо поставить media query:

  • at(2) — эквиваленто (min-width: 401px) and (max-width: 600px)
  • from(2) — эквиваленто (min-width: 401px)
  • to(2) — эквиваленто (max-width: 600px)
  • between(2, 4) — эквиваленто (min-width: 401px) and (max-width: 1050px)

Это позволяет кратко и эффективно распределять стили модулей по диапазонам. Использование большого количества промежутков позволяет охватить все классы устройств, при этом не вдаваясь в чрезмерную конкретику.

Если у вас появится вопрос по использованию Breakpoint Slicer, не стесняйтесь задать его в багтрекере (если знаете английский, то лучше на английском).
Tags:
Hubs:
+110
Comments 64
Comments Comments 64

Articles