Ao colocar uma dica ou um menu suspenso, geralmente você quer posicioná-lo em relação a outro elemento na página. Embora existam maneiras de usar o posicionamento absoluto para conseguir esse efeito, requisitos mais complexos historicamente recorrem ao posicionamento de itens usando JavaScript.
O posicionamento de âncora CSS oferece uma maneira de posicionar declarativamente um elemento em relação a outro.
Elementos de tethering
Para transformar um elemento em âncora, atribua a ele um valor anchor-name
de qualquer string que comece com dois traços. Esse é o identificador que o elemento posicionado vai usar para encontrar a âncora. É útil dar a ele um nome descritivo. Você pode até mesmo dar a um elemento vários nomes de âncora, se ele for usado como uma âncora de maneiras diferentes.
É preciso definir algumas propriedades no elemento posicionado para que ele possa ser fixado. Primeiro, você precisa extrair o elemento do fluxo do documento para que ele flutue, definindo position: absolute
ou position: fixed
.
Em seguida, defina a âncora a que você quer vincular, definindo position-anchor
como o nome da âncora que você definiu nela.
Por fim, você precisará definir como posicionar a âncora. Você vai saber mais sobre position-area
mais adiante neste módulo.
#anchor {
anchor-name: --my-anchor;
}
#positionedElement {
position: absolute;
position-anchor: --my-anchor;
position-area: end;
}
Conexões implícitas
Os popovers são ainda mais simples de vincular. Quando você abre um popover usando um botão com um popovertarget
ou definindo um source
com showPopover({source})
, o popover já tem uma âncora implícita definida. Como um popover já está flutuando com position: fixed
por padrão, para posicionar um popover, basta definir a posição.
#anchor{}
#positionedElement {
position-area: end;
margin: unset;
}
Definir o escopo das possíveis âncoras
Você pode implementar o posicionamento de âncora como parte de um componente para usar um padrão, como um menu suspenso, em vários lugares. Se você estiver usando o mesmo anchor-name
várias vezes, como garantir que cada elemento posicionado encontre a âncora correta?
As soluções em JavaScript envolvem adicionar IDs exclusivos a cada âncora e fazer referência a ela no elemento posicionado. Isso se torna complicado, e o CSS tem uma solução mais simples com anchor-scope
.
A propriedade anchor-scope
define quais nomes de âncora serão correspondidos apenas entre um elemento e seus descendentes. Ele aceita uma lista de um ou mais nomes de âncora ou a palavra-chave all
para limitar o escopo de todos os nomes de âncora definidos.
Um anchor-scope
é adicionado a um ancestral do elemento posicionado e do elemento de ancoragem que não contém outros elementos de ancoragem com o mesmo nome. Muitas vezes, isso está na raiz do componente reutilizável.
O exemplo a seguir mostra a diferença que anchor-scope
faz quando aplicado a elementos repetidos com o mesmo anchor-name
. No exemplo, todos os elementos <img>
e os banners de imagem fazem referência ao nome de âncora --image
. Quando anchor-scope
é aplicado aos elementos <li>
, position-anchor: --image
corresponde apenas ao elemento <img>
no mesmo elemento <li>
do banner. Caso contrário, ele corresponde ao último <img>
renderizado.
Posicionamento
Agora que você vinculou o elemento à âncora, é hora de posicioná-lo. O posicionamento de âncora oferece dois métodos de posicionamento: position-area
e a função anchor()
.
position-area
A propriedade position-area
permite posicionar um elemento ao redor da âncora especificando uma ou duas palavras-chave. Isso abrange muitos casos de uso comuns e geralmente é um bom ponto de partida.
Como o position-area
funciona
position-area
funciona criando um novo bloco de contenção para o elemento posicionado em uma área gerada pelas bordas da âncora e o bloco de contenção original do elemento posicionado.
Embora haja muitas palavras-chave disponíveis para position-area
, elas podem ser divididas em algumas categorias para facilitar a compreensão. O site Anchor-tool.com é uma ótima ferramenta para explorar a sintaxe.
Palavras-chave físicas
Você pode usar as palavras-chave físicas top
, left
, bottom
, right
e center
. Por exemplo, position-area: top right
vai colocar o elemento posicionado acima e à direita da âncora. Essas palavras-chave também têm equivalentes de eixo físico, y-start
, x-start
, y-end
e x-end
.
Palavras-chave lógicas
Você também pode usar palavras-chave lógicas, block-start
, block-end
, inline-start
e inline-end
. Por exemplo, position-area: block-end inline-start
vai colocar o elemento posicionado abaixo e à esquerda da âncora em idiomas como o inglês ou depois da âncora no eixo de bloco e antes da âncora no eixo inline no modo de escrita do documento. center
também pode ser usado com uma palavra-chave lógica.
Você também pode omitir o eixo se estiver especificando palavras-chave lógicas, com o eixo de bloco primeiro e o inline depois. position-area: start end
é igual a position-area: block-start inline-end
ou até mesmo position-area: inline-end block-start
.
Abrangendo várias áreas de grade
Até agora, você deve ter percebido que essas opções só permitem colocar o elemento posicionado em um único espaço da grade. Adicionar o prefixo span
a propriedades físicas ou lógicas adiciona o espaço adjacente da grade central. position-area: span-top right
será posicionado à direita da âncora e de baixo para cima do bloco de contêiner original do elemento posicionado.
Uma posição-área comum para um menu suspenso é position-area: block-end span-inline-end
.
A palavra-chave span-all
abrange três linhas ou colunas.
Palavra-chave única
Se você definir apenas uma palavra-chave, o outro eixo será definido automaticamente. Isso funciona como esperado, mas pode ser útil entender como funciona.
Se a palavra-chave fornecida for clara sobre o eixo, o outro eixo será calculado como span-all
. Isso significa que position-area: bottom
é equivalente a position-area: bottom span-all
, e o elemento posicionado ficará abaixo da âncora e terá toda a largura do bloco de contêiner disponível.
Por outro lado, se a palavra-chave não indicar claramente um eixo, ela será repetida. position-area: start
é equivalente a start start
e é colocado na parte superior esquerda da âncora em idiomas da esquerda para a direita.
A função anchor()
Para casos de uso mais avançados, talvez o position-area
não atenda aos seus requisitos. A função anchor()
permite definir propriedades de encarte individuais com base na posição de outro elemento. Isso resulta em um comprimento de CSS, o que significa que você pode usá-lo em cálculos e com outras funções de CSS. Além disso, você pode vincular lados diferentes a âncoras diferentes.
A função anchor()
usa um nome e um lado de âncora. Se o elemento tiver uma âncora padrão, definida com position-anchor
ou implicitamente, por exemplo, com um popover, você poderá omitir o nome da âncora.
.positionedElement {
block-start: anchor(--my-anchor start);
/* OR */
position-anchor: --my-anchor;
block-start: anchor(start);
}
Valores substitutos
Se não for possível encontrar uma âncora para uma função anchor()
, toda a declaração será inválida. Isso pode acontecer se a âncora for renderizada depois do elemento posicionado ou se não houver um elemento com anchor-name
correspondente. Para resolver isso, defina uma duração ou porcentagem alternativa.
.positionedElement {
block-start: anchor(--my-anchor, 100px)
}
No exemplo anterior, o valor à esquerda do elemento posicionado está ancorado em --focused-anchor
, mas esse anchor-name
só existe quando o primeiro botão é passado ou focado. Como uma função anchor()
é resolvida para um comprimento, você pode usar outra âncora como substituição. Se não fornecermos um substituto, o elemento posicionado não será posicionado.
Palavras-chave de âncora lateral
O valor do lado da âncora escolhe qual das bordas da âncora será posicionada. Assim como position-area
, o valor do lado da âncora é compatível com vários tipos diferentes de sintaxe.
Tipo | Valores | Descrição |
---|---|---|
Físico | top , left , bottom , right |
As palavras-chave físicas correspondem a um lado específico da âncora, mas só podem ser usadas no mesmo eixo do encarte do elemento posicionado que você está definindo. Por exemplo, |
Lado | inside , outside |
A palavra-chave Por exemplo, |
Lógica | start , end , self-start , self-end |
As palavras-chave lógicas se referem aos lados da âncora com base no modo de escrita do elemento posicionado com |
Porcentagem | 0% - 100% |
Um valor de porcentagem posiciona o elemento ao longo do eixo do início ao fim da âncora no eixo especificado. |
Este exemplo mostra como um valor de porcentagem sempre vai do início ao fim no eixo especificado:
Como usar o anchor()
Como anchor()
é um comprimento, ele é muito flexível. É possível manipular o valor com funções CSS como max()
e calc()
.
Uma limitação é que só é possível usar funções anchor()
em propriedades de encarte.
O exemplo anterior adiciona um plano de fundo atrás do painel de detalhes aberto que é animado de maneira suave quando um painel diferente é aberto e se estende para incluir um painel de detalhes em que o cursor está parado. Para isso, ele usa min()
para escolher o menor comprimento entre duas âncoras.
#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)))
);
}
O exemplo também usa calc()
para adicionar espaço inline ao redor do painel aberto.
Usar o tamanho da âncora
Você também pode usar a função anchor-size()
para usar as dimensões da âncora no tamanho, na posição ou na margem do elemento posicionado.
anchor-size()
usa um nome de âncora ou a âncora padrão. Por padrão, ele usa o tamanho da âncora no eixo em que está sendo usado. Assim, width: anchor-size()
retorna a largura da âncora. Você também pode usar o outro eixo especificando o comprimento desejado com as palavras-chave físicas width
e height
ou as palavras-chave lógicas block
, inline
, self-block
e self-inline
.
Como lidar com o estouro
Você criou um componente de menu suspenso e usou o posicionamento de âncora para colocar o menu suspenso onde queria. Mas, ao mover o menu para o outro lado da tela ou usá-lo em um menu de usuário, o nome do usuário fica muito longo. De repente, o menu suspenso sai da tela. E agora?
O posicionamento de âncora do CSS tem um sistema integrado que permite criar rapidamente um conjunto robusto de substituições quando o elemento posicionado fica fora do bloco de contêiner.
Opções alternativas
A regra position-try-fallbacks
usa uma lista de opções de substituição. Quando a posição padrão transborda, cada opção é testada em ordem até que haja uma posição que não transborde.
É possível usar qualquer valor position-area
como uma opção substituta. Neste exemplo, em modos de escrita da esquerda para a direita, como o inglês, o elemento posicionado vai tentar ficar na parte de baixo da âncora, abrangendo as colunas central e direita. Se isso transbordar, ele tentará ser posicionado na parte de baixo da âncora, abrangendo as colunas esquerda e central. Se isso também transbordar, a posição vai voltar para a posição padrão, mesmo que isso transborde.
.positioned-element {
position-area: block-end span-inline-end;
position-try-fallbacks: block-end span-inline-start;
}
Há também várias palavras-chave flip-
que processam casos de substituição comuns. flip-block
e flip-inline
tentam inverter o elemento nos eixos de bloco e inline. Eles também podem ser combinados com flip-block flip-inline
para inverter os dois eixos. O valor flip-start
vira o elemento posicionado em uma linha diagonal do início até os cantos finais da âncora.
Você também pode criar uma opção de substituição personalizada com @position-try
. Assim, é possível definir as margens, o alinhamento e até mesmo mudar a âncora.
@position-try --menu-below {
position-area: bottom span-right;
margin-top: 1em;
}
#positioned-element {
position-try: --menu-below;
}
flip-block
e flip-inline
podem ser adicionados às opções de substituição @position-try
para criar uma variante.
#positioned-element {
position-try: --menu-below, flip-inline --menu-below;
}
No exemplo anterior, o navegador segue estas etapas, parando assim que encontra uma solução que não transborda.
- O elemento é colocado com
position-area: end
, na parte inferior direita da âncora. - Se isso transbordar, o elemento será colocado com a opção de substituição personalizada chamada
--bottom-span-right
, que o coloca composition-area: bottom span-right
e uma margem extra abaixo. - Se isso transbordar, o elemento será colocado com
flip-inline --bottom-span-right
, que combina a opção de substituição personalizada comflip-inline
, que é essencialmenteposition-area: bottom span-left
. - Se isso transbordar, o elemento será colocado usando a opção de substituição personalizada
--use-alternate
, que o coloca abaixo de uma âncora completamente diferente. - Se isso transbordar, o elemento vai voltar ao posicionamento original, com
position-area: end
, mesmo que isso cause transbordamento.
Ordem de fallback
Por padrão, quando a posição inicial transborda, o navegador tenta cada opção em position-try-fallbacks
até encontrar uma posição que não transborde. É possível substituir esse comportamento com position-try-order
para testar cada opção de substituição e usar aquela que tem mais espaço em um eixo especificado.
É possível especificar o eixo com as palavras-chave lógicas most-block-size
e most-inline-size
ou com as palavras-chave físicas most-height
e most-width
.
position-try-order
e position-try-fallbacks
podem ser combinados com a abreviação position-try
, com a ordem vindo primeiro.
Rolagem
Quando um usuário rola a tela, ele espera que a página se mova de maneira fluida. Para isso, os navegadores têm limites de uso do posicionamento de âncora durante a rolagem.
É possível vincular um elemento posicionado a âncoras em diferentes contêineres de rolagem, mas o elemento só se move em resposta à rolagem de uma das âncoras. Esse será o elemento âncora padrão, que é a âncora implícita de um popover ou o valor de position-anchor
.
O elemento posicionado permanece visível mesmo quando a âncora é rolada para fora da visualização. Para ocultar o elemento posicionado quando a âncora estiver oculta, defina position-visibility: anchors-visible
. Isso se aplica não apenas quando a âncora é rolada demais, mas também se ela estiver oculta de outras maneiras, por exemplo, com visibility: hidden
.
Teste seu conhecimento
Quais são os valores válidos para o lado em anchor()
?
inside
25%
25px
25px
possa ser usado como o valor substituto, apenas porcentagens podem ser usadas para o lado.block-start
start
Quais são os valores válidos para position-area
?
top
block-end inline-end
block-start block-end
Quais propriedades são compatíveis com a função anchor()
?
top
margin-left
inset-block-start
transform
O que acontece se houver várias âncoras com o mesmo anchor-name
?