Адаптивная вёрстка сайта
Правила для
kind:website
. В приложении раскладка считается синхронно, до первого кадра, и ничего из перечисленного ниже там не проявляется — всё это свойства КОМПИЛЯЦИИ в страницу.
Каждое утверждение здесь — замер на выводе компилятора или на живой странице, а не рассуждение. Где число, там оно измерено.
MUST: полосу уровня страницы вести по размерному классу
Шапка, подвал, геройский блок, сетка разделов — по
$theme.sizeClass
. Стиль по классу опускается в
@media
:
Flex direction:{$theme.sizeClass == "compact" ? "vertical" : "horizontal"}
$Copy
$Picture
даёт
@media (max-width: 599.98px) { #r0 { flex-direction: column } }
.
@media
спрашивает ОКНО и не ждёт раскладки, поэтому отвечает правильно в самом первом кадре — и даже внутри поддерева, которое ещё скрыто.
MUST:
LayoutBuilder
— только боксу, чья ширина не равна ширине окна
Колонка, карточка, боковая панель, диалог. Там он и незаменим: компонент подстраивается под место, где стоит, а не под окно.
LayoutBuilder maxWidth:@w
Flex direction:{w < 600 ? "vertical" : "horizontal"}
Text "left"
Text "right"
Почему не всюду.
@container
не может ответить, пока его бокс не разложен, а у скрытого поддерева размера нет вовсе: правило не срабатывает, остаётся база, а база — самая широкая полоса, то есть десктопная раскладка. Замерено на шапке консоли, которую гвард держал под
display: none
: десктопная строка навигации вычислялась как
flex
, бургер как
none
, и оба значения менялись ровно в момент показа.
MUST NOT:
if:
по
$theme.sizeClass
Стиль по классу становится полосой
@media
;
условие по классу — нет
. Оно сворачивается на сборке, и узкая ветка уезжает в HTML с
display: none
навсегда:
Text "узко" if:{$theme.sizeClass == "compact"} // → <span style="display: none">узко</span>
Ни правила в таблице, ни строчки в скрипте, ни предупреждения. Телефон получает десктопную ветку и не узнаёт об этом никогда.
Ветвить: стилем по классу, условием по ширине
LayoutBuilder
, либо
Switcher
— когда различается сама структура, а не расположение одного и того же.
MUST: условие по ширине держать чистым
if:{w > 760}
— одна переменная, и это правило таблицы стилей:
@container (max-width: 759.98px) { … display: none }
. Первый кадр уже верный.
if:{menu && w > 760}
— смесь, и она уходит в рантайм: ветка выбирается после гидратации, то есть вторым кадром. Ширину из такого условия стоит вынести наружу, оставив в нём только состояние.
SHOULD:
{w}
, а не
$w
Под
LayoutBuilder
это разные вещи:
SizedBox width:$w // запеклось: 3120px в HTML, навсегда
SizedBox width:{w} // живое: calc(var(--v-maxWidth_1, 3120) * 1px)
$
берёт значение на сборке,
{}
оставляет выражение. Сборка идёт на самой широкой полосе —
последний брейкпоинт × 2 + 640
, при умолчаниях
3120 px
, — потому что краулер наблюдателя не запускает и обязан прочитать полную десктопную страницу.
Что решает CSS, а что рантайм
| написано | во что опускается | когда отвечает |
|---|---|---|
стиль по
$theme.sizeClass
|
@media
|
до раскладки, моргать нечем |
if:
только по ширине, длина в px под
LayoutBuilder
|
@container
|
когда бокс разложен |
| цвет, строка, текст, смешанное условие — по ширине |
ResizeObserver
→ состояние
|
после гидратации, второй кадр |
Верхняя строка предпочтительнее нижней. Выбирать вручную нечего: компилятор опускает что может, остальное оставляет рантайму, — но ЧТО написано, тем и определяется строка.
SHOULD NOT: фиксированная ширина в пикселях у структурного блока
Строка в 1200 px переполняет телефон. Исключение — карточки в
Wrap
: им ширина нужна, а перенос делает
Wrap
.
То же про диалоги:
Container width:440
внутри диалога на узком экране вылезает. Ограничивать стоит
ConstrainedBox #constraints maxWidth:
.
Картинке размеры в разметке не нужны
Собственный размер картинки компилятор читает из её файла и пишет атрибутами
width
/
height
, оставляя показ стилю. Поэтому
Image src:"data/images/logo.svg" height:15
держит своё место ещё до того, как байты приехали. Просить об этом нечего — и не надо подставлять числа руками: они разойдутся с файлом при первой же его замене.
Первые картинки документа компилятор не делает ленивыми: ленивая выборка картинки первого экрана откладывает её на время после раскладки. Замер до правки на шапке консоли: строка уезжала на 50,6 px при приходе логотипа, и так на каждом переходе между разделами.