Статьи

Sass vs. LESS vs. Stylus: Перестрелка препроцессора

Владение истинной силой препроцессора CSS — это приключение. Существует множество языков, синтаксисов и функций, и все они готовы к использованию прямо сейчас .

В этой статье мы рассмотрим различные функции и преимущества использования трех разных препроцессоров — Sass , LESS и Stylus .


Препроцессоры создают CSS, который работает во всех браузерах.

Препроцессоры CSS3 — это языки, написанные с единственной целью добавления интересных и изобретательных функций в CSS без нарушения совместимости браузера. Они делают это путем компиляции кода, который мы пишем, в обычный CSS, который можно использовать в любом браузере вплоть до каменного века. Существуют тысячи функций, которые препроцессоры вносят в таблицу, и в этой статье мы расскажем о некоторых из опубликованных, а также о некоторых из них, которые не были опубликованы. Давайте начнем.


Наиболее важной частью написания кода в препроцессоре CSS является понимание синтаксиса. К счастью для нас, синтаксис (или может быть) идентичен обычному CSS для всех трех препроцессоров.

Sass и LESS используют стандартный синтаксис CSS. Это делает чрезвычайно простым преобразование существующего файла CSS в любой препроцессор. Sass использует расширение .scss а LESS — расширение .scss . Базовый файл Sass или LESS можно настроить, как показано ниже:

1
2
3
4
/* style.scss or style.less */
h1 {
  color: #0982C1;
}

Как вы могли заметить, это обычный CSS, который прекрасно компилируется как в Sass, так и в LESS.

Важно отметить, что Sass также имеет более старый синтаксис, в котором пропущены точки с запятой и фигурные скобки. Хотя это все еще существует, оно устарело, и мы не будем использовать его в этом примере. Синтаксис использует .sass файла .sass и выглядит так:

1
2
3
/* style.sass */
h1
  color: #0982c1

Синтаксис стилуса гораздо более многословен. Используя .styl файла .styl , Stylus принимает стандартный синтаксис CSS, но он также принимает некоторые другие варианты, где скобки, двоеточия и точки с запятой являются необязательными. Например:

01
02
03
04
05
06
07
08
09
10
11
12
/* style.styl */
h1 {
  color: #0982C1;
}
 
/* omit brackets */
h1
  color: #0982C1;
 
/* omit colons and semi-colons */
h1
  color #0982C1

Использование разных вариантов в одной и той же таблице стилей также допустимо, поэтому следующее будет скомпилировано без ошибок.

1
2
3
4
5
h1 {
  color #0982c1
}
h2
  font-size: 1.2em

Переменные могут быть объявлены и использованы по всей таблице стилей. Они могут иметь любое значение, которое является значением CSS (например, цвета, числа [включенные единицы] или текст). На них можно ссылаться в любом месте нашей таблицы стилей.

К переменным Sass добавляется символ $ а значение и имя разделяются точкой с запятой, как и свойство CSS.

1
2
3
4
5
6
7
8
9
$mainColor: #0982c1;
$siteWidth: 1024px;
$borderStyle: dotted;
 
body {
  color: $mainColor;
  border: 1px $borderStyle $mainColor;
  max-width: $siteWidth;
}

Переменные LESS точно такие же, как переменные Sass, за исключением того, что к именам переменных добавляется символ @ .

1
2
3
4
5
6
7
8
9
@mainColor: #0982c1;
@siteWidth: 1024px;
@borderStyle: dotted;
 
body {
  color: @mainColor;
  border: 1px @borderStyle @mainColor;
  max-width: @siteWidth;
}

Переменные стилуса не требуют ничего перед ними, хотя они допускают использование символа $ . Как всегда, конечная точка с запятой не обязательна, но знак равенства между значением и переменной является. Стоит отметить, что Stylus (0.22.4) компилируется, если мы добавляем символ @ к имени переменной, но не применяем значение при обращении к нему. Другими словами, не делай этого.

1
2
3
4
5
6
7
8
mainColor = #0982c1
siteWidth = 1024px
$borderStyle = dotted
 
body
  color mainColor
  border 1px $borderStyle mainColor
  max-width siteWidth

Каждый из вышеуказанных файлов будет компилироваться в один и тот же CSS. Вы можете использовать свое воображение, чтобы увидеть, насколько полезными могут быть переменные. Нам больше не нужно будет менять один цвет, и нам придется двадцать раз его набирать, или мы хотим изменить ширину нашего сайта, и нам придется покопаться, чтобы найти его. Вот CSS после компиляции:

1
2
3
4
5
body {
  color: #0982c1;
  border: 1px dotted #0982c1;
  max-width: 1024px;
}

Если нам нужно ссылаться на несколько элементов с одним и тем же родителем в нашем CSS, может быть утомительно продолжать писать родителя снова и снова.

