С выходом Sass 3.2 начал продвигаться в массы путь объектно-ориентированного CSS (OOCSS), принося с собой принцип DRY и программистское мышление. Media queries и OOCSS стали жизненно важны для современной фронтенд разработки.
Sass имеет очень полезный функционал, не широко известный content. Можно думать о content, как о yield — позволяет нам определить sass @mixin, который имеет вложенный CSS. Это позволит сэкономить драгоценные часы и уменьшить повторение кода и значительно упростит работу с media queries.
Для начала надо объявить переменные, которые будут определять точки входа для устройств и добавим слой абстракции в наши media queries. Для этого создадим @mixin respond-to:
Код лучше читается и мгновенно больше смысла, чем расшифровка, например, media only screen and (max-width: 320px) and (orientation: portrait).
Вся магия заключается в content, который позволяет нам передать в CSS свойства, которые мы хотим применить в соответствии с медийным запросом выше. Мы не можем знать, что в будущем будет требовать дизайн, но через эту абстракцию будет легко обновлять стили, когда эти изменения произойдут.
После компиляции Sass мы получим нужный CSS:
Если необходимо применять CSS, для чего угодно меньше ipad-lanscape, например, то можно не расписывать вариации respond-to, а сделать новый @mixin, который будет адаптирован под разные устройства:
Все это очень прекрасно и позволяет делать интересные интерфейсы, но не будет работать в IE ниже девятой версии. Решение проблемы заключается в генерирование раздельных стилевых файлов:
В файле для IE объявляются переменные
Также есть некоторые ограничения на использование @extend внутри media queries… Это означает, что если вы используете @extend в media queries, вы можете только расширить селекторы, которые появляются в том же блоке. Например, такой код работает отлично:
Такой вариант ошибочен:
Но мы можем поступить иначе, использовав silent classes, которые не попадают в стили, пока не сделать их @extend.
Получим правильно откомпилированный CSS:
Кроме того, всем бы хотелось, чтобы откомпилированный CSS был меньше и CSS правила отдельного запроса были скомбинированы, например:
Хотелось бы получить:
Вместо этого получаем:
Работая с Rails 3.1+ и Sprockets можно использовать джем sprockets-media_query_combiner, чтобы CSS правила были оптимизировано скомбинированы.
Также есть неплохой джем, который можно использовать в проекте responder, для более удобного использования media queries.
Посетители, просматривающие ваш сайт на планшетах или телефоне обязательно поблагодарят вас.
Давайте посмотрим, что нового
Sass имеет очень полезный функционал, не широко известный content. Можно думать о content, как о yield — позволяет нам определить sass @mixin, который имеет вложенный CSS. Это позволит сэкономить драгоценные часы и уменьшить повторение кода и значительно упростит работу с media queries.
Как это работает
Для начала надо объявить переменные, которые будут определять точки входа для устройств и добавим слой абстракции в наши media queries. Для этого создадим @mixin respond-to:
$small: 320px;
$large: 1024px;
@mixin respond-to($media) {
@if $media == handhelds {
@media only screen and (max-width: $small) { @content; }
}
@else if $media == medium-screens {
@media only screen and (min-width: $small + 1) and (max-width: $large - 1) { @content; }
}
@else if $media == wide-screens {
@media only screen and (min-width: $large) { @content; }
}
}
.block {
float: left;
width: 250px;
@include respond-to(handhelds) { width: 100% ;}
@include respond-to(medium-screens) { width: 125px; }
@include respond-to(wide-screens) { float: none; }
}
Код лучше читается и мгновенно больше смысла, чем расшифровка, например, media only screen and (max-width: 320px) and (orientation: portrait).
Вся магия заключается в content, который позволяет нам передать в CSS свойства, которые мы хотим применить в соответствии с медийным запросом выше. Мы не можем знать, что в будущем будет требовать дизайн, но через эту абстракцию будет легко обновлять стили, когда эти изменения произойдут.
После компиляции Sass мы получим нужный CSS:
.block {
float: left;
width: 250px;
}
@media only screen and (max-width: 320px) {
.block {
width: 100%;
}
}
@media only screen and (min-width: 321px) and (max-width: 1023px) {
.block {
width: 125px;
}
}
@media only screen and (min-width: 1024px) {
.block {
float: none;
}
}
Если необходимо применять CSS, для чего угодно меньше ipad-lanscape, например, то можно не расписывать вариации respond-to, а сделать новый @mixin, который будет адаптирован под разные устройства:
$ipad-landscape: 980px;
@mixin apply-to($ltgt, $device) {
$extrema: null;
@if $ltgt == less-than {
$extrema: max;
}
@if $ltgt == greater-than {
$extrema: min
}
@if $device == $ipad-landscape {
@media only screen and (#{$extrema}-width: $ipad-landscape) {
@content;
}
}
}
.block {
@include apply-to(less-than, ipad-landscape) {
background: black;
}
}
С какими проблемами можно столкнуться
Все это очень прекрасно и позволяет делать интересные интерфейсы, но не будет работать в IE ниже девятой версии. Решение проблемы заключается в генерирование раздельных стилевых файлов:
<!--[if lte IE 8]>
<link rel="stylesheet" href="css/all-old-ie.css">
<![endif]-->
<!--[if gt IE 8]><!-->
<link rel="stylesheet" href="css/all.css">
<!--<![endif]-->
В файле для IE объявляются переменные
$old-ie: true;
и необходимые фиксирование ширины и импортируется основной стилевой файл. В основном стилевом файле переменные IE $old-ie будут принимать значение false по умолчанию. Необходимо будет написать @mixin для IE и расширить функционал apply-to:@mixin old-ie {
@if $old-ie {
@content;
}
}
@mixin apply-to($ltgt, $device) {
$extrema: null;
@if $ltgt == less-than {
$extrema: max;
}
@if $ltgt == greater-than {
$extrema: min
}
@if $fix-mqs-ipad-landscape {
@content;
}
@else {
@media screen and (#{$extrema}-width: $device) {
@content;
}
}
}
.block {
@include apply-to(less-than, $ipad-landscape) {
float: left;
width: 70%;
@include old-ie {
content: 'Все то, что может понадобиться для IE';
}
}
}
Также есть некоторые ограничения на использование @extend внутри media queries… Это означает, что если вы используете @extend в media queries, вы можете только расширить селекторы, которые появляются в том же блоке. Например, такой код работает отлично:
@media only screen and (max-width: 320px) and (orientation: portrait){
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
}
Такой вариант ошибочен:
.error {
border: 1px #f00;
background-color: #fdd;
}
@media only screen and (max-width: 320px) and (orientation: portrait) {
.seriousError {
@extend .error;
border-width: 3px;
}
}
Но мы можем поступить иначе, использовав silent classes, которые не попадают в стили, пока не сделать их @extend.
//silent class
%big {
width: 20px;
height: 20px;
}
.block_1 {
@extend %big;
}
.block_2 {
@include respond-to('large'){
@extend %big;
}
}
.block_3 {
@include respond-to('large'){
@extend %big;
}
}
Получим правильно откомпилированный CSS:
.block_1 {
height: 20px;
width: 20px;
}
@media screen and (min-width: 600px) {
.block_2, .block_3 {
height: 20px;
width: 20px;
}
}
Кроме того, всем бы хотелось, чтобы откомпилированный CSS был меньше и CSS правила отдельного запроса были скомбинированы, например:
.profile-pic {
@media screen and (max-width: 320px) {
width: 100px;
float: none;
}
}
.biography {
@media screen and (max-width: 320px) {
font-size: 15px;
}
}
Хотелось бы получить:
@media screen and (max-width: 320px) {
.profile-pic {
width: 100px;
float: none;
}
.biography {
font-size: 15px;
}
}
Вместо этого получаем:
@media screen and (max-width: 320px) {
.profile-pic {
width: 100px;
float: none;
}
}
@media screen and (max-width: 320px) {
.biography {
font-size: 15px;
}
}
Работая с Rails 3.1+ и Sprockets можно использовать джем sprockets-media_query_combiner, чтобы CSS правила были оптимизировано скомбинированы.
Также есть неплохой джем, который можно использовать в проекте responder, для более удобного использования media queries.
Посетители, просматривающие ваш сайт на планшетах или телефоне обязательно поблагодарят вас.