Используем препроцессор sass

2666
views

sass

Вы давно хотите изучить sass, но не знали с чего начать? Или вы и так уже используете sass, но знания поверхностные и их хотелось бы прокачать? Данная статья поможет вам уверенно использовать всю мощь препроцессора sass и получать удовольствие от работы с ним.

Ранее я публиковал статью о том, как начать работать с less. Теперь же я хочу поведать о более предпочтительном для меня препроцессоре sass.

Что такое sass?

Sass (Syntactically Awesome Style Sheets) — это препроцессор стилей css. Sass добавляет такой функционал к css, что работать с ним становится значительно легче, быстрее и приятней.

Установка sass и как с ним работать

Это первый вопрос которым задается веб-разработчик, который хочет начать использовать препроцессор. Есть несколько вариантов:

  • Использовать родной компилятор Ruby Sass gem install sass и компилировать его с помощью команды sassc myfile.scss myfile.css
  • Использовать GUI программы: Hammer, CodeKit, Koala или Compass
  • Воспользоваться таск-менеджерами или консольными утилитами: gulp, grunt, libsass

По опыту могу сказать, что если вы один разработчик фронт-енда на проекте, то выбрать можно то, что удобней именно для вас. Если не нравится пользоваться консолью или прописывать таски для менеджера, то программы с графическим интерфейсом отлично подойдут. Но если же у вас крупный проект, с которым работают несколько людей с разными операционными системами, то однозначно лучше использовать gulp или grunt.

В чем разница между .sass и .scss?

В первых версиях sass формат файлов был .sass. В нем использовался специфический синтаксис, который отличался от синтаксиса css. Такой синтаксис не многим приглянулся и с 3 версии был введен новый формат .scss , который полностью такой же, как и в обычном css. Можно даже старый файл css переименовать в scss и он будет компилироваться.


После того, как мы установили компилятор sass, создали файл в проекте с расширением .scss приступим к синтаксису препроцессора.

Переменные

Одним из лучших новшеств, которое добавляет sass в css это использование переменных. Они задаются с помощью символа $

$primaryColor: #eeffcc;

Если вы попробуете скомпилировать этот код, на выходе ничего не будет. Потому что это просто переменная в своем scope. Её необходимо использовать таким образом:

$primaryColor: #eeffcc;

body {
    background: $primaryColor;
}

Говоря про scope я имею ввиду, что у каждой переменной есть как и в js своя область видимости.

$primaryColor: #eeccff;

body {
  $primaryColor: #ccc;
  background: $primaryColor;
}

p {
  color: $primaryColor;
}

// После компиляции у абзаца p будет цвет #eeccff

Но если вы захотите переназначить глобальную переменную внутри класса, можно добавить к значению переменной флаг !global

$primaryColor: #eeccff;

body {
  $primaryColor: #ccc !global;
  background: $primaryColor;
}

p {
  color: $primaryColor;
}

// После компиляции у абзаца p цвет будет #ccc

Есть еще один флаг !default, который позволяет явно задать значение переменных по умолчанию.

Математика

В отличии от css, sass позволяет производить математические вычисления при задании свойств селекторам.

Поддерживаемые операции:

+ Складывание
Вычитание
/ Деление
* Умножение
% Остаток от деления
== Равенство
!= Неравенство

Сразу скажу о «подводных камнях» при работе с математическими символами.

Во-первых символ деления / встречается при задании шрифта font: 14px/16px , и этот символ по умолчанию не обрабатывается как математический между строчными значениями. Для того что бы делить строчные значения их необходимо оборачивать круглыми скобками.

$fontDiff: (14px/16px);

Во-вторых вы не можете смешивать размерности при математических операциях.

//Так нельзя
$container-width: 100% - 20px;

Для обработки примера выше необходимо использовать css свойство calc, так как вычисления должны происходить в момент рендеринга, а не в момент компиляции.

Пример использования математических операций:

$container-width: 100%;

.container {
  width: $container-width;
}

.col-4 {
  width: $container-width / 4;
}

