SASS: Оптимизируем media screen

в 19:21, , рубрики: css, gulp, html, mixin, scss, адаптивная вёрстка, Компиляторы

Приветствую!

Примерно месяц назад я написал статью, в которой выдвинул идею об оптимизации @media screen. Идея заключается в том, чтобы иметь возможность писать значения для всех экранов в одну строку. Более подробно можете почитать по ссылке. Большинство комментариев — это критика относительно реализации, к сожалению идей никто не подкинул. Но если посмотреть с другой стороны, из каждой критики можно вытащить идею, поэтому опираясь на мнение читателей, я поставил себе цель написать миксин, который:

  • легко читается (максимально повторяющий синтаксис sass/scss/css);
  • легко поддерживать (чтобы через год ты понимал, что там написано);
  • гибкий (поддержка максимального количества описаний @media);

Давайте посмотрим, что у меня вышло (репозиторий Github)!

Синтаксис

.class{
    @include media($properties, $orientation);
}

Миксин media поддерживает два параметра $properties и $orientation.
$properties — массив css правил.
$orientation — ориентация экрана (необязательный).

$properties

.class{
    @include media((
        width: 100%;
        height: (lg: 800px, md: 600px, sm: 300px),
        transform: (all: translateX(100px) translateY(100px), sm: translateX(50px) translateY(50px)),
        color: (sm-md: $white, md-lg: $gray),
        font-size: (320: 12px, min-480: 18px, 480-md: 24px, print: 14pt)
    ));
}

Давайте разберем код подробней…

Параметр $properties является массивом, поэтому все свойства берутся в ().

width: 100%;

Обычное правило для всех экранов. компилируется в

.class{
    width: 100%;
  }

Интересное дальше:

height: (lg: 800px, md: 600px, sm: 300px)

Здесь мы описываем высоту для экранов с максимальной шириной lg, md и sm (задаются разработчиком, об этом позже).

Результат компиляции:

@media only screen and (max-width: 1024px) {
    .class{
        height: 800px;
   }
}
@media only screen and (max-width: 768px) {
    .class{
        height: 600px;
   }
}
@media only screen and (max-width: 640px) {
    .class{
        height: 300px;
   }
}

Так же обратите внимание на код ниже:

transform: (all: translateX(100px) translateY(100px), sm: translateX(50px) translateY(50px))

В данном примере присутствует экран all, я думаю вы догадались, что это все экраны. Есть принципиальная разница между all и обычным правилом, как width: 100%. Но об этом так же немного позже.

color: (sm-md: $white, md-lg: $gray)

Здесь я постарался максимально гибко соединить диапазоны экранов между min-width и max-width. Т.е. код, представленный выше скомпилирует минимальную ширину sm (640) — максимальную ширину md (768), и для экранов в этом диапазоне задаст белый цвет текста, или серый для md (768) — lg (1024).

Скомпилированный вариант:

.class{
    @media only screen and (min-width: 768px)  and (max-width: 1024px) {
        color: gray;
    }
}
.class{
    @media only screen and (min-width: 640px)  and (max-width: 768px) {
        color: white;
    }
}

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

font-size: (880: 12px, min-480: 18px, 480-md: 24px, print: 14pt)

Первый экран max-width: 880px. По умолчанию ширина проставляется именно максимальная (так же легко поменять). Для этого экрана получим font-size: 12px;
Второй экран min-480 указывает на то, что будем отталкиваться от минимальной ширины экрана 480px (приставка min-), и в итоге получим font-size: 18px для всех экранов шире 480px.

480-md — создаст кастомный минимальный размер 480px и максимальный md (768). Т.е. это вариант диапазона экранов, как в предыдущем примере, только с произвольным значением.

Обратите внимание, что если написать 480-768 мы получим экран -288px, т.е. знак "-" отработает как минус. Поэтому такой пример стоит взять в кавычки «480-768», если конечно вы намерено не писали операцию с "-" (кстати +, *, / так же будет работать).

print: 14pt

print — является неизменным параметром и предназначен для печати:

@media print {
  .class{
    font-size: 14pt;
  }
}

Надеюсь на данном этапе все понятно… Если нет, с радостью разъясню в комментариях.

