Перевод 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-код.