
Перевод How to get better at writing CSS
Не будем ходить вокруг да около: писать отличный CSS-код может быть трудно. Многие разработчики не хотят этим заниматься: «Я могу сделать что угодно, но это нафиг! Никакого CSS». Когда создаёшь приложение, работа с CSS не приносит удовольствия. Но от него никуда не деться, верно? В смысле, мы сегодня так зациклены на пользовательском опыте и дизайне, что пренебречь CSS не получится.
В начале проекта всё работает прекрасно. У вас есть несколько CSS-селекторов:
.title input #app, проще простого. Но когда приложение разрастается, оно становится уродливым. Вам уже не нравятся ваши селекторы, и вы начинаете писать конструкции наподобие div#app .list li.item a. Пишете один и тот же код снова и снова. Пихаете весь код в конец файла, потому что вам плевать и CSS отстой. И вот результат: 500 строк CSS, который совершенно невозможно сопровождать.Сегодня мы хотим помочь вам лучше овладеть CSS. Чтобы вы посмотрели на свои старые проекты и подумали: «Блин, как я мог это написать?»
«Ладно, — можете подумать вы, — убедили. А что насчёт CSS-фреймворков? Ведь они как раз для этого и предназначены, разве нет? Именно так мы и пишем хороший CSS-код».
Само собой. Но у фреймворков есть ряд недостатков:
- Их использование часто приводит к шаблонному дизайну.
- Трудно настраивать фреймворки или выходить за пределы их возможностей.
- Прежде чем использовать фреймворки, нужно их сначала изучить.
Если на то пошло, вы сейчас читаете эту статью, и на то есть причина, верно? Так что без дальнейших разглагольствований давайте лучше разберёмся в CSS.
Примечание: эта статья не о том, как создавать приложения с прекрасным дизайном. Она о том, как научиться писать удобный в сопровождении CSS-код и как его организовывать.
SCSS
В примерах мы будем использовать SCSS. Это CSS-препроцессор. По сути, он представляет собой расширенный набор CSS: добавляет классные возможности вроде переменных, вложенности, импорта и миксинов.
Давайте рассмотрим возможности, которыми сразу и воспользуемся.
Переменные
SCSS позволяет использовать переменные. Их главное преимущество: многократное использование. Предположим, у вас есть палитра цветов для приложения, и основной цвет синий. Вы используете его везде: как
background-color кнопок, color шапки, в ссылках. СИНИЙ ВЕЗДЕ.И вдруг вам разонравился этот цвет. Теперь вы предпочитаете зелёный.
- Без переменных: придётся изменить каждую строку кода, в которой использован синий цвет.
- С переменными: просто меняете одну переменную ;)
// Declare a variable
$primary-color: #0099ff;
// References a variable
h1 {
color: $primary-color;
}
Вложенность
Благодаря SCSS можно использовать вложенность. Тогда этот код
h1 {
font-size: 5rem;
color: blue;
}
h1 span {
color: green;
}можно превратить в такой:
h1 {
font-size: 5rem;
color: blue;
span {
color: green;
}
}Так гораздо удобнее, верно? Благодаря вложенности вы будете тратить меньше времени на написание сложных селекторов.
Частичные файлы и импорт
Когда речь заходит о сопровождении и читабельности, оказывается невозможно хранить весь код в одном большом файле. Это допустимо при экспериментах или создании маленьких приложений, но на профессиональном уровне… даже не пытайтесь. К счастью, SCSS позволяет нам это делать.
Вы можете создавать частичные файлы, давая им имена с открывающим нижним подчёркиванием:
_animations.scss, _base.scss, _variables.scss и т.д.А для импорта мы воспользуемся директивой
@import. Например, можно сделать так:// _animations.scss
@keyframes appear {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
// header.scss
@import "animations";
h1 {
animation: appear 0.5s ease-out;
}«Ага!» — подумали вы, — «тут ошибка! Написано
_animations.scss, а не animations» ;)Нифига не ошибка. SCSS достаточно умён и знает, что вы имеете в виду частичный файл, когда вы называете его подобным образом.
Это всё, что вам нужно знать о переменных, вложенности, частичных файлах и импорте. У SCSS есть ещё много других возможностей, например, миксины, наследование и прочие директивы (
@for, @if и т. д.), но их мы касаться не будем.Если нужны подробности, почитайте документацию. Она хорошо написана и легка для понимания.
Организация CSS-кода: методология BEM
Я несметное количество раз давал своим классам всеобъемлющие имена. Ну, вы понимаете:
.button .page-1 .page-2 .custom-input.Мы часто не знаем, как давать правильные имена. А это важно делать. Представьте, что вы делаете приложение, и по какой-то причине решили отложить его на несколько месяцев. Или ещё хуже, кто-то забрал у вас проект. Если ваш CSS-код не будет содержать нормальных имён, то в нём трудно будет разобраться.
Решить эту проблему помогает BEM — соглашение по наименованию, расшифровывается как Block Element Modifier — блок, элемент, модификатор.
Методология поможет структурировать код, сделать его более модульным и многократно используемым. Давайте разберёмся, что такое блок, элемент и модификатор.
Блоки
Блок можно считать компонентом. У вас в детстве был конструктор вроде Lego? Как вы строили простой дом? Вам нужны были окно, крыша, дверь, стены, и больше ничего. Это и есть блоки. Они имеют смысл сами по себе.
Именование: имя блока:
.blockПримеры: .
card, .form, .post, . user-navigationЭлементы
А как вам сделать окно для дома из деталей Lego? Возможно, какие-то из них выглядят как части рамы, и если собрать вместе четыре детали, получится прекрасное окно. Так вот эти детали — элементы. Они являются частями блока и нужны для его создания. Но вне блока элементы бесполезны.
Именование: имя блока + __ + имя элемента:
.block__elementПримеры:
.post__author, .post__date, .post__textМодификаторы
Сделав окно, вы захотите покрасить его в зелёный или сделать поменьше. За это отвечают модификаторы — флаги блоков или элементов, используемые для изменения поведения, отображения и так далее.
Именование: имя блока ИЛИ имя элемента + — + имя модификатора:
.block__element--modifier, .block--modifierПримеры:
.post--important, .post__btn--disabledЗамечания
- При использовании BEM вы именуете классами и только классами. Ни ID, ни тегов. Только классы.
- Блоки/элементы могут быть вложены в другие блоки/элементы, но они должны быть полностью независимые. Запомните это слово: независимые. Так что не вставляйте поля в кнопку потому, что вы хотите поместить её под заголовком, иначе кнопка окажется к нему привязана. Вместо этого используйте утилитарные классы.
- Да, ваш HTML-файл раздуется, но не переживайте: это не большая плата за преимущества BEM.
Пример
Вот вам упражнение. Походите по своим любимым или часто посещаемым сайтам и подумайте, что на них может быть блоками, элементами и модификаторами.
Допустим, вот что можно сказать о магазине Google:

Теперь ваша очередь. Полюбопытствуйте и подумайте, что можно улучшить. Естественно, нужно самостоятельно искать, экспериментировать и создавать, чтобы стать лучше в своём деле.
Вот пара примеров, демонстрирующих возможности BEM:
- Пишем отдельный компонент для публикаций: https://codepen.io/thomlom/pen/RJvVdQ.
- Пишем несколько кнопок: https://codepen.io/thomlom/pen/VdgzmJ.
Организация CSS-файлов: паттерн 7–1
Вы всё ещё тут? Отлично! Посмотрим, как можно организовать CSS-файлы. Эта глава поможет вам стать продуктивнее и вы сразу увидите, где можно модифицировать свой CSS-код. А для этого мы познакомимся с паттерном 7-1.
Всё просто, достаточно следовать двум правилам:
- Сохраняйте все частичные файлы в 7 разных папок.
- Импортируйте их в один файл
main.scss, лежащий в корне. И всё.
7 папок
base: сюда кладите весь шаблонный код. Под этим подразумевается CSS-код, который вы будете писать в начале каждого нового проекта. Например: правила типографики, анимации, утилиты (то есть всякие классы вродеmargin-right-large, text-center, …) и т.д.components: имя говорит за себя. В этой папке лежат все компоненты, используемые для создания страниц — кнопки, формы, свайпы, всплывающие окна и т.д.layout: используется для шаблонизации разных частей страницы — заголовок, подвал, навигация, секции, сетка и прочее.pages: иногда у вам может быть страница с каким-то собственным стилем, отличающимся от обычного. Этот стиль кладите в папкуpages.themes: если для вашего приложения есть несколько тем (тёмный режим, администраторская и т. д.), кладите их в эту папку.abstracts: сюда кладите все функции, переменные и миксины. То есть это папка для вспомогательных средств.vendors: у каких приложений или проектов нет внешних библиотек? В эту папку кладите все файлы, которые от вас не зависят.
Основной файл
Импортируем все частичные файлы:
@import abstracts/variables;
@import abstracts/functions;
@import base/reset;
@import base/typography;
@import base/utilities;
@import components/button;
@import components/form;
@import components/user-navigation;
@import layout/header;
@import layout/footer;
...Ну да, выглядит громоздко. Именно так вы и должны были подумать. Эта архитектура адаптирована под большие проекты, а не маленькие. Так что поговорим о версии для проектов поскромнее.
Прежде всего, вам не нужна папка
vendors. Размещайте весь внешний CSS-код в шапке с тегом link. Также можете отказаться от папки themes, если у вас в приложении будет лишь одна тема. Наконец, если не будете использовать на страницах много специфических стилей, то можете избавиться и от папки pages. Осталось 4 папки!У вас есть выбор:
- Хотите организовать CSS-код и следовать паттерну 7–1, тогда сохраните папки
abstracts,components,layoutиbase. - Предпочитаете одну большую папку со всеми частичными файлами и
main.scss, тогда используйте что-то подобное:
sass/ _animations.scss _base.scss _buttons.scss _header.scss ... _variables.scss main.scss
Вам решать.
«Убедили! Но как мне это использовать? Ведь браузеры не поддерживают SCSS-файлы».
Верно подмечено! И теперь мы узнаем, как SCSS компилировать в CSS.
Из SCSS в CSS
Для этого нам понадобятся Node.js и NPM (или Yarn).
Воспользуемся пакетом
node-sass, который позволяет компилировать .scss-файлы в .css-файлы. Его CLI (Command Line Interface) прост в использовании:node-sass <inрut> <outрut> [options]Тут можно использовать разные опции, но нам хватит двух:
-w: отслеживание директории или файла. Это означает, чтоnode-sassотслеживает изменения в коде, которые автоматически компилируются в CSS. Действительно полезно в разработке.--output-style: что мы получим на выходе из CSS-файла, одно из:nested|expanded|compact|compressed.
Если вы любопытны (надеемся, это так, ведь разработчик должен быть любопытным!), то здесь найдёте всю документацию.
Теперь мы знаем, какими инструментами воспользуемся. Дальше ещё проще:
- Создайте проект:
mkdir my-app && cd my-app - Инициализируйте его:
npm init - Добавьте библиотеку:
node-sass:npm install node-sass --save-dev - Создайте папки и файлы
index.htmlиmain.scss:
touch index.html mkdir -p sass/{abstracts,base,components,layout} css cd sass && touch main.scss - Положите в файл
package.jsonэти скрипты:
{ ... "scripts": { "watch": "node-sass sass/main.scss css/style.css -w", "build": "node-sass sass/main.scss css/style.css --output-style compressed" }, ... } - Добавьте в тег
headфайлаindex.htmlссылку на скомпилированный CSS-файл:
<!DOCTYPE html> <html lang=”en”> <head> <meta charset=”UTF-8"> <meta name=”viewport” content=”width=device-width, initial-scale=1.0"> <meta http-equiv=”X-UA-Compatible” content=”ie=edge”> <link rel=”stylesheet” href=”css/style.css”> <title>My app</title> </head> <body> <h1 class=”heading”>My app</h1> </body> </html>
Вот и всё! Когда будете кодить, выполните
npm run watch и откройте в браузере index.html. Если хотите минифицировать CSS, просто выполните npm run build.Бонусы
Добавляем горячую перезагрузку live reload
Для повышения продуктивности вам может понадобиться горячая перезагрузка вместо ручной перезагрузки локального
index.html.Для этого:
- Установите пакет
live-server:npm install -g live-server
Обратите внимание: это глобальный пакет. - Добавьте
npm-run-allв зависимости проекта:npm install npm-run-all --save-dev: это позволит одновременно исполнять много скриптов. - Добавьте в
package.jsonэти скрипты:
{ ... "scripts": { "start": "npm-run-all --parallel liveserver watch", "liveserver": "live-server", "watch": "node-sass sass/main.scss css/style.css -w", }, ... }
Теперь выполните
npm run start и будете сразу видеть все изменения.Добавляем автоматический префиксер
Отлично, инструменты для разработки настроены! Теперь поговорим об инструменте для сборки: Autoprefixer (postcss-плагин). Он парсит CSS и добавляет к правилам вендорские префиксы, используя значения с Can I Use.
Когда вы собираете сайт, вы можете использовать новые фичи, которые поддерживаются не всеми браузерами. И добавить эту поддержку можно с помощью вендорских префиксов.
Например:
-webkit-animation-name: myAnimation;
-moz-animation-name: myAnimation;
-ms-animation-name: myAnimation;Как вы понимаете, писать такое вручную утомительно. Поэтому нам нужен автоматический префиксер, который сделает наш CSS-код совместимым со всеми браузерами без внесения дополнительного уровня сложности.
Итак, нам нужно:
- Компилировать все SCSS-файлы в один основной CSS-файл.
- Запрефиксить CSS-файл с помощью Autoprefixer.
- Сжать CSS-файл.
Остался последний, третий шаг, так что не расходитесь, мы почти закончили:
- Добавляем две зависимости,
postcss-cliиautoprefixer: npm install autoprefixer postcss-cli --save-dev - Модифицируем скрипт
buildи добавляем вpackage.jsonэти скрипты:
{ ... "scripts": { "start": "npm-run-all --parallel liveserver watch", "liveserver": "live-server", "watch": "node-sass sass/main.scss css/style.css -w", "compile": "node-sass sass/main.scss css/style.css", "prefix": "postcss css/style.css --use autoprefixer -o css/style.css", "compress": "node-sass css/style.css css/style.css --output-style compressed", "build": "npm-run-all compile prefix compress" ... }
Если теперь выполнить
npm run build, ваш CSS-код будет сжат и будут добавлены вендорские префиксы!Но знаете, что лучше всего? Мы подготовили для вас репозиторий на тот случай, если хотите быстро начать.
Иииииии на сегодня всё! Теперь вы готовы писать удобный в сопровождении, модульный и многократно используемый CSS-код.