Статьи

Управление отзывчивыми точками останова с помощью Sass

Имея дело с адаптивным дизайном, вы часто определяете множество медиа-запросов, проверяете различные свойства с различными значениями. Поскольку он может быстро запутаться, обычно считается хорошей практикой использовать Sass (или любой другой препроцессор) для обработки отзывчивых точек останова.

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

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

С переменными

Смотреть AtoZ: Sass
Узнайте Sass буква за буквой

Во-первых, есть способ, используемый Bootstrap и Foundation , который состоит из определения переменных, а затем их использования в директивах @media . Другими словами, у вас будет файл конфигурации, содержащий множество переменных, готовых к использованию как есть.

Вот как Bootstrap делает это:

 // Defining values $screen-sm-min: 768px; $screen-xs-max: ($screen-sm-min - 1); $screen-md-min: 992px; $screen-sm-max: ($screen-md-min - 1); $screen-lg-min: 1200px; $screen-md-max: ($screen-lg-min - 1); // Usage @media (max-width: $screen-xs-max) { ... } @media (min-width: $screen-sm-min) { ... } @media (max-width: $screen-sm-max) { ... } @media (min-width: $screen-md-min) { ... } @media (max-width: $screen-md-max) { ... } @media (min-width: $screen-lg-min) { ... } 

Foundation делает еще один шаг вперед, избавляя от необходимости вводить min-width и max-width , работая со стригированными медиазапросами все вместе, а не со значениями пикселей.

 // Defining values $small-range: (0em, 40em); /* 0, 640px */ $medium-range: (40.063em, 64em); /* 641px, 1024px */ $large-range: (64.063em, 90em); /* 1025px, 1440px */ $xlarge-range: (90.063em, 120em); /* 1441px, 1920px */ $xxlarge-range: (120.063em); /* 1921px */ // Defining media queries $screen: "only screen" !default; $landscape: "#{$screen} and (orientation: landscape)" !default; $portrait: "#{$screen} and (orientation: portrait)" !default; $small-up: $screen !default; $small-only: "#{$screen} and (max-width: #{upper-bound($small-range)})" !default; $medium-up: "#{$screen} and (min-width:#{lower-bound($medium-range)})" !default; $medium-only: "#{$screen} and (min-width:#{lower-bound($medium-range)}) and (max-width:#{upper-bound($medium-range)})" !default; $large-up: "#{$screen} and (min-width:#{lower-bound($large-range)})" !default; $large-only: "#{$screen} and (min-width:#{lower-bound($large-range)}) and (max-width:#{upper-bound($large-range)})" !default; $xlarge-up: "#{$screen} and (min-width:#{lower-bound($xlarge-range)})" !default; $xlarge-only: "#{$screen} and (min-width:#{lower-bound($xlarge-range)}) and (max-width:#{upper-bound($xlarge-range)})" !default; $xxlarge-up: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)})" !default; $xxlarge-only: "#{$screen} and (min-width:#{lower-bound($xxlarge-range)}) and (max-width:#{upper-bound($xxlarge-range)})" !default; // Usage @media #{$small-up} { ... } @media #{$small-only} { ... } @media #{$medium-up} { ... } @media #{$medium-only} { ... } @media #{$large-up} { ... } @media #{$large-only} { ... } @media #{$xlarge-up} { ... } @media #{$xlarge-only} { ... } @media #{$xxlarge-up} { ... } @media #{$xxlarge-only} { ... } 

Есть одна вещь, которая мне не нравится в каждом методе: в Bootstrap я должен печатать (min-width: ...) каждый раз. В Foundation мне нужно интерполировать переменную, которая уродлива и раздражает. Конечно, мы могли бы придумать способ исправить оба недостатка.

С автономным миксином

Я считаю, что одна из самых популярных публикаций CSS-Tricks — это сообщения о медиа-запросах в Sass 3.2 . В этой статье Крис Койер объясняет, как он использовал прежнюю идею Мейсона Уэнделла, которая также использовала прежнюю идею Джеффа Крофта, чтобы назвать свои отзывчивые контрольные точки с помощью Sass.

Наименование точек останова важно, потому что оно дает смысл абстрактному значению. Вы всегда знаете, что такое 767px ? Я не. Я бы лучше знал, что мы имеем дело с маленькими экранами . Это то, что Bootstrap и Foundation начали делать для хранения медиазапросов в переменных; Вы знаете, переменные названы.

Таким образом, мы могли бы создать миксин, который принимает имя (в основном строку) в качестве единственного параметра, выплевывая медиа-запрос. Правильно?

 @mixin respond-to($breakpoint) { @if $breakpoint == "small" { @media (min-width: 767px) { @content; } } @else if $breakpoint == "medium" { @media (min-width: 992px) { @content; } } @else if $breakpoint == "large" { @media (min-width: 1200px) { @content; } } } 

Затем мы можем использовать это так:

 @include respond-to(small) { ... } @include respond-to(medium) { ... } @include respond-to(large) { ... } 

Это на самом деле хорошо, и по двум причинам: он не только имеет смысл сам по себе, но также централизует все точки останова в одном месте: в ядре mixin. Если вам когда-либо 992px изменить эту 992px останова 992px на 970px , вам не нужно сканировать все ваши таблицы стилей; все, что вам нужно сделать, это обновить миксин, и все будет работать как шарм.

Однако есть еще две вещи, которые не совсем верны с этим миксином:

  1. Точки останова не могут быть легко извлечены из mixin в файл конфигурации
  2. Это так излишне!

С настраиваемым миксином

Чтобы решить наши два новых недостатка, нам нужно составить какой-то список из наших контрольных точек. Затем этот список можно перемещать, помещать в файл конфигурации, оставлять в ядре mixin, что угодно.

Что было бы очень круто, так это способ сопоставить имя со значением. При использовании Sass 3.3+ существует очень простой способ сделать это: карты . Представленные в Sass 3.3, карты делают именно это: они связывают ключи со значениями.

 $breakpoints: ( 'small' : 767px, 'medium' : 992px, 'large' : 1200px ); 

