— Двигать пиксели в CSS и так было трудно! А теперь мне говорят, насколько круто использовать несемантические названия классов, встроенные стили в HTML и даже писать стили CSS на JavaScript!
[Вставь тут гифку из «Гриффинов»] — Ха!
Иллюстрации из Dinosaur Comics Райана Норта
Как ни странно, CSS считается одновременно одним из самых простых и одним из самых сложных языков для веб-разработчика. Определённо он достаточно прост в начале — вы определяете свойства стиля, значения для конкретных элементов и… это практически всё, что нужно знать! Однако в больших проектах ситуация становится довольно запутанной и сложной, чтобы организовать CSS каким-то осмысленным образом. Изменение любой строчки CSS для стилизации элемента на одной странице часто ведёт к непредвиденным последствиям для элементов на других страницах.
Чтобы разобраться в присущей сложности CSS, созданы самые разные виды передовых практик. Проблема в том, что до сих пор нет единого мнения, какие из них являются лучшими, а многие из них полностью противоречат друг другу. Если вы впервые пытаетесь выучить CSS, то такая ситуация дезориентирует, мягко говоря.
Цель этой статьи — показать исторический контекст, как развивались техники и инструменты CSS до их нынешнего состояния в 2018 году. Поняв эту историю будет легче понять каждый подход и как с выгодой его использовать. Итак, начнём!
Использование CSS для базовых стилей
Начнём с простейшего веб-сайта, используя только простой файл
index.html
, который ссылается на отдельный файл index.css
:<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Modern CSS</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<header>This is the header.</header>
<main>
<h1>This is the main content.</h1>
<p>...</p>
</main>
<nav>
<h4>This is the navigation section.</h4>
<p>...</p>
</nav>
<aside>
<h4>This is an aside section.</h4>
<p>...</p>
</aside>
<footer>This is the footer.</footer>
</body>
</html>
Пока мы не используем никаких классов или id в HTML, только семантические теги. Вообще без использования CSS веб-сайт выглядел бы так (с текстом-заполнителем):
Нажмите здесь для реального примера
Функционально, но не очень симпатично. Можем добавить CSS для улучшения базового оформления в
index.css
:/* BASIC TYPOGRAPHY */
/* from https://github.com/oxalorg/sakura */
html {
font-size: 62.5%;
font-family: serif;
}
body {
font-size: 1.8rem;
line-height: 1.618;
max-width: 38em;
margin: auto;
color: #4a4a4a;
background-color: #f9f9f9;
padding: 13px;
}
@media (max-width: 684px) {
body {
font-size: 1.53rem;
}
}
@media (max-width: 382px) {
body {
font-size: 1.35rem;
}
}
h1, h2, h3, h4, h5, h6 {
line-height: 1.1;
font-family: Verdana, Geneva, sans-serif;
font-weight: 700;
overflow-wrap: break-word;
word-wrap: break-word;
-ms-word-break: break-all;
word-break: break-word;
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
h1 {
font-size: 2.35em;
}
h2 {
font-size: 2em;
}
h3 {
font-size: 1.75em;
}
h4 {
font-size: 1.5em;
}
h5 {
font-size: 1.25em;
}
h6 {
font-size: 1em;
}
Здесь бóльшая часть CSS — это стили оформления (шрифты с размерами, высота строк и проч.), с некоторыми стилями цветов и центрированной вёрсткой. Вам пришлось бы изучать дизайн, чтобы узнать хорошие значения этих параметров (тут стили из sakura.css), но сам код CSS здесь не слишком сложен для чтения. Результат выглядит примерно так:
Нажмите здесь для реального примера
Какова разница! Это посыл CSS — простой способ добавить стили в документ, без программирования или сложной логики. К сожалению, всё становится немного сложнее, когда мы начинаем использовать CSS для чего-то большего, чем просто оформление и цвета (с этим разберёмся дальше).
Использование CSS для разметки
В 1990-е годы, до того как технология CSS получила широкое распространение, существовало немного вариантов для разметки содержимого на странице. HTML изначально проектировался как язык для создания простых документов, а не динамических веб-сайтов с боковыми меню, колонками и т.д. В те времена разметку часто производили HTML-таблицами — вся страница целиком помещалась в таблицу, которая использовалась для организации контента по колонкам и строкам. Такой подход работал, но обратной стороной была тесная увязка содержания и представления — если вы хотели изменить разметку на сайте, иногда приходилось переписывать значительный объём HTML.
CSS дал сильный толчок к разделению контента (написанного на HTML) и представления (написанного на CSS). Появился способ вынести всю разметку из HTML (больше никаких таблиц) в CSS. Важно отметить, что CSS как и HTML тоже изначально не был спроектирован для разметки страниц, поэтому первые попытки разметки трудно назвать изящными.
Посмотрим, как это работает на практике с нашим вышеприведённым примером. Прежде чем определить какую-либо разметку CSS, сначала сбросим все поля и отступы (которые влияют на вычисление разметки), а также разметим секции разными цветами (не для красоты, а для их визуального различении при тестировании разных макетов).
/* RESET LAYOUT AND ADD COLORS */
body {
margin: 0;
padding: 0;
max-width: inherit;
background: #fff;
color: #4a4a4a;
}
header, footer {
font-size: large;
text-align: center;
padding: 0.3em 0;
background-color: #4a4a4a;
color: #f9f9f9;
}
nav {
background: #eee;
}
main {
background: #f9f9f9;
}
aside {
background: #eee;
}
Теперь веб-сайт временно будет выглядеть так:
Нажмите здесь для реального примера
Сейчас мы готовы использовать CSS для разметки контента на странице. Оценим три разных подхода в хронологическом порядке, начиная с классических float-макетов.
Макет на основе float
Свойство CSS float первоначально ввели для размещения изображения внутри колонки текста слева или справа (что вы часто видели в газетах). Веб-разработчики начала 2000-х воспользовались преимуществом того факта, что вы можете назначить свойство float не только изображениям, но любому элементу, то есть можно создать иллюзию строк и колонок, назначая float для целых div'ов контента. Но опять же, float не предназначен для этой цели, так что такую иллюзию трудно осуществить последовательным образом.
В 2006 году A List Apart опубликовал популярную статью «В поисках Святого Грааля», которая изложила подробный и тщательный подход к созданию макета, известного как Святой Грааль — заголовок, три колонки и нижний колонтитул. Сейчас кажется безумием, что такой довольно простой макет называли Святым Граалем, но вот так трудно было создать устойчивый макет на чистом CSS.
Ниже показан макет на основе float для нашего примера на основе техники, описанной в статье:
/* FLOAT-BASED LAYOUT */
body {
padding-left: 200px;
padding-right: 190px;
min-width: 240px;
}
header, footer {
margin-left: -200px;
margin-right: -190px;
}
main, nav, aside {
position: relative;
float: left;
}
main {
padding: 0 20px;
width: 100%;
}
nav {
width: 180px;
padding: 0 10px;
right: 240px;
margin-left: -100%;
}
aside {
width: 130px;
padding: 0 10px;
margin-right: -100%;
}
footer {
clear: both;
}
* html nav {
left: 150px;
}
Глядя на CSS, можно заметить несколько хаков, необходимых для работы макета (отрицательные границы, свойство
clear: both
, жёстко запрограммированные вычисления ширины и др.) — в статье подробно объясняется необходимость каждого из этих хаков. Вот как выглядит результат:Нажмите здесь для реального примера
Неплохо, но по трём цветам видно, что у колонок неодинаковая высота, а страница не заполняет всю высоту экрана. Это неизбежные проблемы при использовании подхода на основе float. Всё, что может сделать float, это прижать контент к левой или правой границе секции — в CSS нет средств повлиять на высоту контента в других секциях. В течение многих лет у проблемы отсутствовало простое решение, пока не появились макеты на основе flexbox.
Макет на основе flexbox
Свойство flexbox в CSS впервые предложили в 2009 году, но оно не получило широкой поддержки в браузерах примерно до 2015 года. Свойство спроектировано для определения, как распределяется пространство в одной колонке или строке, что делает его более подходящим способом вёрстки, чем float. Таким образом, после десяти лет использования макетов на основе float веб-разработчики наконец-то смогли применять CSS для вёрстки без хаков, присущих макетам на float.
Ниже показан макет на основе flexbox для нашего примера. Он сделан на базе техники, описанной на сайте Solved by Flexbox (популярный ресурс, где публикуются различные примеры на flexbox). Обратите внимание, что для работы flexbox требуется дополнительный враппер div вокруг трёх колонок в HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Modern CSS</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<header>This is the header.</header>
<div class="container">
<main>
<h1>This is the main content.</h1>
<p>...</p>
</main>
<nav>
<h4>This is the navigation section.</h4>
<p>...</p>
</nav>
<aside>
<h4>This is an aside section.</h4>
<p>...</p>
</aside>
</div>
<footer>This is the footer.</footer>
</body>
</html>
Вот код flexbox в CSS:
/* FLEXBOX-BASED LAYOUT */
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.container {
display: flex;
flex: 1;
}
main {
flex: 1;
padding: 0 20px;
}
nav {
flex: 0 0 180px;
padding: 0 10px;
order: -1;
}
aside {
flex: 0 0 130px;
padding: 0 10px;
}
Это гораздо более компактный код по сравнению с макетом на основе float! Свойства и значения flexbox на первый взгляд немного сбивают с толку, но они устраняют необходимость в большом количестве хаков вроде негативных границ — огромная победа. Вот как выглядит результат:
Нажмите здесь для реального примера
Намного лучше! Все колонки одинаковой высоты и занимают всю высоту страницы. В некотором смысле это выглядит идеально, но у такого подхода есть пара небольших недостатков. Во-первых, поддержка браузеров — сейчас все современные браузеры поддерживают flexbox, но некоторые старые браузеры никогда не будут его поддерживать. К счастью, разработчики браузеров делают существенные шаги, чтобы закончить жизненный цикл старых версий, что сделает более стабильной среду разработки для веб-дизайнеров. Другой недостаток — тот факт, что нам нужно добавлять в разметку
<div class="container">
— было бы хорошо обойтись без этого. В идеальном мире любой макет CSS вообще не потребует редактировать разметку HTML.Но самый большой недостаток — в самом коде CSS. Flexbox устраняет много хаков float, но код не такой выразительный, каким он мог быть для описания макета. Flexbox CSS трудно прочитать и получить визуальное понимание, как все элементы лягут на страницу. Из-за этого вы пытаетесь угадать правильные параметры — и проверяете, что получилось.
Важно ещё раз подчеркнуть, что flexbox создан для размещения элементов в одной колонке или строке — он не создан для вёрстки целой страницы! Даже хотя он исправно с этим справляется (намного лучше, чем подход на основе float), для вёрстки в нескольких колонках или строках были специально разработаны другие спецификации. Они называются CSS grid.
Макет на основе grid
CSS grid впервые предложили в 2011 году (ненамного позже flexbox), но прошло долгое время, пока браузеров стали его поддерживать. На начало 2018 года CSS grid поддерживается большинством современных браузеров (огромный шаг вперёд по сравнению с ситуацией год-два назад).
Ниже показан макет на основе grid для нашего примера. Он сделан на базе первого метода, описанного в этой статье по хитростям CSS. Обратите внимание, что в этом примере мы можем избавиться от
<div class="container">
, который приходилось добавлять в макет на основе flexbox. Здесь мы просто используем оригинальный HTML без каких-либо изменений. Вот как выглядит CSS:/* GRID-BASED LAYOUT */
body {
display: grid;
min-height: 100vh;
grid-template-columns: 200px 1fr 150px;
grid-template-rows: min-content 1fr min-content;
}
header {
grid-row: 1;
grid-column: 1 / 4;
}
nav {
grid-row: 2;
grid-column: 1 / 2;
padding: 0 10px;
}
main {
grid-row: 2;
grid-column: 2 / 3;
padding: 0 20px;
}
aside {
grid-row: 2;
grid-column: 3 / 4;
padding: 0 10px;
}
footer {
grid-row: 3;
grid-column: 1 / 4;
}
Результат визуально идентичен макету на основе flexbox. Однако здесь код CSS намного лучше в том смысле, что он явно показывает искомый макет. Размер и форма колонок и строк определены в селекторе body, а каждый элемент сетки непосредственно определяется по своему положению.
Единственное, что может смущать — это свойство
grid-column
, которое определяет начальную и конечную позиции колонки. Оно может смущать, потому что в этом примере три колонки, но используются числа от 1 до 4. Ситуация проясняется, если взглянуть на иллюстрацию:Нажмите здесь для реального примера
Первая колонка начинается в позиции 1 и заканчивается в позиции 2, вторая колонка начинается в 2 и заканчивается в 3, а третья колонка начинается в позиции 3, а заканчивается в позиции 4. В заголовке указано свойство
grid-column
со значением 1 / 4
для расширения на всю страницу, в nav указано grid-column
со значением 1 / 2
для расширения на первую колонку и т.д.Когда вы привыкнете к синтаксису grid, то станет понятно, что это идеальный способ осуществлять вёрстку в CSS. Единственный реальный недостаток — поддержка не во всех браузерах. Но опять же ситуация значительно улучшилась за последний год. Трудно переоценить значение CSS grid как первого реального инструмента в CSS, который действительно изначально создан для вёрстки, то есть для вёрстки всей страницы целиком. В каком-то смысле веб-дизайнерам всегда приходилось быть очень консервативными при создании креативных макетов, поскольку до последнего времени инструменты оставались очень хрупкими, требовали разнообразных хаков и нестандартных лазеек. Теперь с появлением CSS grid возникает потенциал для новой волны креативных дизайнерских макетов, которые невозможно было создать никогда раньше — замечательные времена!
— Получил? Забавно, что когда меняешь что-то в CSS, то оно ломает что-нибудь ещё!
— Возможно, но с новыми спецификациями вроде flexbox и grid всё стало гораздо лучше!
— Ха! В CSS гораздо больше трудностей, а не только вёрстка!
Использование CSS-препроцессора для нового синтаксиса
До сих пор мы рассматривали использование CSS для простых стилей и макетов. Сейчас изучим инструменты, которые помогают работать с самим языком CSS. Начнём с CSS-препроцессоров.
CSS-препроцессор позволяет писать стили на других языках, которые потом преобразуются в CSS, чтобы их понял браузер. Это было исключительно важно во времена, когда браузеры слишком медленно внедряли поддержку новых функций. Первый популярный CSS-препроцессор Sass вышел в 2006 году. В нём реализовали новый краткий синтаксис (отступы вместо скобок, отсутствие точек с запятой и т.д.) и добавили продвинутые функции, отсутствующие в CSS, такие как переменные, вспомогательные функции и вычисления. Вот как выглядит цветная секция из нашего предыдущего примера при использовании Sass с переменными:
$dark-color: #4a4a4a
$light-color: #f9f9f9
$side-color: #eee
body
color: $dark-color
header, footer
background-color: $dark-color
color: $light-color
main
background: $light-color
nav, aside
background: $side-color
Заметьте, как символом
$
обозначаются повторно используемые переменные. Скобки и точки с запятой отсутствуют, что делает синтаксис более чистым. Чистый синтаксис — это приятно, но функции вроде переменных произвели настоящую революцию в то время, поскольку открыли новые возможности для написания чистого и поддерживаемого CSS.Для использования Sass нужно установить Ruby. Этот язык программирования используется для компиляции кода Sass в обычный CSS. Затем нужно установить Sass gem, потом запустить команду в командной строке для преобразования ваших файлов .sass в файлы .css. Вот пример, как выглядит такая команда:
sass --watch index.sass index.css
Эта команда преобразует код Sass из файла
index.sass
в обычный CSS в файле index.css
(аргумент --watch
указывает на запуск каждый раз, когда входные данные изменяются после сохранения, что удобно).Такой процесс известен как этап сборки, и в 2006 году это был довольно значительный барьер для входа. Если вы накоротке с языками программирования вроде Ruby, то для вас всё просто. Но многие фронтенд-разработчики в то время работали только с HTML и CSS, где не требуется подобный инструментарий. Так что это немалое требование к разработчику — изучать целую экосистему, чтобы воспользоваться функциями CSS-препроцессора.
В 2009 году вышел CSS-препроцессор Less. Он тоже написан на Ruby и обладает схожим функционалом с Sass. Ключевым отличием стал синтаксис, который сделали максимально похожим на CSS. Это значит, что любой код CSS одновременно является валидным кодом Less. Вот тот же пример на синтаксисе Less:
@dark-color: #4a4a4a;
@light-color: #f9f9f9;
@side-color: #eee;
body {
color: @dark-color;
}
header, footer {
background-color: @dark-color;
color: @light-color;
}
main {
background: @light-color;
}
nav, aside {
background: @side-color;
}
Он почти не отличается (только префикс
@
вместо $
для переменных), но не так красиво выглядит, как пример Sass. Здесь мы видим те же фигурные скобки и точки с запятой, как в CSS. Но факт близости к CSS упростил веб-дизайнерам освоение этого препроцессора. В 2012 году Less переписали для использования JavaScript (в частности, Node.js) вместо Ruby при компиляции. После этого Less стал работать быстрее, чем его конкуренты на Ruby, а сам препроцессор стал привлекательнее для разработчиков, которые уже используют Node.js в работе.Для преобразования приведённого кода в обычный CSS требуется сначала установить Node.js, затем установить Less и запустить команду:
lessc index.less index.css
Команда преобразует код Less из файла
index.less
в обычный CSS в файле index.css
. Обратите внимание, что команды lessc
нет способа следить за изменением файлов, как это делает sass
. Так что вам придётся использовать какой-нибудь другой инструмент для автоматического отслеживания и компиляции файлов .less
, что немного усложняет процесс. Опять же, здесь нет ничего сложного для программистов, которые привыкли использовать инструменты командной строки, но это значительный барьер для обычных дизайнеров, которые просто желают использовать CSS-препроцессор.Когда Less приобрёл популярность, разработчики Sass добавили в свой препроцессор новый синтаксис SCSS в 2010 году (надмножество CSS, похожее на Less). Они также выпустили LibSass, порт движка Ruby Sass на C/C++, что ускорило его работу и сделало доступным для программирования на различных языках.
Ещё один альтернативный CSS-препроцессор Stylus вышел в 2010 году. Он написан на Node.js и отличается более чистым синтаксисом по сравнению с Sass или Less. Обычно в обсуждении CSS-препроцессоров упоминаются эти три программы как самые популярные (Sass, Less и Stylus). В конце концов, они все очень похожи по функционалу, так что вы не ошибётесь, выбрав любую из них.
Однако некоторые считают, что в последнее время значение CSS-препроцессоров уменьшилось, потому что браузеры наконец-то начали внедрять некоторые из их функций (такие как переменные и вычисления). Более того, существует противоположный подход — постобработка CSS, из-за которой CSS-препроцессоры могут полностью устареть (очевидно, это спорный вопрос). CSS-постпроцессоры мы сейчас и рассмотрим.
Использование CSS-постпроцессора для функций преобразования
CSS-постпроцессор использует JavaScript для анализа и преобразования вашего CSS в валидный CSS. В этом смысле он довольно похож на CSS-препроцессор — его можно рассматривать как иной способ решить ту же проблему. Ключевое отличие в том, что CSS-препроцессор применяет специальный синтаксис для определения объекта трансформации, а CSS-постпроцессор умеет разбирать оригинальный CSS-код и трансформировать его без какого-либо специального синтаксиса. Лучше всего показать это на примере. Посмотрим на часть CSS из вышеупомянутого примера, где мы определяли стиль тегов заголовка:
h1, h2, h3, h4, h5, h6 {
-ms-hyphens: auto;
-moz-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
Строчки со второй по четвёртую называются вендорными префиксы. Браузеры используют вендорные префиксы, когда тестируют новые функции CSS или используют их в экспериментальном режиме. Таким образом разработчики могут протестировать эти функции до окончательной реализации в браузере. Здесь префикс
-ms
для браузера Microsoft Internet Explorer, префикс -moz
для Mozilla Firefox и префикс -webkit
для браузеров на движке Webkit (такие как Google Chrome, Safari и последние версии Opera).Довольно неудобно вставлять эти разные вендорные префиксы для использования свойств CSS. Хорошо бы, чтобы какой-нибудь инструмент автоматически делал это за нас в случае необходимости. Такое можно провернуть с помощью CSS-препроцессоров. Например, в синтаксисе SCSS:
@mixin hyphens($value) {
-ms-hyphens: $value;
-moz-hyphens: $value;
-webkit-hyphens: $value;
hyphens: $value;
}
h1, h2, h3, h4, h5, h6 {
@include hyphens(auto);
}
Здесь мы используем функцию mixin в Sass, которая однажды определяет кусок CSS — а затем везде повторно использует его. Когда этот файл компилируется в регулярный CSS, любой оператор
@include
заменится на код CSS из соответствующего @mixin
. В целом это неплохое решение, но вы несёте ответственность за определение mixin для каждого свойства CSS, где требуется указание вендорных префиксов. Эти определения mixin требуют поддержки: когда браузеры официально внедрят какие-то функции CSS, вы можете захотеть удалить ненужные вендорные префиксы.Вместо mixin хотелось бы просто писать нормальный CSS, чтобы инструмент автоматически находил свойства, которым нужны префиксы, и добавлял их куда надо. CSS-постпроцессор умеет работать именно таким образом. Например, если используете PostCSS с плагином autoprefixer, то можете писать совершенно обычный CSS без каких-либо вендорных префиксов, а постпроцессор сделает всю работу:
h1, h2, h3, h4, h5, h6 {
hyphens: auto;
}
Если запустить CSS-постпроцессор на этом коде, то вместо строчки
hyphens: auto;
появятся все соответствующие вендорные префиксы (в соответствии с правилами автозамены из плагина autoprefixer, которые не нужно вручную менять). То есть вы можете просто писать обычный CSS, не беспокоясь о какой-то совместимости или специальном синтаксисе, и это здорово!Кроме autoprefixer есть и другие плагины для PostCSS, позволяющие вытворять поистине крутые штуки. Плагин cssnext позволяет применять экспериментальные функции CSS. Плагин CSS modules автоматически изменяет классы во избежание конфликтов имён. Плагин stylelint находит ошибки и противоречивые условия в вашем CSS. Эти инструменты по-настоящему стартовали в последние год или два, демонстрируя такие возможности рабочего процесса разработчика, какие не были доступны никогда раньше!
Однако за прогресс приходится платить. Установка и использование CSS-постпроцессора вроде PostCSS требует больше усилий по сравнению с CSS-препроцессором. Вам не только придётся установить и запустить инструменты из командной строки, но также установить и сконфигурировать отдельные плагины и определить более сложный набор правил (вроде того, какие браузеры принимать в расчёт и т. д.). Вместо запуска PostCSS прямо из командной строки многие разработчики интегрируют его в конфигурируемые системы сборки вроде Grunt, Gulp или webpack. Так легче управлять всеми разными инструментами сборки, которые вы можете использовать для фронтенда.
Примечание: Если вы никогда не использовали современные системы сборки для фронтенда, то может показаться, что необходимо усвоить слишком много информации. Если хотите начать с чистого листа, почитайте мою статью «Современный JavaScript для динозавров», где разъясняется весь необходимый инструментарий JavaScript, необходимый для использования этих современных функций во фронтенд-разработке.
Стоит заметить, что вокруг CSS-постпроцессоров развернулись споры. Некоторые говорят, что терминология слишком путаная (одни считают, что все эти инструменты следует называть CSS-препроцессорами; другие говорят, что их нужно называть просто CSS-процессорами и т.д.). Кто-то верит, что CSS-постпроцессоры вообще устранят необходимость в CSS-препроцессорах, кто-то считает, что их следует использовать вместе. В любом случае, нужно изучать CSS-постпроцессоры, если вы хотите выжать всё возможное из CSS.
— Ха! Мне кажется, CSS меняется слишком быстро для своего же блага.
— Ну, не всё сразу!
— Ха! Погоди, в смысле?
— Ты жалуешься, что CSS трудный, и одновременно жалуешься, что люди делают инструменты для его улучшения!
— Возможно! Но одними инструментами не исправишь CSS!
— А вот здесь тебе поможет методология CSS!
Использование методологий CSS для надёжного сопровождения
Инструменты вроде CSS-препроцессоров и CSS-постпроцессоров прошли долгий путь к повышению удобства разработки на CSS. Но одних этих инструментов недостаточно для решения проблемы с поддержкой больших кодовых баз CSS. Чтобы решить эту проблему, начали создавать разные методические рекомендации о том, как писать CSS — обычно их называют методологии CSS.
Прежде чем углубиться в какую-то конкретную методологию CSS, важно понять, по каким причинам долговременная поддержка CSS настолько сложна. Ключевая проблема — в глобальной природе CSS. Каждый установленный вами стиль глобально применяется ко всем частям страницы. На вас возлагается работа или ввести подробную конвенцию именований для поддержки уникальных названий классов, или ввести правила CSS specificity для определения, какой стиль должен применяться к каждому элементу. Методологии CSS предлагают организованный способ писать CSS, чтобы избежать этих болевых точек в больших кодовых базах. Рассмотрим некоторые популярные методологии в хронологическом порядке.
OOCSS
OOCSS (Object Oriented CSS) впервые представили в 2009 году как методологию, на двух основных принципах. Первый принцип — отделять структуру от оболочки. Это значит, что CSS с определением структуры (как макет) не должен смешиваться с CSS, который определяет оболочку (как цвета, шрифты и т.д.). Так проще переделывать оболочку, то есть внешний вид приложения. Второй принцип — отделять контент от контейнера. Это значит представлять элементы как повторно используемые объекты с ключевой идеей, что объект должен выглядеть одинаково независимо от своего положения на странице.
OOCSS предлагает хорошо продуманные методические рекомендации, но не очень точно описывает специфику этого подхода. Последующие методологии вроде SMACSS взяли ключевые концепции и добавили больше подробностей, чтобы с ними было легче работать.
SMACSS
SMACSS (Scalable and Modular Architecture for CSS) появилась в 2011 году как методология, которая рекомендует писать CSS в пяти отдельных категориях: основные правила, правила макета, модули, правила состояния и правила темы. Методология SMACSS также рекомендует определённую конвенцию относительно именования. Например, в правилах макета названия классов следует предварять префиксом
l-
или layout-
. В правилах состояния названия классов должны предваряться префиксами, которые описывают состояние, например, is-hidden
или is-collapsed
.В SMACSS гораздо больше конкретной специфики, чем в OOCSS, но эта методология по-прежнему требует тщательного обдумывания, какие правила CSS следует отнести в каждую из категорий. Последующие подходы вроде BEM частично берут на себя принятие решений, так что их проще использовать на практике.
BEM
Представленная в 2010 году методология BEM (Block, Element, Modifier) основана на разделении пользовательского интерфейса на независимые блоки. Блок — это повторно используемый компонент (примером может быть поисковая форма, определённая как
<form class="search-form"></form>
). Элемент представляет собой меньшую часть блока, и его нельзя повторно использовать самого по себе (примером может быть кнопка из поисковой формы, определённая как <button class="search-form__button">Search</button>
). Модификатор — это сущность, определяющая внешний вид, состояние или поведение блока или элемента (примером будет отключённая кнопка поисковой формы, определённая как <button class=«search-form__button search-form__button--disabled»>Search</button>).Методология BEM проста для понимания, с конкретной конвенцией присвоения имён, что позволяет новичкам применять её без необходимости принимать какие-то сложные решения. Обратная сторона медали в том, что некоторые названия классов довольно многословны и не соответствуют традиционным правилам указания семантических названий. Впоследствии появились новые методологии вроде Atomic CSS, где этот нетрадиционный подход вышел на принципиально новый уровень!
Atomic CSS
Методология Atomic CSS (также известная как Functional CSS) появилась в 2014 году. Она базируется на идее создании маленьких узкоспециализированных классов с названиями, которые основаны на визуальной функции. Этот подход полностью противоположен вышеупомянутым OOCSS, SMACSS и BEM: вместо того, чтобы расценивать элементы на странице как повторно используемые объекты, Atomic CSS вообще игнорирует эти объекты и применяет повторно используемые узкоспециализированные служебные классы, чтобы установить стиль каждого элемента. Так что вместо
<button class="search-form__button">Search</button>
вы получите что-то вроде <button class="f6 br3 ph3 pv2 white bg-purple hover-bg-light-purple">Search</button>
.Если первой вашей реакцией на этот пример будет отпрянуть в ужасе — вы не одиноки. Многие рассматривают эту методологию как абсолютное нарушение устоявшихся лучших практик CSS. Однако прошло немало содержательных дискуссий, где подвергается сомнению эффективность этих практик в некоторых случаях. Эта статья хорошо расставляет акценты, как традиционное разделение задач приводит к созданию CSS, который зависит от HTML (даже при использовании методологий вроде BEM), в то время как «атомарный» или функциональный подход заставляет создавать HTML, который зависит от CSS. Оба варианта приемлемы, но при ближайшем рассмотрении вы обнаружите, что полное разделение CSS и HTML невозможно в принципе!
Другие методологии CSS вроде CSS в JS на самом деле включают в себя понимание, что CSS и HTML всегда будут зависеть друг от друга. Это признание привело к созданию одной из самых противоречивых методологий на сегодняшний день…
CSS в JS
Методология CSS в JS представлена в 2014 году. Она базируется на определении стилей CSS не в отдельной таблице стилей, а прямо внутри каждого компонента. Данная методология разработана для фреймворка React JavaScript (который и сам выбрал неоднозначный подход определения HTML для компонента прямо в JavaScript вместо отдельного файла HTML). Изначально методология использовала вложенные стили, но в поздних реализациях JavaScript генерировал код CSS (с уникальными названиями классов по компоненту) и вставлял его в документ вместе с тегом style.
Методология CSS в JS тоже полностью противоречит устоявшимся лучшим практикам CSS по разделению содержимого. Дело в том, что со временем наши способы использования веба кардинально изменились. Изначально веб состоял в основном из статичных сайтов — там отделение содержимого HTML от представления CSS вполне имело смысл. В наше время Сеть используется для динамических веб-приложений — здесь имеют смысл повторно используемые компоненты.
Цель методологии CSS в JS состоит в том, чтобы разрешить определять компоненты с жёсткими границами, которые состоят из своих собственных инкапсулированных HTML/CSS/JS, так что CSS из одного компонента не имеет возможности повлиять на другие компоненты. React стал одним из первых популярных фреймворков, который продвигал эти компоненты с жёсткими границами. Под его влиянием такие же компоненты ввели в других популярных фреймворках, таких как Angular, Ember и Vue.js. Важно отметить, что методология CSS в JS относительно новая, так что в этой области продолжается много экспериментов — разработчики пытаются установить новые лучшие практики для CSS в эпоху компонентов для веб-приложений.
Легко запутаться в таком большом количестве разных методологий CSS, но важно помнить, что не существует единственно верного подхода — вы должны представлять их как разные доступные инструменты, которые можно использовать, когда у вас на руках достаточно сложная кодовая база CSS. Здесь удобно иметь выбор из разных продуманных подходов, так что все последние эксперименты в этой области принесут пользу каждому разработчику в долговременной перспективе!
Заключение
Вот так выглядит современный CSS в двух словах. Мы обсудили использование CSS для базовых стилей со свойствами оформления, использование CSS для разметки с использованием float, flexbox и grid, использование CSS-препроцессора для нового синтаксиса, такого как переменные и mixin'ы, использование CSS-постпроцессора для функций трансформации, таких как добавление вендорных префиксов, а также методологии CSS для надёжного сопровождения и преодоления глобальной природы стилей CSS. У нас не было шанса подробно разобраться во многих других функциях CSS, таких как продвинутые селекторы, переходы, анимации, формы, динамические переменные — список можно продолжать долго. В CSS многое можно обсудить — если кто-то говорит, что это просто, то он наверное и половины не знает!
С современным CSS определённо может быть неудобно работать, потому что он продолжает изменяться и развиваться быстрыми темпами. Но важно помнить исторический контекст, как развивалась Сеть с годами — и приятно знать, что куча умных людей работают над конкретными инструментами и методологиями, чтобы лучшие практики CSS развивались вместе с вебом. Сейчас захватывающее время, чтобы быть веб-разработчиком, и я надеюсь, что эта информация послужит картой в вашем путешествии!
— Ха! Но все крутые парни по-прежнему ненавидят CSS, верно?
— Как я говорил, не всё сразу!
—… ладно. Дай хоть насладиться CSS-мемами, потому что CSS КРУТ [надпись выходит за пределы границ]