Раскладка
Раскладка — расстановка элементов строкой, колонкой или сеткой. Во Framework её задают утилиты в разметке; эта глава описывает Flex, Grid, контейнер страницы, промежутки и видимость.
Компонент не раскладывает себя сам
Важное правило Framework: CSS компонента оформляет его части, но не расставляет их. Цвет, размер, граница, скругление приходят из компонента. Флекс-контейнер, в котором лежат части, пишется в разметке утилитами.
Причина — переиспользование. Одна и та же часть встречается в разных композициях, и раскладку выбирает тот, кто собирает страницу. Это продолжение общего принципа: компонент отвечает за свой вид, страница — за расположение.
Цена такого решения — забытый класс. Никакой ошибки не будет: элемент просто не станет контейнером, и его части соберутся в угол.
<span class="sf-radio-button-box flex">…</span>
<span class="sf-radio-button-box flex justify-center items-cross-center">…</span>
В первой строке точка радиокнопки окажется в углу кольца, во второй — по центру.
Smart-компоненты собирают свою разметку сами и так не ломаются (см. Где живёт разметка). Ошибка возможна там, где разметку пишет человек: в шаблоне проекта, в примере, на странице.
Подсказка в исходнике. Над каждым правилом компонента, которому нужна
раскладка, в исходном CSS стоит комментарий utility-hint со списком
утилит, как их задумал макет. Обязательна не вся подсказка: значения по
умолчанию (flex-row, flex-nowrap, justify-start) ничего не меняют.
Обязательно остальное — сам flex, колонка, перенос, выравнивание не от
начала. Выравнивание по поперечной оси подсказка записывает классом
.items-center; в разметке компонента ставьте items-cross-center — так
написаны примеры справочника. Класс items-center тоже существует, но
центрирует по обеим осям (place-items: center), поэтому из подсказки его
не копируют.
/* utility-hint: display/flex (.flex) flex-direction/row (.flex-row)
flex-wrap/nowrap (.flex-nowrap) justify-content/center (.justify-center)
align-items/center (.items-center) */
.sf-radio-button .sf-radio-button-box { … }
Проверка на странице. Статически это не проверить: значение может прийти
из утилиты, из CSS проекта, из инлайна или из модификатора компонента, а
опубликованный CSS содержит вложенные @supports, @layer и :where().
Итог знает только браузер, поэтому документация предлагает проверку, которая
работает в странице:
<script src="/ru/assets/tools/layout-check.js"></script>
Содержимое файла можно и вставить в консоль. Результат — таблица в консоли и
массив, который возвращает sfLayoutCheck(); функции можно передать корень,
чтобы проверить часть страницы. Проверка ничего не меняет на странице и
ничего не отправляет. Это инструмент разработки, в рабочую сборку его не
включают.
Сообщается только доказуемое:
- элемент стал контейнером, но выравнивание в нём осталось по умолчанию — решение из макета до страницы не дошло;
- элементу задан
gap, а контейнером он не стал — промежуток между частями не применяется.
Модификатор компонента считается решением, а не упущением: sf-menu--horizontal
затем и написан, чтобы меню шло строкой. Проверка снимает модификаторы части и
смотрит, изменится ли значение; если изменилось, его поставил модификатор.
Остальное ошибкой не считается: страница вправе прийти к тому же виду другим
способом (text-align, отступами, сеткой родителя). Скрытые элементы и подписи
без вложенных элементов проверка пропускает.
Flex: строка и колонка
Флекс-контейнер — основной способ расставить элементы в линию.
| Задача | Утилиты |
|---|---|
| Включить Flex | flex, inline-flex |
| Направление | flex-row, flex-col, flex-row-reverse, flex-col-reverse |
| Перенос | flex-wrap, flex-nowrap, flex-wrap-reverse |
| Промежуток между элементами | gap-*, gap-x-*, gap-y-* |
| Выравнивание по основной оси | justify-start, justify-center, justify-between… |
| Выравнивание по поперечной оси | items-cross-start, items-cross-center, items-cross-stretch… |
| Обе оси сразу | center-center, start-center, end-end… |
| Поведение элемента | flex-1, flex-none, grow, shrink-none, basis-1/3 |
| Выравнивание одного элемента | self-cross-center, self-main-end |
<div class="flex items-cross-center justify-between gap-1">
<span>Заголовок</span>
<button type="button" class="sf-button sf-button--default sf-button--primary sf-button--size-1">
<span class="sf-button-text-container">Действие</span>
</button>
</div>
Оси main и cross. Framework называет оси раскладки по смыслу:
основная (main) — вдоль потока, поперечная (cross) — поперёк. При
flex-col основная ось становится вертикальной, и justify-center
центрирует по вертикали. Имена items-cross-* и self-cross-* напоминают
об этом.
Выравнивание по основной оси записывается утилитами justify-*.
Сокращения обеих осей (center-center) читаются как «основная — поперечная»:
start-center — к началу по основной оси и по центру по поперечной.
Grid: сетка
Сетка нужна, когда элементы выстраиваются сразу по двум осям.
| Задача | Утилиты |
|---|---|
| Включить Grid | grid, inline-grid |
| Число колонок | grid-col-1…grid-col-12, grid-col-none, grid-col-subgrid |
| Размещение элемента | col-span-2, col-span-full, col-start-3, row-span-2 |
| Автоматические дорожки | auto-cols-fr, auto-rows-min, поток grid-flow-* |
| Промежутки | gap-*, col-gap-*, row-gap-* |
grid-col-3 создаёт три равные колонки, которые не распирает содержимое
(repeat(3, minmax(0, 1fr))). subgrid позволяет вложенной сетке
выровняться по колонкам родителя.
<ul class="grid grid-col-1 md:grid-col-2 lg:grid-col-3 gap-3">
<li>…</li>
<li class="md:col-span-2">…</li>
</ul>
Контейнер страницы
container — блок на всю доступную ширину с боковыми отступами. Начиная с
каждой контрольной точки его максимальная ширина и боковые отступы растут.
Это обычная обёртка основного содержимого страницы. Сам контейнер не
центрируется: внешних отступов он не задаёт, поэтому по центру его ставит
m-inline-auto.
sm:container, md:container и другие варианты с условием начиная со
своей контрольной точки ограничивают ширину контейнера её ступенью и дальше
не растут: до ступени контейнер занимает всю ширину.
max-container-1…max-container-8 на предке ограничивают ширину всех
вложенных container на десктопе. Ступени ссылаются на шкалу размеров —
от --sf-h5 до --sf-i4. Так один класс на обёртке задаёт ширину содержимого
всего раздела.
<body class="max-container-3">
<main class="container m-inline-auto">…</main>
</body>
Макеты страниц целиком — шапки, боковые колонки, области — описаны в разделе Макеты и композиция (см. Области страницы). Утилиты раскладки — их строительный материал.
Пример: шапка, первый экран и карточки
Простую страницу без документа композиции собирают одними утилитами и готовыми компонентами:
<header class="border-bottom-1 border-outline-variant">
<div class="container m-inline-auto p-y-2 flex flex-wrap items-cross-center justify-between gap-2">
<a href="/">Название проекта</a>
<nav aria-label="Основное меню">
<ul class="list-none m-0 p-0 flex flex-wrap gap-2">
<li><a href="/catalog/">Каталог</a></li>
<li><a href="/contacts/">Контакты</a></li>
</ul>
</nav>
</div>
</header>
<main class="container m-inline-auto flex flex-col gap-4 p-y-4">
<section class="flex flex-col gap-2 md:w-2/3">
<h1 class="sf-h-1 m-0">Заголовок первого экрана</h1>
<p class="sf-body-large m-0 color-on-surface-variant">Одна фраза о том, что получит посетитель.</p>
<a href="/start/" class="sf-button sf-button--default sf-button--primary sf-button--size-2 self-cross-start">
<span class="sf-button-text-container">Начать</span>
</a>
</section>
<ul class="list-none m-0 p-0 grid grid-col-1 md:grid-col-2 lg:grid-col-3 gap-3">
<li class="p-2 radius-surface bg-surface-container flex flex-col gap-1">
<h2 class="sf-h-4 m-0">Первая карточка</h2>
<p class="m-0 color-on-surface-variant">Короткое описание.</p>
</li>
<!-- остальные карточки -->
</ul>
</main>
Здесь контейнер центрирует содержимое, шапка переносит меню на узком экране,
первый экран занимает две трети ширины начиная с md, а сетка карточек идёт
в одну колонку на телефоне, в две — от md и в три — от lg. Отступы и
промежутки взяты со шкалы интерфейса и сами подрастают на десктопе. Кнопка
действия — ссылка с классами кнопки, потому что она ведёт на другую страницу
(см. Доступность: что компонент даёт и что остаётся за автором).
Меню, которое на узком экране сворачивается в кнопку, — уже поведение, а не раскладка: для него нужен компонент или скрипт проекта, например Drawer с меню внутри.
Промежутки: gap, space или отступы
Расстояние между соседями задаётся тремя способами, и у каждого своё место:
gap-*— для Flex и Grid. Промежуток задаёт контейнер, детям ничего знать не нужно. Это основной способ:gap-*,gap-x-*,gap-y-*.space-x-*,space-y-*— для обычного потока, где контейнер не Flex и не Grid. Утилита задаёт отступ каждому ребёнку, кроме первого.m-*— для одного конкретного элемента, когда отступ — его собственное свойство, а не правило ряда.
Видимость и печать
hidden убирает элемент из раскладки, invisible скрывает его, сохраняя
место. С условиями получается адаптивное отображение: hidden lg:block —
элемент появляется только на десктопе.
sr-only прячет элемент визуально, но оставляет его экранным читалкам;
not-sr-only возвращает видимость. Для печати — отдельные классы
print-hidden, print-block, print-flex.
Смотрите также: Анатомия: корень, части, модификаторы, состояния — части компонента; Где живёт разметка — разметка Smart-компонентов; Области страницы — макеты страниц.