//  Скомпилируется в:
//  .container {
//   width: 100%;
//  }
//
//  .col-4 {
//      width: 25%;
//  }

 Функции

В sass есть множество стандартных функций, со списком которых можно ознакомиться тут.

Например при использовании функции darken() можно в одну строку задать фон при наведении для кнопки, без подбора цветов в photoshop или в вашей IDE.

$awesome-blue: #2196F3;
 
a {
  padding: 10 15px;
  background-color: $awesome-blue;
}
 
a:hover {
  background-color: darken($awesome-blue,10%);
}

//Скомпилируется в:
//a {
//  padding: 10 15px;
//  background-color: #2196F3; 
//}
// 
//a:hover {
//  background-color: #0c7cd5; 
//}

Вложенность

Наверное самое полезной и удобной фичей в sass является вложенность. Классы можно вкладывать внутрь других классов сохраняя древовидную структуру как в html. С таким функционалом появляются огромные возможности.

Для понимания, обычно в css что бы задать свойства элемента находящегося внутри родителя мы задаем селектор таким образом:

.container {
    width: 100%;
}
.container h1 {
    color: red;
}

В sass же этот же код можно записать так:

.container {
    width: 100%;
    h1 {
        color: red;
    }
}

Правда же здорово? Но для полной гибкости вложенности существует оператор & , который позволяет обращаться к родителю.

a.myAnchor {
    color: blue;
    &:hover { //скомпилируется как a.myAnchor:hover
        text-decoration: underline;
    }
    &:visited { //скомпилируется как a.myAnchor:visited
        color: purple;
    }
}

Также есть оператор @at-root, который скомпилирует дальнейший код на уровень выше. То есть на ровне с родителем.

.first-component {
    .text { font-size: 1.4rem; }
    .button { font-size: 1.7rem; }
    @at-root .second-component {
        .text { font-size: 1.2rem; }
        .button { font-size: 1.4rem; }
    }
}

после компиляции css будет выглядеть так:

.first-component .text {
  font-size: 1.4rem;
}
.first-component .button {
  font-size: 1.7rem;
}
.second-component .text {
  font-size: 1.2rem;
}
.second-component .button {
  font-size: 1.4rem;
}

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

Не используйте больше 4 уровней вложенности в sass.

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

Импортирование

Импортирование в sass позволяет разбивать файл стилей на несколько логических файлов, которые в дальнейшем будут склеены в один с помощью директивы @import.

@import "part/grids.scss";

По факту вам даже необязательно нужно указывать формат файла.

@import "part/grids";

Если имя файла будет начинаться с нижнего подчеркивания _partial.scss, то он будет выполнен, но на выходе файл css не выдаст. Так обычно называют все файлы scss, которые будут импортироваться в главном файле, что бы выполниться они выполнились, но побочных файлов css не создали.

Наследование

В sass директива @extend позволяет наследовать стили другого класса, заданного ранее.
Например у вас есть стили input, а вам необходимо стилизовать похожий input, но модифицированный.

.input {
  border-radius: 3px;
  border: 4px solid #ddd;
  color: #555;
  font-size: 17px;
  padding: 10px 20px;
  display: inline-block;
  outline: 0;
}

.error-input {
  @extend .input;
  border:4px solid #e74c3c;
}

Обращу внимание, что данная директива не дублирует стили предыдущего класса, а дописывает текущий селектор через запятую к первому. Итоговый css будет выглядеть так:

.input, .error-input {
  border-radius: 3px;
  border: 4px solid #ddd;
  color: #555;
  font-size: 17px;
  padding: 10px 20px;
  display: inline-block;
  outline: 0;
}

.error-input {
  border: 4px solid #e74c3c;
}

Но что если мы хотим прописать так сказать шаблон, для еще не существующего класса? Для этого нужно использовать символ % вместо точки перед именем класса.

%input-style {
    font-size: 14px;
}

input {
    @extend %input-style;
    color: black;
}

При использовании символа %, код не будет скомпилирован в css сам по себе, а лишь в классе-наследнике.

