Позиционируйте тултипы, поповеры и выпадающие меню относительно любого элемента — без единой строки JavaScript. Нативно, декларативно и с поддержкой во всех современных браузерах.
Десятилетиями позиционирование тултипа рядом с кнопкой, выпадающего меню под пунктом навигации или поповера возле ссылки требовало JavaScript — Popper.js, Floating UI, Tippy.js или собственной реализации логики позиционирования. Каждый скролл, ресайз и изменение DOM требовал пересчёта позиции.
CSS Anchor Positioning кардинально меняет эту ситуацию. Это нативный CSS-модуль, позволяющий «привязать» любой позиционируемый элемент к другому элементу — «якорю» — используя только CSS. Браузер сам обрабатывает позиционирование, определение переполнения и запасные варианты размещения.
В этом руководстве я расскажу всё, что нужно для использования CSS Anchor Positioning в продакшене: от базового тултипа до продвинутых паттернов с Popover API, sizing, fallback-ами и миграции с JavaScript-библиотек.
CSS Anchor Positioning получил полную кросс-браузерную поддержку в рамках инициативы Interop 2026. Текущий статус:
| Браузер | Версия | Статус |
|---|---|---|
| Chrome | 125+ | Полная поддержка |
| Edge | 125+ | Полная поддержка |
| Safari | 26+ | Полная поддержка |
| Firefox | 147+ | Полная поддержка |
| Opera | 111+ | Полная поддержка |
| Samsung Internet | 27+ | Полная поддержка |
Все основные браузеры выпустили стабильную поддержку к маю 2026. Firefox 147 стал последним дополнением, завершив кросс-браузерную картину. Как фокусная область Interop 2026, эта возможность прошла тщательное кросс-браузерное тестирование для обеспечения единообразного поведения.
Полифиллы не требуются. CSS Anchor Positioning работает во всех текущих браузерах. Для критически важного UI, который должен работать в очень старых браузерах (Chrome <125, Safari <26, Firefox <147), предусмотрите fallback на Popper.js или Floating UI — но это редко необходимо для современных веб-приложений.
У CSS Anchor Positioning есть три фундаментальных свойства, которые вы будете использовать в каждом проекте:
anchor-name — Определение якоря
Сначала пометьте элемент как якорь с помощью anchor-name. Значение — dashed ident
(как имя CSS-переменной), на которое будут ссылаться другие элементы:
/* Определяем элемент-якорь */
.trigger-button {
anchor-name: --tooltip-anchor;
}
Сам якорь невидим с точки зрения позиционирования — это просто точка привязки. Любой элемент может быть якорем: кнопки, ссылки, изображения, даже текстовые узлы в span.
position-anchor — Привязка к якорю
На элементе, который нужно позиционировать (целевом элементе), установите
position-anchor со ссылкой на якорь:
/* Позиционируем этот элемент относительно якоря */
.tooltip {
position: absolute;
position-anchor: --tooltip-anchor;
}
Важно: Целевой элемент обязательно должен иметь position,
отличное от static (например, absolute, fixed или
relative). Иначе anchor positioning не сработает.
position-area — Куда разместить
position-area — самый интуитивный способ задать позицию цели относительно якоря.
Он использует сеточную модель: якорь в центре, а вы указываете, в какой «области» вокруг
него должна появиться цель:
.tooltip {
position: absolute;
position-anchor: --tooltip-anchor;
position-area: top center;
/* Цель появляется по центру над якорем */
}
.tooltip-right {
position: absolute;
position-anchor: --tooltip-anchor;
position-area: center right;
/* Цель появляется справа по центру */
}
Значение position-area состоит из двух частей через пробел:
top, center, bottomleft, center, right
Возможные комбинации образуют сетку 3×3: top left, top center,
top right, center left, center center (перекрывает якорь),
center right, bottom left, bottom center,
bottom right.
Вот полностью рабочий тултип на чистом CSS — без JavaScript:
<button class="anchor">
Наведи на меня
</button>
<div class="tooltip">Я тултип на чистом CSS!</div>
<style>
.anchor {
anchor-name: --tip-anchor;
position: relative;
}
.tooltip {
position: absolute;
position-anchor: --tip-anchor;
position-area: top center;
position-try-fallbacks: bottom center, center right;
background: #1a1a2e;
color: white;
padding: 0.5rem 1rem;
border-radius: 6px;
font-size: 0.85rem;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
}
.anchor:hover + .tooltip,
.anchor:focus-visible + .tooltip {
opacity: 1;
}
</style>
Тултип появляется над кнопкой при наведении. Если он выходит за край окна, браузер
автоматически пробует bottom center, затем center right —
всё декларативно, без JavaScript.
Свойство position-try-fallbacks делает CSS Anchor Positioning по-настоящему
готовым к продакшену. Оно определяет список альтернативных позиций, которые браузер
пробует, если основная не помещается в окне:
.dropdown {
position: absolute;
position-anchor: --menu-anchor;
position-area: bottom left;
position-try-fallbacks:
top left,
bottom right,
top right,
flip-block,
flip-inline;
}
Браузер проверяет каждую позицию по порядку и выбирает первую, где целевой элемент
полностью помещается в окне. Ключевые слова flip-block и
flip-inline — сокращения: flip-block отражает позицию по
блок-оси (верх ↔ низ), а flip-inline — по inline-оси (лево ↔ право).
Совет: Начните с flip-block и flip-inline как
основных fallback-ов. Они покрывают самые частые сценарии переполнения одной строкой каждая.
Добавляйте конкретные позиции только когда нужен точный контроль.
Выпадающие меню — один из лучших сценариев использования CSS Anchor Positioning. Вот полная реализация без JavaScript для позиционирования:
<nav>
<button class="menu-trigger" popovertarget="menu1">
Продукты
</button>
<div id="menu1" class="dropdown" popover>
<a href="#">Веб-разработка</a>
<a href="#">Мобильные приложения</a>
<a href="#">Консалтинг</a>
</div>
</nav>
<style>
.menu-trigger {
anchor-name: --menu-anchor;
}
.dropdown {
position: absolute;
position-anchor: --menu-anchor;
position-area: bottom left;
position-try-fallbacks:
top left,
flip-block;
width: anchor-size(width);
border: 1px solid #e2e8f0;
border-radius: 8px;
background: white;
padding: 0.5rem;
box-shadow: 0 4px 16px rgba(0,0,0,0.1);
margin-top: 4px;
}
.dropdown a {
display: block;
padding: 0.5rem 1rem;
text-decoration: none;
color: #1a1a2e;
border-radius: 4px;
}
.dropdown a:hover {
background: #f1f5f9;
}
</style>
Ключевые детали: anchor-size(width) делает меню той же ширины, что и кнопка-триггер,
position-try-fallbacks: top left, flip-block корректно обрабатывает переполнение,
а Popover API (popover + popovertarget) управляет открытием/закрытием
и отображением в top-layer без JavaScript.
Popover API и CSS Anchor Positioning идеально дополняют друг друга. Popover API отвечает за отображение в top-layer (элементы появляются выше всех z-index-стеков), управление фокусом, закрытие по клику вне элемента и обработку клавиши ESC — а Anchor Positioning определяет, где на экране появится поповер.
<button popovertarget="notif-popover" style="anchor-name: --notif-anchor;">
Уведомления (3)
</button>
<div id="notif-popover" popover
style="position: absolute;
position-anchor: --notif-anchor;
position-area: bottom right;">
<h4>Новые уведомления</h4>
<p>У вас 3 непрочитанных сообщения.</p>
</div>
Всё. Поповер открывается по клику на кнопку, появляется привязанным к правому нижнему углу кнопки, а клик вне его или нажатие ESC закрывает. Всё нативное — никаких обработчиков событий, никаких расчётов позиции.
<button class="bell-btn" style="anchor-name: --bell;">
🔔
<span class="badge">3</span>
</button>
<style>
.badge {
position: absolute;
position-anchor: --bell;
position-area: top right;
translate: 25% -25%;
background: #ef4444;
color: white;
font-size: 0.7rem;
padding: 0.1em 0.4em;
border-radius: 999px;
min-width: 1.2em;
text-align: center;
}
</style>
Свойство translate позволяет точно настроить позицию — здесь выдвигая бейдж
немного за верхний правый угол иконки колокольчика, именно там, где и должны быть бейджи
уведомлений.
anchor-size()
Функция anchor-size() позволяет позиционированным элементам задавать размеры
относительно их якоря. Это чрезвычайно полезно для выпадающих меню, автокомплитов и
контекстных панелей, которые должны соответствовать размерам триггера:
.autocomplete-popup {
position: absolute;
position-anchor: --search-anchor;
position-area: bottom left;
/* Та же ширина, что и у поля поиска */
width: anchor-size(width);
/* От 100px до 300px в зависимости от высоты якоря */
max-height: anchor-size(height, 300px);
min-height: anchor-size(height, 100px);
}
/* С именованным якорем */
.dropdown-panel {
position: absolute;
position-anchor: --btn-anchor;
width: anchor-size(--btn-anchor width, 200px);
}
Функция anchor-size() принимает два аргумента:
width, height, block или inline
Можно ссылаться на конкретный якорь по имени: anchor-size(--my-anchor width),
что полезно, когда элемент позиционируется относительно одного якоря, а размер берёт от другого.
Если ваш проект использует Popper.js или Floating UI, вот как мигрировать на CSS Anchor Positioning. Миграция удивительно проста для большинства сценариев:
// JavaScript
import { createPopper } from '@popperjs/core';
const button = document.querySelector('.trigger');
const tooltip = document.querySelector('.tooltip');
const popperInstance = createPopper(button, tooltip, {
placement: 'top',
modifiers: [
{ name: 'flip', options: { fallbackPlacements: ['bottom', 'right'] } },
{ name: 'offset', options: { offset: [0, 8] } },
],
});
<style>
.trigger {
anchor-name: --trigger;
}
.tooltip {
position: absolute;
position-anchor: --trigger;
position-area: top center;
position-try-fallbacks: bottom center, center right;
margin-bottom: 8px; /* заменяет offset */
}
</style>
В 90% случаев можно заменить Popper.js/Floating UI несколькими строками CSS. Оставшиеся 10% — сложные анимации, порталы, перетаскиваемые тултипы — могут всё ещё выигрывать от JS-библиотеки, но разрыв быстро сокращается по мере развития нативных возможностей.
| Возможность | CSS Anchor Positioning | Popper.js / Floating UI |
|---|---|---|
| Размер бандла | 0 КБ (нативный) | ~6 КБ (gzip) |
| Обнаружение переполнения | Автоматически через position-try-fallbacks | Runtime-вычисления |
| Обработка ресайза | Автоматически (нативный браузер) | Обработчики событий + пересчёт |
| Обработка скролла | Автоматически | Обработчики скролла |
| Поддержка старых браузеров | Chrome 125+, Safari 26+, FF 147+ | IE11+ |
| Динамический контент | Автоматически | с вызовом update() |
| Сложные анимации | CSS transitions/animations | Встроенные transitions |
| Сложность настройки | Декларативно (одно CSS-свойство) | JavaScript-инициализация |
Самая частая ошибка. Целевому элементу нужно position: absolute,
position: fixed или position: relative. Без этого
anchor positioning молча ничего не делает.
Если у элемента-якоря стоит overflow: hidden или contain: paint,
позиционированный элемент может быть обрезан. Переместите позиционированный элемент
за пределы переполняющего контейнера или используйте position: fixed
вместо position: absolute.
anchor-name должен быть dashed ident (например, --my-anchor), и
position-anchor должен ссылаться на то же самое имя. Опечатки не вызывают
ошибок — элемент просто не будет позиционирован.
При использовании Popover API атрибут popover должен быть на позиционируемом
элементе (тултипе/дропдауне), а не на якоре. Атрибут popovertarget ставится
на кнопку.
Chrome DevTools и Firefox DevTools показывают связи якорей на панели Elements. В Chrome
у позиционированного элемента появляется бейдж «anchor» — кликните его, чтобы увидеть
подсвеченную связь с якорем. На панели Computed также отображается, какая стратегия
position-try-fallbacks активна.
CSS Anchor Positioning и CSS Container Queries — это дополняющие, а не конкурирующие возможности. Container Queries позволяют компоненту менять стиль в зависимости от размера родительского контейнера. Anchor Positioning даёт элементу возможность привязаться к позиции другого элемента. Вместе они создают по-настоящему адаптивные компоненты, осознающие свой контекст.
Например, карточка может использовать Container Queries для адаптации макета при разных размерах, а её тултип — Anchor Positioning, чтобы оставаться привязанным к иконке информации, независимо от положения карточки на странице.
Создаю интерактивные UI — услуги разработки
anchor-name и позиционируете цель через position-anchor и position-area. Браузер автоматически обрабатывает обнаружение переполнения, запасные позиции и пересчёт при ресайзе.position-area задаёт основную позицию (например, top center, bottom right). position-try-fallbacks определяет запасные позиции на случай, если основная выходит за границы окна. Браузер перебирает fallback-и по порядку и использует первый помещающийся на экране.popover привязывается к кнопке-триггеру через position-anchor. Поповер открывается рядом с кнопкой, появляется в top-layer (выше всех z-index), а браузер управляет фокусом, закрытием по клику вне элемента и клавишей ESC.anchor-size() позволяет задавать размер элемента на основе размеров якоря. Например, width: anchor-size(width) делает выпадающее меню той же ширины, что и кнопка. Можно указать запасное значение: width: anchor-size(--anchor width, 200px). Идеально для выпадающих меню, автокомплитов и контекстных панелей.
CSS Anchor Positioning — одна из тех редких возможностей, которая фундаментально упрощает
создание интерфейсов. Больше не нужно устанавливать npm-пакет для позиционирования в каждом
проекте с тултипом или дропдауном. Больше никаких комбинаций ResizeObserver +
обработчиков scroll. Просто чистый, декларативный CSS, который браузер
выполняет эффективно.
Я использую CSS Anchor Positioning в продакшене с момента выхода Chrome 125. Это устранило тысячи строк JavaScript из клиентских проектов. Если вы планируете новое веб-приложение или рефакторинг существующего — сейчас лучшее время для внедрения.
Нужна помощь во внедрении современных CSS-паттернов в вашем проекте? Я создаю production-веб-приложения с использованием новейших стандартов CSS и JavaScript — давайте обсудим ваш следующий проект.
Нужна помощь с внедрением современных CSS-паттернов, созданием веб-приложения или миграцией с JavaScript-библиотек позиционирования на нативный CSS?