01
02
03
04
05
06
07
08
09
10
11
12
section {
  margin: 10px;
}
section nav {
  height: 25px;
}
section nav a {
  color: #0982C1;
}
section nav a:hover {
  text-decoration: underline;
}

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

Все три препроцессора имеют одинаковый синтаксис для вложенных селекторов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
section {
  margin: 10px;
 
  nav {
    height: 25px;
 
    a {
      color: #0982C1;
   
      &:hover {
        text-decoration: underline;
      }
    }
  }
}

Это скомпилированный CSS из кода выше. Это точно так же, как когда мы начинали — как удобно!

01
02
03
04
05
06
07
08
09
10
11
12
section {
  margin: 10px;
}
section nav {
  height: 25px;
}
section nav a {
  color: #0982C1;
}
section nav a:hover {
  text-decoration: underline;
}

Миксины — это функции, которые позволяют повторно использовать свойства в нашей таблице стилей. Вместо того, чтобы просматривать нашу таблицу стилей и менять свойство несколько раз, теперь мы можем просто изменить его в нашем миксине. Это может быть очень полезно для определения стиля элементов и префиксов поставщиков. Когда миксины вызываются из селектора CSS, аргументы миксина распознаются, и стили внутри миксина применяются к селектору.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
/* Sass mixin error with (optional) argument $borderWidth which defaults to 2px if not specified */
@mixin error($borderWidth: 2px) {
  border: $borderWidth solid #F00;
  color: #F00;
}
 
