При размещении подсказки или раскрывающегося меню часто требуется позиционировать их относительно другого элемента на странице. Хотя для достижения этого эффекта существовали способы использования абсолютного позиционирования, для более сложных задач традиционно приходилось прибегать к позиционированию элементов с помощью JavaScript.
Позиционирование якорей CSS позволяет декларативно позиционировать элемент относительно другого элемента.
Элементы привязки
Чтобы сделать элемент якорем, ему присваивается значение anchor-name
представляющее собой любую строку, начинающуюся с двух дефисов. Это идентификатор, который позиционируемый элемент будет использовать для поиска своего якоря, и полезно дать ему описательное имя. Вы даже можете присвоить элементу несколько имён якорей, если он будет использоваться в качестве якоря разными способами.
Вам потребуется задать несколько свойств позиционируемого элемента, чтобы его можно было привязать. Во-первых, нужно вывести элемент из потока документа, сделав его плавающим, установив position: absolute
или position: fixed
.
Далее вам нужно будет указать, к какому якорю вы хотите привязаться, установив в качестве значения position-anchor
заданное вами для якоря имя якоря.
Наконец, вам нужно будет указать, как расположить якорь. Подробнее о position-area
вы узнаете далее в этом модуле.
#anchor {
anchor-name: --my-anchor;
}
#positionedElement {
position: absolute;
position-anchor: --my-anchor;
position-area: end;
}
Неявные привязки
Привязать поповеры ещё проще. Когда вы открываете поповер с помощью кнопки с popovertarget
или устанавливая source
с помощью showPopover({source})
, у поповера уже установлен «неявный якорь». Поскольку поповер уже плавающий и по умолчанию имеет фиксированное position: fixed
, для его позиционирования достаточно просто задать позицию.
#anchor{}
#positionedElement {
position-area: end;
margin: unset;
}
Определение потенциальных якорей
Вы можете реализовать позиционирование якоря как часть компонента, чтобы использовать шаблон, например, раскрывающееся меню, в нескольких местах. Если вы используете одно и то же anchor-name
несколько раз, как убедиться, что каждый позиционируемый элемент находит правильный якорь?
Решения JavaScript предполагают добавление уникальных идентификаторов к каждому якорю и последующую ссылку на них из позиционируемого элемента. Это довольно громоздко, и в CSS есть более простое решение — свойство anchor-scope
.
Свойство anchor-scope
определяет, какие имена якорей будут сопоставляться только между элементом и его потомками. Оно принимает список из одного или нескольких имён якорей или ключевое слово all
чтобы ограничить область действия всех определённых имён якорей.
anchor-scope
в идеале следует добавлять к предку как позиционируемого элемента, так и якорного элемента, который не содержит других якорных элементов с тем же именем. Часто это происходит в корне повторно используемого компонента.
В следующем примере показано, как свойство anchor-scope
применяется к повторяющимся элементам с одинаковым anchor-name
. В этом примере все элементы <img>
и баннеры изображений ссылаются на имя якоря --image
. При применении anchor-scope
к элементам <li>
свойство position-anchor: --image
будет соответствовать только элементу <img>
внутри того же элемента <li>
, что и баннер, в противном случае оно будет соответствовать последнему отображённому элементу <img>
.
Позиционирование
Теперь, когда вы привязали элемент к якорю, пора его позиционировать. Для позиционирования якоря предусмотрены два метода: position-area
и функция anchor()
.
position-area
Свойство position-area
позволяет позиционировать элемент вокруг якоря, указав одно или два ключевых слова. Это охватывает множество распространённых случаев использования и часто является хорошей отправной точкой.
Как работает position-area
position-area
работает, создавая новый содержащий блок для позиционируемого элемента в области, образованной краями якоря и исходного содержащего блока позиционируемого элемента.
Хотя для position-area
доступно множество ключевых слов, их можно разбить на несколько категорий для более легкого понимания. Anchor-tool.com — отличный инструмент для изучения синтаксиса.
Физические ключевые слова
Вы можете использовать физические ключевые слова top
, left
, bottom
, right
и center
. Например, position-area: top right
разместит позиционируемый элемент выше и правее якоря. У этих ключевых слов также есть физические эквиваленты по осям: y-start
, x-start
, y-end
и x-end
.
Логические ключевые слова
Вы также можете использовать логические ключевые слова: block-start
, block-end
, inline-start
и inline-end
. Например, position-area: block-end inline-start
разместит позиционируемый элемент под и слева от анкера в таких языках, как английский, или после анкера на оси блока и перед анкером на оси строки в режиме написания документа. center
также можно использовать с логическим ключевым словом.
Вы также можете опустить ось, если указываете логические ключевые слова, указав сначала блочную ось, а затем встроенную. position-area: start end
— это то же самое, что position-area: block-start inline-end
или даже position-area: inline-end block-start
.
Охват нескольких областей сетки
До сих пор вы, возможно, заметили, что эти параметры позволяют размещать позиционируемый элемент только в пределах одного пространства сетки. Добавление префикса span
к физическим или логическим свойствам добавляет смежное центральное пространство сетки. position-area: span-top right
будет позиционироваться справа от якоря и от нижней части якоря до верхней части исходного содержащего блока позиционируемого элемента.
Распространенной областью позиционирования для раскрывающегося меню является position-area: block-end span-inline-end
.
Ключевое слово span-all
охватывает 3 строки или столбца.
Одно ключевое слово
Если вы задаёте только одно ключевое слово, вторая ось задаётся автоматически. В целом, всё работает так, как и ожидалось, но может быть полезно понять, как это работает.
Если указанное ключевое слово однозначно определяет ось, другая ось вычисляется как span-all
. Это означает, что position-area: bottom
эквивалентно position-area: bottom span-all
, и позиционируемый элемент будет находиться под якорем и будет иметь доступ ко всей ширине содержащего его блока.
С другой стороны, если ключевое слово явно не указывает на ось, оно повторяется. position-area: start
эквивалентно start start
и размещается в левом верхнем углу якоря в языках с письмом слева направо.
Функция anchor()
Для более сложных случаев использования position-area
может не соответствовать вашим требованиям. Функция anchor()
позволяет задавать индивидуальные свойства вставки в зависимости от положения другого элемента. Это преобразуется в длину CSS , что позволяет использовать её в вычислениях и с другими функциями CSS. Кроме того, вы также можете привязывать разные стороны к разным якорям.
Функция anchor()
принимает имя и сторону якоря. Если у вашего элемента есть якорь по умолчанию, заданный с помощью position-anchor
или неявно, например, с помощью всплывающего окна, вы можете опустить имя якоря.
.positionedElement {
block-start: anchor(--my-anchor start);
/* OR */
position-anchor: --my-anchor;
block-start: anchor(start);
}
Резервные значения
Если для функции anchor()
не удаётся найти якорь, всё объявление будет недействительным. Это может произойти, если якорь отображается после позиционируемого элемента или если нет элемента с совпадающим anchor-name
. Для решения этой проблемы можно задать резервную длину или процент.
.positionedElement {
block-start: anchor(--my-anchor, 100px)
}
В предыдущем примере значение left позиционируемого элемента привязано к --focused-anchor
, но это anchor-name
существует только при наведении курсора или фокусе на первой кнопке. Поскольку функция anchor()
преобразуется в длину, можно использовать другой якорь в качестве резервного варианта. Если бы мы не предоставили резервный вариант, позиционируемый элемент не был бы спозиционирован.
Ключевые слова на якорной стороне
Значение стороны якоря определяет, к какому краю якоря будет прикрепляться якорь. Подобно position-area
, значение стороны якоря поддерживает несколько различных типов синтаксиса.
Тип | Ценности | Описание |
---|---|---|
Физический | top , left , bottom , right | Физические ключевые слова соответствуют определенной стороне якоря, но могут использоваться только на той же оси, что и вставка позиционируемого элемента, которую вы устанавливаете. Например, |
Сторона | inside , outside | Ключевое слово Например, |
Логический | start , end , self-start , self-end | Логические ключевые слова ссылаются на стороны якоря на основе режима записи позиционируемого элемента с |
Процент | 0% - 100% | Процентное значение размещает позиционируемый элемент вдоль оси от начала до конца якоря на указанной оси. |
В этом примере показано, как процентное значение всегда идет от начала до конца по указанной оси:
Использование anchor()
Поскольку anchor()
— это длина, он очень гибкий. Вы можете управлять значением с помощью CSS-функций, таких как max()
и calc()
.
Одним из ограничений является то, что функции anchor()
можно использовать только для свойств-вставок.
В предыдущем примере фон за открытой панелью сведений добавляется плавно, анимируется при открытии другой панели и растягивается, включая в себя наведённую на неё панель сведений. Для этого используется min()
который выбирает наименьшее расстояние между двумя якорями.
#indicator{
/* Use the smaller of the 2 values: */
inset-block-start: min(
/* 1. The start side of the default anchor, which is the open `<details>` element */
anchor(start),
/* 2. The start side of the hovered `<details>` element. */
anchor(--hovered start,
/* If no `<details>` element is hovered, this falls back to infinity px, so that the other value is smaller, and therefore used. */
var(calc(1px * infinity)))
);
}
В примере также используется calc()
для добавления внутреннего пространства вокруг открытой панели.
Используя размер якоря
Вы также можете использовать функцию anchor-size()
чтобы использовать размеры якоря для размера, положения или поля позиционируемого элемента.
anchor-size()
принимает имя якоря или использует якорь по умолчанию. По умолчанию используется размер якоря по оси, по которой он используется, поэтому width: anchor-size()
вернет ширину якоря. Вы также можете использовать другую ось, указав нужную длину с помощью физических ключевых слов width
и height
или логических ключевых слов block
, inline
, self-block
и self-inline
.
Обработка переполнения
Вы создали компонент раскрывающегося меню и использовали позиционирование якорей, чтобы разместить его там, где нужно. Но затем вы перемещаете меню на другую сторону экрана или используете его для пользовательского меню, и имя пользователя становится слишком длинным. Внезапно ваш раскрывающийся список исчезает с экрана. Что теперь?
Позиционирование якорей CSS имеет встроенную систему, которая позволяет быстро создать надежный набор резервных вариантов, когда позиционируемый элемент оказывается за пределами содержащего его блока.
Запасные варианты
Правило position-try-fallbacks
принимает список резервных вариантов. При переполнении позиции по умолчанию каждый вариант будет перебран по порядку, пока не найдётся позиция, не вызывающая переполнения.
В качестве резервного варианта можно использовать любое значение position-area
. В этом примере, в режимах письма слева направо, например, в английском языке, позиционируемый элемент будет пытаться разместиться внизу якоря, охватывая центральный и правый столбцы. Если это значение выходит за пределы, он будет пытаться разместиться внизу якоря, охватывая левый и центральный столбцы. Если и это значение выходит за пределы, позиция вернется к положению по умолчанию, даже если оно выходит за пределы.
.positioned-element {
position-area: block-end span-inline-end;
position-try-fallbacks: block-end span-inline-start;
}
Существует также несколько ключевых слов flip-
, которые обрабатывают распространённые резервные случаи. flip-block
и flip-inline
пытаются перевернуть элемент относительно блочной и строчной осей. Их также можно комбинировать с flip-block flip-inline
для переворота относительно обеих осей. Значение flip-start
переворачивает позиционируемый элемент относительно диагональной линии от начального до конечного угла якоря.
Вы также можете создать собственный резервный вариант с помощью @position-try
— это позволит вам задать поля, выравнивание и даже изменить привязку.
@position-try --menu-below {
position-area: bottom span-right;
margin-top: 1em;
}
#positioned-element {
position-try: --menu-below;
}
Для создания варианта к резервным опциям @position-try
можно добавить flip-block
и flip-inline
.
#positioned-element {
position-try: --menu-below, flip-inline --menu-below;
}
В предыдущем примере браузер выполняет следующие шаги и останавливается, как только находит решение, не приводящее к переполнению.
- Элемент размещается с
position-area: end
, в правом нижнем углу якоря. - Если это переполняется, элемент размещается с пользовательской резервной опцией с именем
--bottom-span-right
, которая размещает его сposition-area: bottom span-right
, с дополнительным полем снизу. - Если это переполняется, элемент помещается с
flip-inline --bottom-span-right
, который объединяет пользовательский резервный параметр сflip-inline
, который по сути являетсяposition-area: bottom span-left
. - Если это значение выходит за пределы указанного диапазона, элемент размещается с использованием резервной опции
--use-alternate
, которая помещает его под совершенно другой якорь. - Если произойдет переполнение, элемент возвращается в исходное положение с
position-area: end
, даже если известно, что это приведет к переполнению.
Резервный порядок
По умолчанию при переполнении исходной позиции браузер пробует все варианты из position-try-fallbacks
пока не найдётся вариант, не вызывающий переполнения. Вы можете переопределить это поведение с помощью position-try-order
чтобы протестировать каждый вариант резервного варианта и использовать тот, который занимает больше всего места по указанной оси.
Ось можно указать либо с помощью логических ключевых слов most-block-size
и most-inline-size
, либо с помощью физических ключевых слов most-height
и most-width
.
position-try-order
и position-try-fallbacks
можно комбинировать с помощью сокращенной записи position-try
, при этом порядок должен идти первым.
Прокрутка
При прокрутке страницы пользователь ожидает, что страница будет двигаться плавно. Чтобы добиться этого, браузеры ограничивают использование якорных точек при прокрутке.
Хотя позиционируемый элемент можно привязать к якорям в разных контейнерах прокрутки, он будет перемещаться только в ответ на прокрутку одного из якорей. Это будет якорь по умолчанию, который может быть либо неявным якорем из всплывающего окна, либо значением position-anchor
.
Обратите внимание, что позиционируемый элемент остаётся видимым, даже если якорь прокручивается. Чтобы скрыть позиционируемый элемент, когда якорь скрыт, установите position-visibility: anchors-visible
. Это относится не только к ситуации, когда якорь находится за пределами прокрутки, но и к другим способам его скрытия, например, с помощью visibility: hidden
.
Проверьте свое понимание
Каковы допустимые значения для стороны в anchor()
?
inside
25%
25px
25px
, но для стороны можно использовать только проценты.block-start
start
Каковы допустимые значения для position-area
?
top
block-end inline-end
block-start block-end
Какие свойства поддерживают функцию anchor()
?
top
margin-left
inset-block-start
transform
Что произойдет, если есть несколько якорей с одинаковым anchor-name
?