Современный CSS для динозавров

Автор оригинала: Peter Jang
  • Перевод

— Двигать пиксели в 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 КРУТ [надпись выходит за пределы границ]
Поддержать автора
Поделиться публикацией

Похожие публикации

Комментарии 40

    +10
    Большое спасибо от динозавра.
      +1
      Присоединюсь. Еще раз убедился что в наших условиях пока старые рептилоидные технологии не стоит выкидывать.

      Подождём когда grid станет нормой.
        0
        По данным caniuse у гридов 86.59%. На мой взгляд, достаточный процент, для того, что бы в новых проектах использовать только CSS Grid
          +1
          Это если у вас проектный подход. А если вы поддерживаете один большой проект со старой клиентской базой, то grid пока что оставляете для хипстеров — пущай обкатают =)
            +3

            Угумс. Скажите кому-то, что для удобства разработчиков вы отказались от 13% покупателей — и они сразу наймут другого разработчика.

              0
              В корпоративных проектах разработчики могут настоять на использовании конкретных версий браузеров. Скажут бизнесу, что 13% времени они будут реализовать бизнес-требования, а 87% времени обеспечивать поддержку браузеров вроде IE10 и может быстро оказаться, что только одну версию одного браузера надо поддерживать.
                0
                Эххх… Когда я бросил webdev, верстальщики матерились на IE6…
                +1
                Ну у нас обязательная поддержка последних двух версий Хрома и ФФ, последней версии Сафари и Эджа. И всё. Бизнес принял спокойно. Никого не уволили.
                  0
                  Здорово, если последние две: это свежевышедшая и ESR
                  0

                  Отказались от немерянной красоты любой ценой для 13% покупателей !== «отказались от 13% покупателей». Если у 87%, которые могут, будет быстро и сказочно красиво, а у 13% — попроще, чуть менее красиво, но так же быстро, никто не пострадает. Юзеры не сидят в 5 одновременно открытых браузерах и не сверяют попиксельное совпадение, они заходят на сайт и либо жмут кнопку заказа, либо нет.


                  Сайты не обязаны выглядеть одинаково во всех браузерах! Адаптивная верстка подразумевает адаптацию не только к разрешению экрана, но и к другим возможностям окружения юзера. Именно для этого придумали @supports.

                    +1
                    Тут вы правы. Однако я отвечал на комментарий
                    достаточный процент, для того, что бы в новых проектах использовать только CSS Grid
                  +1
                  98% у них. Просто caniuse не учитывает ЯндексБраузер.
                  Он даже для border-radius выдает 84% caniuse.com/#search=border-radius
                  Хотя в реальности он только на OperaMini не работает.
                    0
                    Там можно выбрать, в процентах от чего считать. При выборе от отслеживаемых картина становится намного лучше. И там уже у border-radius 98.79%, а вот у гридов 85.65%, что по моему весьма соответствует истине.
                      0
                      Вы про all tracked? Он у флексов в РФ 99.44%, если с префиксами.
                      upd. Пардон, перепутал, оригинальный комментарий был про гриды, а не флексы. Вы правы.
                +1
                Поддерживаю. Стало намного яснее.
                А то с одной стороны динозавр, а с другой стороны как слепой котёнок шарашишься под табуреткой, а вокруг сплошные ножки: замуровали, демоны!
              • НЛО прилетело и опубликовало эту надпись здесь
                  +1
                  По мне гриды снаружи (общий каркас/макет), флексы внутри (вспомогательные списки/блоки).
                  Но гриды всё ещё молодая технология, поэтому надо учитывать ЦА ресурса.
                  В целом неплохо написано тут: developer.mozilla.org/ru/docs/Web/CSS/CSS_Grid_Layout/Relationship_of_Grid_Layout
                  • НЛО прилетело и опубликовало эту надпись здесь
                • НЛО прилетело и опубликовало эту надпись здесь
                    0
                    Они являются частью боксовой модели, описывающей отношения элементов контента внутри контейнера к которому применёно соответствующее свойство.
                    0
                    Учитывая, что динозавры у нас не только разработчики, но и пользователи, Бутстрап 3 пока все еще актуален и в новых проектах, где важна поддержка как можно большего числа устройств, он все еще используется. Согласно аналитике посещаемость некоторых моих сайтов, с браузеров, которые не поддерживают гриды и тп, все еще около 14 %, это слишком много, чтобы забить на поддержку. Конечно, в идеальном мире, пользователи обновляют браузеры, сносят ХР и рьяно несутся устанавливать десятку, но в нашем мире куча старых смартфонов с дефолтными браузерами, пользователей ИЕ 8-9… и тд и тп.
                    Ну а если уж заговорили о препроцессорах, то неплохо было бы рассказать, что многие фишки препроцессоров уже внедрены в стандартный CSS и могут использоваться вот прям здесь и сейчас, так что не надо ставить сборщик, движок и тд… просто тыкай ф5 и смотри себе результат.
                      0
                      посещаемость некоторых моих сайтов, с браузеров, которые не поддерживают гриды и тп, все еще около 14 %

                      многие фишки препроцессоров уже внедрены в стандартный CSS и могут использоваться вот прям здесь и сейчас,

                      Переменные в CSS поддерживаются примерно теми же браузерами, что и гриды. Какое-то противоречие получается между двумя абзацами вашего комментария.

                        0
                        Нативные переменные совершенно не взаимозаменяемы с препроцессорными.
                          +1

                          Да, отличия есть, но задача "избавиться от повторяющихся значений и задавать константы в едином месте" решается и там и там одинаково.

                            0
                            Отличия не просто есть, они принципиальные. Вся суть, соль и цимес нативных переменных в том, что они динамические.
                            Это одновременно и супер-достоинство, и супер-недостаток. Достоинство потому что это очень крутая фича, которая позволяет иной раз избавиться от сотен строк лишнего кода. Недостаток — потому что не полифилится. И пока что сидим курим бамбук.
                              0
                              не полифилится
                              Есть частичный полифил:
                              codepen.io/aaronbarker/full/MeaRmL
                              Форк с улучшениями:
                              gist.github.com/SahAssar/53a796f9aa5f89f9f16c92ca2607cdf6
                              + по мелочи:
                              gist.github.com/frenkel/709d6d54d638f419e9ff2d148ee53287
                                0
                                Всё это, конечно, интересно как эксперимент, но на практике бесполезно. Насколько я понял из кода, оно один раз проходит по стилям и подставляет константы (причем почему-то не парсит имеющееся css-дерево, а грузит стили аяксом — повторно). Использовать css-переменные в таком качестве — это всё равно что из пушки по воробьям. Там вся сила в динамике и многоуровневых зависимостях. А просто подставить константы — препроцессор сделает это не только не хуже, а пожалуй даже удобнее. Реализовывать же всю спецификацию полностью — очень сложно, глючно, тормознуто.
                      0
                      То что нужно! Спасибо за статью.
                        0
                        Спасибо! Понравился перевод! (было бы здорово, если перевели про javascript, который был упомянут в статье)
                        0
                        Для меня, как человека, который никак не может вникнуть в «магию» CSS, свойство CSS grid — это манна небесная.
                          0
                          Ага, сколько у нас гугл выдает результатов по запросу «How do I center my website» — аж 16+ миллионов. А чтобы формочка была по центру вертикальному и горизонтальному? Сколько там костылей для старых IE, ФФ и прочих, плюс тысячи вариантов для мобильных девайсов. А всего то человек хочет Х пикселей шириной/высотой и по центру!

                          А синтаксис этих решений, явно не дает нормальному человеку диназавру понять причем тут автоматический отступ (margin: auto).
                          0
                          Интересно. Может в будущем появится уникальный язык оформления. Вообще отличающийся от текущих мастодонтов, делающий упор на динамику, асинхронность. Отличием от методологии того же React'а, Vim'а будет непосредственная интеграция в броузерные движки, унификация функционала… Ну, мечтать не вредно, как говорится.
                          Я, честно говоря, не думаю, что веб-разработчику стоит выносить мозг абсолютно всем, что есть на текущий момент. В любое время все может перекрутиться. А устаканивание притормаживается повышенной конкуренцией (что имеет свои плюсы по части инноваций).
                            0
                            Спасибо за статью. Работал на фронтенде много в 2004-2006гг. Много изменилось как я погляжу. Создается впечатление что ФЕ все никак не может себя найти. Фреймворков для ФЕ как грибов после дождя. Что из этого выбирать для будущего проекта, например который будет заточен под последний chrome/ff/ie/opera?

                            Что пугает, это куча приблуд которые нужно запускать до, после и вовремя разработки: lassc, npm, bower, gulp, grunt, webpack(?) и прочее — не совсем радует.

                            Я старый динозавр, помню до «ajax», мы динамически айфреймы создавали, постили туда ХМЛ, submit-тили этот ХМЛ и потом считывали из этого фрейма, т.к. нужно было чтобы без «browser refresh» фитчи работали =)
                              +1
                              Что пугает, это куча приблуд которые нужно запускать до, после и вовремя разработки: lassc, npm, bower, gulp, grunt, webpack(?) и прочее — не совсем радует.

                              "Нужно" — неправильное слово. Всё можете делать по старинке, эти "приблуды" лишь помогают экономить время. По крайней мере в теории ) А так пишите CSS, HTML и JS под целевые браузеры и не парьтесь :) Только не удивляйтесь, если у коллег-конкурентов будут меньшие сроки разработки и меньшая скорость работы приложений при прочих равных:)

                                0

                                Гриды лично мне сильно упростили верстку и это очень замечательно. Я последовательный несторонник БЭМ, надеюсь объекты вытеснят файловую верстку и весь зоопарк из bower, gulp,grunt. Я вот не помню пихал я в iframe swf или нет. Надо архивы поднять :)

                                  0

                                  Если речь идет об относительно свежих Chrome / Firefox и даже Edge, то значительная часть ES6 и большая часть CSS3 там поддерживается нативно. Так что под них вполне можно программировать без зоопарка утилит на node.js. Другое дело что IE11 продолжает поддерживаться до 2020 года, а в нем даже arrow functions нет.

                              0
                              А есть пост-процессоры, которые кушают програмер-френдли grid, а на выхлопе дают пусть и кошмарный винегрет из хаков margin/float, но зато с максимальной поодержкой зоопарка браузеров?
                              Разработчикам же всё равно, что будет лежать на сервере. Лишь бы «исходники» были доступны.
                                0
                                но прошло долгое время, пока браузеров стали его поддерживать

                                исправьте на «браузеры», плз

                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                Самое читаемое