Sass Guidelines
Руководство по написанию разумного, поддерживаемого и масштабируемого Sass.
You are viewing the Russian translation by Даниил Пронин, Pavel Demyanenko and Tim Arbaev of the original Sass Guidelines from Kitty Giraudel.
This version is exclusively maintained by contributors without the review of the main author, therefore might not be completely authentic.
Сотрудничество
Sass Guidelines – открытый проект, которым я руковожу в свободное время. Излишне говорить, что это довольно большой объем работы – держать всё задокументированным в последней версии. К счастью, мне помогает множество участников, особенно когда речь заходит о поддержании десятков разных переводов. Обязательно поблагодарите их!
Теперь, если вы чувстствуете, что готовы к сотрудничеству – пожалуйста, было бы здорово твитнуть, рассказать об этом или открыть Pull Request с исправлением ошибок в репозитории на GitHub!
Прежде, чем мы начнём: если вам понравился этот документ, или он оказался полезен вам или вашей команде, пожалуйста, подумайте о его поддержке, чтобы я мог продолжать работу над ним!
О Sass
Вот так Sass описывает сам себя в своей документации:
Sass — это расширение CSS, которое добавляет силу и элегантность к основному языку.
Основая цель Sass — исправить недостатки CSS. Как мы все знаем, это не самый лучший язык в мире [указать источник]. Являясь довольно простым для освоения, он может быстро стать запутанным, особенно на больших проектах.
Вот тут-то и вступает в свою роль Sass как метаязык, который улучшает синтаксис CSS, чтобы предоставить дополнительные возможности и удобные инструменты. Между тем, Sass остаётся консервативным в отношении языка CSS.
Цель не в том, чтобы превратить CSS в полнофункциональный язык программирования; Sass хочет лишь помочь там, где не справляется CSS. Поэтому начать использовать Sass – не сложнее, чем начать изучать CSS: он просто добавляет дополнительные возможности поверх CSS.
Есть много способов использовать эти возможности. Какие-то способы хороши, какие-то – не очень, а некоторые вообще необычные. Это руководство предназначено для того, чтобы дать последовательный и документированный подход для написания кода на Sass.
Ruby Sass или LibSass
Первый коммит в Sass был сделан в конце 2006, более 10 лет назад. Излишне говорить, что с тех пор проект прошёл долгий путь. Изначально разработанный на Ruby, он получил множество портов. Самый популяный – LibSass (написан на С/C++), сейчас близок к полной совместимости с оригинальной Ruby-версией.
В 2014 году команды Ruby Sass и LibSass решили подождать синхронизации версий, прежде чем двигаться дальше. С тех пор LibSass активно выпускает версии, чтобы догнать старшего брата. Последние оставшиеся несоответствия собраны и перечислены мной в проекте Sass-Compatibility. Если вы знаете о несовместимости между этими двумя версиями, которой нет в списке, пожалуйста, создайте соответствующий issue.
Вернёмся к выбору компилятора. На самом деле, всё зависит от вашего проекта. Если это Ruby on Rails, вам лучше использовать Ruby Sass, который идеально подходит для такого случая. Также следует помнить, что Ruby Sass — это эталонная реализация и всегда будет обгонять LibSass. А если вы хотите перейти c Ruby Sass на LibSass, то эта статья для вас.
В не-Ruby проектах, LibSass, вероятно, будет лучше, поскольку он в основном предназначем для интеграции. Так что, если вы хотите использовать, скажем, Node.js, node-sass — ваш выбор.
Sass или SCSS
Существует довольно много путаницы относительно семантики имени Sass, и не зря: Sass означает как препроцессор, так и свой собственный синтаксис. Не очень удобно, не так ли?
Как видите, Sass первоначально описал синтаксис, определяющей характеристикой которого является его чувствительность к вложености. Вскоре в Sass решили сократить разрыв между Sass и CSS, реализовав CSS-подобный синтаксис под названием SCSS или Sassy CSS. Девиз: “если это правильный CSS, то это правильный SCSS”.
С тех пор, Sass (препроцессор) предоставляет два различных синтаксиса: Sass (не все буквы заглавные, пожалуйста), также известный как синтаксис с отступами, и SCSS. Какой из них использовать, в значительной степени зависит от вас, так как оба строго равны по возможностям. Это лишь вопрос эстетики.
Cинтаксис Sass опирается на отступы, чтобы избавиться от скобок, точки с запятой и других символов пунктуации, что приводит к более компактному и более короткому синтаксису. Между тем, SCSS проще в обучении, так как он лишь дополняет CSS.
Лично я предпочитаю SCSS вместо Sass, потому что он близок к CSS и более дружелюбен для большинства разработчиков. Поэтому я буду использовать SCSS в этом руководстве. Вы можете переключиться на Sass-синтаксис .
Другие препроцессоры
Sass — это препроцессор, коих много. Самый серьёзный соперник — это Less, написанный на Node.js, который стал весьма популярен благодаря CSS-фреймворку Bootstrap (до 4-й версии). Также есть Stylus, который довольно много позволяет, но несколько сложнее в использовании, и к тому же имеет меньшее сообщество.
Почему стоит выбрать Sass, а не другой препроцессор? — действительно, актуальный вопрос. Не так давно мы рекомендовали использовать Sass для проектов на Ruby, потому что Sass был создан в Ruby и хорошо работает с Ruby on Rails. Теперь, когда LibSass догнал (в основном) оригинальный Sass, это уже не актуальный совет.
То, что мне нравится в Sass, так это его консервативный подход к CSS. Дизайн Sass основан на строгих принципах: большая часть проектного подхода приходит из мнений команды о том, что: а) добавление новых возможностей не должно вносить существенного усложнения, но быть адекватно полезным, и б) должно быть достаточно беглого взгляда на блок стилей, чтобы понять, что он делает. Кроме того, Sass более внимательно относится к деталям, чем другие препроцессоры. Насколько я могу судить, ведущие разработчики уделяют много внимания обеспечению совместимости с CSS и тщательно следят, чтобы поведение было предсказуемым. Иначе говоря, Sass – это программное обеспечение, предназначенное для решения актуальных задач; привносит полезную функциональность в CSS там, где CSS не справляется.
Кроме препроцессоров, стоит также упомянуть такие инструменты, как PostCSS и cssnext, которые получили значительное внимание в течение последних нескольких месяцев.
PostCSS обычно (и неправильно) называют «постпроцессором». Предполагаю, что это связано с не совсем удачным названием, а так же тем, что PostCSS парсит CSS, который уже был обработан препроцессором. Хоть PostCSS и можно так использовать, но это не обязательно, так что это скорее просто «процессор».
Он позволяет получать доступ к «токенам» таблиц стилей (таким, как селекторы, свойства и значения), обрабатывать их с помощью JavaScript, выполнять какие-либо операций и компилировать результаты в CSS. Например, популярная библиотека Autoprefixer работает на основе PostCSS. Она парсит каждое правило, проверяя нужны ли вендорные префиксы, сверяясь с базой CanIUse, после чего удаляет или добавляет необходимые префиксы.
Это невероятно мощный инструмент для создания библиотек, которые работают с любым препроцессором (а также ванильным CSS), но PostCSS не так прост в использовании. Для работы с ним нужно знать JavaScript, а API иногда может сбить с толку. В то время как Sass предоставляет лишь набор полезных возможностей для написания CSS, PostCSS предоставляет прямой доступ к CSS AST (абстрактное синтаксическое дерево) и JavaScript.
Короче говоря, Sass проще и может решить большинство ваших задач. С другой стороны, с PostCSS сложнее совладать (если вы не достаточно хорошо разбираетесь в JavaScript), но он невероятно мощный. Нет причин, чтобы не использовать и то и другое. PostCSS даже предоставляет для этого официальный SCSS-парсер.
Спасибо Cory Simmons за помощь в работе над этим разделом.
Введение
Почему стайлгайд
Стайлгайд – это не просто приятный документ для чтения, обрисовывающий идеальное состояние вашего кода. Это ключевой документ в жизни проекта, описывающий, как и почему код должен быть написан. Для небольших проектов это может показаться излишним, но очень помогает сохранять кодовую базу чистой, масштабируемой и лёгкой в поддержке.
Излишне говорить, что чем больше разработчиков участвуют в проекте, тем больше руководств требуется. Так же, чем больше проект, тем более важен стайлгайд.
Гарри Робертс очень хорошо об этом говорит в CSS Guidelines:
Стайлгайд (заметьте, не визуальный) является ценным инструментом для команд, которые:
- создают и поддерживают продукты в разумные сроки;
- имеют ряд разработчиков, различающихся способностями и специальностями;
- имеют ряд различных разработчиков, работающих над продуктом в любой момент времени;
- имеют постоянную текучку кадров;
- имеют много разного кода, в который разработчики погружаются.
Дисклеймер
Во-первых: это не CSS-стайлгайд. В этом документе не будут обсуждаться именование CSS-классов, модульный подход и вопрос об ID в мире CSS. Это руководство направлено только на работу с Sass.
Кроме того, это мой личный стайлгайд, и поэтому он весьма субъективен. Думайте об этом, как о наборе методологий и советов, которые я улучшал на протяжении многих лет. Это также даёт мне возможность поделиться ссылками на полезные ресурсы, так что не забудьте проверять разделы дальнейшего чтения.
Очевидно, что данный подход не единственный, может подойдет к вашему проекту, а может и нет. Не стесняйтесь брать отсюда код и подстраивать его под себя. Как говорят у нас, ваш пробег может отличаться (в том смысле, что в вашей ситуации может быть по-другому).
Ключевые принципы
В общем, всё, что я хочу донести этим стайлгайдом, так это что Sass должен быть предельно прост, насколько это возможно.
Спасибо моим глупым эскпериментам, таким как битовые операции, итераторы и генераторы и парсер JSON на Sass, и теперь мы все хорошо знаем что можно сделать с этим препроцессором.
Между тем, CSS является простым языком. Sass, предназначенный для написания CSS, не должен стать значительно сложнее обычного CSS. Принцип KISS (Keep It Simple Stupid, делай это проще, тупица) является ключевым моментом и в некоторых случаях может даже взять верх над принципом DRY (Don’t Repeat Yourself, не повторяйся).
Иногда лучше немного повторяться, чтобы держать код понятным, а не строить тяжелую, громоздкую, сложную систему, которая полностью нечитаема и сложна в поддержке.
Кроме того, позвольте мне еще раз процитировать Гарри Робертса, прагматизм – козырь совершенства. В какой-то момент, вы, вероятно, пойдёте против правил, описанных здесь. Если это имеет смысл — сделайте это. Код – просто средство, а не цель.
Расширение стайлгайда
Большая часть этого стайлгайда строго субъективна. Я изучал и применял Sass в течение нескольких лет и выработал множество принципов, которые помогают, когда дело доходит до написания таблиц стилей. Я понимаю, что эти принципы не всем подойдут и придутся по нраву, и это совершенно нормально.
Несмотря на это, я считаю, что руководство следует дополнять. Расширить Sass Guideliness довольно просто: достаточно иметь документ, в котором указано, что код следует данному стайлгайду за исключением некоторых моментов, которые перечисляются ниже.
Пример расширения стайлгайда можно найти в репозитории SassDoc:
Это расширение для Node Styleguide от Felix Geisendörfer. Все, что определяет этот документ, описано в Node Styleguide.
Синтаксис и форматирование
Если вы спросите меня, что таблица стилей должна делать в первую очередь – так это показать, как мы хотим преподнести наш код.
Когда несколько разработчиков участвуют в написании CSS проекта(ов), то лишь вопрос времени, когда один из них начнёт делать вещи по-своему. Руководство стилей способствуют не только в согласованности, но и помогает, когда приходит время читать и обновлять код.
Грубо говоря, мы хотим (бесстыдно вдохновлён CSS Guidelines):
- двойные (2) отступы пробелом, никаких табов;
- в идеале, 80-символьную ширину строк;
- правильно написанные многострочные CSS правила;
- осмысленное использование пробелов.
// Yep
.foo {
display: block;
overflow: hidden;
padding: 0 1em;
}
// Nope
.foo {
display: block; overflow: hidden;
padding: 0 1em;
}
// Так как Sass использует отступозависивый синтаксис,
// то и не существует неправильного способа форматирования
.foo
display: block
overflow: hidden
padding: 0 1em
Строки
Поверите ли, но строки играют весьма важную роль и в CSS и в Sass экосистемах. Большинство CSS значений — либо длины либо идентификаторы, так что на самом деле очень важно придерживаться некоторых рекомендаций при работе со строками в Sass.
Кодировка
Чтобы избежать потенциальных проблем с кодировкой символов, крайне рекомендуется использовать кодировку UTF-8 в основной таблице стилей, используя директиву @charset
. Убедитесь, что она идёт первой строкой в таблице стилей и перед ней ничего нет.
@charset 'utf-8';
@charset 'utf-8'
Кавычки
CSS не требует, чтобы строки были помещены в кавычки, даже те, что содержат пробелы. Возьмите названия семейства шрифтов, например: не имеет значения, оборачиваете ли вы их в кавычки для CSS-парсера или нет.
Из-за этого, Sass также не требует помещения строк в кавычки. Более того (и, к счастью, согласитесь), строка в кавычках является точным соответствием её двойника без кавычек (например, строка 'abc'
строго равна abc
).
Языки, которые не требуют, чтобы строки были в кавычках, определенно, в меньшинстве, так что строки должны всегда быть обёрнуты в одинарные кавычки в Sass (одну проще набрать, чем двойную, на QWERTY-клавиатуре). Кроме того, для согласованности с другими языками, в том числе с двоюродным братом CSS – JavaScript’ом, есть несколько причин для такого выбора:
- названия цветов рассматриваются как цвета, когда без кавычек, что может привести к серьёзным проблемам;
- большинство синтаксических анализаторов будут в шоке от строк без кавычек;
- это помогает общей читаемости;
- нет обоснованной причины не оборачивать строки в кавычки.
// Yep
$direction: 'left';
// Nope
$direction: left;
// Yep
$direction: 'left'
// Nope
$direction: left
Как указано в спецификации CSS, директива @charset
должна быть объявлена в двойных кавычках чтобы считаться валидной. Однако, Sass позаботится об этом во время компилирования, так что финальный результат будет всегда правильный. Можете спокойно использовать одинарные кавычки даже для @charset
.
Строки как значения CSS
Специальные значения CSS (идентификаторы), такие как initial
или sans-serif
требует не быть закавыченными. В самом деле, объявление font-family: 'sans-serif'
потерпит неудачу, потому что CSS ожидает идентификатор, а не строку с кавычками. Именно поэтому, мы не оборачиваем в кавычки эти значения.
// Yep
$font-type: sans-serif;
// Nope
$font-type: 'sans-serif';
// Okay I guess
$font-type: unquote('sans-serif');
// Yep
$font-type: sans-serif
// Nope
$font-type: 'sans-serif'
// Okay I guess
$font-type: unquote('sans-serif')
Следовательно, можно провести различие между строками, которые должны использоваться как значения CSS (идентификаторы CSS), как в предыдущем примере, и строками, которые привязаны к типу данных Sass, например, к ключам мапы.
Первое без кавычек, а второе в одинарных кавычках.
Строки, содержащие кавычки
Если строка содержит одну или несколько одинарных кавычек, можно воспользоваться оборачиванием строки в двойный кавычки ("
), чтобы избежать применение эскейп-последовательностей в строке.
// Okay
@warn 'You can\'t do that.';
// Okay
@warn "You can't do that.";
// Okay
@warn 'You can\'t do that.'
// Okay
@warn "You can't do that."
УРЛы
URL тоже должны быть в кавычках, по тем же причинам, что и выше:
// Yep
.foo {
background-image: url('/images/kittens.jpg');
}
// Nope
.foo {
background-image: url(/images/kittens.jpg);
}
// Yep
.foo
background-image: url('/images/kittens.jpg')
// Nope
.foo
background-image: url(/images/kittens.jpg)
Числа
В Sass число – это тип данных, включая всё, от безразмерных чисел до длин, длительности, частоты, углов и так далее. Это позволяет проводить на них расчёты.
Нули
В десятичных положительных значениях чисел меньше единицы следует ставить нуль перед точкой. Никогда не ставить незначащие нули после точки.
// Yep
.foo {
padding: 2em;
opacity: 0.5;
}
// Nope
.foo {
padding: 2.0em;
opacity: .5;
}
// Yep
.foo
padding: 2em
opacity: 0.5
// Nope
.foo
padding: 2.0em
opacity: .5
В Sublime Text и других редакторах с поддержкой поиска и замены регулярными выражениями очень легко добавить незначащий нуль в начало (большинства, если не всех) чисел с плавающей точкой. Просто замените \s+\.(\d+)
на \ 0.$1
. Обратите внимание на пробел перед 0
.
Единицы измерения
При работе с длинами, 0
(нуль) никогда не должен иметь единицу измерения.
// Yep
$length: 0;
// Nope
$length: 0em;
// Yep
$length: 0
// Nope
$length: 0em
Внимательно, эта практика относится только к длинам. Нуль без единиц измерения для свойств времени, таких как transition-delay
не допускается. Теоретически, если нуль без единиц измерения указан для продолжительности, это объявление признаётся недействительным и отбрасывается. Не все браузеры столько строги, но некоторые да. Короче говоря: опускать единицу измерения только для длин.
Самая распространённая ошибка о числах в Sass, которую можно только представить – это думать, что единицы измерения – всего лишь строки, которые можно запросто прилагать к числу. Хотя это и звучит как правда, но единицы измерения работают совсем не так. Думайте о единицах измерения в контексте алгебраических символов. Например, в реальном мире, умножение 5 дюймов на 5 дюймов даст вам 25 квадратных дюймов. Та же логика применима и к Sass.
Чтобы добавить единицу измерения в число, нужно умножить это число на 1 единицу измерения.
$value: 42;
// Yep
$length: $value * 1px;
// Nope
$length: $value + px;
$value: 42
// Yep
$length: $value * 1px
// Nope
$length: $value + px
Заметим, что прибавление 0 единиц этого значения также работает, но я скорее бы порекомендовал вышеупомянутый метод умножения, так как прибавление 0 единиц измерения может быть немного запутанным. Действительно, при попытке преобразовать число в другую единицу измерения, прибавление нуля не провернёт этот трюк. Подробнее в этой статье.
$value: 42 + 0px;
// -> 42px
$value: 1in + 0px;
// -> 1in
$value: 0px + 1in;
// -> 96px
$value: 42 + 0px
// -> 42px
$value: 1in + 0px
// -> 1in
$value: 0px + 1in
// -> 96px
В конце концов, всё зависит от того, чего вы пытаетесь достичь. Просто имейте в виду, что добавление единицы измерения как строки – не лучшее решение.
Чтобы убрать единицу измерения из значения, нужно разделить его на одну единицу этой же меры.
$length: 42px;
// Yep
$value: $length / 1px;
// Nope
$value: str-slice($length + unquote(''), 1, 2);
$length: 42px
// Yep
$value: $length / 1px
// Nope
$value: str-slice($length + unquote(''), 1, 2)
Добавляя единицу измерения как строку в число превращает всё в строку, препятствуя любым дополнительным операциям над значением. Разделение числа и единицы измерения тоже возвращает строку. Это не то, чего вы хотите. Используйте длины, не строки.
Вычисления
Числовые рассчёты должны всегда быть в круглых скобках. Мало того, что это требование значительно улучшает читаемость, оно также предотвращает некоторые крайние случаи, заставляя Sass считать содержимое скобок.
// Yep
.foo {
width: (100% / 3);
}
// Nope
.foo {
width: 100% / 3;
}
// Yep
.foo
width: (100% / 3)
// Nope
.foo
width: 100% / 3
Магические числа
“Магическое число” - это термин старой школы программирования для неименованных числовых констант. В принципе, это просто случайное число, которое просто работает™ и ещё не привязано к какому-либо логическому объяснению.
Излишне говорить, магические числа — чума, и их следует избегать любой ценой. Если вы не можете найти разумное объяснение тому, почему число работает, добавьте обширный комментарий, объясняющий, как вы туда попали и почему вы думаете, что это работает. Признание в том, что вы не знаете, почему что-то работает, будет еще более полезным для следующего разработчика, чем исследования происходящего на пустом месте.
/**
* 1. Магическое число. Это минимальное число, которое я смог найти, чтобы выровнять верх
* `.foo` с его предком. В идеале мы должны исправить это по-правильному.
*/
.foo {
top: 0.327em; /* 1 */
}
/**
* 1. Магическое число. Это минимальное число, которое я смог найти, чтобы выровнять верх
* `.foo` с его предком. В идеале мы должны исправить это по-правильному.
*/
.foo
top: 0.327em /* 1 */
По теме у CSS-Tricks есть потрясающая статья о магических числах в CSS, которую я призываю вас прочитать.
Цвета
Цвета занимают важное место в языке CSS. Естественно, Sass является ценным союзником, когда дело доходит до управления цветами, в основном – путём предоставления мощных функций.
Sass настолько полезен, когда приходится манипулировать цветами, что интернет прямо зацвёл от обилия статей на эту тему. Позвольте порекомендовать несколько хороших:
- How to Programmatically Go From One Color to Another
- Using Sass to Build Color Palettes
- Dealing with Color Schemes in Sass
Цветовые форматы
Для того, чтобы сделать цвета простыми, насколько возможно, советую соблюдать следующий порядок предпочтения цветовых форматов:
- Обозначение HSL;
- Обозначение RGB;
- Шестнадцатеричная нотация. Предпочтительно в нижнем регистре и по возможности укороченная.
Названия стандартных цветов CSS не следует использовать, разве что для быстрого прототипирования. Именно так, это английские слова и некоторые из них сослужат плохую службу для описания цвета, который они означают, особенно для тех, кому английский не родной язык. Кроме того, эти названия не очень-то сематичны; например grey
в действительности темнее, чем darkgrey
, и путаница между grey
и gray
может привести к мешанине при использовании этого цвета.
Представление HSL – не только самое простое для человеческого мозга [указать источник], но у него и самый лёгкий способ настройки цвета путём регулировки цветового тона, насыщенности и яркости индивидуально.
RGB по-прежнему имеет преимущество, показывая прямо сейчас, что цвет более синий, зелёный или красный. Таким образом, этот способ может в некоторых случаях быть удачным, особенно при описании чистых красных, зеленых и синих цветов. Но это не делает его лёгким в построении цвета из трёх частей.
Наконец, шестнадцатеричное представление слишком сложно для расшифровки человеческим умом. Используйте его только в случае крайней необходимости.
// Yep
.foo {
color: hsl(0, 100%, 50%);
}
// Also yep
.foo {
color: rgb(255, 0, 0);
}
// Meh
.foo {
color: #f00;
}
// Nope
.foo {
color: #FF0000;
}
// Nope
.foo {
color: red;
}
.foo
color: hsl(0, 100%, 50%)
// Also yep
.foo
color: rgb(255, 0, 0)
// Nope
.foo
color: #f00
// Nope
.foo
color: #FF0000
// Nope
.foo
color: red
При использовании обозначений HSL или RGB, всегда пишите один пробел после запятой (,
) и не ставьте пробел между скобками ((
, )
) и содержимым.
// Yep
.foo {
color: rgba(0, 0, 0, 0.1);
background: hsl(300, 100%, 100%);
}
// Nope
.foo {
color: rgba(0,0,0,0.1);
background: hsl( 300, 100%, 100% );
}
// Yep
.foo
color: rgba(0, 0, 0, 0.1)
background: hsl(300, 100%, 100%)
// Nope
.foo
color: rgba(0,0,0,0.1)
background: hsl( 300, 100%, 100% )
Цвета и переменные
При использовании цвета более одного раза, сохраняйте его в переменной с осмысленным названием, описывающим цвет.
$sass-pink: hsl(330, 50%, 60%);
$sass-pink: hsl(330, 50%, 60%)
Теперь вы можете использовать эту переменную, когда захотите. Однако, если ваше использование сильно привязано к теме, я бы не советовал использовать переменные как есть. Вместо этого, храните их в других переменных с именем, объясняющим, как она должна быть использована.
$main-theme-color: $sass-pink;
$main-theme-color: $sass-pink
Так вы воспрепятствуете изменениям темы, ведущим к чему-то вроде $sass-pink: blue
. Эта статья здорово объясняет, почему важно учитывать ваши цветовые переменные.
Осветление и затемнение цветов
Обе функции lighten
и darken
манипулируют цветами пространства HSL, добавляя или вычитая в пространстве HSL. В принципе, они ни что иное, как алиасы для параметра $lightness
в функции adjust-color
.
Дело в том, что эта функция часто не даёт ожидаемого результата. С другой стороны, функция mix
является хорошим способом осветлить или затемнить цвет, смешивая его либо с white
, либо с ` black`.
Преимуществом использования mix
перед одной из двух указанных функций выше является то, что она будет постепенно меняться на чёрный (или белый), когда вы уменьшаете долю цвета, в то время как darken
и lighten
быстро меняют цвет на чёрный или белый.
Если вы не хотите писать функцию mix
каждый раз, вы можете создать две простых в использовании функции tint
и shade
(которые также являются частью Compass), чтобы сделать то же самое:
/// Немного осветлить цвет
/// @access public
/// @param {Color} $color - цвет для осветления
/// @param {Number} $percentage - процент от `$color` в возвращаемом цвете
/// @return {Color}
@function tint($color, $percentage) {
@return mix(white, $color, $percentage);
}
/// Немного затемнить цвет
/// @access public
/// @param {Color} $color - цвет для затемнения
/// @param {Number} $percentage - процент от `$color` в возвращаемом цвете
/// @return {Color}
@function shade($color, $percentage) {
@return mix(black, $color, $percentage);
}
/// Немного осветлить цвет
/// @access public
/// @param {Color} $color - цвет для осветления
/// @param {Number} $percentage - процент от `$color` в возвращаемом цвете
/// @return {Color}
@function tint($color, $percentage)
@return mix($color, white, $percentage)
/// Немного затемнить цвет
/// @access public
/// @param {Color} $color - цвет для затемнения
/// @param {Number} $percentage - процент от `$color` в возвращаемом цвете
/// @return {Color}
@function shade($color, $percentage)
@return mix($color, black, $percentage)
Функция scale-color
разработана, чтобы изменять свойства более плавно, принимая во внимание, насколько они уже изменены. Результат так же хорош, как и от mix
, но с более удобным вызовом. Хотя, множитель масштабирования – не совсем то же самое.
Списки
Списки Sass эквиваленты массивам. Список представляет собой плоскую структуру данных (в отличие от карт), предназначенную для хранения значений любого типа (в том числе списков со вложенными списками).
Списки должны соблюдать следующие правила:
- либо в одну строку, либо многострочный;
- многострочный необходим, если не помещается в 80-символьную строку;
- если используется для целей CSS, всегда разделяется запятой;
- всегда оборачивается круглыми скобками;
- в многострочном списке ставится запятая после последнего элемента.
// Yep
$font-stack: ('Helvetica', 'Arial', sans-serif);
// Yep
$font-stack: (
'Helvetica',
'Arial',
sans-serif,
);
// Nope
$font-stack: 'Helvetica' 'Arial' sans-serif;
// Nope
$font-stack: 'Helvetica', 'Arial', sans-serif;
// Nope
$font-stack: ('Helvetica', 'Arial', sans-serif,);
// Yep
$font-stack: ('Helvetica', 'Arial', sans-serif)
// Nope (not supported)
$font-stack: (
'Helvetica',
'Arial',
sans-serif,
)
// Nope
$font-stack: 'Helvetica' 'Arial' sans-serif
// Nope
$font-stack: 'Helvetica', 'Arial', sans-serif
// Nope
$font-stack: ('Helvetica', 'Arial', sans-serif,)
При добавлении новых записей в список, всегда используйте прилагаемый API. Не пытайтесь добавлять новые элементы вручную.
$shadows: (0 42px 13.37px hotpink);
// Yep
$shadows: append($shadows, $shadow, comma);
// Nope
$shadows: $shadows, $shadow;
$shadows: (0 42px 13.37px hotpink)
// Yep
$shadows: append($shadows, $shadow, comma)
// Nope
$shadows: $shadows, $shadow
В этой статье, я привожу множество советов и хитростей, как правильно обрабатывать и управлять списками в Sass.
Карты
С помощью Sass, авторы таблиц стилей могут создавать карты (maps) – термин Sass для связных массивов, хэшей или даже объектов JavaScript. Карта – это структура данных, сопоставляющая ключи со значениями. И ключ и значение может быть любым типом данных, включая карты, хотя я это не рекомендую использовать сложные типы данных как ключи карты, просто во имя здравого смысла.
Код карт следует писать следующим образом:
- пробел после двоеточия (
:
); - открывающая скобка (
(
) на той же строке, что и двоеточие (:
); - ключи в кавычках, если это строки (а это так в 99% случаев);
- каждая пара ключ/значение на своей строке;
- запятая (
,
) на конце каждой пары ключ/значение; - закрывающая запятая (
,
) на последней паре, чтобы легче добавлять, удалять или переставлять пункты; - закрывающая скобка (
)
) на своей новой строке; - без пробела или новой строки между закрывающей скобкой (
)
) и точкой с запятой (;
).
Пример:
// Yep
$breakpoints: (
'small': 767px,
'medium': 992px,
'large': 1200px,
);
// Nope
$breakpoints: ( small: 767px, medium: 992px, large: 1200px );
// Yep
$breakpoints: ('small': 767px, 'medium': 992px, 'large': 1200px,)
// Nope
$breakpoints: ( 'small': 767px, 'medium': 992px, 'large': 1200px )
// Nope
$breakpoints: (small: 767px, medium: 992px, large: 1200px,)
// Nope (since it is not supported)
$breakpoints: (
'small': 767px,
'medium': 992px,
'large': 1200px,
)
Записей о картах Sass не столь много, сколь ожидаема была эта возможность. Вот три статьи, которые я рекомендую: Using Sass Maps, Extra Map functions in Sass, Real Sass, Real Maps.
Набор правил CSS
На данный момент, это, в основном, пересмотр того, что все и так знают, но вот как набор правил CSS должен быть написан (по крайней мере, по мнению большинства руководств, в том числе CSS Guidelines):
- связанные селекторы на одной строке; не связанные селекторы на новой строке;
- открывающая скобка (
{
) отделяется от последнего селектора одним пробелом; - каждое объявление на собственной новой строке;
- пробел после двоеточия (
:
); - завершающая точка с запятой (
;
) в конце всех объявлений; - закрывающая скобка (
}
) на своей новой строке; - новая строка после закрывающей скобки
}
.
Пример:
// Yep
.foo, .foo-bar,
.baz {
display: block;
overflow: hidden;
margin: 0 auto;
}
// Nope
.foo,
.foo-bar, .baz {
display: block;
overflow: hidden;
margin: 0 auto }
// Yep
.foo, .foo-bar,
.baz
display: block
overflow: hidden
margin: 0 auto
// Nope
.foo,
.foo-bar, .baz
display: block
overflow: hidden
margin: 0 auto
Дополняя те руководства по CSS, мы должны обратить внимание на:
- локальные переменные объявляются перед любыми объявлениями, потом отделяются от деклараций новой строкой;
- вызовы примесей без
@content
идут перед любым объявлением; - вложенные селекторы всегда идут после новой строки;
- вызовы примесей с
@content
идут после вложенных селекторов; - без новых строк перед закрывающей фигурной скобкой (
}
).
Пример:
.foo, .foo-bar,
.baz {
$length: 42em;
@include ellipsis;
@include size($length);
display: block;
overflow: hidden;
margin: 0 auto;
&:hover {
color: red;
}
@include respond-to('small') {
overflow: visible;
}
}
.foo, .foo-bar,
.baz
$length: 42em
+ellipsis
+size($length)
display: block
overflow: hidden
margin: 0 auto
&:hover
color: red
+respond-to('small')
overflow: visible
Порядок объявлений
Невозможно удержать в голове все обсуждения, где мнения о сортировке объявлений в CSS настолько разнятся. Вообще, можно выявить два лагеря:
- придерживаться алфавитного порядка;
- упорядочивание по назначению (position, display, colors, font, miscellaneous…).
Есть плюсы и минусы в обоих вариантах. С одной стороны, сортировка в алфавитном порядке является универсальной (по крайней мере, для языков, использующих латинский алфавит), поэтому нет никаких споров о сортировке свойств. Тем не менее, мне весьма странно видеть свойства, такие как bottom
и top
, не рядом друг с другом. Почему анимации должны быть перед display
? Есть много странностей с алфавитным упорядочиванием.
.foo {
background: black;
bottom: 0;
color: white;
font-weight: bold;
font-size: 1.5em;
height: 100px;
overflow: hidden;
position: absolute;
right: 0;
width: 100px;
}
.foo
background: black
bottom: 0
color: white
font-weight: bold
font-size: 1.5em
height: 100px
overflow: hidden
position: absolute
right: 0
width: 100px
С другой стороны, сортировка свойств по типу имеет смысл. Каждые объявления, относящиеся к шрифтам, располагаются рядом, как top
и bottom
, и чтение набора правил отчасти становится похожим на чтение рассказа. Но пока вы строго не придерживаетесь определённых соглашений, типа Idiomatic CSS, существует много спорных моментов. Где будет white-space
– рядом со шрифтами или с display
? Где расположить overflow
? Что такое порядок свойств в группе (может быть в алфавитном порядке, о ирония)?
.foo {
height: 100px;
width: 100px;
overflow: hidden;
position: absolute;
bottom: 0;
right: 0;
background: black;
color: white;
font-weight: bold;
font-size: 1.5em;
}
.foo
height: 100px
width: 100px
overflow: hidden
position: absolute
bottom: 0
right: 0
background: black
color: white
font-weight: bold
font-size: 1.5em
Существует также ещё одно интересное поддерево способа упорядочивания, называется Concentric CSS, и, кажется, оно довольно популярно. В своей основе, Concentric CSS опирается на блочную модель, чтобы определить порядок: начинается за пределами, движется внутрь.
.foo {
width: 100px;
height: 100px;
position: absolute;
right: 0;
bottom: 0;
background: black;
overflow: hidden;
color: white;
font-weight: bold;
font-size: 1.5em;
}
.foo
width: 100px
height: 100px
position: absolute
right: 0
bottom: 0
background: black
overflow: hidden
color: white
font-weight: bold
font-size: 1.5em
Должен сказать, я сам не могу определиться. Недавний опрос на CSS-Tricks установил, что более 45% разработчиков упорядочивают свойства по их назначению, против 14% в алфавитном порядке. Кроме того, 39% об этом вообще не думают, и я в том числе.
Поэтому я не буду навязывать вам выбор. Выберите способ, какой вам больше нравится (кроме варианта случайным образом) и следуйте ему в ваших таблицах стилей.
Недавние исследования показали, что использование CSS Comb (которое использует упорядочивание по типу) помогает уменьшить общий размер файла на 2.7% при сжатии Gzip, в сравнении с 1.3%, когда происходит упорядочение по алфавиту.
Вложенность селекторов
Одна особенность Sass, которую не слишком используют многие разработчики – вложенность селекторов. Она позволяет автору таблицы стилей вычислять длинные селекторы, вкладывая короткие селекторы друг в друга.
Общие правила
Например, такая вложенность Sass:
.foo {
.bar {
&:hover {
color: red;
}
}
}
.foo
.bar
&:hover
color: red
…создаст такой CSS:
.foo .bar:hover {
color: red;
}
Начиная с Sass 3.3 можно использовать ссылку на текущий селектор, используя &
, чтобы создать дополнительные селекторы. Например:
.foo {
&-bar {
color: red;
}
}
.foo
&-bar
color: red
…сгенерирует такой CSS:
.foo-bar {
color: red;
}
.foo-bar
color: red
Этот метод часто используется в методологии BEM для генерации селекторов .block__element
и .block--modifier
, основанных на базовом селекторе (т.е. .block
в данном примере).
Выходит анекдотично, что создание новых селекторов из ссылки на текущий селектор (&
) делает новые селекторы недоступными для поиска в кодовой базе, так как они не существуют как таковые.
Проблема с вложенностью селекторов в том, что это в конечном итоге делает код более трудным для чтения. Нужно уметь мысленно вычислять, что получится в результате из уровней вложенности; не всегда вполне очевидно, что за CSS будет в конечном итоге.
Это утверждение становится правдивее, когда селекторы становятся длиннее и ссылки на текущий селектор (&
) более частыми. В какой-то момент риск потерять след и не суметь понять, что происходит, становится настолько высок, что не стоит того.
Для предотвращения таких ситуаций, мы много говорили о правиле Начала несколько лет назад. Оно советует избегать вложенности более трёх уровней, отсылая к сюжету фильма «Начало» Кристофера Нолана. Я буду более резок и рекомендую избегайте вложенности селекторов, насколько это возможно.
Тем не менее, есть, очевидно, несколько исключений из этого правила, и как мы увидим в следующем разделе, это мнение кажется довольно популярным. Вы можете прочитать об этом детальнее в статьях Beware of Selector Nesting и Avoid nested selectors for more modular CSS.
Исключения
Для начала, допускается, и я даже рекомендую, вкладывать псевдоклассы и псевдоэлементы в родительский селектор.
.foo {
color: red;
&:hover {
color: green;
}
&::before {
content: 'pseudo-element';
}
}
.foo
color: red
&:hover
color: green
&::before
content: 'pseudo-element'
Использование вложенности селекторов для псевдоклассов и псевдоэлементов не только имеет смысл (потому что имеет дело с тесно связанными селекторами), но также помогает держать всю информацию о компоненте в одном месте.
Кроме того, при использовании классов, обозначающих состояние, таких как .is-active
, это прекрасно подходит для того, чтобы вкладывать их под селектор компонента, чтобы всё выглядело аккуратно.
.foo {
// …
&.is-active {
font-weight: bold;
}
}
.foo
// …
&.is-active
font-weight: bold
Последнее, но не менее важное – при оформлении элемента часто случается, что он содержится в другом элементе, и тут также хорошо использовать вложенность, чтобы держать всё о компоненте в том же месте.
.foo {
// …
.no-opacity & {
display: none;
}
}
.foo
// …
.no-opacity &
display: none
Как и везде, специфика несколько неуместна, постоянство является ключевым фактором. Если вы чувствуете, что полностью уверены во вложенности селекторов, тогда используйте ее. Просто убедитесь, что вся ваша команда справится с этим.
Если вам понравился Sass Гайдлайн, пожалуйста, поддержите его.
Поддержите Sass ГайдлайнСоглашения по именованию
В этом разделе мы не будем иметь дело с лучшими соглашениями по именованию в CSS для сопровождения и масштабирования; не только потому, что это остаётся за вами, а также потому, что они из области Sass Styleguide. Я предлагаю те, что рекомендованы в CSS Guidelines.
Вот чему можно присвоить имена в Sass, и очень важно, чтобы эти имена были хорошими, чтобы весь код выглядел последовательным и легко читался:
- переменные;
- функции;
- примеси.
Плейсхолдеры Sass (%placeholder
) намеренно исключены из этого списка, так как их можно рассматривать как обычные селекторы CSS и использовать теже принципы именования, что и для классов.
Что же касается переменных, функций и примесей, то мы будем придерживаться чего-то очень CSS-ного: нижние подчеркивания и дефисы, и, прежде всего – смысл.
$vertical-rhythm-baseline: 1.5rem;
@mixin size($width, $height: $width) {
// …
}
@function opposite-direction($direction) {
// …
}
$vertical-rhythm-baseline: 1.5rem
=size($width, $height: $width)
// …
@function opposite-direction($direction)
// …
Константы
Если вы являетесь разработчиком фреймворка или библиотеки, вы можете столкнуться с переменными, которые не должны изменяться ни при каких обстоятельствах: константами. К сожалению (или к счастью?), Sass не даёт какой-либо способ определения таких переменных, поэтому мы должны придерживаться строгих соглашений об именовании.
Как и для многих языков, я предлагаю объявлять константы именами в верхнем регистре. Это не только очень старое соглашение, но и хорошо контрастирует с обычными строчными переменными.
// Yep
$CSS_POSITIONS: (top, right, bottom, left, center);
// Nope
$css-positions: (top, right, bottom, left, center);
// Yep
$CSS_POSITIONS: (top, right, bottom, left, center)
// Nope
$css-positions: (top, right, bottom, left, center)
Если вы действительно хотите покумекать над идеей констант в Sass, вам стоит почитать эту специальную статью.
Пространство имён
Если вы собираетесь распространять ваш код Sass, например, как библиотеку, фреймворк, сетку или что угодно, вы, возможно, захотите рассмотреть пространства имён всех своих переменных, функций, примесей и плейсхолдеров, так, чтобы они не конфликтовали с чьим-либо кодом.
Например, если вы работаете над проектом Sassy Unicorn, который предназначен для использования разработчиками по всему миру, вы можете рассмотреть возможность использования префикса su-
как пространство имен. Это достаточно верно, чтобы предотвратить любые споры в именах, и достаточно коротко, чтобы не испытывать боль при написании кода.
$su-configuration: ( … );
@function su-rainbow($unicorn) {
// …
}
$su-configuration: ( … )
@function su-rainbow($unicorn)
// …
У Kaelig есть очень проницательная статья о глобальном пространстве имен CSS, на случай, если эта тема вас заинтересовала.
Обратите внимание, что автоматическое создание пространств имён, безусловно, цель для предстоящего проекта @import
из Sass 4.0. И так как приход его всё ближе и ближе, то использование библиотек с пространством имён, написанным вручную, может стать сложнее в использовании.
Архитектура
Разработка архитектуры CSS-проекта, вероятно, одна из самых сложных задач, которую придётся сделать в жизни проекта. Сохранять архитектуру последовательной и значимой – ещё сложнее.
К счастью, одно из главных преимуществ использования CSS-препроцессоров – в возможности разделить кодовую базу на несколько файлов без ущерба для производительности (в отличие от CSS-правила @import
). Благодаря @import
в Sass, совершенно безопасно (и на самом деле рекомендуется) использовать столько файлов, сколько необходимо в разработке, все они потом будут собраны в одну таблицу стилей и так попадут на продакшен.
Кроме того, я не могу не подчеркнуть потребность в папках, даже на небольших проектах. Дома вы не кладёте каждый лист бумаги в один и тот же ящик. Вы используете папки; одну для дома, другую для банка, третью для счетов, и так далее. Нет причины поступать иначе при определении структуры CSS-проекта. Разделяйте кодовую базу на папки, чтобы позже легко было найти нужный код.
Существует много популярных архитектур для CSS проектов: OOCSS, Atomic Design, Bootstrap, Foundation и тому подобные… все они имеют свои достоинства, плюсы и минусы.
Я сам использую подход, который очень похож на SMACSS от Джонатана Снука, который фокусируется на сохранении простоты и очевидности.
Я осознал, что архитектура в основном зависит от проекта. Используйте или адаптируйте предложенное решение так, чтобы работать с системой, которая соответствует вашим потребностям.
Компоненты
Существует главное отличие между тем, чтобы сделать код работающим, или сделать его хорошим. Опять таки, CSS – довольно путаный язык [указать источник]. Чем меньше CSS, тем лучше. Мы не хотим иметь дело с мегабайтами кода. Чтобы держать файлы стилей короткими и эффективными – и это не будет для вас сюрпризом – чаще всего будет хорошей идеей подумать об интерфейсе, как о наборе компонентов.
Компоненты могут быть чем угодно, до тех пор, пока они:
- делают одну и только одну вещь;
- могут быть повторно используемы;
- независимы.
Например, форма поиска должна рассматриваться в качестве компонента. Она должна иметь возможность быть используемой повторно на разных страницах, в различных ситуациях. Она не должна зависеть от положения в DOM (в подвале, в боковой панели, в основном содержимом…).
Большинство интерфейсов можно рассматривать как набор маленьких компонентов, и я настоятельно рекомендую вам придерживаться этой парадигмы. Это позволит не только сократить количество CSS, необходимого для всего проекта, но также упростить его поддержку, и прибрать хаотический беспорядок.
Структура компонента
В идеале, компоненты должны располагаться в своих собственных файлах (partial) (в папке components/
, как описано в главе 7-1 pattern), например components/_button.scss
. Стили, описываемые в каждом компоненте должны быть связаны только с:
- стилем самого компонента;
- стилем вариантом компонента, его модификаторами и состояниями;
- стили потомков компонента (то есть детей), если это необходимо.
Если вы хотите, чтобы ваши компоненты можно было стилизовать внешней темой (то есть темой внутри папки themes/
), ограничьтесь объявлением только структурных стилей, такие как размеры (ширина/высота), паддинги, отступы, выравнивание и так далее. Исключитте такие стили как цвет, тени, настройки шрифта, фона и так далее.
В файл компонента можно включать специфичные для этого компонента переменные, плейсхолдеры и даже миксины и функции. Однако имейте в виду, что следует избегать зависимостей (то есть @import
-а) от других компонентов, так как привратит ваш проект в мешанину неконтролируемых зависимостей, которые невозможно поддерживать.
Вот пример компонента кнопка:
// Переменные для кнопки
$button-color: $secondary-color;
// … включите сюда любые правила для кнопки:
// - миксины
// - плейсхолдеры
// - функции
/**
* Кнопки
*/
.button {
@include vertical-rhythm;
display: block;
padding: 1rem;
color: $button-color;
// … etc.
/**
* Инлайновая кнопка для больших экранов
*/
@include respond-to('medium') {
display: inline-block;
}
}
/**
* Иконки внутри кнопок
*/
.button > svg {
fill: currentcolor;
// … etc.
}
/**
* Инлайновая кнопка
*/
.button--inline {
display: inline-block;
}
// Переменные для кнопки
$button-color: $secondary-color
// … включите сюда любые правила для кнопки:
// - миксины
// - плейсхолдеры
// - функции
/**
* Кнопки
*/
.button
+vertical-rhythm
display: block
padding: 1rem
color: $button-color
// ... etc.
/**
* Инлайновая кнопка для больших экранов
*/
+respond-to('medium')
display: inline-block
}
/**
* Иконки внутри кнопок
*/
.button > svg
fill: currentcolor
// ... etc.
/**
* Инлайновая кнопка
*/
.button--inline
display: inline-block
Благодарю David Khourshid за помощь и экспертизу этой главы.
Шаблон 7-1
Возвратимся к архитектуре? Я обычно использую так называемый Шаблон 7-1: 7 папок, 1 файл. Обычно весь наш код можно распределить в 7 папок и один файл в корневом каталоге (обычно с именем main.scss
), который импортирует их все.
base/
components/
layout/
pages/
themes/
utils/
vendors/
И, конечно же:
main.scss
Если вы хотите использовать паттерн 7-1, вот готовый шаблон на Гитхабе. В нём содержится всё что нужно для начала работы по этой архитектуре.
В идеале, в конечном итоге у нас получится что-то такое:
sass/
|
|– abstracts/
| |– _variables.scss # Sass переменные
| |– _functions.scss # Sass функции
| |– _mixins.scss # Sass миксины
| |– _placeholders.scss # Sass плейсхолдеры
|
|– base/
| |– _reset.scss # Reset/normalize
| |– _typography.scss # Типографика
| … # Прочее
|
|– components/
| |– _buttons.scss # Кнопки
| |– _carousel.scss # Карусель
| |– _cover.scss # Обложка
| |– _dropdown.scss # Выпадашка
| … # и так далее
|
|– layout/
| |– _navigation.scss # Навигация
| |– _grid.scss # Сетка
| |– _header.scss # Шапка
| |– _footer.scss # Футер
| |– _sidebar.scss # Сайдбар
| |– _forms.scss # Формы
| … # и так далее
|
|– pages/
| |– _home.scss # Специфичные стили страницы Home
| |– _contact.scss # Специфичные стили страницы Contact
| … # и так далее
|
|– themes/
| |– _theme.scss # Тема по умолчанию
| |– _admin.scss # Тема админа
| … # и так далее
|
|– vendors/
| |– _bootstrap.scss # Bootstrap
| |– _jquery-ui.scss # jQuery UI
| … # и так далее
|
`– main.scss # Главный Sass файл
Файлы с тем же соглашением по именованию, что и выше, начинаются с нижнего подчеркивания.
Папка Base
Папка base/
содержит то, что мы можем назвать общим шаблоном проекта. Там вы можете найти файл сброса, некоторые типографские правила, и, вероятно, стили (я привык их называть _base.scss
), определяющие некоторые стандартные стили для часто используемых элементов HTML.
_base.scss
_reset.scss
_typography.scss
Если в проекте много CSS анимации, то, возможно, стоит добавить файл \_animations.scss
, который будет содержать определения @keyframes
всех анимаций. Если же в проекте всего пара таких штук, оставьте их рядом с селекторами, использующие их.
Папка Layout
Папка layout/
содержит всё, что принимает участие в постройке раскладки сайта или приложения. Эта папка может содержать стили для основных частей сайта (шапка, подвал, навигация, боковая панель…), сетка или даже CSS-стили для всех форм.
_grid.scss
_header.scss
_footer.scss
_sidebar.scss
_forms.scss
_navigation.scss
Папка layout/
может быть названа partials/
, на ваше усмотрение.
Папка Components
Для маленьких компонентов существует папка components/
. В то время, как layout/
– основные (определяют общий каркас), код внутри components/
больше сфокусирован на виджетах и содержит все модули, вроде слайдера, загрузчика и тому подобных виджетов. Обычно файлов в components/
много, если приложение или сайт состоит из множества мелких модулей.
_media.scss
_carousel.scss
_thumbnails.scss
Папка components/
может называться modules/
, на ваше усмотрение.
Папка Pages
Если у вас есть стили, зависящие от страницы, лучше положить их в папку pages/
, в файл, названный как и страница. Например, не редкость – иметь очень специфичные стили для главной страницы, следовательно, существует потребность в _home.scss
в pages/
.
_home.scss
_contact.scss
В зависимости от способа деплоя, эти файлы можно назвать по-своему, чтобы избежать их объединения с другими стилями. На ваше усмотрение.
Папка Themes
В больших сайтах и приложениях не редко имеются различные темы оформления. Есть разные способы работы с темами, я лично предпочитаю складывать их в папку themes/
.
_theme.scss
_admin.scss
Это очень зависит от проекта и не сильно распространено.
Папка Abstracts
Папка abstracts/
собирает все инструменты и хелперы Sass в проекте. Каждая глобальная переменная, функция и примесь должна быть помещена сюда.
Правило для этой папки в том, что она не должна создавать CSS при компиляции сама по себе. Это не что иное, как Sass хелперы.
_variables.scss
_mixins.scss
_functions.scss
_placeholders.scss
(часто называется_helpers.scss
)
При работе над очень большим проектом с большим количеством абстракций, возможно, стоит их группировать по темам, а не по типу. Например, типографику (_typography.scss
), темы оформления (_theming.scss
), и так далее. Каждый файл содержит все относящиеся к нему хелперы: переменные, функции, миксины и плейсхолдеры. Это сильно облегчит понимание и обслуживание кода, особенно когда файлы становятся очень длинными.
Папка abstracts/
может также быть названа utilities/
или helpers/
, на ваше усмотрение.
Папка Vendors
И последнее, но не менее важное, большинство проектов будут иметь папку vendors/
, содержащую все CSS-файлы из внешних библиотек и фреймворков – Normalize, Bootstrap, jQueryUI, FancyCarouselSliderjQueryPowered и так далее. Нахождение этих файлов в этой папке – хороший способ сказать: “Эй, это не я писал, не мой код, не моя ответственность”.
_normalize.scss
_bootstrap.scss
_jquery-ui.scss
_select2.scss
Если вы хотите что-то переопределить в файлах любого вендора, то я рекомендую вам ввести восьмую папку vendors-extensions/
, в которой вы будете хранить файлы с точно такими же именами, что и файлы, которые они переопределяют.
Например, файл vendors-extensions/_boostrap.scss
, содержит все CSS-правила, переопределящие стандартные CSS-правила Bootstrap. Это сделано для того, чтобы не править сами внешние модули, что является совсем не здоровской идеей.
Файл Main
Главный файл (обычно называемый main.scss
) должен быть единственным файлом Sass, который не начинается с нижнего подчеркивания. Этот файл не должен содержать ничего, кроме @import
и комментариев.
Файлы должны быть импортированы в соответствии с папками размещения, один за другим, в следующем порядке:
abstracts/
vendors/
base/
layout/
components/
pages/
themes/
Чтобы улучшить читаемость, главный файл должен следовать этим рекомендациям:
- один файл на один
@import
; - один
@import
на строку; - не вставлять пустую строку между файлами из одной папки;
- вставлять пустую строку после последнего импорта из папки;
- не писать расширения файлов и нижние подчеркивания.
@import 'abstracts/variables';
@import 'abstracts/functions';
@import 'abstracts/mixins';
@import 'abstracts/placeholders';
@import 'vendors/bootstrap';
@import 'vendors/jquery-ui';
@import 'base/reset';
@import 'base/typography';
@import 'layout/navigation';
@import 'layout/grid';
@import 'layout/header';
@import 'layout/footer';
@import 'layout/sidebar';
@import 'layout/forms';
@import 'components/buttons';
@import 'components/carousel';
@import 'components/cover';
@import 'components/dropdown';
@import 'pages/home';
@import 'pages/contact';
@import 'themes/theme';
@import 'themes/admin';
@import vendors/bootstrap
@import vendors/jquery-ui
@import utils/variables
@import utils/functions
@import utils/mixins
@import utils/placeholders
@import base/reset
@import base/typography
@import layout/navigation
@import layout/grid
@import layout/header
@import layout/footer
@import layout/sidebar
@import layout/forms
@import components/buttons
@import components/carousel
@import components/cover
@import components/dropdown
@import pages/home
@import pages/contact
@import themes/theme
@import themes/admin
Существует ещё один способ импорта, который я считаю допустимым. С одной стороны, файл становится более читаемым. С другой стороны, его обновление становится немного более болезненным. Во всяком случае, вам решать, что лучше, это не имеет большого значения. Основной файл следует следующим принципам:
- один
@import
на папку; - разрыв строки после
@import
; - каждый файл на отдельной строке;
- пустая строка после последнего импорта файла из папки;
- не писать расширения файлов и нижние подчеркивания.
@import
'abstracts/variables',
'abstracts/functions',
'abstracts/mixins',
'abstracts/placeholders';
@import
'vendors/bootstrap',
'vendors/jquery-ui';
@import
'base/reset',
'base/typography';
@import
'layout/navigation',
'layout/grid',
'layout/header',
'layout/footer',
'layout/sidebar',
'layout/forms';
@import
'components/buttons',
'components/carousel',
'components/cover',
'components/dropdown';
@import
'pages/home',
'pages/contact';
@import
'themes/theme',
'themes/admin';
@import
vendors/bootstrap,
vendors/jquery-ui
@import
utils/variables,
utils/functions,
utils/mixins,
utils/placeholders
@import
base/reset,
base/typography
@import
layout/navigation,
layout/grid,
layout/header,
layout/footer,
layout/sidebar,
layout/forms
@import
components/buttons,
components/carousel,
components/cover,
components/dropdown
@import
pages/home,
pages/contact
@import
themes/theme,
themes/admin
О глобинге
В программировании, глоб шаблоны определяют набор файлов через символы подстановки, такие как *.scss
. В общем, глоббинг означает определение набора файлов на основе выражения вместо списка имен файлов. Применимо к Sass, это означает импортирование составных файлов в основной файл main file с глоб шаблоном, а не перечислением их по отдельности. Таким образом, основной файл будет выглядеть так:
@import 'abstracts/*';
@import 'vendors/*';
@import 'base/*';
@import 'layout/*';
@import 'components/*';
@import 'pages/*';
@import 'themes/*';
@import 'abstracts/*'
@import 'vendors/*'
@import 'base/*'
@import 'layout/*'
@import 'components/*'
@import 'pages/*'
@import 'themes/*'
Sass не поддерживает глоббинг из коробки, потому что он может привести к опасным последствиям, так как в CSS имеет значение порядок определения правил. При динамическом импорте правил (обычно в алфавитном порядке) отсутствует контроль над порядком импорта файлов, что может привести к трудноотлавливаемым побочным эффектам.
Как было сказано ранее, в строгой компонентно-основаной архитектуре с особым контролем за перетеканием стилей от одного компонента к другому, порядок импорта не особо важен, и в таком случае, использование глоб-импорта допустимо. Тогда становится легче добавлять и удалять компоненты, а обновлять главный файл при этом не требуется.
При использовании Ruby Sass, есть Ruby гем, который называется sass-globbing который включает именно эту возможность. Если разработка на node-sass, остаётся полагаться либо на Node.js, либо на любой сборщик, который позаботится о подобной сборке (Gulp, Grunt и т.д.).
Файл позора
Это интересная идея, которая стала популярна благодаря Гарри Робертсу, Дэйву Руперту и Крису Койеру и состоит в том, чтобы складывать все хаки и код, которым вы не гордитесь, в файл позора. Поэтому этот файл и имеет такое драматическое название – _shame.scss
, и импортируется в самом конце.
/**
* Особое исправление навигации.
*
* Кто-то использовал ID в коде шапки (`#header a {}`), который перекрывает
* селекторы nav (`.site-nav a {}`). Используйте `!important`, чтобы
* перекрыть их, до тех пор, пока я не перепишу шапку.
*/
.site-nav a {
color: #BADA55 !important;
}
/**
* Особое исправление навигации.
*
* Кто-то использовал ID в коде шапки (`#header a {}`), который перекрывает
* селекторы nav (`.site-nav a {}`). Используйте `!important`, чтобы
* перекрыть их, до тех пор, пока я не перепишу шапку.
*/
.site-nav a
color: #BADA55 !important
Адаптивный веб-дизайн и точки останова
Я не думаю, что надо рассказывать, что такое адаптивный веб-дизайн, так как он сейчас везде. Тем не менее, вы можете задаться вопросом: почему раздел об адаптивном веб-дизайне находится в руководсте по Sass? Просто есть кое-какие приёмы для облегчения работы с точками останова, так что я подумал, что будет неплохо перечислить их здесь.
Именование точек останова
Я думаю, что медиа-запросы не должны быть привязаны к специальным устройствам. Например, определённо плохая идея – специально нацеливаться на iPad или устройства на Blackberry. Медиа-запросы должны обслуживать диапазон размеров экрана, пока нет перехода к следующему медиа-запросу.
По этим же причинам наименование точек останова не должно соотвествовать устройствам, а иметь более общие названия. Тем более, что некоторые телефоны теперь больше, чем планшеты, а некоторые планшеты больше экранов маленьких компьютеров, и тому подобное…
// Yep
$breakpoints: (
'medium': (min-width: 800px),
'large': (min-width: 1000px),
'huge': (min-width: 1200px),
);
// Nope
$breakpoints: (
'tablet': (min-width: 800px),
'computer': (min-width: 1000px),
'tv': (min-width: 1200px),
);
// Yep
$breakpoints: ('medium': (min-width: 800px), 'large': (min-width: 1000px), 'huge': (min-width: 1200px))
// Nope
$breakpoints: ('tablet': (min-width: 800px), 'computer': (min-width: 1000px), 'tv': (min-width: 1200px))
Таким образом, любое соглашение по именованию, которое даёт кристально чистое понимание, что дизайн не привязан к конкретным устройствам, будет работать до тех пор, пока даёт ощущение масштаба.
$breakpoints: (
'семечка': (min-width: 800px),
'росток': (min-width: 1000px),
'растение': (min-width: 1200px),
);
$breakpoints: ('семечка': (min-width: 800px), 'росток': (min-width: 1000px), 'растение': (min-width: 1200px))
В предыдущем примере используются вложенные карты для определения точек останова, но по большому счёту, всё зависит от способа управления точками останова, на который вы опираетесь. Вы можете выбрать строки, а не внутренние карты для большей гибкости (например '(min-width: 800px)'
).
Управление точками останова
После того, как вы объявили ваши точки останова, вам нужен способ, чтобы использовать их в медиа-запросах. Есть много способов сделать это, но, должен сказать, я большой поклонник получения точек останова из карт через функцию геттер. Эта система является одновременно простой и эффективной.
/// Управление отзывчивостью.
/// @access public
/// @param {String} $breakpoint - точка останова
/// @requires $breakpoints
@mixin respond-to($breakpoint) {
$raw-query: map-get($breakpoints, $breakpoint);
@if $raw-query {
$query: if(
type-of($raw-query) == 'string',
unquote($raw-query),
inspect($raw-query)
);
@media #{$query} {
@content;
}
} @else {
@error 'Не указано значение для `#{$breakpoint}`. '
+ 'Пожалуйста, убедитесь, что точка останова объявлена в карте `$breakpoints`.';
}
}
/// Управление отзывчивостью.
/// @access public
/// @param {String} $breakpoint - точка останова
/// @requires $breakpoints
=respond-to($breakpoint)
$raw-query: map-get($breakpoints, $breakpoint)
@if $raw-query
$query: if(type-of($raw-query) == 'string', unquote($raw-query), inspect($raw-query))
@media #{$query}
@content
@else
@error 'Не указано значение для `#{$breakpoint}`. '
+ 'Пожалуйста, убедитесь, что точка останова объявлена в карте `$breakpoints`.';
Очевидно, что это довольно упрощенный менеджер точек останова, который не будет работать, когда надо обрабатывать произвольные или множественные точки остановки. Если вам нужно управление отзывчивостью с расширенными настройками, могу порекоммендовать вам не изобретать колесо, а воспользоваться отличными решениями: Sass-MQ, Breakpoint или include-media.
Если вы хотите больше узнать о том, как разобраться с медиа-запросами в Sass, то и SitePoint, и CSS-Tricks имеют отличные статьи на эту тему.
Использование медиа-запросов
Не так давно ещё были довольно жаркие дебаты о том, где именно должны быть описаны медиа-запросы: должны ли они быть в селекторах (как это позволяет Sass) или строго отделены от них? Я должен сказать, что я искренний защитник системы медиа-запросов-внутри-системы, я думаю, что это хорошо сочетается с идеей компонентов.
.foo {
color: red;
@include respond-to('medium') {
color: blue;
}
}
.foo
color: red
+respond-to('medium')
color: blue
Это создаст следующий CSS:
.foo {
color: red;
}
@media (min-width: 800px) {
.foo {
color: blue;
}
}
Вы могли слышать, что это правило приводит к дублированию медиа-запросов в получаемом CSS. Это, безусловно, верно. Хотя, были сделаны тесты, которые говорят о том, что это не имеет особого значения, если за дело берётся Gzip (или аналог):
… мы выяснили, были ли влияния на производительность комбинированных и рассеяных медиа-запросов, и пришли к выводу, что различие является минимальным в худшем случае, а по существу и не существует.
— Сэм Ричардс относительно Breakpoint
Теперь, если вы действительно обеспокоены дублированием медиа-запросов, вы всё ещё можете использовать инструмент, чтобы объединить их, например, этот gem, однако я должен вас предупредить о возможных побочных эффектах перемещения CSS-кода. Вы остаетёсь без представления о порядке кода, что является важным.
Если вам понравился Sass Гайдлайн, пожалуйста, поддержите его.
Поддержите Sass ГайдлайнПеременные
Переменные являются сутью любого языка программирования. Они позволяют нам использовать значения без необходимости копировать их снова и снова. Самое главное, что они позволяют обновлять это значение очень просто. Никакого больше поиска с заменой или ручной рутины.
Однако, CSS – это ни что иное, как огромная корзина, куда сложены все наши яйца. В отличие от многих языков, в CSS нет никаких реальных областей видимости в CSS. Поэтому приходится уделять особое внимание при добавлении переменных из-за риска конфликтов между ними.
Я советую создавать переменные только когда это имеет смысл. Не создавайте новые переменные чёрт знает зачем, это не поможет. Новая переменная должна быть создана только тогда, когда выполняются следующие условия:
- значение повторяется хотя бы дважды;
- значение скорее всего будет обновлено хотя бы один раз;
- все вхождения значения привязаны к переменной (т.е не по стечению обстоятельств).
В принципе, нет никакого смысла объявлять переменную, которая никогда не будет обновлена или которая используется только в одном месте.
Области видимости
Области видимости переменных в Sass с годами менялись. До недавнего времени, объявленые переменных в пределах наборов правил и других областей видимости были локальными по умолчанию. Однако, если уже была глобальная переменная с тем же именем, изменение значения локальной переменной изменило бы глобальную. Начиная с версии 3.4, Sass правильно отрабатывает задумку областей видимости и создаёт новую локальную переменную вместо перезаписи глобальной.
Документация говорит о затенении глобальной переменной. При объявлении переменной, уже существующей в глобальной области видимости, во внутренней области видимости (селектор, функция, примесь…), локальная переменная называется затенённой глобальной. В общем, она перезаписывается только для локальной области видимости.
Следующий фрагмент кода объясняет задумку затенения переменных.
// Объявить глобальную переменную на корневом уровне.
$variable: 'initial value';
// Создать примесь, которая перезаписывает глобальные переменные.
@mixin global-variable-overriding {
$variable: 'mixin value' !global;
}
.local-scope::before {
// Создать локальную переменную, которая затеняет глобальную.
$variable: 'local value';
// Применить примесь: она перезапишет глобальную переменную.
@include global-variable-overriding;
// Вывести значение переменной.
// Здесь значение из **локальной** переменной, так как она глобальную.
content: $variable;
}
// Вывести эту переменную в другом селекторе, который не делает затенения.
// Здесь значение **глобальное**, как и ожидалось.
.other-local-scope::before {
content: $variable;
}
// Объявить глобальную переменную на корневом уровне.
$variable: 'initial value'
// Создать примесь, которая перезаписывает глобальные переменные.
@mixin global-variable-overriding
$variable: 'mixin value' !global
.local-scope::before
// Создать локальную переменную, которая затеняет глобальную.
$variable: 'local value'
// Применить примесь: она перезапишет глобальную переменную.
+global-variable-overriding
// Вывести значение переменной.
// Здесь значение из **локальной** переменной, так как она затеняет
// глобальную.
// Вывести эту переменную в другом селекторе, который не делает затенения.
// Здесь значение **глобальное**, как и ожидалось.
.other-local-scope::before
content: $variable
Флаг !default
При построении библиотеки, фреймворка, сетки или любого кода Sass, который предназначен для использования другими разработчиками, все переменные должны быть определены с флагом !default
, чтобы они могли быть перезаписаны.
$baseline: 1em !default;
$baseline: 1em !default
Благодаря этому, разработчик может определить свою собственную переменную $baseline
перед импортом вашей библиотеки, при этом она не будет переопределена.
// Переменная разработчика
$baseline: 2em;
// Ваша библиотека определяет `$baseline`
@import 'your-library';
// $baseline == 2em;
// Переменная разработчика
$baseline: 2em
// Ваша библиотека определяет `$baseline`
@import your-library
// $baseline == 2em
Флаг !global
Флаг !global
следует использовать только тогда, когда вы переопределяете глобальную переменную из локальной области видимости. При определении переменной на корневом уровне, флаг global
должен быть опущен.
// Yep
$baseline: 2em;
// Nope
$baseline: 2em !global;
// Yep
$baseline: 2em
// Nope
$baseline: 2em !global
Много переменных или карты
Существуют преимущества использования карт перед несколькими отдельными переменными. Главным преимуществом является возможность использовать карты в циклах, чего нельзя сделать с отдельными переменными.
Другое преимущество использования карт заключается в способности создать небольшую функцию-геттер для получения значений, чтобы обеспечить удобный API. Например, рассмотрим следующий код Sass:
/// Карта Z-index’ов, собирает все Z-слои приложения
/// @access private
/// @type Map
/// @prop {String} key - Имя слоя
/// @prop {Number} value - значение Z, соответствущее ключу
$z-indexes: (
'modal': 5000,
'dropdown': 4000,
'default': 1,
'below': -1,
);
/// Получение значения z-index из имени слоя
/// @access public
/// @param {String} $layer - Имя слоя
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
@return map-get($z-indexes, $layer);
}
/// Карта Z-index’ов, собирает все Z-слои приложения
/// @access private
/// @type Map
/// @prop {String} key - Имя слоя
/// @prop {Number} value - значение Z, соответствущее ключу
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)
/// Получение значения z-index из имени слоя
/// @access public
/// @param {String} $layer - Имя слоя
/// @return {Number}
/// @require $z-indexes
@function z($layer)
@return map-get($z-indexes, $layer)
Extend
Директива @extend
– одна из возможностей, которая сделала Sass таким известным несколько лет назад. Напомню: она позволяет Sass оформить элемент A именно так, как будто бы он также соответствует селектору B. Разумеется, эта возможность является ценным союзником при написании модульного CSS.
Однако настоящее предназначение @ extend
заключается в поддержании отношений (соединений) в расширенных селекторах между наборами правил. Что именно это значит?
- Селекторы имеют соединения (например,
.bar
в.foo > .bar
должны иметь родителя.foo
); - Эти соединения соотносятся на расширенный селектор (например, ``.baz { @extend .bar; }
будет создавать
.foo > .bar, .foo > .baz`); - Объявления расширенного селектора будут использоваться совместно с расширяемым селектором.
Учитывая это, нетрудно увидеть, как расширение селекторов с мягкими соединениями могут привести к взрыву селектора. Если .baz .qux
расширяет .foo .bar
, то результирующий селектор может быть .foo .baz .qux
или .baz .foo .qux
, так как .foo
и .baz
являются общими предками. Они могут быть родителями, дедушками и далее.
Всегда пытайтесь определить отношения через плейсхолдеры селектора, а не реальные селекторы. Это даст вам свободу использования (и изменения) любого соглашения по именованию для ваших селекторов, и поскольку отношения определяются только один раз внутри плейсхолдеров, у вас гораздо меньше шансов создать непреднамеренные селекторы.
Для наследования стилей используйте только @extend
, если расширяется селектор .class
или %placeholder
- это своего рода расширенный селектор. Например, .error
своего рода .warning
, так что .error
может расширять .warning
.
%button {
display: inline-block;
// … стили кнопки
// Взаимосвязь: %button есть ребёнок %modal
%modal > & {
display: block;
}
}
.button {
@extend %button;
}
// Yep
.modal {
@extend %modal;
}
// Nope
.modal {
@extend %modal;
> .button {
@extend %button;
}
}
%button
display: inline-block
// … стили кнопки
// Взаимосвязь: %button есть ребёнок %modal
%modal > &
display: block
.button
@extend %button
// Yep
.modal
@extend %modal
// Nope
.modal
@extend %modal
> .button
@extend %button
Есть ситуации, в которых расширяющие селекторы могут быть полезны, и стоят того, чтобы их использовать. Тем не менее, всегда имейте в виду эти правила, чтобы не попасть в беду:
- Используйте указание
@extend
исключительно на%placeholder
‘ы, а не на обычные селекторы. - Когда расширяете классы, делайте это только с другим классом и никогда с составным селектором.
- Убедитесь, что
%placeholder
, который вы расширяете, присутствует как можно реже в таблице стилей. - Избегайте расширять общие селекторы предков (т.е.
.foo .bar
) или общие селекторы-сиблинги (одного уровня) (т.е..foo ~ .bar
). This is what causes selector explosion. Это и вызывает селекторный взрыв.
Говорят, что @extend
уменьшает размер файла, так как комбинирует селекторы, а не дублирует код. Это правда, однако разница нивелируется, если используется сжатие Gzip
Таким образом, если вы не можете использовать Gzip (или любой аналог) то применение @extend
может и имеет смысл, особенно если вес таблицы стилей является узким местом производительности проекта.
Extend и медиа-запросы
Расширять селекторы стоит только в пределах одной медиа-видимости (директива @media
). Думайте о медиа-запросе как о другой области.
%foo {
content: 'foo';
}
// Nope
@media print {
.bar {
// Это не работает. Ещё хуже: это ломает.
@extend %foo;
}
}
// Yep
@media print {
.bar {
@at-root (without: media) {
@extend %foo;
}
}
}
// Yep
%foo {
content: 'foo';
&-print {
@media print {
content: 'foo print';
}
}
}
@media print {
.bar {
@extend %foo-print;
}
}
%foo
content: 'foo'
// Nope
@media print
.bar
// Это не работает. Ещё хуже: это ломает.
@extend %foo
// Yep
@media print
.bar
@at-root (without: media)
@extend %foo
// Yep
%foo
content: 'foo'
&-print
@media print
content: 'foo print'
@media print
.bar
@extend %foo-print
По поводу @extend
мнения чрезвычайно полярны, до такой степени, что многие разработчики, включая меня, выступают против него, о чём вы можете прочитать в следующих статьях:
Подводя итог вышесказанному, я советую использовать @extend
только для обслуживания взаимосвязи между селекторами. Если два селектора имеют схожие характеристики, то это идеальный случай для применения @extend
. Если они независят друг от друга, но у них совпадают несколько свойств, то @mixin
может подойти здесь лучше. Лучше понять как выбрать что-то из этих двух вариантов в этой статье.
Благодарю David Khourshid за его помощь и экспертизу этой главы.
Примеси (Миксины)
Примеси – одна из самых важных частей из всего языка Sass. Они являются ключом к повторному использованю и DRY компонентам. Они позволяют авторам определить стили, которые будут повторно использоваться по всей таблице стилей, без надобности к использованию таких неосмысленных классов, как .float-left
.
Они могут содержать полный набор правил CSS и в значительной степени всё, что разрешено в любом месте документа Sass. Они могут даже принимать аргументы, прямо как функции. Излишне говорить, что их возможности безграничны.
Но я чувствую, что должен вас предупредить о злоупотреблении силой примесей. Опять же, ключевое слово здесь – это простота. Это очень заманчиво – строить чрезвычайно мощные примеси с огромным количеством логики. Это называется техническим усложением и большинство разработчиков страдает от этого. Не усложняйте код, и, прежде всего, сохраняйте его простым. Если примесь становится больше, чем 20 строк или около того, то она должна быть разбита на более мелкие части или полностью пересмотрена.
Основы
Как было сказано, примеси чрезвычайно полезны, и вы должны их использовать. Правило гласит, что если вам случится встретить набор свойств CSS, которые всегда появляются вместе по какой-либо причине (то есть не случайно), то вы можете поместить их в примесь. Хак Micro-clearfix от Николаса Галлагера заслуживает быть помещенным в примесь (без аргументов), например.
/// Помощник для сброса внутреннего обтекания
/// @author Николас Галлагер
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix {
&::after {
content: '';
display: table;
clear: both;
}
}
/// Помощник для сброса внутреннего обтекания
/// @author Николас Галлагер
/// @link http://nicolasgallagher.com/micro-clearfix-hack/ Micro Clearfix
@mixin clearfix
&::after
content: ''
display: table
clear: both
Еще один обоснованный пример: примесь для определения размера элемента, одновременно определяющий и ширину
, и высоту
. Код станет не только легче набирать, но и легче читать.
/// Помощник для определения размера
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
/// Помощник для определения размера
/// @author Kitty Giraudel
/// @param {Length} $width
/// @param {Length} $height
=size($width, $height: $width)
width: $width
height: $height
Для более сложных примеров примесей, взгляните на эту примесь для генерации CSS треугольников, эту примесь для создания длинных теней или эту примесь для полифилла CSS градиентов для старых браузеров.
Безаргументные примеси
Иногда примеси нужны только чтобы избежать повторения одной и той же группы свойств снова и снова, здесь не нужны никакие параметры, имеются достаточные значения по умолчанию, поэтому нам необязательно передавать аргументы.
В таких случаях, можно безопасно опустить скобки при их вызове. Ключевое слово @include
(или знак +
в синтаксисе на отступах) уже действует как индикатор что это вызов примеси; нет необходимости в скобках в данном случае.
// Yep
.foo {
@include center;
}
// Nope
.foo {
@include center();
}
// Yep
.foo
+center
// Nope
.foo
+center()
Список аргументов
Когда имеете дело с неизвестным количеством аргументов в примеси, используйте arglist
, а не список. Думайте об arglist
как о восьмом скрытом недокументированном типе данных Sass, неявность которого позволяет использовать произвольное количество аргументов в примеси или функции, подписи которых содержат ...
.
@mixin shadows($shadows...) {
// type-of($shadows) == 'arglist'
// …
}
=shadows($shadows...)
// type-of($shadows) == 'arglist'
// …
Теперь, когда вы делаете примесь, которая принимает несколько аргументов (3 или более), подумайте дважды, прежде чем создавать один список – может быть, будет легче передавать их по одному.
Sass очень умён в работе с примесями и объявлениями функций, так что вы можете передавать список или карту в качестве списка аргументов для функции или примеси, и это считается как рядом аргументов.
@mixin dummy($a, $b, $c) {
// …
}
// Yep
@include dummy(true, 42, 'kittens');
// Yep but nope
$params: (true, 42, 'kittens');
$value: dummy(nth($params, 1), nth($params, 2), nth($params, 3));
// Yep
$params: (true, 42, 'kittens');
@include dummy($params...);
// Yep
$params: (
'c': 'kittens',
'a': true,
'b': 42,
);
@include dummy($params...);
=dummy($a, $b, $c)
// …
// Yep
+dummy(true, 42, 'kittens')
// Yep but nope
$params: (true, 42, 'kittens')
$value: dummy(nth($params, 1), nth($params, 2), nth($params, 3))
// Yep
$params: (true, 42, 'kittens')
+dummy($params...)
// Yep
$params: ('c': 'kittens', 'a': true, 'b': 42,)
+dummy($params...)
Для получения дополнительной информации о том, лучше ли использовать несколько аргументов, список или список аргументов, SitePoint имеет приятную статью по этой теме.
Примеси и вендорные префиксы
Написание пользовательских примесей для обработки префиксов для неподдерживаемых или частично поддерживаемых свойств CSS может быть очень заманчивым. Но мы не будем это делать. Для начала, если вы можете использовать Autoprefixer, используйте Autoprefixer. Это сделает код Sass вашего проекта всегда соотвествующим последним обновлениям и сделает работу это лучше, чем ваш код для подстановки префиксов.
К сожалению, Autoprefixer не всегда подходит. Если вы используете Bourbon или Compass, вы уже наверника знаете, что они поставляют коллекцию примесей для обработки вендорных префиксов. Используйте их.
Если вы не можете использовать ни Autoprefixer, ни Bourbon и Compass, то тогда вы должны использовать вашу собственную примесь для подстановки префиска свойствам CSS. Но, пожалуйста, не делайте по примеси на каждое свойство, вручную выводя каждый вендор.
// Nope
@mixin transform($value) {
-webkit-transform: $value;
-moz-transform: $value;
transform: $value;
}
// Nope
=transform($value)
-webkit-transform: $value
-moz-transform: $value
transform: $value
Делайте это по-умному.
/// Примесь, которая выводит вендорные префиксы
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - свойство CSS без префикса
/// @param {*} $value - Сырое значение свойства CSS
/// @param {List} $prefixes - Список префиксов для вывода
@mixin prefix($property, $value, $prefixes: ()) {
@each $prefix in $prefixes {
-#{$prefix}-#{$property}: $value;
}
#{$property}: $value;
}
/// Примесь, которая выводит вендорные префиксы
/// @access public
/// @author KittyGiraudel
/// @param {String} $property - свойство CSS без префикса
/// @param {*} $value - Сырое значение свойства CSS
/// @param {List} $prefixes - Список префиксов для вывода
=prefix($property, $value, $prefixes: ())
@each $prefix in $prefixes
-#{$prefix}-#{$property}: $value
#{$property}: $value
Использование этой примеси будет очень простым:
.foo {
@include prefix(transform, rotate(90deg), ('webkit', 'ms'));
}
.foo
+prefix(transform, rotate(90deg), ('webkit', 'ms'))
Пожалуйста, помните о том, что это плохое решение. Например, это не поможет справиться со сложными плейсхолдерами, такими как те, которые нужны для Flexbox. Поэтому использование Autoprefixer будет куда лучшим вариантом.
Условные операторы
Вы уже, наверное, знаете, что Sass предоставляет условные операторы, такие как @if
и @else
. Пока в вашем коде нет сложной логики, нет необходимости и в условных операторах. Фактически, они в основном нужны для библиотек и фреймворков.
Тем не менее, если вам когда-нибудь понадобится использовать их, пожалуйста, следуйте следующим рекоммендациям:
- Никаких скобок, покуда они не обязательны;
- Всегда пустая строка перед
@if
; - Всегда разрыв строки после открывающей фигурной скобки (
{
); @else
на одной строке с предыдущей закрывающей скобкой (}
);- Всегда новая пустая строка после последней закрывающей скобки (
}
), если на следующей строке не стоит закрывающая скобка (}
).
// Yep
@if $support-legacy {
// …
} @else {
// …
}
// Nope
@if ($support-legacy == true) {
// …
}
@else {
// …
}
// Yep
@if $support-legacy
// …
@else
// …
// Nope
@if ($support-legacy == true)
// …
@else
// …
При тестировании на отрицающее значение, всегда используйте ключевое слово not
, а не проверки на false
или null
.
// Yep
@if not index($list, $item) {
// …
}
// Nope
@if index($list, $item) == null {
// …
}
// Yep
@if not index($list, $item)
// …
// Nope
@if index($list, $item) == null
// …
Всегда помещайте переменную часть слевой стороны условия, а (не)ожидаемый результат с правой. Перевёрнутые условия часто более сложно читать, особенно неопытным разработчикам.
// Yep
@if $value == 42 {
// …
}
// Nope
@if 42 == $value {
// …
}
// Yep
@if $value == 42
// …
// Nope
@if 42 == $value
// …
При использовании условных операторов внутри функции для возврата другого результата, основанного на некоторых условиях, убедитесь, что @return
находится вне условных операторов.
// Yep
@function dummy($condition) {
@if $condition {
@return true;
}
@return false;
}
// Nope
@function dummy($condition) {
@if $condition {
@return true;
} @else {
@return false;
}
}
// Yep
@function dummy($condition)
@if $condition
@return true
@return false;
// Nope
@function dummy($condition)
@if $condition
@return true
@else
@return false
Если вам понравился Sass Гайдлайн, пожалуйста, поддержите его.
Поддержите Sass ГайдлайнЦиклы
Благодаря предоставленным в Sass комплексным структурам данных, таких, как списки и карты, не удивляет и возможность перебора по этим объектам.
Тем не менее, наличие циклов, как правило, подразумевает умеренно сложную логику, что, вероятно, не относится к Sass. Перед использованием цикла убедитесь, что он имеет смысл, и что он на самом деле решает задачу.
Each
Цикл @each
, безусловно, наиболее часто используемый из трёх циклов, предусмотренных Sass. Он предоставляет чистый API для перебора списка или карты.
@each $theme in $themes {
.section-#{$theme} {
background-color: map-get($colors, $theme);
}
}
@each $theme in $themes
.section-#{$theme}
background-color: map-get($colors, $theme)
При переборе карты всегда используйте имена переменных $key
и $value
ради последовательности.
@each $key, $value in $map {
.section-#{$key} {
background-color: $value;
}
}
@each $key, $value in $map
.section-#{$key}
background-color: $value
Также соблюдайте следующие принципы, чтобы сохранить читаемость:
- Всегда пустая строка перед
@each
; - Всегда пустая строка после закрывающей скобки (
}
), если на следующей строке нет закрывающей скобки (}
).
For
Цикл @for
может быть полезным, когда скомбинирован с псевдоклассом CSS :nth-*
. Исключая сценарии, когда предпочтительнее использовать цикл @each
, если вам надо пройтись по какому-нибудь объекту.
@for $i from 1 through 10 {
.foo:nth-of-type(#{$i}) {
border-color: hsl($i * 36, 50%, 50%);
}
}
@for $i from 1 through 10
.foo:nth-of-type(#{$i})
border-color: hsl($i * 36, 50%, 50%)
Всегда используйте $i
как переменную для соблюдения соглашения, пока у вас нет веских причин изменить её, никогда не используйте ключевое слово to
, используйте through
. Многие разработчики даже и не знают, что Sass предоставляет такие варианты; использование разных может привести к путанице.
Также следуйте следующим принципам, чтобы сохранить читаемость:
- Всегда пустая строка перед
@each
; - Всегда пустая строка после закрывающей скобки (
}
), если на следующей строке не закрывающая скобка (}
).
While
Цикл @while
не имеет абсолютно никакого применения в реальном проекте Sass, особенно из-за того, что нет способа остановить цикл изнутри. Не используйте его.
Ошибки и предупреждения
Если и есть возможность, которая часто упускается из виду разработчиками, использующих Sass, то это возможность динамически выводить предупреждения и ошибки. Sass поставляется с тремя указаниями для вывода содержимого в стандартной системе вывода (CLI, компилятор…):
@debug
;@warn
;@error
.
Отложим @debug
в сторону, так как очевидно, что он нацелен на отладку SassScript, который не является нашей целью здесь. Нам остаются @warn
и @error
, которые с виду одинаковые, за исключением того, что один останавливает компилятор, а другой нет. Позволю вам самим додумать, какой из них что делает.
В любом Sass проекте найдётся непаханое поле для применения предупреждений и ошибок. Обычно любая примесь или функция, за исключением специальных типов или аргументов, может выкинуть ошибку, если произойдёт что-то неожиданное, или вывести предупреждение, когда делает предположение.
Предупреждения
Возьмём функцию из Sass-MQ, предполагающую конвертирование из px
в em
, например:
@function mq-px2em($px, $base-font-size: $mq-base-font-size) {
@if unitless($px) {
@warn 'Assuming #{$px} to be in pixels, attempting to convert it into pixels.';
@return mq-px2em($px + 0px);
} @else if unit($px) == em {
@return $px;
}
@return ($px / $base-font-size) * 1em;
}
@function mq-px2em($px, $base-font-size: $mq-base-font-size)
@if unitless($px)
@warn 'Assuming #{$px} to be in pixels, attempting to convert it into pixels.'
@return mq-px2em($px + 0px)
@else if unit($px) == em
@return $px
@return ($px / $base-font-size) * 1em
Если единица измерения значения отсутствует, то функция подразумевает, что это пиксели. С этой точки зрения, предположение может быть рискованным для пользователя и поэтому он должен быть предупреждён, что программа сделает что-то, что может быть неожиданным поведением.
Ошибки
Ошибки, в отличие от предупреждений, предотвращают компилятор от дальнейшей работы. Обычно они останавливают сборку и выводят сообщение в поток вывода, также как и в stack trace, что весьма удобно для отладки. Из-за этого ошибки должны быть выведены только тогда, когда уже нет возможности для выполнения программы. Когда есть возможность, попробуйте обойти эту проблему и вывести вместо этого предупреждение.
Как пример, давайте предположим, что вы хотите сделать функцию-геттер для доступа к значениям определенной карты. Вы можете вывести ошибку, если нужный ключ не существует в карте переменных.
/// Карта Z-index’ов, собирает все Z-слои приложения
/// @access private
/// @type Map
/// @prop {String} key - Имя слоя
/// @prop {Number} valye - значение Z, соответствующее ключу
$z-indexes: (
'modal': 5000,
'dropdown': 4000,
'default': 1,
'below': -1,
);
/// Получение значения z-index из имени слоя
/// @access public
/// @param {String} $layer - Имя слоя
/// @return {Number}
/// @require $z-indexes
@function z($layer) {
@if not map-has-key($z-indexes, $layer) {
@error 'Нет слоя с именем `#{$layer}` в $z-indexes. '
+ 'Слой должен быть одним из #{map-keys($z-indexes)}.';
}
@return map-get($z-indexes, $layer);
}
/// Карта Z-index’ов, собирает все Z-слои приложения
/// @access private
/// @type Map
/// @prop {String} key - Имя слоя
/// @prop {Number} valye - значение Z, соответствущее ключу
$z-indexes: ('modal': 5000, 'dropdown': 4000, 'default': 1, 'below': -1,)
/// Получение значения z-index из имени слоя
/// @access public
/// @param {String} $layer - Имя слоя
/// @return {Number}
/// @require $z-indexes
@function z($layer)
@if not map-has-key($z-indexes, $layer)
@error 'Нет слоя с именем `#{$layer}` в $z-indexes. '
+ 'Слой должен быть одним из #{map-keys($z-indexes)}.';
@return map-get($z-indexes, $layer)
Больше информации, как эффективно использовать @error
, в этом введении в обработку ошибок.
Инструменты
Здорово, что такие пополярные CSS-препроцессоры, как Sass, поставляются с экосистемой фреймворков, плагинов, библиотек и инструментов. После восьми лет существования мы приближаемся к точке, где всё, что может быть написано на Sass, будет написано на Sass.
Тем не менее, я советую снизить количество зависимостей к минимальному. Управление зависимостями чем-то похоже на ад, в котором вы не хотели бы оказаться. Кроме того, нет особой необходимости использовать внешние зависимости, когда работаете с Sass.
Compass
Compass – основной фреймворк Sass, разработанный Крисом Эппстейном, одним из ключевых разработчиков Sass, и я не вижу веских причин для снижения его популярности в последнее время, если вам интересно моё мнение.
Тем не менее, я больше не использую Compass, и главная причина в том, что он сильно замедляет Sass. Ruby Sass сам по себе весьма медленный, так что добавить ещё больше Ruby и сверху положить Sass не сильно помогает.
Дело в том, что мы используем очень малую часть фреймворка. Compass огромен. Кросс-браузерная поддержка – лишь вершина айсберга. Математические функции, помощники изображений, спрайты… Есть ещё много того, что может быть сделано этим фреймворком.
К сожалению, это всё сахар, и каких-либо уникальных возможностей в нём нет. Исключение – лишь механизм построения спрайтов, который по-настоящему хорош, но Grunticon и Grumpicon тоже отлично справляются и более выгодны в том, что могут быть подключенны в процессе сборки.
Конечно же, я не отрицаю использование Compass, как впрочем и не рекомендую, тем более, что он не совместим с LibSass (хоть и были предприняты усилия для этого). Если вы чувствуете, что вам стоит использовать его, то это достаточно справедливо, но я не думаю, что вы получите много от него в конце концов.
Ruby Sass в настоящее время подвергается некоторым выдающимся оптимизациям, которые специально предназначены для тяжёлых стилей со множеством функций и примесей. Они должны резко повысить его производительность до точки, когда Compass и другие фреймворки не будут больше замедлять Sass.
Системы сеток
Отказ от использования системы сеток – не вариант, потому что адаптивный веб-дизайн повсюду. Для того, чтобы дизайн выглядел хорошо на всех размерах, мы используем систему сеток для расположения элементов. Чтобы избежать необходимости писать код этой системы сеток снова и снова, некоторые блестящие умы создали системы сеток многоразового использования.
Позвольте сказать прямо: я не большой поклонник систем сеток. Конечно, я вижу их потенциал, но я думаю, что большинство из них полностью излишни и в основном используются для рисования красных столбцов на белом фоне в презентациях дизайнеров. Когда в последний раз вы думали, что слава-Богу-что-я-использовал-этот-инструмент-для-построения-этой-сетки-2-5-3.1-π? Всё верно, никогда. Потому что в большинстве случаев вы просто хотите обычную 12-колоночную сетку и ничего больше.
Если вы используете CSS-фреймворк для вашего проекта, такой как Bootstrap или Foundation, то он, скорее всего, уже включает в себя систему сеток и в этом случае я бы рекомендовал использовать именно его, чтобы избежать необходимость иметь дело с ещё одной зависимостью.
Если вы не привязаны к особой системе сеток, то вам будет приятно знать, что есть два первоклассных движка модульных сеток для Sass: Susy и Singularity. Обе делают гораздо больше, чем вам когда-нибудь понадобится, так что вы можете выбрать тот, который вы предпочитаете между этими двумя, и убедитесь, что все ваши крайние случаи – даже самые изящные из них – будут покрыты. Если вы спросите меня, то я отвечу: Susy имеет немного лучшее сообщество, но это лишь моё мнение.
Или вы можете использовать что-то менее популярное, типа csswizardry-grids. В общем, ваш выбор не будет иметь большого влияния на стиль написания кода, так что это в значительной степени зависит от вас.
SCSS-lint
Проверка качества кода всегда очень важна. Как правило, следующие рекомендации из руководста помогают уменьшить количество ошибок в коде, но никто не совершенен и всегда есть что улучшить. Таким образом можно сказать, что проверка кода так же важна, как и его комментирование.
SCSS-lint инструмент для сохранения читаемости и чистоты вашх файлов CSS. Он полностью настраиваемый и легко встраивается в ваш существующий набор инструментов.
К счастью, рекомендации SCSS-lint очень похожи на те, что описаны в данном документе. Для того, чтобы настроить SCSS-lint в соответствии с Sass Guidelines, я рекомендую следующие настройки:
linters:
BangFormat:
enabled: true
space_before_bang: true
space_after_bang: false
BemDepth:
enabled: true
max_elements: 1
BorderZero:
enabled: true
convention: zero
ChainedClasses:
enabled: false
ColorKeyword:
enabled: true
ColorVariable:
enabled: false
Comment:
enabled: false
DebugStatement:
enabled: true
DeclarationOrder:
enabled: true
DisableLinterReason:
enabled: true
DuplicateProperty:
enabled: false
ElsePlacement:
enabled: true
style: same_line
EmptyLineBetweenBlocks:
enabled: true
ignore_single_line_blocks: true
EmptyRule:
enabled: true
ExtendDirective:
enabled: false
FinalNewline:
enabled: true
present: true
HexLength:
enabled: true
style: short
HexNotation:
enabled: true
style: lowercase
HexValidation:
enabled: true
IdSelector:
enabled: true
ImportantRule:
enabled: false
ImportPath:
enabled: true
leading_underscore: false
filename_extension: false
Indentation:
enabled: true
allow_non_nested_indentation: true
character: space
width: 2
LeadingZero:
enabled: true
style: include_zero
MergeableSelector:
enabled: false
force_nesting: false
NameFormat:
enabled: true
convention: hyphenated_lowercase
allow_leading_underscore: true
NestingDepth:
enabled: true
max_depth: 1
PlaceholderInExtend:
enabled: true
PrivateNamingConvention:
enabled: true
prefix: _
PropertyCount:
enabled: false
PropertySortOrder:
enabled: false
PropertySpelling:
enabled: true
extra_properties: []
PropertyUnits:
enabled: false
PseudoElement:
enabled: true
QualifyingElement:
enabled: true
allow_element_with_attribute: false
allow_element_with_class: false
allow_element_with_id: false
SelectorDepth:
enabled: true
max_depth: 3
SelectorFormat:
enabled: true
convention: hyphenated_lowercase
class_convention: '^(?:u|is|has)\-[a-z][a-zA-Z0-9]*$|^(?!u|is|has)[a-zA-Z][a-zA-Z0-9]*(?:\-[a-z][a-zA-Z0-9]*)?(?:\-\-[a-z][a-zA-Z0-9]*)?$'
Shorthand:
enabled: true
SingleLinePerProperty:
enabled: true
allow_single_line_rule_sets: false
SingleLinePerSelector:
enabled: true
SpaceAfterComma:
enabled: true
SpaceAfterPropertyColon:
enabled: true
style: one_space
SpaceAfterPropertyName:
enabled: true
SpaceAfterVariableColon:
enabled: true
style: at_least_one_space
SpaceAfterVariableName:
enabled: true
SpaceAroundOperator:
enabled: true
style: one_space
SpaceBeforeBrace:
enabled: true
style: space
allow_single_line_padding: true
SpaceBetweenParens:
enabled: true
spaces: 0
StringQuotes:
enabled: true
style: single_quotes
TrailingSemicolon:
enabled: true
TrailingZero:
enabled: true
TransitionAll:
enabled: false
UnnecessaryMantissa:
enabled: true
UnnecessaryParentReference:
enabled: true
UrlFormat:
enabled: false
UrlQuotes:
enabled: true
VariableForProperty:
enabled: false
VendorPrefixes:
enabled: true
identifier_list: base
include: []
exclude: []
ZeroUnit:
enabled: true
Если вы не уверены в необходимости использования SCSS-lint, то советую прочитать эти замечательные статьи: Clean Up your Sass with SCSS-lint, Improving Sass code quality on theguardian.com и An Auto-Enforceable SCSS Styleguide.
Если вы хотите подключить SCSS-lint в процесс сборки Grunt, вам будет приятно знать, что есть расширение Grunt для этого – grunt-scss-lint.
Кроме того, если вы в погоне за приложением, которое работает с SCSS-lint и тому подобным, ребята из Thoughtbot (Bourbon, Neat…) работают над Hound.
Слишком длинно; Не читал
Это руководство по написанию стилей весьма длинное и часто полезно иметь под рукой краткие итоги. Ниже представлен такой конспект.
Ключевые принципы
- Любое руководство по стилю предназначено для поддержания постоянства. Если вы не согласны с какими-то правилами из Гайдлана Sass, это будет справедливо только пока вы постоянно не согласны с ними.
- Код Sass должен быть как можно более простым. Избегайте построения сложным систем, пока таковая не будет совершенно необходима.
- Помните, что иногда KISS (Keep It Simple, Stupid) лучше, чем DRY (Don’t Repeat Yourself).
Syntax & formatting
- Отступ двумя (2) пробелами, никаких табов.
- Строки должны быть по возможности короче 80 сиволов. Смело разбивайте их на несколько строк при необходимости.
- CSS должен быть правильно написан, по возможности следуя CSS Guidelines от Harry Roberts.
- Пользуйтесь пробелами, отделяйте ими разные элементы, правила и декларации. Не стесняйтесь пользоваться пустыми строками, от этого плохо не бывает.
Строки
- Крайне рекомендуется объявлять директиву
@charset
первой строкой таблицы стилей. - Когда применяются как идентификаторы CSS, строки должны быть заключены в одинарные кавычки. УРЛы также должны быть заключены в кавычки.
Numbers
- Sass не различает числа, целые и с точкой, так что незначащие нули в конце следует опустить. А вот нуль перед точкой улучшает читаемость и должен ставиться.
- Нулевая (0) длина не должна содержать единицу измерения.
- Манипуляции с единицами измерения следует рассматривать как арифметические действия, а не строковые операции.
- Для улучшения читаемости, вычисления оборачиваются круглыми скобками. Также, сложные математические операции могут быть разбиты на меньшие фрагменты.
- Магические числа драматически ухудшают поддержку кода и их следует избегать всегда. Если уж используете их, подробно комментируйте их сомнительную полезность в каждом случае.
Colors
- Цвета должны указываться по возможности в HSL, затем RGB, только затем шестнадцетиричное представление (в нижнем регистре и укороченной форме). Ключевые слова цветов использовать не следует.
- Когда осветляется или затемняется цвет, предпочтительно использовать
mix(..)
вместоdarken(..)
иlighten(..)
.
Списки
- Списки должны разделяться запятыми, кроме случая прямой передачи значений CSS строкой с разделителями-пробелами.
- Оборачивание в круглые скобки также служит улучшению читаемости кода.
- Списки в строку не должны иметь завершающей запятой, а многострочные — должны.
Карты
- Карты, сожержащие более одной пары пишутся в несколько строк.
- Для облегчения поддержки кода, после последняя пара значений следуют поставить запятую.
- Ключи карты, которые являются строками должны быть заключены в кавычки как любые другие строки.
Порядок объявлений
- Не имеет значения, какого порядка объявления свойств придерживаться (по алфавиту, по типу и т.д.), лишь бы использовался постоянно какой-то один.
Вложенность селекторов
- Избегайте вложенность селектором, если это не необходимо (то есть в большинстве случаев).
- Применяйте вложенность селекторов для псевдоклассов и псевдоэлементов.
- Медиа-запросы также могут вкладываться в селектор, к которому они относятся.
Соглашения по именованию
- Лучше всего придерживаться способа именования как в CSS, то есть (кроме пары исключений) нижний регистр и разделение дефисом.
Комментирование
- CSS — хитроумный язык; не стесняйтесь писать подробные комментарии о коде, который выглядит (или является) странным.
- Для переменных, функций, примесей и плейсхолдеров, расположенных в публичном API, используйте комментарии SassDoc.
Переменные
- Обязательно используйте флаг
!default
для любых переменных публичного API, чтобы их можно было безопасно изменить. - Не используйте флаг
!global
на корневом уровне, так как это может привести к нарушению синтаксиса Sass в будущем.
Extend
- Применяйте расширение плейсхолдеров, а не существующих CSS селекторов.
- Расширяйте плейсхолдеры по возможности по очереди, чтобы избежать побочных эффектов.
Если вам понравился Sass Гайдлайн, пожалуйста, поддержите его.
Поддержите Sass Гайдлайн
Комментирование
CSS является сложным языком, полным хаков и курьёзов. Из-за этого его стоит подробно комментировать, особенно, если вы или кто-то ещё собирается читать и обновлять код спустя полгода или год. Не ставьте себя или кого-нибудь другого в положение я-не-писал-этого-о-боже-почему.
Для комментариев в CSS есть обширное поле деятельности. Они могут пояснять:
И я, наверное, забыл много других различных причин. Комментирование занимает очень мало времени, когда делается вместе с написанием кода, так что делайте это в нужное время. Возвращаясь на кусок кода, чтобы комментировать его, не только совершенно невозможно, но и крайне раздражительно.
Написание комментариев
В идеале, любой набор CSS правил должен предшествовать комментарию в стиле Си, объясняя цель блока CSS. Этот комментарий также принимает пронумерованные объяснения по поводу конкретных частей набора правил. Например:
В основном, всё, что не является очевидным на первый взгляд, должно быть прокомментировано. Нет такого понятия, как слишком много документации. Помните, что вы не можете комментировать слишком много, так что пишите комментарии ко всему, что стоит того.
Комментируя раздел Sass, используйте встроенные комментарии Sass вместо блока в Си-стиле. Это сделает комментарий невидимым на выходе, даже в расширенном режиме в процессе разработки.
Заметьте, что такой же способ поддерживается и Гайдлайном CSS в его разделе Комментирование.
Документирование
Каждая переменная, функция, примесь и плейсхолдер, который предназначен для повторного использования во всём коде, должны быть задокументированы как часть глобального API с использованием SassDoc.
Необходимо три слеша (
/
).SassDoc выполняет две основные задачи:
Вот пример примеси, обширно документированной в SassDoc: