Чувствую себя немного идиотом, потому что сам не раз рассказывал людям, что одно из главных преимуществ 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, я бы советовал следующее:
- Сделайте anchor и позиционируемый элемент соседями.
- Разместите anchor раньше в DOM.
Часть меня любит такой упрощённый совет: его легко понять, запомнить и объяснить другим.
Но куда большая часть меня это ненавидит. CSS подарил нам странный новый класс проблем. Раньше не приходилось вылавливать подобные сбои именно такого рода, и я не в восторге от появления ещё одного направления для отладки. Так что повторю ещё раз: если CSS-спецификация и движки могут это исправить в будущем — им точно стоит попробовать.
Если вас смущает не только то, когда anchor positioning работает, но и как именно потом располагать элементы, вот ещё два полезных ориентира:
- Во-первых,
anchor-toolочень помогает вспомнить, как работает вся эта история соspan— у меня лично она до сих пор не уложилась в голове до конца. - Во-вторых, область, к которой вы привязываетесь, в каком-то смысле похожа на ячейку grid, поэтому внутри неё можно использовать
alignиjustify. Но где именно находится эта «ячейка»? Она называется Inset-Modified Containing Block (IMCB), и у Брамуса есть хорошее объяснение. Частьinsetтут, по сути, означает «сужение области» за счёт сдвига её границ внутрь. Ну и да, аббревиатура IMCB подозрительно близка к ICBM — и, пожалуй, обе способны устроить вам взрыв мозга.
Теги: css, anchor, layout