Os usuários esperam ver mais informações relacionadas sem mudar completamente o contexto. Mostrar uma dica quando um usuário quer mais informações pode ser útil para fornecer definições de um termo, esclarecer a ação que um botão somente de ícone vai realizar ou fornecer mais orientações sobre o campo do formulário.
Como criar a dica
Para criar um popover com o comportamento necessário, adicione o atributo popover="hint" a um elemento <div> ou outro elemento semanticamente apropriado. Quando o usuário abre a dica, as outras dicas de popover="hint" são ocultadas, mas as de auto ou manual não. Ele também lida com a dispensa de dicas aninhadas.
Ele também oferece um comportamento de dispensa leve. Assim, quando um usuário clica ou foca fora do popover, ele é dispensado.
O elemento de dica precisa ter um atributo id com um valor exclusivo:
<!-- MANDATORY: The tooltip container `<div>` must have a `popover` attribute.
the value of `"hint"` ensures it can be "light dismissed". -->
<div popover="hint" id="tooltip">Tooltip content</div>
Um usuário demonstra interesse nas informações adicionais ao passar o cursor ou focar em um elemento <a> ou <button>. O elemento precisa ter um atributo interestfor que corresponda ao atributo id da dica.
<!-- The `interestfor` attribute can be applied to a `<button>` element: -->
<button interestfor="tooltip">Tooltip trigger</button>
<!-- The `interestfor` attribute can also be applied to an `<a>` element: -->
<a interestfor="tooltip" href="">Tooltip trigger</a>
O acionador precisa ter um indicador visual para mostrar que há mais informações disponíveis ao interagir com ele.
Acessibilidade integrada ao interestfor
Quando você usa interestfor, o navegador lida com a fiação da tecnologia adaptativa para você:
- Semântica implícita: um destino com
popover="hint"ganha um papel mínimo implícito detooltip. NÃO definarole="tooltip"por conta própria. - Associação implícita: o navegador associa implicitamente o elemento de origem ao destino usando
aria-describedbyquando o destino é texto simples ouaria-detailsquando o destino contém conteúdo interativo. NÃO adicionearia-describedbyouaria-detailsao gatilho. - Conteúdo interativo: como a associação muda para
aria-detailsquando necessário, o destino pode conter conteúdo interativo (por exemplo, um link dentro de um "card de interesse").
Restrições de acessibilidade (WCAG 1.4.13)
Mesmo com o interestfor processando a semântica acima, sua implementação AINDA PRECISA atender às diretrizes WCAG 1.4.13 (conteúdo ao passar o cursor ou focar):
- Dispensável: os usuários precisam conseguir dispensar a dica sem mover o cursor ou o foco do teclado (por exemplo, pressionando a tecla
Escape). O atributo nativopopovergerencia essa vinculação automaticamente. - Passagem do cursor: o ponteiro precisa se mover sobre o conteúdo da dica sem que ela desapareça. Isso permite que os usuários com ferramentas de ampliação leiam o texto da dica com segurança.
- Persistente: a dica precisa permanecer visível até que o acionador de passagem do cursor ou de foco seja removido, o usuário a dispense explicitamente ou o conteúdo não seja mais válido.
Como posicionar a dica
A dica é posicionada usando o posicionamento de âncora CSS. Quando a dica é aberta usando interestfor, o elemento acionador se torna automaticamente uma âncora implícita para o popover.
Em navegadores mais recentes que oferecem suporte ao posicionamento de âncora nativo, não é necessário definir um anchor-name no acionador ou um position-anchor na dica. É possível posicionar a dica diretamente em relação à âncora implícita usando position-area e processar a inversão de colisão com position-try-fallbacks:
[popover] {
/* Implicit anchor from interestfor: no anchor-name or position-anchor needed */
position-area: top;
position-try-fallbacks: flip-block;
margin: unset;
}
Estratégias de fallback
Alternativas e suporte do navegador para invocadores de interesse
Os invocadores de interesse precisam ser preenchidos condicionalmente usando o pacote de polyfill interestfor do NPM. Prefira agrupar o polyfill em vez de usar a CDN.
OBRIGATÓRIO: detecte o recurso verificando a propriedade interestForElement em HTMLButtonElement.prototype e carregue o polyfill somente quando não houver suporte nativo.
<script type="module">
if (!HTMLButtonElement.prototype.hasOwnProperty("interestForElement")) {
// CDN link only used for example, prefer bundling.
await import("https://unpkg.com/interestfor@latest");
}
</script>
Limitações do polyfill de CSS
Ao usar o polyfill, a API CSS muda um pouco para compensar a falta de suporte nativo a pseudoclasses e propriedades:
- Pseudoclasses: o polyfill não pode definir pseudoclasses
:interest-sourcee:interest-targetreais. Por isso, ele aplica as classes.interest-sourcee.interest-target. OBRIGATÓRIO: combine-os com:is()para oferecer suporte aos estados nativos e polyfilled.
/* Styles to apply when the effect is being previewed */
:is(:interest-source, .interest-source) { /* ... */ }
:is(:interest-target, .interest-target) { /* ... */ }
- Propriedades CSS: para
interest-delay,interest-delay-starteinterest-delay-end, o polyfill exige o uso de variáveis CSS, já que não pode ler as propriedades personalizadas diretamente em todos os navegadores.
/* Adjust the start and end delay for interest invokers */
[interestfor] {
--interest-delay-start: 0.2s;
interest-delay-start: var(--interest-delay-start);
--interest-delay-end: 0.1s;
interest-delay-end: var(--interest-delay-end);
}
Alternativas e suporte do navegador para Popover
A API Popover é, em grande parte, um aprimoramento progressivo, mas os comportamentos que a definem (promoção de camada superior, fechamento leve e invocação de popovertarget) não têm equivalente somente em CSS. Os navegadores mais antigos precisam de um polyfill ou de um substituto manual, se você preferir não enviar um.
Polyfill: para oferecer suporte ao atributo popover em navegadores mais antigos, carregue condicionalmente @oddbird/popover-polyfill. OBRIGATÓRIO: detecte o recurso verificando a propriedade popover em HTMLElement.prototype e carregue o polyfill somente quando não houver suporte nativo. NÃO o carregue incondicionalmente.
Com um bundler ou mapa de importação:
// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
import("@oddbird/popover-polyfill");
}
Sem um bundler, importe de uma CDN dentro de um <script type="module">:
<script type="module">
if (!("popover" in HTMLElement.prototype)) {
import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
}
</script>
Observação sobre o estilo: o polyfill não pode definir a pseudoclasse :popover-open real. Por isso, ele aplica uma classe .\:popover-open. OBRIGATÓRIO: combine os dois com :is() ou :where(). Caso contrário, os navegadores que não têm :popover-open vão descartar toda a regra:
[popover]:is(:popover-open, .\:popover-open) {
display: block;
}
Como alternativa, para um substituto legado sem um polyfill, use position: fixed e calcule manualmente as coordenadas usando getBoundingClientRect() ou use o posicionamento padrão com inset: auto, se isso for aceitável para o caso de uso.
O popover-polyfill não polyfill o comportamento de hinting em navegadores que oferecem suporte a popover, mas não a popover="hint". Nesses navegadores, uma dica aberta pelo foco pode permanecer aberta quando uma segunda dica é aberta ao passar o cursor.
Para oferecer suporte a navegadores sem posicionamento de âncora, use o polyfill @oddbird/css-anchor-positioning. Como alternativa, use @supports para especificar uma posição de fallback.
Ao usar o polyfill @oddbird/css-anchor-positioning para oferecer suporte a navegadores legados, saiba que ele não é compatível com âncoras implícitas ou position-area em popovers. Defina explicitamente um anchor-name no gatilho, defina position-anchor no popover e posicione usando as funções de inserção anchor() em vez de position-area:
<!-- MANDATORY: Conditionally install the anchor positioning polyfill -->
<script type="module">
if (!("anchorName" in document.documentElement.style)) {
await import("https://unpkg.com/@oddbird/css-anchor-positioning");
}
</script>
button[interestfor="tooltip-attrs"] {
/* MANDATORY: Each trigger and popover pair must have a unique anchor name, referenced by `anchor-name` on the trigger and `position-anchor` on the popover. */
anchor-name: --tooltip-attrs;
}
#tooltip-attrs {
position-anchor: --tooltip-attrs;
/* If using the anchor positioning polyfill with a popover, DO use `anchor()` functions, and not `position-area. */
top: anchor(bottom);
left: anchor(right);
margin: unset;
}