Ухоженная! Теперь нам нужно только настроить наш предыдущий миксин, чтобы получить значения с карты, вместо того, чтобы жестко кодировать все:

 @mixin respond-to($breakpoint) { // Retrieves the value from the key $value: map-get($breakpoints, $breakpoint); // If the key exists in the map @if $value != null { // Prints a media query based on the value @media (min-width: $value) { @content; } } // If the key doesn't exist in the map @else { @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. " + "Please make sure it is defined in `$breakpoints` map."; } } 

Также обратите внимание на это крутое небольшое улучшение: если $breakpoint не найден на карте точек останова, пользователь получает предупреждение благодаря директиве @warn . Это помогает с отладкой на случай, если что-то пойдет не так.

Теперь наш миксин не только очень СУХОЙ, но и очень хорошо обрабатывает ошибки. Тем временем мы удалили одну функцию из нашей системы: возможность проверять, какое свойство мы хотим ( min-width , max-width , max-height …). Тем не менее, если вы используете подход «сначала для мобильных устройств» , эта версия вполне подойдет вам, поскольку вам не понадобится ничего, кроме медийных запросов min-width .

Но если вы хотите контролировать тип медиа-запроса для дампа, вы можете захотеть добавить эту функцию обратно в нашу систему. Для этого я недавно предложил довольно элегантное решение, которое не добавляет сложности в коде. На самом деле, он основан на том факте, что карты Sass используют тот же синтаксис, что и медиазапросы CSS (например, (property: value) ).

[Карты] не имеют прямой параллели в CSS, хотя они синтаксически похожи на выражения медиа-запросов
Sass ссылка

 $breakpoints: ( 'small' : ( min-width: 767px ), 'medium' : ( min-width: 992px ), 'large' : ( min-width: 1200px ) ); @mixin respond-to($name) { // If the key exists in the map @if map-has-key($breakpoints, $name) { // Prints a media query based on the value @media #{inspect(map-get($breakpoints, $name))} { @content; } } // If the key doesn't exist in the map @else { @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. " + "Please make sure it is defined in `$breakpoints` map."; } } 

Как видите, это больше не делает наш миксин. На самом деле, нам даже удалось изменить его, чтобы сделать его легче! Среди изменений нам нужен был способ печати карты, потому что вы могли заметить, что значения из карт точек останова — это карты, а также действительные медиа-запросы CSS. К сожалению, если вы попытаетесь распечатать карту Sass, вы можете столкнуться со следующей ошибкой:

(min-width: 767px) не является допустимым значением CSS.

Вот где пригодится функция inspect . Согласно ссылке Sass, он возвращает строку, содержащую значение в качестве своего представления Sass . Другими словами, это единственный способ напечатать карту Sass без сбоя компилятора.

Итак, подведем итог тому, что делает наш миксин:

  1. Он проверяет, существуют ли запрошенные точки останова на карте точек останова.
  2. Если он существует, он печатает медиа-запрос на основе значения запрошенной точки останова
  3. Если это не так, он предупреждает пользователя, чтобы проверить свой код

Просто! Если мы оглянемся на недостатки нашего предыдущего решения, то заметим, что больше нет проблем с кодом WET ( Write Everything Twice ) или негибкими медиа-запросами. Однако есть одна вещь, которую эта система не позволяет: сложные медиа-запросы. Под сложным я подразумеваю медиазапросы, включающие несколько компонентов (например, screen and (min-width: 767px) ).

Поскольку он основан на том факте, что простой мультимедийный запрос CSS является допустимой картой Sass, он очень затрудняет объявление более сложных мультимедийных запросов. Тем не менее, я не только счел весьма маловероятным, что нам понадобятся такие запросы, но наши предыдущие решения (за исключением чисто переменных от Bootstrap и Foundation) также не позволили нам сделать это.

С внешним инструментом

И последнее, но не менее важное: если по какой-то причине вам не хочется создавать собственный миксины, вы можете использовать существующий инструмент для обработки точек останова медиазапроса. Есть несколько интересных расширений Sass, которые хорошо справляются со своей задачей:

Все три являются первоклассными инструментами Sass, поэтому не стесняйтесь выбирать любой из них. Вот крошечная сравнительная доска, если вам трудно выбрать одну:

SassMQ точка остановки Расставаться
Тип MQ *-width Любые Любые
Откат без запросов Ага Ага Ага
Сложность API просто очень просто средний
Сложность кода очень просто Complexe просто
дополнительный Режим отладки Singularity.gs

Если я что-то пропустил или есть информация, которую нужно добавить, обязательно поделитесь.

SassMQ

 // Configuration $mq-responsive: true; $mq-static-breakpoint: desktop; $mq-breakpoints: ( mobile: 320px, tablet: 740px, desktop: 980px, wide: 1300px ); // Example selector { @include mq($from: mobile) { property: value; } } 

точка остановки

 $high-tide: 500px; $ex-presidents: 600px 800px; $surfboard-width: max-width 1000px; $surfboard-height: (min-height 1000px) (orientation portrait); selector { @include breakpoint($high-tide) { property: value; } } 

Расставаться

 $breakup-breakpoints: ( 'thin' '(max-width: 35.999em)', 'wide' '(min-width: 36em)', 'full' '(min-width: 61em)' ); selector { @include breakup-block('thin') { property: value; } } 

Последние мысли

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

Всегда соблазнительно написать фрагмент кода, который охватывает все возможные варианты, готовит вам кофе и стирает белье, но всегда есть риск, что в конечном итоге инструмент не сможет использовать никто другой, кроме вас. При работе в команде простота имеет значение.

В любом случае, не забудьте выбрать правильный инструмент для правильной работы. ?