С выходом Sass 3.2 начал продвигаться в массы путь объектно-ориентированного CSS (OOCSS), принося с собой принцип DRY и программистское
Давайте посмотрим, что нового
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.
Посетители, просматривающие ваш сайт на планшетах или телефоне обязательно поблагодарят вас.
Автор: xeLL