Pull to refresh

Использование Media Queries в Sass 3.2

Reading time4 min
Views64K
С выходом Sass 3.2 начал продвигаться в массы путь объектно-ориентированного CSS (OOCSS), принося с собой принцип DRY и программистское мышление. Media queries и OOCSS стали жизненно важны для современной фронтенд разработки.



Давайте посмотрим, что нового


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.

Посетители, просматривающие ваш сайт на планшетах или телефоне обязательно поблагодарят вас.
Tags:
Hubs:
Total votes 32: ↑31 and ↓1+30
Comments5

Articles