При создании всплывающих подсказок или всплывающих окон с помощью позиционирования привязки CSS браузер может автоматически «перевернуть» элемент в резервное положение, если в противном случае он переполнит область просмотра. В таких случаях может потребоваться скорректировать стиль позиционированного контента, например изменить положение стрелки, указывающей от позиционированного контента к якорю.
Запросы закрепленных контейнеров решают эту проблему, позволяя запрашивать активное состояние позиционирования элемента и соответствующим образом применять стили. Общие сведения о позиционировании закрепленных раскрывающихся списков и всплывающих меню с переворотом при столкновении с областью просмотра (без изменения стиля стрелки направления) см. в разделе Раскрывающиеся списки с учетом области просмотра.
Проблема
Представьте себе всплывающую подсказку, которая по умолчанию появляется над ее привязкой. Внизу есть стрелка вниз. Если пользователь прокрутит страницу и подсказка переместится под якорь, стрелка будет указывать в неправильном направлении и находиться не с той стороны подсказки.
Решение: запросы к закрепленным контейнерам
By setting container-type: anchored on your positioned element, you turn it into a query container that knows about its own anchor-positioned state. Затем вы можете использовать запрос @container anchored(), чтобы обновить дочерние или псевдоэлементы.
1. Создайте подсказку и триггер
Создайте подсказку с помощью Popover API. Вызов всплывающего окна через popovertarget автоматически устанавливает неявное якорное соединение с кнопкой триггера, поэтому явные anchor-name или position-anchor не требуются.
<button popovertarget="tooltip" id="anchor" aria-describedby="tooltip">anchor</button>
<div id="tooltip" popover role="tooltip"></div>
Сбросьте стили отступов и полей всплывающего окна для использования с позиционированием привязки, но только если позиционирование привязки поддерживается.
@supports (anchor-name: --my-anchor) {
[popover] {
inset: auto;
margin: unset;
}
}
2. Настройте контейнер
Примените container-type: anchored к размещаемому элементу. Чтобы включить переворачивание, для этого элемента также необходимо определить position-try-fallbacks.
#tooltip {
position: fixed;
position-area: block-start;
position-try-fallbacks: flip-block;
/* Enable anchored container queries */
container-type: anchored;
}
3. Стиль на основе резервного объявления
Используйте @container anchored(fallback: <value>), чтобы применить стили, когда активен определенный резервный вариант.
Как и все запросы контейнеров, @container может стилизовать только потомков контейнера. Обычно для создания стрелок используются псевдоэлементы ::before и ::after, которые обрабатываются как дочерние элементы и могут быть стилизованы напрямую. Однако, чтобы настроить стиль самой подсказки (как показано на шаге 4), мы добавим в нее дочерний элемент и создадим стрелку в его псевдоэлементе ::before.
<div id="tooltip" popover role="tooltip">
<div class="tooltip-content">Tooltip</div>
</div>
.tooltip-content::before {
/* Default "down" arrow for the 'top' position */
content: "▼";
position: absolute;
inset-block-end: 0;
inset-inline-start: 1rem;
}
/* Update to an "up" arrow when the 'flip-block' fallback (bottom) is active */
@container anchored(fallback: flip-block) {
.tooltip-content::before {
content: "▲";
inset-block-start: 0;
inset-block-end: auto;
}
}
4. Настраиваю стиль контейнера
Если вам нужно изменить свойства самого контейнера (например, margin или background-color) при его повороте, используйте внутренний элемент-оболочку.
- Примените
container-type: anchoredк внешнему позиционированному элементу. - Укажите внутренний элемент в блоке
@container.
@container anchored(fallback: flip-block) {
.tooltip-content {
border-radius: 0 0 .5rem .5rem;
margin-block-start: 0.25rem;
}
}
Рекомендации
- Используйте логические резервные варианты. Используйте ключевые слова, такие как
flip-blockиflip-inlineвposition-try-fallbacks, для более простых запросов, которые автоматически обрабатывают RTL и различные режимы записи. - Используйте псевдоэлементы для стрелок. Стрелки подсказок носят чисто декоративный характер и идеально подходят для
::beforeили::after, стиль которых можно задать с помощью запросов к закрепленному контейнеру без дополнительной DOM.
Резервные стратегии
Позиционирование стрелки на основе примененного резервного варианта – это прогрессивное улучшение, и другого способа реагировать на резервную позицию нет. Чтобы скрыть стрелку в браузерах, которые не поддерживают запросы контейнера для позиционирования привязки, проверьте поддержку CSS с помощью @supports (container-type: anchored).
@supports (container-type: anchored) {
.tooltip-content::before {
content: "▼";
}
}
Резервные варианты и поддержка Popover в браузерах
Popover API в основном представляет собой прогрессивное улучшение, но его определяющие характеристики – продвижение верхнего слоя, легкое отклонение и вызов popovertarget – не имеют эквивалента только для CSS. Для старых браузеров нужен полифил или резервный вариант, если вы не хотите его использовать.
Полифил. Чтобы обеспечить поддержку атрибута popover в старых браузерах, условно загрузите @oddbird/popover-polyfill. ОБЯЗАТЕЛЬНО. Проверьте наличие свойства popover в HTMLElement.prototype и загрузите полифил, только если встроенная поддержка отсутствует. Не загружайте его без необходимости.
С помощью сборщика или карты импорта:
// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
import("@oddbird/popover-polyfill");
}
Если вы не используете сборщик, импортируйте из CDN в <script type="module">:
<script type="module">
if (!("popover" in HTMLElement.prototype)) {
import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
}
</script>
Ограничение, связанное со стилями. Полифил не может определить настоящий псевдокласс :popover-open, поэтому вместо него применяется класс .\:popover-open. ОБЯЗАТЕЛЬНО. Объедините эти два правила с помощью :is() или :where(), иначе браузеры, не поддерживающие :popover-open, будут игнорировать правило целиком.
[popover]:is(:popover-open, .\:popover-open) {
display: block;
}
В качестве альтернативы для устаревшего резервного варианта без полифила используйте position: fixed и вручную рассчитайте координаты с помощью getBoundingClientRect() или полагайтесь на позиционирование по умолчанию с помощью inset: auto, если это приемлемо для вашего случая.
Браузеры, не поддерживающие Popover API, также не поддерживают позиционирование привязки, поэтому подсказка будет появляться в центре экрана.