Лекция 5. Организация CSS и CSS-инструменты

Веб-программирование

Лекция 5 Организация CSS
и инструменты

Веб-программирование · лекция 5 из 16

На прошлой лекции

🎛Переменныеодин раз объявить, везде использовать
📱Адаптивностьмедиазапросы, clamp(), @container
🎞Движениеtransform, transition, @keyframes

Всё это сошлось в одной карточке. Сегодня карточек триста, и пишут их пять человек одновременно.

Масштаб

страница из ЛР 2

~200

строк, один автор

крупный сервис

100 000+

строк, десятки авторов

Разница не только в объёме. На двухстах строках все правила помещаются в голове. На ста тысячах — ни в чьей.

Кофейня на углу

Наш проект на сегодня. Лендинг небольшой кофейни: шапка, меню, кнопка «Заказать». Один разработчик, один style.css.

☕
Капучино Заказать Эспрессо и молоко · 220 ₽

За лекцию он вырастет в сеть из тридцати кофеен. Счётчик в углу покажет, как.

☕ 200 строк · 1 разработчик

CSS не масштабируется
сам по себе

Сегодня за 90 минут

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

Часть 1 · 10 минут Проблема масштаба

Когда CSS становится много

Кофейня растёт

🏪 Открылась вторая точка Нужны меню, доставка и страница вакансий. Наняли ещё двоих разработчиков.
☕ 2 000 строк · 3 разработчика

Три болезни большого CSS

🌐Общие именалюбой класс виден всей странице
⚔️Война специфичностейчтобы перебить правило, пишут селектор длиннее
📈Только растётудалить страшно, поэтому дописывают

Ни одна из них не видна на двухстах строках. Все три — неизбежны на двух тысячах.

☕ 2 000 строк · 3 разработчика

Болезнь 1. Общие имена

menu.css · пишет Аня

.title {
    color: #7a5530;
    font-size: 26px;
}

delivery.css · пишет Борис

.title {
    color: #fff;
    font-size: 14px;
}

В CSS нет областей видимости. Оба файла подключены на сайте, и .title в меню и .title в доставке — это один и тот же .title.

☕ 2 000 строк · 3 разработчика

Кто победит

Специфичность одинаковая — 0,1,0. Значит, по правилам каскада из лекции 2 решает порядок: побеждает файл, подключённый позже.

<link rel="stylesheet" href="menu.css">
<link rel="stylesheet" href="delivery.css"> <!-- победит -->

Борис ничего не ломал. Он даже не открывал страницу меню. Но заголовок меню теперь белый, четырнадцатым кеглем.

☕ 2 000 строк · 3 разработчика

Болезнь 2. Война специфичностей

  1. .button { background: brown; }Аня делает кнопку
  2. .menu .button { background: green; }Борис перебивает длиннее
  3. .page .menu .list .button { … }Аня — ещё длиннее
  4. #header .menu .button { … }Борис достаёт id
  5. .button { background: brown !important; }ядерное оружие

🥚 На главной странице курса есть пасхалка !important

Чем кончается эта война

!important против !important: снова решает специфичность и порядок, только теперь перебить нечем. Следующий шаг — style="" прямо в разметке.

Специфичность из лекции 2, которую мы считали на бумаге, в большом проекте становится оружием. И каждый выстрел делает следующий выстрел дороже.
☕ 2 000 строк · 3 разработчика

Болезнь 3. CSS только растёт

.promo-banner { … }            /* кто-то использует? */
.promo-banner-new { … }        /* вроде новый */
.promo-banner-new-2 { … }
.old-header .title { … }       /* старая шапка? её уже нет? */
.title-fix { … }
.title-fix-final { … }
.title-fix-final-v2 { … }    /* не трогать!!! */
.btn, .button, .btn-main { … }
.mt-10-important { margin-top: 10px !important; }
append-only
☕ 2 000 строк · 3 разработчика

Почему правила не удаляют

По CSS нельзя понять, кто им пользуется. Класс могут добавлять из шаблона, из JavaScript, из письма рассылки. Удалишь .promo-banner — и где-то сломается то, чего ты не видел.

