Чувствую себя немного идиотом, потому что сам не раз рассказывал людям, что одно из главных преимуществ anchor positioning в CSS — возможность позиционировать элементы относительно других независимо от их места в DOM. И вот это самое «независимо» и оказывается проблемой.

Нет, не совсем так. Полной свободы тут нет. Извиняюсь. У anchor positioning есть ряд ограничений, которые поначалу кажутся довольно неочевидными. Это новый тип проблем — по крайней мере, лично я не припомню, чтобы в CSS раньше встречалось что-то очень похожее.

Я специально немного драматизирую, потому что правда считаю: людям, которые развивают CSS, стоило бы что-то с этим сделать. Я уверен, что у текущего поведения есть причины, и почти готов поставить доллар на то, что одна из них — производительность. Но сейчас это слишком уж похоже на ловушку, в которую слишком легко попасть. Мне сложно отделаться от мысли, что механизм поиска anchor-элемента внутри большой CSS-машины мог бы делать условный «второй проход» и надёжнее находить нужную привязку.

Если у вас есть аккаунт в CodePen, откройте это демо и подвигайте элементы в DOM так, как показано в видео, — и вы сразу увидите проблему.

Это можно исправить

Да, перемещать tooltip перед anchor-элементом в DOM — немного искусственный пример. Формально можно просто так не делать. Но сама ситуация хорошо показывает, что здесь нельзя свободно переставлять элементы по DOM и ожидать, что всё продолжит работать.

У Темани Афиф есть хорошая статья на эту тему, и я повторю ключевую мысль оттуда:

Anchor-элемент должен быть полностью рассчитан layout-движком раньше, чем элемент, который к нему привязывается.

Из-за этого приходится гораздо внимательнее думать о значении position. Почти со стопроцентной вероятностью элемент, который вы позиционируете относительно anchor, будет иметь position: absolute;. Но куда важнее поведение самого anchor-элемента.

Если anchor и привязанный к нему элемент — соседние элементы, и у anchor задано любое значение position, кроме стандартного static, то anchor обязан идти в DOM раньше.

Если же элементы расположены в DOM иначе — например, anchor является родителем или вообще находится в другой части дерева, — нужно следить, чтобы они находились в одном и том же containing block, либо чтобы родитель anchor всё ещё оставался со значением position: static. У Темани есть более подробный разбор, где это объясняется глубже и понятнее.

У Джеймса Стаки Вебера тоже есть статья по этой теме. Его рекомендация ещё конкретнее:

Чтобы повысить шансы на корректную работу anchor positioning, я бы советовал следующее:

  1. Сделайте anchor и позиционируемый элемент соседями.
  2. Разместите anchor раньше в DOM.

Часть меня любит такой упрощённый совет: его легко понять, запомнить и объяснить другим.

Но куда большая часть меня это ненавидит. CSS подарил нам странный новый класс проблем. Раньше не приходилось вылавливать подобные сбои именно такого рода, и я не в восторге от появления ещё одного направления для отладки. Так что повторю ещё раз: если CSS-спецификация и движки могут это исправить в будущем — им точно стоит попробовать.


Если вас смущает не только то, когда anchor positioning работает, но и как именно потом располагать элементы, вот ещё два полезных ориентира:

  1. Во-первых, anchor-tool очень помогает вспомнить, как работает вся эта история со span — у меня лично она до сих пор не уложилась в голове до конца.
  2. Во-вторых, область, к которой вы привязываетесь, в каком-то смысле похожа на ячейку grid, поэтому внутри неё можно использовать align и justify. Но где именно находится эта «ячейка»? Она называется Inset-Modified Containing Block (IMCB), и у Брамуса есть хорошее объяснение. Часть inset тут, по сути, означает «сужение области» за счёт сдвига её границ внутрь. Ну и да, аббревиатура IMCB подозрительно близка к ICBM — и, пожалуй, обе способны устроить вам взрыв мозга.

Теги: css, anchor, layout

Источник