Миксины

Директива миксинов в sass невероятно полезна, она по сути выполняет схожий функционал как и @extend, только выполняя при этом функцию, в которую можно передать параметры.

Sass использует директиву @mixin для задание функции миксина и директиву @include для использования миксина.

Давайте для примера создадим миксин, который будет задавать media queries для респонсива.

Первым шагом будет определение миксина:

@mixin media($queryString){

}

В дальнейшем мы будем вызывать миксин media и передавать в нем аргумент $queryString
Внутри миксина мы можем использовать аргумент, динамически передавая в нем различные параметры.

@mixin media($queryString){
    @media #{$queryString} {
      @content;
    }
}

Так как мы хотим, что бы строка, которая передается в аргументе функции выполнялась как код, её необходимо обернуть в #{}.
Вторым кусочком пазла является директива @content, когда миксином оборачиваются стили, то они будут доступны через директиву @content.

Вот как будет выглядеть вызов миксина:

.container {
    width: 900px;
    @include media("(max-width: 767px)"){
        width: 100%;
    }
}

Директива функции

С помощью директивы @function можно создавать функции похожие на миксины, разница только в том, что такие функции отдают не стили, а итоговое значение директивой @return.

@function getColumnWidth($width, $columns,$margin){
    @return ($width / $columns) - ($margin * 2);
}

Теперь мы можем использовать данную функцию в коде ниже:

$container-width: 100%;
$column-count: 4;
$margin: 1%;

.container {
  width: $container-width;
}

.column {
  background: #1abc9c;
  height: 200px;
  display: block;
  float: left;
  width: getColumnWidth($container-width,$column-count,$margin);
  margin: 0 $margin;
}

Не дурно, да?

Демо

Теперь на основе полученных знаний мы построим собственную настраиваемую сетку с responsive design.

Прежде всего зададим карту настроек сетки:

$settings: (
    maxWidth: 800px,
    columns: 12,
    margin: 15px,
    breakpoints: (
        xs: "(max-width : 480px)",
        sm: "(max-width : 768px) and (min-width: 481px)",
        md: "(max-width : 1024px)  and (min-width: 769px)",
        lg: "(min-width : 1025px)"
    )   
);

Теперь объявим миксин, который будет генерировать нашу сетку.

@mixin renderGridStyles($settings){

}

Так как целью является построить сетку для всех  media queries, то мы сделаем цикл, который будет пробегаться по всем @each значениям карты настроек, которую мы будем считывать с помощью директивы map-get.

@mixin renderGridStyles($settings){
  $breakpoints: map-get($settings, "breakpoints");
  @each $key, $breakpoint in $breakpoints {
    @include media($breakpoint) {
      
    }
  }
}

Нам нужно создать сетку с колонками используя цикл. Для этого создадим еще один миксин renderGrid. С помощью map-get мы получим нужные значения, а с помощью директивы @while пройдемся по ним. Для динамического создания имен классов колонок будем использовать итератор $i.

@mixin renderGrid($key, $settings) {
  $i: 1;
  @while $i <= map-get($settings, "columns") {
    .col-#{$key}-#{$i} {
      float: left;
      width: 100% * $i / map-get($settings,"columns");
    }
    $i: $i+1;
  }
}

Теперь создадим контейнер для рядов нашей сетки:

.container {
    padding-right: map-get($settings, "margin");
    padding-left: map-get($settings, "margin");
    margin-right: auto;
    margin-left: auto;
}

.row {
    margin-right: map-get($settings, "margin") * -1;
    margin-left: map-get($settings, "margin") * -1;
}

Все готово! Мы создали 12-ти колончатую сетку с поддержкой отзывчивого дизайна, которую легко можно изменять с помощью карты настроек.

Данная статья является вступительной, в дальнейшем я опубликую подробнее о синтаксисе sass, архитектуре стилей для крупных проектов и многое другое. Так что подписывайтесь на мой блог и будете в курсе новых публикаций.

Подписаться на блог по эл. почте