Поэтому безопасная стратегия — никогда ничего не удалять и дописывать поверх. Через год половина файла — мёртвый код, который все боятся тронуть.

☕ 2 000 строк · 3 разработчика

Две ветки, один main

Аня сверстала меню с коричневой кнопкой, Борис — доставку с зелёной. У обоих есть классы .title, .item и .button. По отдельности всё выглядит как задумано.

Ветки сливают в общую. Какого цвета станет кнопка в меню?

☕ 2 000 строк · 3 разработчика

Проблема не в свойствах,
а в именах и порядке Значит, лечить её надо договорённостями

Часть 2 · 20 минут Порядок в файлах
и именах

Методологии и БЭМ

Шаг 1. Один файл → папка

styles/
  base/          сброс, типографика, переменные
    reset.css
    tokens.css
  components/    один компонент — один файл
    button.css
    card.css
    header.css
  pages/         то, что есть только на одной странице
    delivery.css
  main.css       только подключения, без правил
☕ 2 000 строк · 3 разработчика

Один компонент — один файл

Удаляете компонент — удаляете его файл. Ничего не остаётся висеть, и не нужно гадать, какие правила были «его».

Две тысячи строк никуда не делись, но теперь у каждой строки есть адрес: стиль кнопки ищут в button.css, а не поиском по всему проекту.

☕ 2 000 строк · 3 разработчика

Порядок подключения — как каскад

/* main.css — от общего к частному */
@import "base/reset.css";
@import "components/button.css";
@import "components/card.css";
@import "pages/delivery.css";

При равной специфичности побеждает то, что подключено позже. Поэтому частное — в конце: странице можно поправить компонент, а компоненту сброс.

Склеивать файлы в один будет сборщик — это лекция 10.

Шаг 2. Договориться об именах

Папки не спасают от главной болезни: .title в menu.css и .title в delivery.css всё ещё один и тот же класс.

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

☕ 2 000 строк · 3 разработчика
2009

БЭМ: Блок, Элемент, Модификатор

Придумали в Яндексе. Десятки сервисов, сотни разработчиков, общие шапки, поиск и кнопки — проблема общих имён там стояла в полный рост.

Сегодня это самая распространённая методология именования в мире, а не только в России.

bem.info — методология БЭМ

Три слова

🧱Блокнезависимый компонент: card, menu, button
🧩Элементчасть блока, без него не существует: card__title
🎨Модификаторвариант блока или элемента: button--primary

Вся методология — это три понятия и два разделителя.

Как читать имя

card__title--large

Карточка по БЭМ

.coffee .coffee__pic .coffee__name .coffee--featured
☕
Капучино Заказать Эспрессо и молоко · 220 ₽
.coffee__desc .coffee__order

По одному имени понятно, где искать стиль и кому он принадлежит.

Разметка и стили

<article class="coffee coffee--featured">
  <div class="coffee__pic">☕</div>
  <h3 class="coffee__name">
    Капучино
  </h3>
  <button class="coffee__order">
    Заказать
  </button>
</article>
.coffee { … }
.coffee--featured { … }

.coffee__pic { … }
.coffee__name { … }
.coffee__order { … }

В CSS — плоский список одиночных классов. Ни тегов, ни вложенности.

Про разделители

В исходном БЭМ Яндекса модификатор отделяется одним подчёркиванием: button_primary. Вариант с двумя дефисами — button--primary — придумали позже, он читается легче и сейчас встречается чаще.

Какой выбрать — неважно. Важно, чтобы весь проект писал одинаково. Мы используем два дефиса.

Правило 1. Только классы

не по БЭМ

.menu li a { … }
#header .title { … }

по БЭМ

.menu__link { … }
.header__title { … }

У всех правил одинаковая специфичность — 0,1,0. Войне из части 1 не на чем стоять: перебивать нечего, побеждает порядок, и он предсказуем.

☕ 2 000 строк · 3 разработчика

Правило 2. Нет элементов элементов

🙅
.menu__list__item__link — повторяет вложенность DOM
👉
.menu__link — элемент принадлежит блоку

Разметку внутри блока будут переделывать. Если имя повторяет структуру, при каждой переделке придётся переименовывать и CSS.

Правило 3. Модификатор не живёт один

