Тултипы без JS: Забудь про Popper.js и лишние килограммы в бандле
Признайся, сколько раз ты подключал тяжелые библиотеки вроде Tippy.js или Popper.js только для того, чтобы показать маленькую плашку с текстом при наведении? Мы привыкли тащить в проект десятки килобайт JavaScript там, где современные браузеры уже давно справляются сами. Тултипы — это классический пример того, как мы по инерции продолжаем использовать сложные решения для простых задач. Сегодня разберем, как выкинуть костыли и собрать идеальную подсказку, которая не боится overflow: hidden и не требует ни единой строчки скриптов.
Как мы страдали раньше
Старая школа верстки предлагала нам два пути, и оба были с подвохом. Первый — использование псевдоэлементов ::before и ::after в связке с content: attr(data-tooltip). Это выглядело изящно до тех пор, пока кнопка не оказывалась внутри контейнера с обрезанными краями. Тултип просто исчезал в небытие, как только пытался выйти за границы родителя.
Второй путь — вложенные спаны с position: absolute. Чтобы это работало, родителю приходилось задавать position: relative, что напрочь ломало иерархию слоев (z-index). Мы тратили часы, пытаясь высчитать отступы и приручить каскадные слои CSS, чтобы подсказка не перекрывалась соседними элементами. Настоящий кошмар начинался при попытке спозиционировать тултип так, чтобы он не вылетал за границы экрана.
Как делать правильно в 2026 году
На дворе эпоха Anchor Positioning API. Это киллер-фича, которая позволяет «привязать» один элемент к другому, даже если они находятся в абсолютно разных частях DOM-дерева. Теперь тултип может лежать хоть в самом конце <body>, что идеально с точки зрения доступности (A11Y), но при этом он будет следовать за своей кнопкой-якорем как приклеенный.
Для реализации нам понадобятся всего два свойства: anchor-name для триггера и position-anchor для самого тултипа. Это позволяет нам навсегда забыть про проблемы с z-index и переполнением контейнеров. Подробнее о механике работы этого чуда ты можешь почитать в статье про якорное позиционирование в CSS, а здесь мы сразу перейдем к практике.
Готовый сниппет кода
Этот код создает тултип, который автоматически привязывается к кнопке и отображается при наведении или фокусе. Обрати внимание, как чисто выглядит HTML.
<!-- Триггер с уникальным именем якоря -->
<button class="trigger" style="anchor-name: --my-tooltip;">
Наведи на меня
</button>
<!-- Тултип, который может лежать где угодно -->
<div role="tooltip" class="hint" style="position-anchor: --my-tooltip;">
Я привязан к кнопке через CSS!
</div>
<style>
.hint {
/* Основная магия */
position: absolute;
top: anchor(bottom);
left: anchor(center);
transform: translateX(-50%) translateY(8px);
/* Стилизация */
background: #333;
color: white;
padding: 8px 12px;
border-radius: 6px;
font-size: 14px;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease;
}
/* Показываем при наведении на триггер */
.trigger:hover + .hint,
.trigger:focus + .hint {
opacity: 1;
}
</style>
Частая ошибка новичков
Самый частый косяк — забывать про доступность. Многие делают тултипы только для мышки через :hover. Но как насчет пользователей, которые перемещаются по сайту с помощью клавиатуры? Если твой тултип не открывается по :focus, ты отрезаешь часть аудитории.
Также не забывай про атрибуты aria-describedby. Тултип — это не просто красивая плашка, это информация. Скринридер должен понимать, что текст внутри подсказки относится именно к этой кнопке. Всегда связывай id тултипа с атрибутом триггера, иначе твой крутой CSS-код будет бесполезен для инклюзивного веба. И помни: если текст в тултипе слишком длинный, лучше использовать современные методы переноса, о которых мы писали в статье про text-wrap: balance.
🔥 Больше фишек, готовых сниппетов и передовых подходов к CSS мы публикуем в нашем Telegram-канале. Подписывайтесь, чтобы не пропустить!