Back

Criando um Tooltip Puro em CSS

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 opacity e visibility (não display) para que o tooltip possa aparecer e desaparecer suavemente.
  • pointer-events: none evita 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-describedby apropriadas 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 o id de um elemento real e visível no DOM — não para um pseudo-elemento. Como esta técnica usa ::after, omita aria-describedby a 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.

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 content em 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 use aria-describedby apontando 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..

OpenReplay