не работает

<button class="button--primary">

так и задумано

<button class="button button--primary">

.button даёт всё общее — отступы, шрифт, скругление. .button--primary добавляет только отличие — цвет. Без основного класса у кнопки нет основы.

Правило 4. Место выбирает родитель

блок сам решает

.card {
    padding: 16px;
    margin-top: 24px;
}

решает тот, кто кладёт

.card { padding: 16px; }

.catalog__card {
    margin-top: 24px;
}

Внутренние отступы — дело блока, внешние и позиция — дело того, кто его использует. Иначе блок не переиспользовать: в каждом новом месте его отступ будет мешать.

Микс: два блока на одном узле

<ul class="menu">
  <li class="menu__item card">…</li>
</ul>

Один элемент — одновременно menu__item и блок card. Меню отвечает за положение карточки в списке, карточка — за свой вид.

Так правило 4 и выполняется на практике: внешнее задаёт .menu__item, внутреннее — .card.

Цена

<button class="order-form__submit
               order-form__submit--disabled">

Длинно. Некрасиво. Классы повторяют имя блока по десять раз.

Зато через полгода по этой строке понятно всё: какая форма, какая кнопка, в каком состоянии и в каком файле её стиль. В команде из двадцати человек это дороже красоты.

Те же ветки, но по БЭМ

Аня называет классы menu__…, Борис — delivery__…. Свойства те же, цвета те же. Сливаем ещё раз.

☕ 2 000 строк · 3 разработчика

Игра: БЭМ или не БЭМ

Десять фрагментов кода. В каждом нужно решить: всё по правилам или что-то нарушено — и что именно.

Другие методологии

OOCSS2008. Разделять структуру и оформление: «коробка» отдельно, «краска» отдельно
SMACSS2011. Пять категорий правил: база, раскладка, модули, состояния, темы

Идеи у всех общие: называть по назначению, а не по виду (.warning, а не .red), и держать специфичность низкой.

Запоминать не нужно — нужно узнавать в чужом коде.

А что, если имена
будет следить машина?

2015

CSS Modules

Card.module.cssпишем .title
→
сборщикделает имя уникальным
→
.Card_title__x7f2aполучает браузер

Имена пишутся короткими, как в первой ЛР. Конфликт невозможен технически: у каждого файла свой хвост.

CSS-in-JS

Следующий шаг той же идеи: стили пишутся прямо в коде компонента на JavaScript, а уникальные имена генерируются на лету, при работе страницы.

Несколько лет это был самый модный подход в мире React. Сейчас от него во многом уходят: генерация стилей в браузере стоит времени при каждой отрисовке.

Знать слово нужно: в чужих проектах он встретится.

БЭМ — договорённость людей.
CSS Modules — та же договорённость,
но её соблюдает сборщик.

Часть 3 · 15 минут Препроцессоры

Sass и вложенность

Кофейня растёт

🏙 Сеть из десяти кофеен У каждой свой фирменный цвет: на её странице кнопки, рамки и заголовки должны быть в нём.

Один и тот же набор правил теперь написан десять раз с разными цветами. И каждое исправление — тоже десять раз.

☕ 5 000 строк · 5 разработчиков

Десять раз одно и то же

