Не будем ходить вокруг да около, скажем прямо: процесс написания хорошего CSS-кода может быть очень и очень тяжёлым. Многие разработчики не хотят связываться со стилями. Они готовы заниматься всем, чем угодно, но только не CSS.
Автор материала, перевод которого мы предлагаем сегодня вашему вниманию, говорит, что он и сам не любил ту часть веб-разработки, которая имеет отношение к CSS. Но от этого никуда не деться. В наши дни огромное внимание уделяется дизайну, и тому, что называют «пользовательским опытом», а без CSS тут никак не обойтись. Цель этого материала — помочь всем желающим улучшить свои навыки в разработке и применении стилей веб-страниц.
Проблемы CSS
В самом начале нового проекта стили обычно выглядят просто и понятно. Скажем, имеется совсем мало CSS-селекторов, вроде .title
, input
, #app
, работа с которыми никому не покажется трудной.
Но, по мере роста приложения, стили превращаются в кошмар. Разработчик начинает путаться в CSS-селекторах. Он обнаруживает, что пишет нечто вроде div#app .list li.item a
. Однако работу останавливать нельзя, поэтому программист продолжает использовать подобные конструкции, CSS-код запихивают куда-нибудь в конец файла. И правда — кого интересуют стили? Да и сам по себе CSS — это такая ерунда… В результате получается 500 строк совершенно неподдерживаемого, ужасного CSS.
Мне хочется, чтобы дочитав эту статью, вы взглянули бы на свои предыдущие проекты и подумали: «Ну ничего ж себе, как же я мог такое написать?».
Возможно, вы думаете сейчас, что «писать CSS» — это значит пользоваться CSS-фреймворками. Ведь предназначены они именно для того, чтобы облегчить работу со стилями, и именно с их использованием пишут хороший CSS-код. Всё это так, но у CSS-фреймворков есть определённые недостатки:
- Часто их использование ведёт к появлению скучного, однообразного, банального дизайна.
- Стили фреймворков трудно настраивать, сложности может вызывать и необходимость сделать что-то такое, что выходит за рамки фреймворка.
- Фреймворки, перед их использованием, необходимо изучать.
И, в конце концов, вы ведь читаете это не для того, чтобы ознакомиться с неким фреймворком? Поэтому займёмся CSS. Сразу хотелось бы отметить, что материал это не о том, как создавать красивые дизайны для приложений. Он — о том, как писать качественный CSS-код, который легко поддерживать, и о том, как правильно его организовывать.
SCSS
В своих примерах я буду использовать SCSS. Это — CSS-препроцессор. Фактически, SCSS является надмножеством CSS. В нём имеются некоторые весьма интересные возможности, такие, как переменные, вложенные конструкции, импорт файлов, миксины. Обсудим возможности SCSS, которыми мы будем пользоваться.
▍Переменные
В SCSS можно пользоваться переменными. Основной плюс применения переменных — возможность их повторного использования. Представим, что у нас имеется набор цветов для приложения. Основной цвет — голубой. В результате этот цвет применяется буквально повсюду. Он используется в свойстве background-color
кнопок, в свойстве color
заголовка страницы, и во многих других местах.
И вот вы, вдруг, решаете поменять голубой на зелёный. Если выполнять такую замену без использования переменных — придётся отредактировать весь код, все строки, где используется старый цвет. Если же воспользоваться переменной, то поменять придётся лишь её значение. Вот как выглядит использование переменных:
// Объявление переменной
$primary-color: #0099ff;
// Использование переменной
h1 {
color: $primary-color;
}
▍Вложенные конструкции
SCSS поддерживает вложенные конструкции. Вот обычный CSS:
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
, а мы, в файле header.scss
, используем команду @import "animations"
. Однако ошибки здесь нет. SCSS — система достаточно интеллектуальная для того, чтобы понять, что в подобной ситуации разработчик имеет в виду соответствующий файл.
Это — всё, что нам надо знать о переменных, о вложенных конструкциях, о фрагментировании стилей, и об импорте. В SCSS есть и другие возможности, вроде миксинов, наследования, и других директив (среди них — @for
, @if
и ещё некоторые), но мы тут о них говорить не будем.
Если вы хотите познакомиться с SCSS поближе — взгляните на соответствующую документацию.
Организация CSS-кода: методология БЭМ
Я уже и не помню, сколько раз я использовал универсальные термины для именования CSS-классов. В результате у меня получались такие имена, думаю, знакомые всем: .button
, .page-1
, .page-2
, .custom-input
.
Часто мы попросту не знаем, как именовать некие сущности. Но это очень важно. Что если вы занимались разработкой приложения, а потом, по какой-то причине, отложили работу на несколько месяцев? Или, а это уже куда хуже, что, если кто-то другой взялся за этот проект? Если в CSS-коде используются неподходящие имена, его сложно будет понять без анализа других частей приложения.
Методология БЭМ (Блок, Элемент, Модификатор) — это компонентный подход к веб-разработке. В частности, речь идёт о соглашении по именованию сущностей. Эта методология позволяет структурировать код, способствует разбиению его на модули и помогает в его повторном использовании. Поговорим о блоках, элементах и модификаторах.
▍Блоки
Блоки можно рассматривать как компоненты. Наверняка, вы играли в детстве в 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
▍Примечания
- При использовании БЭМ имена дают исключительно классам. Никаких ID или тегов — только классы.
- Блоки или элементы могут быть вложены в другие блоки или элементы, но они должны быть полностью независимыми. Это очень важно. Поэтому, например, не надо назначать кнопке поля из-за того, что вы хотите поместить её под заголовком, в противном случае кнопка окажется связанной с заголовком. Используйте вместо этого вспомогательные классы.
- При применении методологии БЭМ HTML-файлы будут перегружены именами, но это — небольшая плата за те возможности, которые даёт нам БЭМ.
▍Упражнение
Вот вам упражнение. Посмотрите внимательно на сайты, которые вам нравятся, или на те, которыми вы чаще всего пользуетесь, и подумайте о том, что на них может быть блоком, что — элементом, а что — модификатором.
Например, вот что у меня получилось в результате анализа Google Store.
Анализ сайта
Теперь — ваша очередь. Посмотрите на сайт, подумайте о том, как его можно улучшить. Для того, чтобы развиться в какой-то области, человеку надо самостоятельно искать информацию, экспериментировать и создавать что-то новое.
▍Примеры
Вот пример, подготовленный средствами Codepen, демонстрирующий возможности БЭМ. Тут мы по-разному оформляем нечто вроде публикаций в некоем блоге. Вот HTML-код этого примера.
<div class="post">
<span class="post__author">Thomas</span> <span class="post__date">3 minutes ago</span>
<p class="post__text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam sit voluptatem aut quis quisquam veniam delectus sequi maxime ullam, inventore blanditiis quia commodi maiores fuga, facere quaerat doloremque in. Nisi!</p>
</div>
<div class="post mt-large post--important">
<span class="post__author">Thomas</span> <span class="post__date">2 hours ago</span>
<p class="post__text">Voluptatem incidunt autem consequatur neque vitae aliquam, adipisci voluptatum. Ipsum excepturi dolores exercitationem rem ab similique consequatur nesciunt, tempora aut vel unde.</p>
</div>
Вот SCSS-стили:
.post {
display: inline-block;
padding: 1rem;
background-color: #ccc;
border: 1px solid #222;
border-radius: 5px;
&--important {
background-color: yellow;
}
&__author {
font-size: 1.2rem;
font-weight: bold;
color: blue;
}
&__date {
float: right;
}
&__text {
line-height: 2rem;
font-size: 1.3rem;
}
}
.mt-large {
margin-top: 3rem;
}
А вот то, что в итоге получилось.
Оформление «публикаций» с использованием БЭМ
Рассмотрим ещё один пример. Тут, пользуясь БЭМ, мы оформляем кнопки. Вот HTML-код этого примера.
<div>
<button class="btn">
Click me
</button>
<button class="btn btn--danger">
Danger
</button>
<button class="btn btn--success">
Success
</button>
<button class="btn btn--small">
Small
</button>
<button class="btn btn--big">
Big
</button>
<button class="btn btn--border">
Border
</button>
</div>
Вот SCSS-стили.
.colors {
font-size: 1.5rem;
font-family: sans-serif;
}
.btn {
background-color: #FF6B93;
color: #fff;
text-transform: uppercase;
padding: 1.5rem 2.5rem;
border-radius: 4px;
transition: all .2s;
font-size: 1.3rem;
border: none;
letter-spacing: 2px;
cursor: pointer;
&:hover {
background-color: #D15879;
}
&:focus {
outline: none;
}
&--danger {
background-color: #FF3B1A;
&:hover {
background-color: #D43116;
}
}
&--success {
background-color: #00D123;
&:hover {
background-color: #00AB1D;
}
}
&--small {
padding: 1rem 2rem;
font-size: 1rem;
}
&--big {
padding: 1.8rem 4.5rem;
font-size: 1.7rem;
}
&--border {
background-color: #fff;
color: #FF6B93;
border: 1px solid #FF6B93;
&:hover {
background-color: #FF6B93;
color: #fff;
}
}
}
А вот — результат.
Оформление кнопок с использованием методологии БЭМ
Организация CSS-файлов: шаблон «7-1»
Давайте поговорим об организации CSS-файлов. То, что вы узнаете из этой части нашего разговора, позволит вам работать продуктивнее, и поможет, в соответствующих ситуациях, мгновенно находить CSS-код, который надо изменить. Для того чтобы всего этого добиться, нам понадобится изучить шаблон «7-1».
Возможно, сейчас вам покажется, что как-то уж слишком странно называется этот шаблон. Однако ничего странного тут нет, и пользоваться им очень просто. Для этого достаточно соблюсти два простых правила:
- Все файлы с SCSS-фрагментами надо разместить в 7 разных папках.
- Все эти файлы нужно импортировать в один файл,
main.scss
, расположенный в корневой директории, в которой лежат все эти папки.
Название шаблона, в результате, можно расшифровать, как «7 папок — 1 файл». Как видите, всё не так уж и сложно. Поговорим об этом шаблоне подробнее.
▍7 папок
Вот папки, о которых идёт речь:
base
: в этой папке надо разместить весь, так сказать, «шаблонный» код. Под «шаблонным» кодом здесь понимается весь тот CSS-код, который приходится писать при создании нового проекта. Например: типографские правила, анимации, утилиты (то есть — классы вродеmargin-right-large
,text-center
), и так далее.components
: название этой папки явно указывает на то, что в ней будет храниться. Речь идёт о стилях компонентов, используемых для сборки страниц. Это — кнопки, формы, всяческие слайдеры, всплывающие окна, и так далее.layout
: эта папка применяется для хранения стилей элементов макетов страниц. Это — шапка и подвал страницы, навигационная область, различные разделы страницы, сетка, и так далее.pages
: иногда в проекте нужны страницы, обладающие собственным специфическим стилем, который отличается от стиля остальных страниц. Описания стилей для таких вот особенных страниц и попадают в эту папку.themes
: если веб-проект предусматривает использование различных тем оформления (скажем, нечто вроде «dark mode», или «admin»), стили для них надо положить сюда.abstracts
: в эту папку попадают всяческие вспомогательные вещи — функции, переменные, миксины.vendors
: редкий сайт обходится без внешних зависимостей. В этой папке хранятся стили, которые созданы не тем, кто разрабатывает конкретный сайт. Сюда, например, можно сохранить файлы проекта Font Awesome, стили Bootstrap и прочее подобное.
▍Файл main.scss
Именно в этот файл импортируются все те фрагменты стилей, которые разложены по вышеописанным семи папкам. Выглядеть некоторая часть этого файла может так:
@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;
Не могу не согласиться с тем, что выглядит вся эта конструкция из семи папок довольно масштабной. Однако тут надо отметить, что эта архитектура рассчитана на большие проекты. Для маленьких проектов можно использовать адаптированную версию шаблона «7-1». Особенности этой версии заключаются в том, что в ней можно обойтись без некоторых папок. Так, тут можно отказаться от папки vendors
, поместив ссылки на внешние по отношению к проекту файлы стилей в тег link
. Далее, можно обойтись без папки themes
, так как, вероятно, в небольшом веб-приложении темы оформления использоваться не будут. И, наконец, можно избавиться от папки pages
, так как в этом проекте, скорее всего, не будет страниц, стиль которых сильно отличается от общего стиля. В результате из семи папок остаётся всего четыре.
Далее, занимаясь маленьким проектом, можно пойти одним из двух путей:
- Если вы предпочитаете воспользоваться тем, что осталось от шаблона «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
Для того чтобы преобразовать SCSS-код в CSS, вам понадобится платформа Node.js и менеджер пакетов NPM (или Yarn).
Мы будем использовать пакет node-sass
, который позволяет компилировать .scss
-файлы в .css
-файлы. Это — инструмент командной строки, пользоваться им несложно. А именно вызов node-sass
выглядит так:
node-sass <input> <output> [options]
Здесь доступно множество опций. Мы остановимся на двух:
- Опция
-w
позволяет организовать наблюдение за папкой или файлом. То есть,node-sass
будет следить за изменениями в коде, и, когда они происходят, автоматически компилировать файлы в CSS. Эта возможность весьма полезна в процессе разработки. - Опция
--output-style
определяет стиль выходного CSS-файла. Тут доступно несколько вариантов:nested
,expanded
,compact
,compressed
. Эту опцию мы будем использовать для сборки готового CSS-файла.
Если вы — человек любопытный (надеюсь — так оно и есть, ведь разработчику любопытство только на пользу), то вам, скорее всего, интересно будет взглянуть на документацию к пакету node-sass
.
Итак, с инструментами мы определились, теперь осталось самое простое. Для того чтобы преобразовать SCSS в CSS, надо выполнить следующие шаги:
Создайте папку проекта и перейдите в неё:
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"
},
...
}
Добавьте ссылку, ведущую к скомпилированному CSS-файлу, в тег head
файла index.html
:
<!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
.
Дополнительные полезности
▍Интерактивная перезагрузка страницы
Возможно вам, для повышения производительности труда, захочется организовать интерактивную перезагрузку страницы. Это удобнее ручной перезагрузки 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
На данном этапе у вас имеется настроенная среда разработки, что очень хорошо. Теперь поговорим об инструментах для сборки проекта, и, в частности, о пакете autoprefixer. Это — инструмент (речь идёт о postcss-плагине), который парсит CSS-код и добавляет префиксы производителей браузеров к CSS-правилам, используя данные с Can I Use.
В ходе создания сайта программист может использовать некие новые возможности, которые не поддерживаются полностью всеми браузерами. Префиксы браузеров направлены на решение целого ряда задач, среди которых — разработка кросс-браузерных веб-приложений.
Код с префиксами браузеров выглядит примерно так:
-webkit-animation-name: myAnimation;
-moz-animation-name: myAnimation;
-ms-animation-name: myAnimation;
Несложно заметить, что писать такой код весьма утомительно. Для того чтобы облегчить задачу обеспечения совместимости нашего CSS-кода с различными браузерами, не переусложняя проект, мы и воспользуемся пакетом autoprefixer
. Тут понадобится выполнить следующие действия:
- Скомпилируем все SCSS-файлы в один основной CSS-файл.
- Добавим в этот файл префиксы браузеров с помощью
autoprefixer
. - Сожмём этот CSS-файл.
Это, в общем-то, завершающий этап работы над проектом. Итак, вот что надо сделать для использования autoprefixer
:
Добавьте в проект две зависимости — postcss-cli
и autoprefixer
:
npm install autoprefixer postcss-cli --save-dev
Добавьте в package.json
следующий код и модифицируйте скрипт build
:
{
...
"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, то теперь, узнав о том, как писать модульный CSS-код, который удобно поддерживать и использовать повторно, вы будете заниматься разработкой стилей продуктивно и с удовольствием.
Уважаемые читатели! Как вы создаёте стили для ваших веб-проектов?
Автор: ru_vds