40 Модуль 8 Архитектура стилей 17 мин урок 15 из 25

Организация проекта на 5000 строк

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

Что ты научишься делать

  • Разложишь один большой файл по папкам так, чтобы нужное находилось за секунды
  • Заведёшь порядок подключения, при котором ничего не дерётся
  • Научишься находить и безопасно удалять мёртвые стили

#Как из порядка получается хаос

Файл на восемьсот строк ещё читается: нужное находится поиском. На двух тысячах поиск перестаёт помогать — совпадений слишком много. На пяти тысячах открывать файл страшно.

Хаос никогда не создаётся сознательно. Он набегает по строчке: правило дописали в конец, потому что «так быстрее», значение продублировали, потому что «в тот раз работало».

Структура нужна не ради красоты. Она отвечает на один вопрос: где лежит то, что я сейчас правлю, и куда положить то, что я сейчас пишу.

#Раскладка по папкам

HTMLСтруктура, которая работает
styles/  main.css              подключает всё, задаёт порядок слоёв  base/    reset.css           сброс браузерных стилей    tokens.css          переменные: палитра, шкалы, тени    typography.css      заголовки, текст, ссылки    forms.css           базовый вид полей  layout/    container.css       ширины и поля страницы    grid.css            сетки раскладки    header.css          шапка и подвал  components/    button.css          по файлу на компонент    card.css    modal.css  utilities/    spacing.css         отступы по шкале    visibility.css      скрытие, доступность

Правило деления простое и совпадает со слоями каскада из двадцать шестого урока.

base — то, что действует на голые теги. layout — то, что расставляет блоки по странице. components — сущности со своими именами. utilities — одиночные правки, побеждающие всё.

#Порядок подключения

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

CSSmain.css
/* Порядок слоёв объявлен первой строкой — дальше он нерушим */@layer reset, tokens, base, layout, components, utilities;@import url("base/reset.css")       layer(reset);@import url("base/tokens.css")      layer(tokens);@import url("base/typography.css")  layer(base);@import url("base/forms.css")       layer(base);@import url("layout/container.css") layer(layout);@import url("layout/grid.css")      layer(layout);@import url("layout/header.css")    layer(layout);@import url("components/button.css") layer(components);@import url("components/card.css")   layer(components);@import url("components/modal.css")  layer(components);@import url("utilities/spacing.css")    layer(utilities);@import url("utilities/visibility.css") layer(utilities);

#Комментарии, которые не врут

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

Так не надо

/* Отступ 16 пикселей */
padding: 16px;

/* Красный цвет */
color: #c8394a;

Комментарий пересказывает код. Поменяется значение — комментарий начнёт врать, и никто этого не заметит.

Так надо

/* 34px — высота липкой шапки: под неё
   резервируем место при переходе по якорю */
scroll-padding-top: 34px;

/* Safari до 17 не понимал :has() внутри
   @supports — поэтому проверка отдельной строкой */
@supports selector(:has(*)) {}

Объясняет причину и контекст. Такой комментарий отвечает на вопрос, который возникнет через полгода у другого человека.

#Мёртвые стили

В любом проекте старше года есть правила, которые больше нигде не применяются. Опасность не в весе файла, а в том, что их боятся удалять: непонятно, не сломается ли что-то.

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

  1. Найди кандидатов

    Вкладка Coverage в инструментах разработчика показывает, какая часть CSS не использовалась при обходе страниц. Это не приговор, а список для проверки.

  2. Проверь поиском по всему проекту

    Ищи имя класса не только в разметке, но и в скриптах и шаблонах. Классы, собираемые из кусков строк, поиск не найдёт — это главный риск.

  3. Пометь, а не удаляй

    Добавь комментарий /* кандидат на удаление, проверено 12.03 */ и выложи. Через пару недель, если никто не пожаловался, удаляй.

  4. Удаляй отдельным коммитом

    Один коммит — только удаление, без других правок. Если что-то сломается, откатить будет одно движение.

#Простой стайлгайд

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

Никакого инструмента не нужно: обычная HTML-страница, подключающая те же стили.

HTMLstyleguide.html
<link rel="stylesheet" href="styles/main.css"><main class="container stack gap-8">  <section>    <h2>Кнопки</h2>    <div class="row gap-2">      <button class="btn btn--primary">Основная</button>      <button class="btn btn--ghost">Второстепенная</button>      <button class="btn btn--primary" disabled>Недоступная</button>    </div>  </section>  <section>    <h2>Карточки</h2>    <div class="grid gap-4">      <!-- обычная, со скидкой, без картинки, длинное название -->    </div>  </section></main>

#@supports как страховка

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

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

CSSОбе ветки рабочие
/* База: работает везде */.cards {  display: flex;  flex-wrap: wrap;  gap: 16px;}.card { flex: 1 1 240px; }/* Улучшение: применяется целиком или не применяется вовсе */@supports (grid-template-rows: subgrid) {  .cards {    display: grid;    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));    grid-auto-rows: auto 1fr auto;  }  .card {    grid-row: span 3;    grid-template-rows: subgrid;  }}

