Stylus - препроцессор CSS
Знакомимся со Stylus - синтаксис и базовые возможности
В одной из предыдущих статей мы установили и запустили Gulp
В предыдущей статье рассмотрели первый инструмент для ускорения процесса верстки - Pug
Второй инструмент для ускорения процесса верстки - Stylus
Что такое Stylus?
Stylus - препроцессор CSS - имеет свой синтаксис и может быть сгенерирован в CSS
Существует несколько популярных препроцессоров CSS - Sass (Scss), Less, Stylus
Stylus наименее популярный среди них, но я выбрал именно его. По возможностям, которые я использую, Stylus не уступает остальным. Но, так как предпочитаю минимализм во всем, то для меня синтаксис Stylus оказался самым комфортным из всех вышеперечисленных
Как и другие препроцессоры, Stylus имеет много преимуществ над обычным CSS - переменные, миксины, операторы, функции, импорты и так далее. В статье расскажу о базовых возможностях, которые очень упрощают и ускоряют написание стилей
Синтаксис Stylus
Сравним CSS и Stylus - слева синтаксис Stylus, справа синтаксис CSS
Пример на Codepen
Визуальные отличия от синтаксиса CSS
- Не нужны фигурные скобки
- Не нужны точки с запятой после каждого свойства
- Не нужны двоеточия после названия свойства
Тем не менее Stylus воспринимает обычный синтаксис CSS, то есть рядом с синтаксисом Stylus можно вставить обычный CSS
Логические отличия от синтаксиса CSS
- Вложенность селекторов осуществляется через отступ Tab
- Возможность зависимости от названия родительского класса
Пример 1: Стилизуем ненумерованный список
На CSS это выглядит следующим образом
CSS
ul {
padding: 0;
margin: 0;
}
ul li {
list-style: none;
}
ul li a {
font-size: 18px;
text-decoration: underline;
}
Чтобы не писать цепочку селекторов от родительского до дочернего, в Stylus используем отступы Tab
Stylus
ul
padding 0
margin 0
li // генерируется селектор ul li
list-style none
a // генерируется селектор ul li a
font-size 18px
text-decoration underline
Пример 2: Стилизуем навигацию
CSS
.nav {
background: #fafafa;
}
.nav__flex {
display: flex;
}
.nav__item {
background: #fff;
}
.nav__item:not(:last-child) {
margin-right: 30px;
}
.nav__item a {
font-size: 18px;
text-transform: uppercase;
text-decoration: underline;
color: #0d3b66;
}
.nav__item a:hover {
text-decoration: none;
}
.nav__item_active {
background: #0d3b66;
}
.nav__item_active a {
color: #fff;
}
Если в обычном CSS решим переименовать родительский селектор .nav
в .navigation
, то необходимо будет искать все селекторы, которые зависят от него, и каждый переименовывать вручную.
В Stylus существует специальный служебный символ - &
, который указывает на родительский селектор.
Stylus
.nav
background #fafafa
&__flex // генерируется селектор .nav__flex (Элемент по методологии БЭМ)
display flex
&__item // генерируется селектор .nav__item (Элемент по методологии БЭМ)
background #fff
&:not(:last-child) // .nav__item:not(:last-child)
margin-right 30px
a // .nav__item a
font-size 18px
text-transform uppercase
text-decoration underline
color #0D3B66
&:hover // .nav__item a:hover
text-decoration none
&_active // генерируется селектор .nav__item_active (Модификатор по методологии БЭМ)
background #0D3B66
a // .nav__item_active a
color #fff
Если в Stylus решим переименовать родительский селектор .nav
в .navigation
, то нужно будет переименовать только его, а так как дочерние селекторы зависят от наименования родительского селектора, то будут переименованы автоматически
Дополнительные возможности
Переменные
Переменные объявляются следующим образом - название_переменной = значение переменной
. Название переменной может состоять просто из слова на английском языке, но предпочитаю имена переменных начинать со знака $
, чтобы не было пересечений с CSS свойствами и визуально было легче воспринимать переменные в файле стилей
Значением переменной может быть любое значение CSS-свойства, например - цвет, размер шрифта, размер отступа и так далее.
$main = #0D3B66
$second = #FF5964
$title-size = 48px
$padding = 30px
Используем объявленные переменные
$main = #0D3B66
$second = #FF5964
$title-size = 48px
$padding = 30px
body
background $main // генерируется background: #0d3b66;
.section
&__body
padding $padding // генерируется padding: 30px;
&__title
color $second // генерируется color: #ff5964;
font-size $title-size // генерируется font-size: 48px;
Будут сгенерированы следующие CSS стили
body {
background: #0d3b66;
}
.section__body {
padding: 30px;
}
.section__title {
color: #ff5964;
font-size: 48px;
}
Миксины
Миксины позволяют писать намного меньше стилей вручную. Они могут содержать в себе целый блок свойств, которые при верстке повторяются неоднократно, а также при необходимости принимать параметры
Объявление миксинов - название_миксина(параметр, параметр)
, и на следующей строке после отступа Tab указываем свойство или несколько свойств (каждое свойство на отдельной строке)
// Плавный переход из одного состояния элемента в другое
tr()
transition all .3s ease
// Масштабируем изображение на всю область родительского элемента
fit()
display block
width 100%
height 100%
object-fit cover
Используем объявленные миксины
tr()
transition all .3s ease
fit()
display block
width 100%
height 100%
object-fit cover
a
color red
tr() // генерируется свойство transition: all .3s ease;
&:hover
color blue
.image
width 400px
height 300px
img
fit() // генерируются все свойства, которые прописаны в миксине fit()
Сгенерированный CSS
a {
color: #f00;
transition: all 0.3s ease;
}
a:hover {
color: #00f;
}
.image {
width: 400px;
height: 300px;
}
.image img {
display: block;
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
}
Также в миксинах можно передавать параметры. Название параметра может быть произвольным словом на английском языке
tr(duration) // duration - продолжительность
transition all duration ease
a
color red
tr(.5s) // генерируется свойство transition: all 0.5s ease;
&:hover
color blue
Сгененированный CSS
a {
color: #f00;
transition: all 0.5s ease;
}
a:hover {
color: #00f;
}
Можно передавать несколько параметров через запятую
tr(prop, duration) // prop - свойство, для которого будем применять плавный переход, duration - продолжительность
transition prop duration ease
a
color red
tr(color,.5s) // генерируется свойство transition: color 0.5s ease;
&:hover
color blue
Сгененированный CSS
a {
color: #f00;
transition: color 0.5s ease;
}
a:hover {
color: #00f;
}
Можно передавать параметры без указания единиц измерения, а единицы измерения указать внутри миксина
tr(duration) // duration - продолжительность
transition all (duration s) ease // в скобках на первом месте - параметр, на втором месте через пробел - единица измерения
fontSize(val)
font-size val em // если у свойства только одно значение, то можно писать без скобок - на первом месте - параметр, на втором месте через пробел - единица измерения
a
color red
fontSize(2) // генерируется свойство font-size: 2em;
tr(.5) // генерируется свойство transition: all 0.5s ease;
&:hover
color blue
Сгененированный CSS
a {
color: #f00;
font-size: 2em;
transition: all 0.5s ease;
}
a:hover {
color: #00f;
}
В миксинах можно использовать объявленные переменные и другие объявленные миксины
$main = #0D3B66
fontSize(val)
font-size val em
button()
fontSize(2)
color $main
a
button()
Из примера выше генерируется следующий CSS
a {
font-size: 2em;
color: #0d3b66;
}
За счет такой гибкости, можно настроить множество миксинов, с которыми вам будет комфортно работать
Пока приводил простые примеры, на которых проще понять принцип работы миксинов.
Рассмотрим пример посложнее - сделаем миксин кнопки
$main = #0D3B66
$second = #FF5964
tr()
transition all .3s ease
btn(height,fontSize) // принимаем два параметра - высота кнопки без единиц измерения, размер шрифта кнопки
height height px // подставляем значение параметра высоты и указываем единицу измерения - пиксели
font-size fontSize // подставляем значение параметра размера шрифта, параметр будет передаваться с единицами измерения
display inline-flex
align-items center
justify-content center
text-align center
text-decoration none
text-transform uppercase
font-weight bold
color $second // подставляем значение переменной $second
background $main // подставляем значение переменной $main
padding 0 (height px) // внутренние боковые отступы будут равняться высоте, подставляем значение параметра высоты
border-radius (height/2) px // используем оператор деления чтобы высчитать закругление углов (о них чуть позже)
tr() // вызываем миксин плавного перехода tr() который сгенерирует transition: all 0.3s ease;
&:hover
background lighten($main,10%) // используем встроенную функцию lighten(), чтобы при наведении фон кнопки становился чуть светлее
// Теперь используя миксин btn(height,fontSize) можем создавать шаблонные кнопки одной строкой, введя только два параметра - высоты и размера шрифта
a.button-large
btn(48,18px)
a.button-small
btn(30, .7rem)
Данный миксин можно будет использовать во всем проекте при создании любого количества кнопок, передавая только необходимые параметры. Миксин можно настроить максимально гибко, передавая и другие параметры, например цвет фона, цвет текста, закругление углов и так далее
В итоге будет сгенерирован следующий CSS
a.button-large {
height: 48px;
font-size: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
text-align: center;
text-decoration: none;
text-transform: uppercase;
font-weight: bold;
color: #ff5964;
background: #0d3b66;
padding: 0 48px;
border-radius: 24px;
transition: all 0.3s ease;
}
a.button-large:hover {
background: #114f89;
}
a.button-small {
height: 30px;
font-size: 0.7rem;
display: inline-flex;
align-items: center;
justify-content: center;
text-align: center;
text-decoration: none;
text-transform: uppercase;
font-weight: bold;
color: #ff5964;
background: #0d3b66;
padding: 0 30px;
border-radius: 15px;
transition: all 0.3s ease;
}
a.button-small:hover {
background: #114f89;
}
Пример на Codepen
Операторы Stylus
Stylus имеет самые различные операторы для вычислений - сложение, вычитание, деление, умножение, отрицание, сравнение, логические операторы и так далее. Все перечислять не буду, покажу пару примеров, как их можно использовать
Если межстрочный интервал line-height в макете указан в пикселях, а в CSS наиболее корректно указывать его относительное значение в зависимости от размера шрифта, то с помощью оператора деления можно быстро вычислить относительное значение - значение межстрочного интервала делим на значение размера шрифта.
Расчеты желательно производить в круглых скобках
p
font-size 18px
line-height (30/18) // например, в макете line-height равен 30px
p.accent
font-size 36px
line-height (48/36) // например, в макете line-height равен 48px
Сгененированный CSS
p {
font-size: 18px;
line-height: 1.666666666666667;
}
p.accent {
font-size: 36px;
line-height: 1.333333333333333;
}
Операторы удобно использовать в миксинах для динамически вычисляемых значений
btn(height)
height height px
font-size (height / 2) px // размер шрифта будет в два раза меньше высоты
padding 0 ((height + 15) px) // размер внутренних бокобых отступов будет суммой значения высоты + 15px
border-radius (height / 2) px // каждый угол будет закруглен ровно на половину от значения высоты
a.button-large
btn(100) // задаем кнопку высотой 100, остальные значения для свойств расчитываются автоматически
Сгененированный CSS
a.button-large {
height: 100px;
font-size: 50px;
padding: 0 115px;
border-radius: 50px;
}
Встроенные функции Stylus
В Stylus большое количество встроенных функций. Рассмотрим некоторые из них
Встроенные функци round() и floor() для округления чисел.
В круглых скобках указываются параметры: первое значение - чаще всего результат деления, второе значение - количество знаков дробной части (после точки/запятой)
p
font-size 18px
line-height round(30/18, 3) // округляет до трех знаков дробной части в большую или меньшую сторону в зависимости от следующего знака дробной части
p.accent
font-size 36px
line-height floor(48/36, 2) // округляет в меньшую сторону до двух знаков дробной части
Сгененированный CSS
p {
font-size: 18px;
line-height: 1.667;
}
p.accent {
font-size: 36px;
line-height: 1.33;
}
Встроенные функции darken() и lighten() для вычисления цвета. Чаще всего применяется при вычислении цвета при наведении на элемент или выделении активного элемента.
В круглых скобках указываются параметры: первое значение - цвет, который будет преобразован, второе значение - насколько процентов цвет будет преобразован
$main = #0D3B66
.circle
background red
&:hover
background darken(red, 15%) // при наведении красный цвет фона становится на 15% темнее
.square
background $main
&:hover
background lighten($main, 20%) // при наведении цвет фона указанный в переменной $main становится на 20% светлее
Сгененированный CSS
.circle {
background: #f00;
}
.circle:hover {
background: #d90000;
}
.square {
background: #0d3b66;
}
.square:hover {
background: #14599b;
}
Импортирование файлов стилей
В больших проектах основной файл CSS становится довольно большим. На этапе разработки Stylus предоставляет возможность разбивать стили на отдельные фрагменты, сохранять их в отдельных *.styl файлах и подключать эти файлы в основной файл стилей
Рассмотрим простой пример - вынесем часть стилей для адаптивности в отдельный файл media.styl и импортируем его в основной файл стилей main.styl
main.styl
.container
max-width 1170px
margin 0 auto
padding 0 15px
@media (max-width: 1199.98px)
.container
max-width 920px
Создадим рядом с main.styl файл media.styl и перенесем в него часть стилей для адаптивности
media.styl
@media (max-width: 1199.98px)
.container
max-width 920px
Импортируем файл media.styl в основной файл стилей main.styl, для этого используем @import
.container
max-width 1170px
margin 0 auto
padding 0 15px
@import media
В итоге генерируется main.css включая стили прописанные в файле media.styl
.container {
max-width: 1170px;
margin: 0 auto;
padding: 0 15px;
}
@media (max-width: 1199.98px) {
.container {
max-width: 920px;
}
}
В больших проектах можно отдельно создавать и импортировать файлы для переменных, миксинов, даже определенных секций. Все это настраивается индивидуально для комфортной разработки в зависимости от задач
В шаблоне gulp-dev, который рассматривали в одной из предыдущих статей, в CSS генерируется только основной файл стилей main.styl (находится в папке app/styl/main.styl) в файл main.css (dist/css/main.css), любые другие *.styl файлы генерироваться не будут - они должны быть импортированы в основной файл main.styl
Возможные проблемы и их решения
Как и в случае с Pug, основная ошибка - это использование в отступах Пробелы вместо Tab. В качестве отступов можно использовать или только Пробелы или только Tab.
Решить эту проблему очень просто. В редакторе кода, в файле main.styl или в любом другом *.styl файле выделяем весь код сочетанием клавиш Ctrl+A и ищем настройку Tab size (в Sublime Text и VS Code справа внизу), нажимаем и выбираем пункт Convert Indentation to Tabs - все отступы конвентируются в Tab
Итоги
Stylus значительно ускоряет процесс верстки, за счет краткого, логичного и понятного синтаксиса, использования переменных, миксинов, операторов, встроенных функций, импортов и прочего. В статье рассмотрены только базовые возможности, но даже эти возможности экономят много времени
Итоговый CSS файл получается чистым, корректно сформатированым, где не будет разных отступов, пропущенных фигурных скобок, двоеточий и точек с запятой ;)
Полезные ссылки
Официальный сайт Stylus
Страница плагина gulp-stylus