Давайте перейдем к параметру $orientation

Тут все намного проще. Есть два варианта ориентации экрана landscape и portrait. Собственно, в случае необходимости, вторым параметром прописываем именно эти значения.

.class{
    @include media((
        width: 100%;
        height: (all: 100%, md: 50%)
    ), portrait);
}

В итоге мы получим:

.class{
     width: 100%;
}
@media only screen and (orientation:portrait){
     .class{
          height: 100%;
     }
}
@media only screen and (max-width: 768px) and (orientation:portrait){
     .class{
          height: 50%;
     }
}

На этом примере можно четко увидеть разницу между all и стандартным правилом. В случае width: 100% правило при любых обстоятельствах подпадает под все экраны. В случае all — все экраны с ориентацией portrait/landscape.

Настройки

Две стандартные переменные, которые нужно отредактировать — это $breakpoints и $media-direction. Вот как они выглядят по умолчанию:

$breakpoints: (
        lg: 1024,
        md: 768,
        sm: 640
) !default; //- размеры экранов
$media-direction: max !default; - направление по умолчанию (max/min)

Т.е. для того чтобы создать себе нужное количество экранов с нужными названиями, размерами и первоначальным направлением (min/max) необходимо создать новые переменные в удобном для вас месте:

$breakpoints: (
        desktop: 1280,
        ipad: 1024,
        tablet: 768,
        mobile: 640
);
$media-direction: min;

Этого достаточно чтобы начать работу.

Как еще можно использовать данный миксин?

Если параметр $properties поместить в переменную, тогда можно получить отличную функцию. Например:

$title-style: (
     line-height: (lg: 24px, md: 20px, sm: 16px),
     font-size: (lg: 20px, md: 16px, sm: 12px;),
     text-align: (all: left, sm: center)
     ...
) 
.block{
     h2{
          color: gray;
          @include media($title-style);
     }
     h3{
          color: black;
          @include media($title-style, landscape);
     }
}

Получаем своего рода extend класс. Согласитесь, это может быть очень удобно.

Подведем итоги

Плюсы

  • легко читаемый — код максимально повторяет синтаксис CSS;
  • легко поддерживаемый — экраны прописаны достаточно понятно, и разобраться в коде не будет проблем;
  • гибкий — мы получили возможность описывать @media screen для всех экранов, диапазоны экранов, минимальную/максимальную ширину динамически, в любой момент есть возможность прописать кастомную ширину, а так же не отходя от кода настраивать правила для печати.

Минусы

  • Отсутствует описание экрана по высоте. К этой части я пока не добрался, и если данный миксин будет вам интересен, я обязательно допишу и такую возможность. Так что не забывайте писать комментарии, чтобы я мог понимать насколько для вас это актуально и полезно.
  • Отсутствует возможности прописывать @include mixin для разных экранов. На данный момент такую возможность реализовать в приведенном выше миксине посредством Sass в принципе невозможно. Насколько это критично, я оставлю вам на размышление, решайте сами, стоит ли жертвовать подобной функцией или нет. Лично для меня это вообще не критично, так как я не могу припомнить, чтобы я вообще когда-нибудь прописывал @include mixin внутри @media screen.

Вывод

Думаю, цель достигнута. Миксин получился достаточно удобным и лаконичным.

Если вы со мной не согласны, пишите комментарии. В любом случае с удовольствием выслушаю ваш совет по улучшению данного миксина, или попробую извлечь что-то полезное из вашей критики.

P.S. Скачать миксин вы можете в репозитории Github по ссылке. _mixin.scss — тот файл, который вам нужен. Так же файл package.json содержит в себе плагины для Gulp, которые было бы неплохо подключить:

  • gulp-autoprefixer добавит префиксы браузеров, там где это необходимо;
  • gulp-group-css-media-queries отлично группирует @media screen;
  • gulp-minify-css оптимизирует css, можно сказать, что данный плагин необходим.

Уверен, что для webpack или для любого другого сборщика, вы без труда найдете аналоги.

Спасибо за внимание!

Автор: Долгалев Евгений

Источник

Поделиться

* - обязательные к заполнению поля