#Что смотреть на ревью

Короткий список вопросов, который ловит большую часть проблем ещё до того, как они попадут в проект.

  • Селектор длиннее двух частей — почему?
  • Есть !important — что он перебивает и нельзя ли иначе?
  • Новое значение цвета или отступа — почему не из шкалы?
  • У компонента появился внешний margin — точно ли это его забота?
  • Правило дописано в конец файла — это его место или так вышло?
  • Добавлен новый компонент — он есть на стайлгайде?

#Когда НЕ надо

  • Двадцать папок на лендинге. Для трёхсот строк структура из пяти каталогов — чистые накладные расходы. Одного файла достаточно, пока поиск работает.
  • Заводить структуру задним числом ради структуры. Большая перекладка файлов — риск без немедленной пользы. Вводи новый порядок в новом коде, старый трогай при очередной правке.
  • Двадцать @import без сборки. Задержка загрузки съест выигрыш от аккуратности.
  • Стайлгайд, который никто не открывает. Если он устарел на полгода, он вреднее отсутствия: показывает то, чего в проекте уже нет.

Где спотыкаются почти все

Файл называется по странице, а не по компоненту

Почему Файл about.css собирает стили всего, что встретилось на странице «О нас». Кнопка оттуда понадобится на другой странице — и её скопируют.

Как надо Файл называется по сущности: button.css, card.css. Страница — это композиция компонентов.

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

Почему Кто-то добавил файл в середину, и утилиты перестали побеждать компоненты. Ошибка проявляется в одном месте и ищется долго.

Как надо Объяви слои каскада: тогда приоритет не зависит от порядка строк.

Мёртвые стили удаляют вместе с другими правками

Почему Если что-то сломалось, непонятно, что именно откатывать: удаление или соседнюю правку.

Как надо Удаление — всегда отдельный коммит.

Комментарии пересказывают код

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

Как надо Пиши почему: причину, ограничение, ссылку на баг.

Мёртвый CSS dead CSS
Правила, которые больше не применяются ни к одному элементу.
Покрытие coverage
Вкладка DevTools, показывающая, какая часть кода использовалась при обходе страниц.
Стайлгайд styleguide
Страница со всеми компонентами в одном месте, включая крайние случаи.
Проверка поддержки @supports
Правило, применяющее блок только если браузер понимает конструкцию.

Проверь себя

  1. Почему файл лучше называть <code>button.css</code>, а не <code>about.css</code>?

    Иначе кнопку со страницы «О нас» скопируют на другую страницу, и появится второй экземпляр тех же стилей.

  2. Что делает порядок подключения файлов нехрупким?

    Со слоями приоритет задаётся один раз и не зависит от того, в каком порядке подключены файлы.

  3. Почему автоматические чистильщики CSS опасны?

    Такие классы указывают в списке исключений вручную — и регулярно об этом забывают.

  4. Какой комментарий полезен через год?

    Он объясняет причину. Комментарии, пересказывающие код, устаревают при первой же правке значения.

  5. Когда <code>@supports</code> действительно необходим?

    Одиночное незнакомое свойство и так игнорируется. Проверка нужна там, где ветки мешают друг другу.

Задание

Разложить свалку

Перед тобой кусок файла, где всё свалено в кучу: сброс, переменные, компонент и утилита идут вперемешку, а порядок держится на удаче — поэтому утилита .text-center не работает.

Наведи порядок: объяви слои reset, tokens, base, components, utilities и разложи по ним существующие правила. Селекторы не меняй, !important не добавляй.

Открыть в песочнице
    Подсказка 1

    Первой строкой: @layer reset, tokens, base, components, utilities;

    Подсказка 2

    Дальше просто оберни существующие правила: @layer reset { * { box-sizing: border-box; } }

    Подсказка 3

    Теговые селекторы h3 и p — это base. Классы .card и .card__title — components. .text-center — utilities.

    Показать решение
    HTMLindex.html
    <article class="card text-center">  <h3 class="card__title">Раф</h3>  <p class="card__text">Должен быть по центру</p></article>
    CSSstyle.css
    @layer reset, tokens, base, components, utilities;@layer reset {  * { box-sizing: border-box; }}@layer tokens {  :root {    --space-4: 16px;    --color-surface: #f4f4f8;  }}@layer base {  h3 { margin: 0 0 6px; font-size: 16px; }  p { margin: 0; font-size: 14px; }}@layer components {  .card {    padding: var(--space-4);    background: var(--color-surface);    border-radius: 12px;    text-align: left;  }  .card__title { color: #16181d; }  .card__text { color: #5b6070; }}@layer utilities {  .text-center { text-align: center; }}

    Проверь себя