.shop--arbat .button   { background: #7a5530; }
.shop--arbat .title    { color: #7a5530; }
.shop--arbat .card     { border-color: #7a5530; }

.shop--lesnaya .button { background: #2e7d32; }
.shop--lesnaya .title  { color: #2e7d32; }
.shop--lesnaya .card   { border-color: #2e7d32; }

/* …и ещё восемь раз: в CSS нет циклов */
☕ 5 000 строк · 5 разработчиков

Что такое препроцессор

Препроцессор — язык поверх CSS. Файл на нём компилируется в обычный CSS до того, как попадёт в браузер.
style.scssпишет разработчик
→
sassкомпилятор
→
style.cssобычный CSS
→
браузерSass не видит

Браузер никогда не узнает, что вы писали на Sass.

2006

Sass

Самый старый и самый распространённый препроцессор. Два синтаксиса: старый — на отступах, без скобок, и SCSS — надмножество CSS: любой CSS-файл уже является корректным SCSS.

Сегодня почти все пишут на SCSS. Расширение файла — .scss.

sass-lang.com

Переменные

$brown: #7a5530;
$radius: 10px;

.button {
    background: $brown;
    border-radius: $radius;
}

Знак доллара вместо двух дефисов. Выглядит знакомо — но работает совсем не так, как переменные из лекции 4.

$brown против --brown

Sass: $brownCSS: --brown
когда работаетпри сборкев браузере
браузер видит#7a5530var(--brown)
наследуетсянетда
меняется на летунетда

Тёмную тему из лекции 4 на $-переменных не сделать: к моменту, когда браузер узнал о prefers-color-scheme, переменных уже нет.

Что выбирать в 2026-м

--переменные

цвета, отступы, темы — всё, что может поменяться при работе страницы

$переменные

вычисления и списки, нужные только при сборке: брейкпоинты, карты цветов для циклов

Часто их сочетают: --brown: #{$brown}; — значение из Sass кладут в настоящую CSS-переменную.

Вложенность

.card {
    padding: 16px;
    &__title { color: $brown; }
    &--featured { border: gold; }
    &:hover { … }
}
.card { padding: 16px; }
.card__title { color: #7a5530; }
.card--featured { border: gold; }
.card:hover { … }

& — «родительский селектор». &__title склеивается в .card__title: весь блок БЭМ в одном месте.

Миксины

@mixin button($bg) {
    padding: 10px 18px;
    border-radius: $radius;
    background: $bg;
    color: #fff;
}

.button        { @include button($brown); }
.button--green { @include button(#2e7d32); }

Кусок правил с параметрами. При сборке он копируется в каждое место, где подключён.

Модули: @use

// main.scss
@use "base/tokens";
@use "components/button";
@use "components/card";

Та же раскладка по папкам из части 2. Файлы с подчёркиванием — _button.scss — сами по себе не компилируются, только подключаются.

На выходе один style.css, без лишних запросов, как у @import в браузере.

Десять кофеен — одно правило

$shops: (arbat: #7a5530, lesnaya: #2e7d32, neva: #2f6aa3);

@each $name, $color in $shops {
    .shop--#{$name} {
        .button { background: $color; }
        .title  { color: $color; }
    }
}

Цикл по карте цветов. Новая кофейня — одна строка в $shops, а не тридцать правил.

☕ 5 000 строк · 5 разработчиков

Осторожно с вложенностью

🙅
.page { .content { .card { .title { a { … } } } } }
👉
.card { &__link { … } }

Первое скомпилируется в .page .content .card .title a — та же война специфичностей из части 1, только её не видно в исходнике. Правило: не глубже одного-двух уровней.

2023

Вложенность — уже в самом CSS

.card {
    padding: 16px;

    &:hover { background: #fbf6ef; }
    .card__title { color: var(--brown); }
}

Без сборки, прямо в браузере, во всех современных браузерах.

Склеится ли имя?

.card {
    &__title { color: brown; }
}

В Sass это .card__title. А если этот код написать в обычном .css-файле?

Не склеится

В нативном CSS &__title не работает. & там — целый селектор, а не кусок текста. Браузер прочитает __title как имя тега, и правило не применится ни к чему.

Поэтому для БЭМ в чистом CSS пишут полное имя элемента: .card__title внутри .card { } или просто отдельным правилом.

Что осталось от Sass в 2026-м

возможностьтеперь
переменныеcustom properties, нативно
вложенностьнативно
вычисленияcalc(), clamp(), нативно
цветовые функцииcolor-mix(), нативно
склейка имён &__titleтолько Sass
миксины, циклы, модулитолько Sass

Sass уже не обязателен, но читать его нужно уметь.

Less и Stylus

Другие препроцессоры с теми же идеями: переменные, вложенность, миксины. Less — на нём был написан Bootstrap до 4-й версии. Stylus — самый лаконичный синтаксис.

Новые проекты на них почти не начинают. Встречаются в легаси — и после Sass читаются без подготовки.

Часть 4 · 8 минут PostCSS

Конвейер для CSS

Кофейня растёт

📱 Владелец открыл сайт на старом айпаде И вёрстка развалилась. У дизайнера и разработчиков всё было в порядке: у них свежие браузеры.

Новое свойство старый Safari понимает только под своим именем — с префиксом -webkit-.

☕ 5 000 строк · 5 разработчиков

Префиксы

.card__pic {
    -webkit-backdrop-filter: blur(8px);   /* старый Safari */
    backdrop-filter: blur(8px);           /* все остальные */
}

Какие свойства в каких браузерах нужно дублировать — меняется каждый месяц. Помнить это вручную невозможно, а забытый префикс находит только пользователь.

2013

PostCSS — не язык

PostCSS — конвейер: разбирает CSS, прогоняет через плагины и собирает обратно. Сам по себе не делает ничего.
style.cssна входе
→
плагин 1
→
плагин 2
→
style.cssна выходе

Autoprefixer

.card__pic {
    -webkit-backdrop-filter: blur(8px); /* дописал он */
    backdrop-filter: blur(8px);         /* писали мы */
}

Префиксы дописываются по данным Can I Use и по списку браузеров, которые проект обещает поддерживать:

// .browserslistrc
> 0.5%, last 2 versions, not dead

postcss-preset-env

Позволяет писать CSS, который понимают ещё не все браузеры. То, что поддержано везде, остаётся как есть; остальное переписывается в понятные всем конструкции.

По сути — Babel для CSS. С ним можно пользоваться новыми возможностями из лекции 4, не дожидаясь, пока обновятся браузеры пользователей.

cssnano: минификация

.card__title {
    margin: 0px 0px 0px 0px;
    color: #ffffff;
    /* заголовок карточки */
}
.card__title{margin:0;color:#fff}

Пробелы, комментарии, лишние нули и повторы — всё, что нужно человеку и не нужно браузеру. Файл становится на треть меньше.

Где PostCSS прячется

Скорее всего, вы будете пользоваться им, ни разу не установив вручную:

Препроцессор и PostCSS

Sass

другой язык, который компилируется в CSS

PostCSS

обработка уже готового CSS: CSS на входе, CSS на выходе

Они не соперники. В одном проекте часто работают оба: сначала Sass собирает CSS, потом PostCSS расставляет префиксы и сжимает.

Часть 5 · 12 минут CSS-фреймворки

Чужой CSS вместо своего

Кофейня растёт

⏰ «Админка для бариста нужна к пятнице» Заказы, остатки, смены. Дизайнера нет, времени нет, выглядеть должно прилично.

Писать кнопки, формы и таблицы с нуля некогда. Нужны готовые.

☕ 8 000 строк · 6 разработчиков
2011

Bootstrap

Сделали в Twitter для своих внутренних инструментов. Готовые сетка, кнопки, формы, таблицы, меню, модальные окна — всё на классах.

Подключаете один CSS-файл, пишете разметку с нужными классами — и получаете аккуратный интерфейс, не написав ни строчки CSS.

getbootstrap.com

Форма заказа за минуту

<form class="card p-3">
  <label class="form-label">Напиток</label>
  <select class="form-select mb-3">…</select>

  <button class="btn btn-primary">Заказать</button>
</form>

mb-3 — margin-bottom третьего размера, p-3 — padding. Запомните эти классы, они ещё понадобятся.

Сетка

<div class="row">
  <div class="col-md-8">Заказы</div>
  <div class="col-md-4">Остатки</div>
</div>

Двенадцать колонок: на широком экране 8 + 4, на узком — друг под другом. Внутри — тот же Flexbox из лекции 3 и те же медиазапросы из лекции 4. Никакой магии.

Цена 1. Все сайты похожи

Добро пожаловатьПодробнее
Добро пожаловатьПодробнее
Добро пожаловатьПодробнее
Добро пожаловатьПодробнее
Добро пожаловатьПодробнее
Добро пожаловатьПодробнее
Добро пожаловатьПодробнее
Добро пожаловатьПодробнее
Добро пожаловатьПодробнее
Добро пожаловатьПодробнее

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

Цена 2. Вес

232 КБ

столько весит bootstrap.min.css. Сетка, карусель, модальные окна, подсказки, аккордеоны — даже если вам нужна была только кнопка.

Обычно используется несколько процентов. Остальное браузер всё равно скачивает и разбирает.

Цена 3. Снова война

/* хотим свою кнопку — перебиваем Bootstrap */
.btn-primary {
    background: #7a5530 !important;
    border-color: #7a5530 !important;
}
.navbar .nav-link.active { … }   /* длиннее, чем у них */

Свой дизайн поверх фреймворка — это та же война специфичностей из части 1. Только противник — двести килобайт чужого CSS.

☕ 8 000 строк · 6 разработчиков

Обещание из лекции 4: @layer

@layer reset, framework, components;

@import "bootstrap.css" layer(framework);

@layer components {
    .btn-primary { background: #7a5530; }

}

Каскадные слои. Порядок объявлен в первой строке, и слой, объявленный позже, побеждает — независимо от специфичности. Без !important.

Кто победит?

@layer reset слабее всех
@layer framework { #header .btn { color: white; } } 1,1,0
@layer components { .btn { color: brown; } } 0,1,0

По специфичности сильнее framework: у него id. Но слои сравниваются раньше специфичности.

Побеждает слой

Кнопка коричневая. components объявлен позже framework — и выигрывает, хотя внутри у framework селектор с id.

Фреймворк кладут в нижний слой — и больше не воюют с ним. Каскад из лекции 2 получил ещё одну ступень: происхождение → слой → специфичность → порядок.

Когда фреймворк — правильный выбор

да

  • админки и внутренние инструменты
  • прототипы и хакатоны
  • команда без дизайнера

нет

  • продукт со своим дизайном
  • важна скорость загрузки
  • сайт должен быть узнаваемым

Админка для бариста — идеальный случай. Сайт кофейни — нет.

Кроме Bootstrap

Bulma, Foundation — та же идея, другие классы. Выбирают по вкусу и по тому, что уже знает команда.

В мире React идею продолжают библиотеки компонентов — MUI, shadcn/ui: там готовы не классы, а целые компоненты с поведением. Это лекция 13.

Часть 6 · 14 минут Utility-first

Tailwind

Кофейня растёт

🌍 Тридцать кофеен, дизайн-система, мобильная версия Двенадцать разработчиков, новые экраны каждую неделю.

БЭМ работает, но CSS всё равно растёт: каждый новый компонент приносит новые правила с теми же отступами и цветами.

☕ 20 000 строк · 12 разработчиков

Одно и то же в разных обёртках

.coffee__order  { padding: 8px 16px; border-radius: 8px; }
.cart__checkout { padding: 8px 16px; border-radius: 8px; }
.promo__more    { padding: 8px 16px; border-radius: 6px; }
.vacancy__apply { padding: 8px 16px; border-radius: 8px; }

Четыре блока, четыре имени — и почти одинаковые свойства. Тысячный компонент добавит ещё одну такую строку.

☕ 20 000 строк · 12 разработчиков

Идея: перевернуть подход

Не придумывать имя каждому компоненту, а собирать вид из маленьких одноцелевых классов прямо в разметке:

p-4rounded-xlbg-whiteshadowhover:shadow-lgmd:flex

Один класс — одно свойство. p-4 — это padding: 1rem, rounded-xl — скругление, shadow — тень.

Та же карточка

<div class="p-4 rounded-2xl border-2 border-coffee-100">
  <h3 class="text-xl font-bold text-coffee-900">Капучино</h3>
  <p class="text-sm text-neutral-500">Эспрессо и молоко</p>
  <button class="px-3 py-1.5 rounded-lg bg-coffee-700">
    Заказать
  </button>
</div>

Своего CSS — ноль строк. Всё, что знает карточка о своём виде, написано прямо на ней.

«Это же
inline-стили!» Главное возражение. Отвечаем по пунктам

Ответ 1. Ограничения

style=""

style="padding: 13px"

утилиты

class="p-3"   /* 12px */
class="p-4"   /* 16px */

p-4 — не любое число, а шаг из шкалы дизайн-системы. Inline-стиль разрешает 13px, утилиты — нет. Поэтому тридцать кофеен выглядят как одна система, а не как тридцать разных сайтов.

Ответ 2. Состояния и экраны

bg-coffee-700hover:bg-coffee-900focus:ring-2disabled:opacity-50
flex-colmd:flex-rowtext-baselg:text-lg

hover:, focus: — псевдоклассы из лекции 2. md:, lg: — медиазапросы из лекции 4. В атрибуте style ни того, ни другого не напишешь.

Ответ 3. CSS перестаёт расти

Новый компонент собирается из классов, которые уже есть. Тысячный экран добавляет в CSS ноль строк — меняется только разметка.

свои классыCSS растёт вместе с проектом
утилитыCSS быстро выходит на плато и дальше почти не растёт
☕ 20 000 строк · 12 разработчиков

Ответ 4. Только то, что используется

Утилит в Tailwind — десятки тысяч. В сборку попадают только те, что реально встретились в ваших файлах: инструмент просматривает разметку и генерирует CSS под неё.

Сравните с Bootstrap: там в браузер уезжает всё, что есть во фреймворке, а здесь — только то, что есть в проекте.

2017

Tailwind CSS

*.jsxваша разметка
→
tailwindищет классы
→
PostCSSсобирает CSS
→
style.cssтолько нужное

Самый популярный utility-first инструмент. Работает поверх PostCSS — та самая связка из части 4.

tailwindcss.com

Тема — на переменных

@import "tailwindcss";

@theme {
    --color-coffee-50:  #f6efe6;
    --color-coffee-700: #7a5530;
    --font-sans: "PT Sans", sans-serif;
}

Объявили --color-coffee-700 — и в проекте появились классы bg-coffee-700, text-coffee-700, border-coffee-700. Дизайн-токены из лекции 4 в чистом виде.

Цена

<button class="inline-flex items-center gap-2 px-4 py-2
  rounded-lg bg-coffee-700 text-white text-sm font-bold
  shadow-sm hover:bg-coffee-900 focus:ring-2
  focus:ring-coffee-300 disabled:opacity-50 md:px-6">

Повторы лечатся компонентами

🙅
сорок классов, скопированных в десять мест
👉
<CoffeeCard /> — классы написаны один раз внутри компонента

Поэтому Tailwind так популярен именно в React: там разметку всё равно режут на компоненты, и длинная строка классов живёт в одном месте.

@apply

.btn {
    @apply px-4 py-2 rounded-lg bg-coffee-700 text-white;
}

Способ собрать утилиты обратно в свой класс. Выглядит как спасение от длинных строк — но если делать так везде, получится обычный CSS с лишним шагом сборки.

Авторы Tailwind советуют им не злоупотреблять: повторы — компонентами, @apply — для редких исключений.

БЭМ даёт имя каждой вещи.
Utility-first обходится
без имён вообще.

Часть 7 · 7 минут Финал

Как выбирать

Одна карточка — четыре способа

Чистый CSS, БЭМ, Bootstrap и Tailwind. Внешне карточки одинаковые. Разница в том, где живут решения и сколько CSS уезжает в браузер.

Двадцать лет за одну лекцию

Как выбирать

вопросесли да
CSS пишут больше двух человек?методология: БЭМ или CSS Modules
Своего дизайна нет, а срок вчера?фреймворк: Bootstrap
Проект на компонентах (React, Vue)?CSS Modules или Tailwind
Проект проживёт годы?что-то из этого — обязательно

Страница из ЛР на двести строк не нуждается ни в чём из этого. И это нормально.

Инструмент выбирают
по боли, а не по моде

Что дальше в курсе

В React-проекте во второй половине курса стили будут на CSS Modules или Tailwind. Сегодня стало понятно, зачем каждый из них и какую проблему он решает.

А пока — для своей страницы из ЛР 2 уже сейчас можно взять две вещи: раскладку по файлам и имена по БЭМ.

Что почитать

ru.bem.infoметодология БЭМ от авторов, по-русски
sass-lang.comи tailwindcss.com — документация
Докапо-русски и человеческим языком
QR-код со ссылкой на раздел CSS справочника «Дока» doka.guide/css Справочник по CSS

Лекция 6. JavaScript

Пять лекций страница выглядела. Дальше она начнёт думать. На этой же лекции — ЛР 3.

Вопросы?

Слайды, демо и игра — в репозитории курса