Criando um Tooltip Puro em CSS
Se você precisa de um tooltip leve e não quer recorrer a uma biblioteca JavaScript para construí-lo, o CSS sozinho dá conta do recado surpreendentemente bem. Sem dependências, sem event listeners — apenas algumas regras CSS bem posicionadas.
Este artigo apresenta uma implementação prática e moderna usando pseudo-elementos, atributos data e transições, juntamente com as considerações de acessibilidade que você realmente precisa conhecer.
Pontos Principais
- Um tooltip puro em CSS pode ser construído usando um pseudo-elemento
::after,content: attr(data-tooltip)e um gatilho:hover/:focus-visible. - Use
opacityevisibility(nãodisplay) para que o tooltip possa aparecer e desaparecer suavemente. pointer-events: noneevita o efeito de tremulação (flicker), impedindo que o próprio tooltip receba eventos de hover.- Tooltips em CSS têm limites reais de acessibilidade — eles não chegam de forma confiável aos leitores de tela e o comportamento de hover é inconsistente em dispositivos com toque.
- Para dicas de UI críticas, recorra ao JavaScript, à Popover API ou a referências
aria-describedbyapropriadas para elementos visíveis.
Como Funciona um Tooltip Puro em CSS
A ideia central é simples: aplique position: relative ao elemento gatilho e use um pseudo-elemento ::after como balão do tooltip, posicionado de forma absoluta em relação ao seu pai. Oculte-o por padrão e revele-o em :hover e :focus-visible.
Como pseudo-elementos não conseguem ler diretamente do DOM, você passa o texto do tooltip através de um atributo data-tooltip e o recupera com content: attr(data-tooltip). Isso mantém seu HTML limpo e evita duplicar o texto em um <span> oculto.
A Estrutura HTML
<button
class="tooltip-trigger"
data-tooltip="Saves your current progress"
>
Save
</button>
Usar um <button> ou uma âncora (<a>) como elemento gatilho é importante. Esses elementos são focáveis nativamente, o que significa que usuários de teclado conseguem alcançá-los sem nenhum trabalho adicional.
Nota: Se você quiser usar
aria-describedby, ele deve apontar para oidde um elemento real e visível no DOM — não para um pseudo-elemento. Como esta técnica usa::after, omitaaria-describedbya menos que você também renderize o texto do tooltip dentro de um elemento real.
O CSS
.tooltip-trigger {
position: relative;
cursor: pointer;
}
/* Tooltip bubble */
.tooltip-trigger::after {
content: attr(data-tooltip);
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%);
background-color: #1a1a1a;
color: #fff;
font-size: 0.8rem;
white-space: nowrap;
padding: 5px 10px;
border-radius: 4px;
/* Hidden by default */
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
z-index: 10;
pointer-events: none;
}
/* Show on hover and keyboard focus */
.tooltip-trigger:hover::after,
.tooltip-trigger:focus-visible::after {
opacity: 1;
visibility: visible;
}
Por que opacity + visibility em vez de display?
A alternância entre display: none e display: block não é animável — o tooltip simplesmente apareceria e desapareceria abruptamente. Usar opacity em conjunto com visibility: hidden permite que você faça o fade do tooltip suavemente, ao mesmo tempo em que o remove da interação do ponteiro quando oculto. Combinar visibility com opacity também impede que o tooltip oculto permaneça visualmente interativo.
Por que pointer-events: none?
Sem isso, o próprio balão do tooltip pode disparar um estado de hover, fazendo com que o tooltip pisque conforme o cursor se move sobre ele. Definir pointer-events: none no elemento ::after evita isso completamente.
Discover how at OpenReplay.com.
Por que transform: translateX(-50%) para Centralizar?
Definir left: 50% move a borda esquerda do tooltip para o centro do gatilho. O deslocamento translateX(-50%) então o puxa de volta pela metade da sua própria largura, centralizando-o independentemente da largura do texto do tooltip — sem necessidade de cálculos de pixels fixos.
Limitações de Acessibilidade que Você Deve Conhecer
Um tooltip puro em CSS via hover tem limitações reais:
- Leitores de tela podem não anunciá-lo. A propriedade
contentem um pseudo-elemento não é lida de forma confiável por todos os leitores de tela. Para informações críticas, inclua-as na UI visível ou usearia-describedbyapontando para um elemento real. - O comportamento de hover é inconsistente em dispositivos com toque. Não se deve confiar em tooltips somente em CSS para informações essenciais.
- Sem role ou live region. Apenas o CSS não consegue comunicar a semântica do tooltip às tecnologias assistivas.
Para dicas suplementares simples em elementos interativos, um tooltip em CSS é adequado. Para qualquer coisa essencial à conclusão de uma tarefa, você vai querer usar JavaScript para gerenciar foco, anúncio e estado ARIA.
Olhando para o Futuro: CSS Anchor Positioning e a Popover API
O CSS Anchor Positioning torna o posicionamento de tooltips muito mais flexível — você pode ancorar um tooltip a qualquer elemento sem depender de position: relative no pai. O suporte dos navegadores ao Anchor Positioning já está amplamente disponível em navegadores modernos, segundo o Can I Use.
Para um comportamento interativo mais sofisticado, a Popover API vale a pena ser explorada como alternativa nativa para UI flutuante interativa.
Conclusão
Um tooltip puro em CSS construído com ::after, content: attr(data-tooltip) e uma transição de visibility/opacity é limpo, rápido e livre de dependências. Combine-o com :focus-visible para suporte ao teclado e você terá uma base sólida. Apenas seja honesto sobre onde os tooltips em CSS deixam a desejar — para qualquer coisa além de dicas suplementares, recorra ao JavaScript ou a um recurso nativo da plataforma como a Popover API.
Perguntas Frequentes
Sim. A posição é controlada pelas propriedades de offset no pseudo-elemento. Use bottom com calc(100% + 8px) para colocá-lo acima, top com calc(100% + 8px) para colocá-lo abaixo, ou use right e left para posicionamento horizontal. Você também pode criar classes variantes como tooltip-bottom ou tooltip-right que sobrescrevem essas propriedades.
O comportamento de hover é inconsistente em dispositivos com toque, portanto tooltips somente em CSS não devem ser usados para informações essenciais. Se o conteúdo do seu tooltip importa no celular, renderize-o em um elemento real controlado por JavaScript, ou use a Popover API, que oferece uma base mais robusta para UI flutuante interativa em diferentes tipos de entrada.
A regra white-space: nowrap mantém os tooltips em uma única linha, o que pode ultrapassar telas estreitas. Substitua-a por um max-width e permita quebra de linha, por exemplo max-width: 240px e white-space: normal. Para detecção dinâmica de bordas, você precisará de JavaScript ou do CSS Anchor Positioning, que oferece comportamento de posicionamento nativo mais flexível em navegadores modernos.
É aceitável para dicas suplementares e não essenciais em elementos focáveis como botões e links. Não é suficiente quando o tooltip carrega informações necessárias para concluir uma tarefa, já que o conteúdo de pseudo-elementos não é anunciado de forma confiável pelos leitores de tela e o comportamento de hover é inconsistente em dispositivos com toque. Para conteúdo crítico, use um elemento real do DOM com aria-describedby e comportamento gerenciado por JavaScript, ou considere a Popover API.
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..