Запасные позиции у края экрана
Основное положение справки находится под кнопкой. Такое правило объясняет связь, но не гарантирует, что длинная панель поместится рядом с нижним краем. Теперь зададим допустимые запасные позиции. Браузер сможет попробовать их, когда первая геометрия не помещается в содержащую область. Мы сохраняем одно содержимое и одну управляющую кнопку; меняется только способ размещения.
position-try-fallbacks содержит упорядоченный набор вариантов. flip-block разворачивает положение вдоль блочной оси, flip-inline — вдоль строчной. Комбинация двух ключевых слов означает один вариант с обоими разворотами. Запятые отделяют разные попытки. Это различие важно: запись трёх попыток не равна одному составному преобразованию.
Запасная геометрия у границ окна
Блочная и строчная оси относятся к направлению письма. Для привычной горизонтальной русской страницы блочный разворот часто означает переход сверху вниз или обратно, но в другом writing mode такая словесная модель будет неточной. Использование логических осей помогает выразить правило без привязки к одному языку. Внутри курса сохраняем горизонтальное письмо, чтобы наблюдение оставалось небольшим.
Правило включается отдельным @supports. Поддержка привязки из предыдущего урока не является автоматической гарантией поддержки всех запасных вариантов. Если новое свойство не распознано, остаётся исходная позиция. Поэтому мы дополнительно ограничиваем высоту и задаём прокрутку панели. Справка не должна делать длинный текст физически недоступным только потому, что подходящее свободное место не найдено.
max-block-size: calc(100dvh - 2rem) учитывает динамическую высоту окна. На мобильном устройстве элементы браузера могут менять доступную область. Это полезный предел, но не волшебное решение для любой экранной клавиатуры и вложенного окна. Такие условия остаются пунктами реального просмотра. При появлении формы внутри справки понадобится проверить, что сфокусированное поле не закрывается клавиатурой.
Если ни один вариант не помещает панель целиком, движок не обязан придумать неизвестный нам идеальный угол. Мы задаём набор разрешённых попыток, а не алгоритм произвольной оптимизации. Для очень большого содержимого лучше пересмотреть сам компонент. Полноценное руководство обычно удобнее читать на собственной странице, а в popover оставить короткую поясняющую часть.
Не добавляем скрытие через position-visibility, поскольку справка должна оставаться доступной для чтения. У декоративной подсказки может быть другой договор, но исчезновение текста при нехватке места здесь нежелательно. Успешная геометрия определяется и смыслом компонента: положение, в котором весь текст доступен прокруткой, может быть полезнее красивой, но обрезанной панели.
Ожидаемое отличие этапа проявится у края окна: вместо сохранения единственного направления браузер сможет применить запасной разворот. Чтобы увидеть причину, сравните тот же документ с исключённым правилом fallback. Это будущее ручное наблюдение; результаты браузерного сравнения при подготовке серии не получены. В следующем уроке оставим геометрию справки и перейдём к смене списка внутри документа.
Полный файл index.html текущего этапа:
<!doctype html>
<html lang="ru"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Учебный каталог</title><link rel="stylesheet" href="styles.css"><script type="module" src="app.js"></script></head>
<body><a href="#main">Перейти к материалам</a><header><a href="index.html">Учебный каталог</a></header><main id="main"><h1>Учебные материалы</h1><p>Каталог «Полка»: статьи о контенте и интерфейсах.</p><button type="button" id="open-lesson" hidden>О проекте урока</button>
<dialog id="lesson-dialog" aria-labelledby="dialog-title"><h2 id="dialog-title">Учебная библиотека</h2><p>Три урока с постоянными ссылками. Карточка дополняет каталог.</p><form method="dialog"><button value="close" autofocus>Закрыть</button></form></dialog><button type="button" id="help-button" popovertarget="help" hidden>Как читать каталог</button>
<aside id="help"><h2>Чтение каталога</h2><p>Откройте название урока. Справка не закрывает доступ к другим ссылкам.</p></aside><ul class="cards"><li class="card" data-topic="content" data-minutes="20"><h2><a href="article.html#markdown">Markdown и структура урока</a></h2><p class="card-description">Разделяем содержание и оформление библиотеки.</p><p class="card-meta">Контент · 20 минут</p></li>
<li class="card" data-topic="interface" data-minutes="35"><h2><a href="article.html#navigation">Навигация учебного каталога</a></h2><p class="card-description">Сохраняем обычные ссылки и последовательность чтения.</p><p class="card-meta">Интерфейс · 35 минут</p></li>
<li class="card" data-topic="content" data-minutes="25"><h2><a href="article.html#urls">Постоянные адреса материалов</a></h2><p class="card-description">Меняем каталог, сохраняя адрес каждой статьи.</p><p class="card-meta">Контент · 25 минут</p></li></ul><p class="notice">Каждый урок доступен по обычной ссылке. Фильтры и эффекты дополняют чтение.</p></main><footer>Полка · учебный проект</footer></body></html>
Полный файл app.js текущего этапа:
document.documentElement.dataset.enhanced = 'true';
const lessonDialog = document.querySelector('#lesson-dialog');
const openLesson = document.querySelector('#open-lesson');
if (typeof lessonDialog.showModal === 'function') {
openLesson.hidden = false;
openLesson.addEventListener('click', () => {
if (!lessonDialog.open) lessonDialog.showModal();
});
lessonDialog.addEventListener('close', () => openLesson.focus());
}
if ('popover' in HTMLElement.prototype) {
document.querySelector('#help').setAttribute('popover', 'auto');
document.querySelector('#help-button').hidden = false;
}
Полный файл styles.css текущего этапа:
* { box-sizing: border-box; }
:root { color-scheme: light; --accent: #6d28d9; --paper: #fff; --ink: #20202a; }
body { margin: 0; color: var(--ink); background: #f7f6fb; font: 1rem/1.6 system-ui, sans-serif; }
header, main, footer { max-width: 72rem; margin-inline: auto; padding: 1.5rem; }
a { color: #5923b5; text-underline-offset: .18em; }
button { font: inherit; padding: .5rem .9rem; cursor: pointer; }
:focus-visible { outline: 3px solid #17693d; outline-offset: 4px; }
[hidden] { display: none !important; }
.cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); list-style: none; padding: 0; }
.card, aside { padding: 1.25rem; border: 1px solid #ddd8e8; border-radius: .7rem; background: white; }
.card h2 { margin-block-start: 0; }
.card-meta { color: #51495f; }
.notice { border-inline-start: .25rem solid var(--accent); padding-inline-start: 1rem; }
dialog { width: min(36rem, calc(100vw - 2rem)); border: 1px solid #b9afca; padding: 1.5rem; border-radius: .8rem; }
dialog::backdrop { background: rgb(20 15 30 / .5); }
@supports (anchor-name: --catalog-help) and (position-area: bottom) {
#help-button { anchor-name: --catalog-help; }
#help[popover] { position: fixed; position-anchor: --catalog-help; position-area: bottom; inset: auto; margin: .5rem; width: min(25rem, calc(100vw - 2rem)); }
}
@supports (position-try-fallbacks: flip-block) {
#help[popover] { position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline; max-block-size: calc(100dvh - 2rem); overflow: auto; }
}
Разбор изменения каталога
Порядок попыток является частью дизайна. Мы предпочитаем разворот вдоль блочной оси, затем строчной, затем обеих. Другой интерфейс может считать более естественным сначала сохранить вертикальную сторону. Такой выбор следует делать по содержимому и расположению кнопки. Не переставляйте варианты только потому, что один случай на большом мониторе выглядит красивее.
Прокрутка внутри справки добавляет ещё одну область. Посетитель должен различать её от прокрутки страницы и не терять доступ к выходу. При небольшом тексте это почти незаметно, но длинный абзац способен выявить неудобство. Не превращайте внутреннюю прокрутку в универсальное оправдание для огромного popover. Если задача требует много чтения, собственная страница часто имеет более ясную адресацию и удобное возвращение.
Для самостоятельного варианта задайте панели длинное пояснение и временно поставьте кнопку ближе к нижней границе. Сравните варианты по доступности всего текста. Затем повторите с короткой справкой. Сохраните наблюдения отдельно от исходников и укажите реальную среду. Число CSS-попыток не равно числу подтверждённых положений: фактический выбор зависит от конкретной геометрии.
Запасная позиция не должна менять смысл самой панели. Если сверху справа вдруг появляется другой текст, пользователь может решить, что открыл отдельную справку. В нашем примере содержание остаётся тем же, а меняется только положение. Даже если дизайн позже добавит стрелку-указатель, её направление следует связать с фактически выбранной геометрией, иначе визуальная связь станет ложной.
Не используем значение margin для принудительного вывода панели за экран. Небольшой промежуток отделяет её от кнопки, а попытки выбирают допустимую сторону. Когда хочется добавить большой отрицательный отступ, сначала рассмотрите containing block и исходные inset. Исправление случайным числом может помочь в одном размере, но сделать остальные состояния менее предсказуемыми.
Заданный список разворотов не является списком проверенных браузерных результатов. Для наблюдения нужно обозначить конкретное положение якоря и размеры панели. Полезный журнал описывает состояние до открытия, выбранную сторону и доступность текста после. Одной фразы «адаптивно работает» недостаточно для передачи, потому что она не показывает, какие условия действительно исследованы.
При увеличении масштаба текста свободное место вокруг кнопки становится меньше, даже если физическое окно то же. Поэтому просмотр только с исходным размером шрифта пропускает важную границу. Будущая оценка должна включать масштаб и длинный текст. Ветка overflow позволяет читать содержимое, но не заменяет решение о том, насколько панель удобна в таком состоянии.
Условия для самостоятельного наблюдения
Это план будущего разбора, а не журнал выполненных проверок. Рассмотрите одинаковые исходные данные и сопоставьте действие с ожидаемым состоянием.
| Условие | Ожидаемое состояние и его граница |
|---|---|
| Кнопка у нижнего края | Первой запасной попыткой становится разворот вдоль блочной оси. |
| Мало места сбоку | Доступен отдельный вариант flip-inline, если он помогает разместить панель. |
| Недостаток по обеим осям | Составной вариант пробует оба разворота в одной попытке. |
| Справка очень длинная | Ограничение высоты и overflow позволяют читать внутреннее содержимое. |
| Все попытки неудобны | Не следует ожидать произвольной новой позиции за пределами заданного набора. |
| Новое свойство отсутствует | Остаётся основной anchor-вариант или стандартный popover из прежней ветки. |
Оглавление серии, курсы ProfessorWeb и полный архив исходников. Для этого урока выберите lesson-05.
Первичные источники: Position fallback options.
Редакционный статус: локальный черновик. Установка, учебные программы, браузерные сценарии, тесты и публикация не выполнялись. Описанные эффекты ожидаемые.