.generic-error {
  padding: 20px;
  margin: 4px;
  @include error();
}
.login-error {
  left: 12px;
  position: absolute;
  top: 20px;
  @include error(5px);
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
/* LESS mixin error with (optional) argument @borderWidth which defaults to 2px if not specified */
.error(@borderWidth: 2px) {
  border: @borderWidth solid #F00;
  color: #F00;
}
 
.generic-error {
  padding: 20px;
  margin: 4px;
  .error();
}
.login-error {
  left: 12px;
  position: absolute;
  top: 20px;
  .error(5px);
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
/* Stylus mixin error with (optional) argument borderWidth which defaults to 2px if not specified */
error(borderWidth= 2px) {
  border: borderWidth solid #F00;
  color: #F00;
}
 
.generic-error {
  padding: 20px;
  margin: 4px;
  error();
}
.login-error {
  left: 12px;
  position: absolute;
  top: 20px;
  error(5px);
}

Все препроцессоры компилируются в один и тот же код ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
.generic-error {
  padding: 20px;
  margin: 4px;
  border: 2px solid #f00;
  color: #f00;
}
.login-error {
  left: 12px;
  position: absolute;
  top: 20px;
  border: 5px solid #f00;
  color: #f00;
}

При написании CSS старомодным способом, мы могли бы использовать следующий код, чтобы применить одинаковые стили к нескольким элементам одновременно:

1
2
3
4
5
p,
ul,
ol {
  /* styles here */
}

Это прекрасно работает, но если нам нужно дополнительно стилизовать элементы по отдельности, для каждого из них должен быть создан другой селектор, и он может быстро запутаться и сложнее в обслуживании. Чтобы противостоять этому, наследование может быть использовано. Наследование — это способность других селекторов CSS наследовать свойства другого селектора.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
.block {
  margin: 10px 5px;
  padding: 2px;
}
 
p {
  @extend .block;
  border: 1px solid #EEE;
}
ul, ol {
  @extend .block;
  color: #333;
  text-transform: uppercase;
}
01
02
03
04
05
06
07
08
09
10
11
.block, p, ul, ol {
  margin: 10px 5px;
  padding: 2px;
}
p {
  border: 1px solid #EEE;
}
ul, ol {
  color: #333;
  text-transform: uppercase;
}

LESS не поддерживает наследование стилей, таких как Sass и Stylus. Вместо добавления нескольких селекторов в один набор свойств он обрабатывает наследование как миксин без аргументов и импортирует стили в свои собственные селекторы. Недостатком этого является то, что свойства повторяются в вашей скомпилированной таблице стилей. Вот как вы бы это настроили:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
.block {
  margin: 10px 5px;
  padding: 2px;
}
 
p {
  .block;
  border: 1px solid #EEE;
}
ul, ol {
  .block;
  color: #333;
  text-transform: uppercase;
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
.block {
  margin: 10px 5px;
  padding: 2px;
}
p {
  margin: 10px 5px;
  padding: 2px;
  border: 1px solid #EEE;
}
ul,
ol {
  margin: 10px 5px;
  padding: 2px;
  color: #333;
  text-transform: uppercase;
}

Как видите, стили из .block были вставлены в селекторы, которым мы хотели передать наследование. Важно отметить, что приоритет может стать проблемой здесь, поэтому будьте осторожны.


В сообществе CSS импорт CSS не одобряется, поскольку он требует нескольких HTTP-запросов. Однако импорт с препроцессором работает иначе. Если вы импортируете файл из любого из трех препроцессоров, он будет буквально включать импорт во время компиляции, создавая только один файл. Имейте в виду, что при импорте обычных файлов .css по умолчанию используется @import "file.css"; код. Кроме того, миксины и переменные могут быть импортированы и использованы в вашей основной таблице стилей. Импорт делает создание отдельных файлов для организации очень полезным.

1
2
3
4
/* file.{type} */
body {
  background: #EEE;
}
1
2
3
4
5
6
@import «reset.css»;
@import «file.{type}»;
 
p {
  background: #0982C1;
}
1
2
3
4
5
6
7
@import «reset.css»;
body {
  background: #EEE;
}
p {
  background: #0982C1;
}

Цветовые функции встроены в функции, которые преобразуют цвет при компиляции. Это может быть чрезвычайно полезно для создания градиентов, темных цветов при наведении и многого другого.

01
02
03
04
05
06
07
08
09
10
11
lighten($color, 10%);
darken($color, 10%);
 
saturate($color, 10%);
desaturate($color, 10%);
 
grayscale($color);
complement($color);
invert($color);
 
mix($color1, $color2, 50%);

Это только краткий список доступных цветовых функций в Sass, полный список доступных цветовых функций Sass можно найти, прочитав документацию Sass .

Цветовые функции можно использовать везде, где цвет является допустимым CSS. Вот пример:

1
2
3
4
5
6
$color: #0982C1;
 
h1 {
  background: $color;
  border: 3px solid darken($color, 50%);
}
01
02
03
04
05
06
07
08
09
10
lighten(@color, 10%);
darken(@color, 10%);
 
saturate(@color, 10%);
desaturate(@color, 10%);
 
spin(@color, 10);
spin(@color, -10);
 
mix(@color1, @color2);

Список всех функций LESS можно найти, прочитав документацию LESS .

Вот пример того, как использовать функцию цвета в LESS:

1
2
3
4
5
6
@color: #0982C1;
 
h1 {
  background: @color;
  border: 3px solid darken(@color, 50%);
}
1
2
3
4
5
lighten(color, 10%);
darken(color, 10%);
 
saturate(color, 10%);
desaturate(color, 10%);

Полный список всех цветовых функций стилуса можно найти, прочитав документацию по стилусу .

Вот пример использования цветовых функций Stylus:

1
2
3
4
5
color = #0982C1
 
h1
  background color
  border 3px solid darken(color, 50%)

Делать математику в CSS довольно полезно, и теперь вполне возможно. Это просто, и вот как это сделать:

1
2
3
4
5
6
body {
  margin: (14px/2);
  top: 50px + 100px;
  right: 100px — 50px;
  left: 10 * 10;
}

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

Это одна из распространенных причин использования препроцессора, и по очень веской причине — это экономит массу времени и слез. Создать миксин для обработки префиксов вендоров легко и экономит много повторений и болезненного редактирования. Вот как это сделать:

1
2
3
4
5
6
7
8
9
@mixin border-radius($values) {
  -webkit-border-radius: $values;
     -moz-border-radius: $values;
          border-radius: $values;
}
 
div {
  @include border-radius(10px);
}
1
2
3
4
5
6
7
8
9
.border-radius(@values) {
  -webkit-border-radius: @values;
     -moz-border-radius: @values;
          border-radius: @values;
}
 
div {
  .border-radius(10px);
}
1
2
3
4
5
6
7
8
9
border-radius(values) {
  -webkit-border-radius: values;
     -moz-border-radius: values;
          border-radius: values;
}
 
div {
  border-radius(10px);
}
1
2
3
4
5
div {
  -webkit-border-radius: 10px;
     -moz-border-radius: 10px;
          border-radius: 10px;
}

Подделка 3D текста с использованием нескольких text-shadows — умная идея. Единственная проблема заключается в том, что изменение цвета после факта является сложным и громоздким. Используя миксины и цветовые функции, мы можем создавать 3D-текст и менять цвет на лету!

01
02
03
04
05
06
07
08
09
10
11
12
13
@mixin text3d($color) {
  color: $color;
  text-shadow: 1px 1px 0px darken($color, 5%),
               2px 2px 0px darken($color, 10%),
               3px 3px 0px darken($color, 15%),
               4px 4px 0px darken($color, 20%),
               4px 4px 2px #000;
}
 
h1 {
  font-size: 32pt;
  @include text3d(#0982c1);
}
01
02
03
04
05
06
07
08
09
10
11
12
13
.text3d(@color) {
  color: @color;
  text-shadow: 1px 1px 0px darken(@color, 5%),
               2px 2px 0px darken(@color, 10%),
               3px 3px 0px darken(@color, 15%),
               4px 4px 0px darken(@color, 20%),
               4px 4px 2px #000;
}
 
span {
  font-size: 32pt;
  .text3d(#0982c1);
}
1
2
3
4
5
6
text3d(color)
  color: color
  text-shadow: 1px 1px 0px darken(color, 5%), 2px 2px 0px darken(color, 10%), 3px 3px 0px darken(color, 15%), 4px 4px 0px darken(color, 20%), 4px 4px 2px #000
span
  font-size: 32pt
  text3d(#0982c1)

Я решил написать text-shadows в одну строку, потому что опускал фигурные скобки.

1
2
3
4
5
6
7
8
9
span {
  font-size: 32pt;
  color: #0982c1;
  text-shadow: 1px 1px 0px #097bb7,
               2px 2px 0px #0875ae,
               3px 3px 0px #086fa4,
               4px 4px 0px #07689a,
               4px 4px 2px #000;
}

Использование числовых операций и переменных для столбцов — идея, с которой я столкнулся, когда впервые играл с CSS-препроцессорами. Объявляя желаемую ширину в переменной, мы можем легко изменить ее в будущем без какой-либо умственной математики. Вот как это делается:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
$siteWidth: 1024px;
$gutterWidth: 20px;
$sidebarWidth: 300px;
 
body {
  margin: 0 auto;
  width: $siteWidth;
}
.content {
  float: left;
  width: $siteWidth — ($sidebarWidth+$gutterWidth);
}
.sidebar {
  float: left;
  margin-left: $gutterWidth;
  width: $sidebarWidth;
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
@siteWidth: 1024px;
@gutterWidth: 20px;
@sidebarWidth: 300px;
 
body {
  margin: 0 auto;
  width: @siteWidth;
}
.content {
  float: left;
  width: @siteWidth — (@sidebarWidth+@gutterWidth);
}
.sidebar {
  float: left;
  margin-left: @gutterWidth;
  width: @sidebarWidth;
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
siteWidth = 1024px;
gutterWidth = 20px;
sidebarWidth = 300px;
 
body {
  margin: 0 auto;
  width: siteWidth;
}
.content {
  float: left;
  width: siteWidth — (sidebarWidth+gutterWidth);
}
.sidebar {
  float: left;
  margin-left: gutterWidth;
  width: sidebarWidth;
}
01
02
03
04
05
06
07
08
09
10
11
12
13
body {
  margin: 0 auto;
  width: 1024px;
}
.content {
  float: left;
  width: 704px;
}
.sidebar {
  float: left;
  margin-left: 20px;
  width: 300px;
}

Использование препроцессора CSS довольно часто. Я расскажу о нескольких забавных, но если вы действительно заинтересованы в их поиске, я рекомендую вам изучить документацию или, что еще лучше, просто начать использовать препроцессор в повседневной работе.

Если вы писали CSS в течение какого-то приличного количества времени, я уверен, что вы достигли точки, где у вас была ошибка где-то и вы просто не смогли ее найти. Если вы чем-то похожи на меня, вы, вероятно, потратили день на то, чтобы вычесать волосы и комментировать различные вещи, чтобы выследить ошибку.

CSS препроцессоры сообщают об ошибках. Это так просто. Если с вашим кодом что-то не так, он говорит вам, где и если вам повезет: почему. Вы можете проверить это сообщение в блоге, если вам интересно узнать, как сообщается об ошибках в разных препроцессорах.

При компиляции с CSS-препроцессором любой комментарий с двойной косой чертой удаляется (например, //comment ), а любой комментарий с косой чертой остается (например, /* comment */ ). При этом используйте двойную косую черту для комментариев, которые вы хотите на некомпилированной стороне, и косую черту для комментариев, которые вы хотите видеть после компиляции.

Просто примечание: если вы компилируете minified, все комментарии удаляются.


Каждый CSS-препроцессор, который мы рассмотрели (Sass, LESS и Stylus), имеет свой собственный уникальный способ решения той же задачи, предоставляя разработчикам возможность использовать полезные, неподдерживаемые функции, сохраняя совместимость браузера и чистоту кода.

Хотя препроцессоры не являются обязательными для разработки, они могут сэкономить много времени и обладают некоторыми очень полезными функциями.

Я призываю вас всех попробовать как можно больше препроцессоров, чтобы вы могли эффективно выбирать любимый и знать, почему он предпочтительнее многих других. Если вы еще не пытались использовать препроцессор для написания своего CSS, я настоятельно рекомендую вам попробовать.

У вас есть любимая функция препроцессора CSS, которую я не упомянул? Есть ли что-то, что можно сделать, а что нет? Дайте нам знать в комментариях ниже!

Особая благодарность Кариссе Смит , моей талантливой подруге, которая создала миниатюру предварительного просмотра для этой статьи.