Отзывчивый веб-дизайн преобразил проектирование и создание сайтов. Он позволил нам отойти от классификации устройств и прибегнуть к медиа-запросам, позволяющим адаптировать разметку к размерам области просмотра браузера. Такой подход, однако, несколько отклоняется от иерархической структуры CSS и описывает элементы относительно области просмотра, а не относительно содержащего их контейнера.
Широкое применение медиа-запросов могло стать неплохим современным решением проблемы, однако оно не имеет долгосрочных перспектив. Медиа-запросы не допускают применение многократно используемых модулей, которые адаптируются на основе размера своих контейнеров.
Что представляет собой отзывчивый веб-дизайн?
Отзывчивый веб-дизайн не ограничивается набором каких-то технологий; скорее, это принципиально иной подход к проектированию и созданию веб-сайтов. Я, как и многие другие, воспринял слова Ethan об отзывчивом веб-дизайне слишком буквально, упустив суть сказанного:
«Жидкие сетки, гибкие изображения и медиа-запросы – это три технических компонента отзывчивого дизайна, однако он также требует иного образа мыслей»
Что касается «технических компонентов»: у нас есть великолепные, мощные инструменты, позволяющие реализовать отзывчивый веб-дизайн. Однако когда дело доходит до «иного образа мыслей», перед нами появляется значительное пространство для роста. Иное мышление должно касаться не только того, как мы проектируем и создаем веб-сайты, но и того, как мы разрабатываем инструменты и технологии, на которых основаны наши сайты.
Модульный дизайн
Когда я изучал, как медиа-запросы могут использоваться в отзывчивом веб-дизайне, я был потрясен открывающими перспективами. Однако это было еще до того, как я узнал о существующих ограничениях. Медиа-запросы прекрасно подходят для адаптации разметки к различным размерам экрана, но они просто ужасны для создания модульного дизайна. Модульные CSS-стили уже сами по себе достаточно сложны, и медиа-запросы нисколько их не упрощают. Реальная модульная разметка должна отзываться не только на размер области просмотра, но и на размеры контейнеров. Однако медиа-запросы основываются на области просмотра, а не на контейнере элемента. Можно возлагать некоторые надежды на новый стандарт CSS, маячащий на горизонте, который является пока еще рабочим черновиком W3C, и который позволит нарушать каскадное наследование и сбрасывать элемент к его значениям по умолчанию. Однако как быть с медиа-запросами?
Хак @media
Веб-разработчики – настоящие гуру в том, чтобы взять что-либо, созданное для одной цели, и использовать это для выполнения совершенно других действий. История Web насыщена такими примерами, и медиа-запросы – не исключение. Стоит поблагодарить Ian Storm Taylor за описание похожих мыслей в статье: «Media Queries Are a Hack». Хаки играют важную роль в Сети, поскольку они позволяют реализовать необходимую функциональность при отсутствии должной поддержки, а также позволяют обеспечить работу кода в устаревших браузерах. Как утверждает W3C, «с помощью медиа-запросов можно подгонять представление к определенному диапазону устройств вывода, не изменяя сам контент». Ключевое слово здесь – «можно», однако если вы можете что-то сделать, это не означает, что вы должны это делать… Но разве у нас есть другой выбор?
Element-запрос
Давайте познакомимся с element-запросом. Что представляет собой этот вид запросов? Element-запрос напоминает медиа-запрос: если условие выполняется, то применяются некоторые CSS-стили. Условия для element-запроса (такие как min-width, max-width, min-height и max-height) зависят от элементов, а не от браузера. К сожалению, CSS пока еще не поддерживает element-запросы, однако это не должно останавливать нас от каких-либо действий.
Абстрактный пример
Рассмотрим следующий пример, в котором навигационное меню должно стать видимым, когда оно достигнет минимальной ширины в 500 пикселей (представляет один из многих возможных синтаксисов):
nav (min-width: 500px) { display: block; }
Сравните это с медиа-запросом, в котором видимость навигационного меню зависит от ширины области просмотра, причем важно учитывать поля (padding) и другие объявления родительских элементов:
@media all and (min-width: 520px) { nav { display: block; } }
Теперь давайте предположим, что нам требуется создать модульный компонент, который должен быть помещен в контейнеры различных размеров на отдельной странице. Один из существующих подходов заключается в добавлении различных тематических классов (как, к примеру, .module—large) для вызова CSS в медиа-запросах. Однако такой подход лишь все усложняет, требуя, чтобы модули знали, как их родитель будет реагировать на различную ширину области просмотра.
Проблемы: неверные и зацикленные условия
Существуют отдельные случаи, когда CSS-стили element-запроса приводят к появлению неверного запроса или вызывают рекурсию. Хотелось бы надеяться, что браузер будет в состоянии обнаружить такие условия и соответствующим образом ответить на них.
Рассмотрим следующие примеры.
Как только элемент достигнет ширины в 500 пикселей, он будет изменен до 200 пикселей, после чего правило больше не будет применяться:
.element (min-width: 500px) { width: 200px; }
Как только ширина элемента достигнет 31.250 em, его размер шрифта будет уменьшен, что изменяет определение модуля em:
.element (min-width: 31.250em) { font-size: 0.75em; }
Как только ширина контейнера достигнет 450 пикселей, размер его дочерних элементов меняется до 400 пикселей, что ужмет и сам контейнер:
.container { float: left; } .child { width: 500px; } .container (min-width: 450px) > .child { width: 400px; }
Можно привести много других похожих примеров, однако вы видите: element-запросы не так просты, как мы думали.
Polyfill-код для element-запросов
Element-запросы выглядят крутыми, однако у них имеются и некоторые существенные проблемы. Чтобы решить их, я написал тестовый polyfill-код. Этот код позволил мне понять, как браузер будет реагировать на различные условия. Как я выяснил впоследствии, polyfill-код мог оказаться важным для всего веб-сообщества, а некоторые разработчики вполне могли использовать element-запросы уже сегодня.
ElementQuery polyfill-скрипт доступен на GitHub – вы можете использовать его, изменять и распространять.
Синтаксис селекторов
Синтаксис, используемый в предыдущих примерах, имеет некоторые ограничения, потому я решил обновить polyfill-код для поддержки синтаксиса селекторов атрибутов. Селектор атрибутов (~=) проверяет, содержится ли значение в разделенном пробелами списке (поддерживается современными браузерами старше Internet Explorer 6).
Следующие примеры демонстрируют CSS-правила с синтаксисом, необходимым для elementQuery polyfill-скрипта.
Правило для одного условия:
header[min-width~="500px"] { background-color: #eee; }
Правило для нескольких условий:
header[min-width~="500px"][max-width~="800px"] { background-color: #eee; }
Правило для родительского элемента:
header[min-width~="31.250em"] nav { clear: both; }
Как это работает
К сожалению, elementQuery polyfill-скрипт требует подключения JavaScript и механизма селекторов Sizzle (который встроен в jQuery). Когда DOM готов, elementQuery сканирует набор document.styleSheets для каждого CSS-правила, которое использует elementQuery. Найдя совпадение, он извлекает следующую информацию:
- Селектор (к примеру, header, ul > li.class)
- Тип запроса (min-width, max-width, min-height, max-height)
- Значение запроса (500px, 31.250em)
Затем elementQuery использует эту информацию для добавления или удаления атрибутов у тех элементов, которые соответствуют указанному селектору и условию запроса.
Расширенная поддержка
Большинство браузеров, за исключением Internet Explorer, не дают доступа к контенту междоменных стилевых таблиц, что приводит к проблемам, когда CSS-файлы берутся из CDN. В дополнение ко всему, парсинг стилевых таблиц занимает некоторое время (правда, не такое длительное). Таким образом, я создал две ветви для elementQuery: master и prod. Master-ветвь включает в себя код, позволяющий извлечь необходимую для elementQuery информацию (селектор, тип запроса, значение запроса) – также эта версия имеет функцию selectors() для экспорта информации. Prod-ветвь запрашивает информацию, которая будет объявлена в Javascript, что позволяет обойти проблему вызова междоменных файлов, а также сокращает время, требуемое на парсинг стилевых таблиц.
Ниже представлен пример того, как выполнить экспорт elementQuery-информации в master-ветви:
console.log(JSON.stringify(elementQuery.selectors()));
А также пример того, как выполнить экспорт elementQuery-информации в prod-ветви:
elementQuery({"header":{"min-width":["500px","31.250em"],"max-width":["800px"]}});
Рабочие примеры
Я разместил несколько рабочих примеров на CodePen (используя master-ветвь), с которыми вы можете экспериментировать и которые вы можете форкать. Мне хотелось бы увидеть результаты работы других людей (которые, возможно, будут круче моих). Обязательно тегируйте их #elementquery, чтобы другие могли найти их.
- Grid: вложенные элементы
- Menu: elementQuery, основанный на ширине
- Blockquote: elementQuery, основанный на высоте
Будьте креативными
Я писал эту статью не для того, чтобы быстро перейти на element-запросы. Я хотел подтолкнуть людей к поиску решения проблем, которые ограничивают нашу среду. Давайте продолжим обсуждать этот путь и сделаем Сеть самым лучшим пространством! Идите и сделайте что-нибудь крутое!
- Посмотреть elementQuery на GitHub
Источник: coding.smashingmagazine.com/2013/06/25/media-queries-are-not-the-answer-element-query-polyfill/
Круть. Хорошо видно в какую сторону народ гребет и что будет завтра. Спасибо за статью.
Спасибо за перевод статьи!