Abordagens Principais para Destaque de Texto

Abordagens Principais para Destaque de Texto


Destacar texto pode parecer simples à primeira vista—apenas mudar o fundo para amarelo—mas na verdade é bastante complexo. Veja este exemplo abaixo, onde a parte destacada abrange múltiplos elementos e contém texto parcial de elementos abaixo.

Highlights across elements

A seguir, vou percorrer várias abordagens comuns para implementar destaque de texto, discutindo seus prós e contras junto com casos de uso práticos para delinear as principais soluções técnicas.

CSS Highlight API — Destaque de Texto Moderno e Eficiente

Esta é atualmente a melhor escolha para implementar destaque de texto, sendo simples de usar e performante. A única desvantagem é que os navegadores precisam de versões relativamente recentes para suporte, embora em 2025 todos os navegadores principais já o suportem.

Objeto Highlight

Primeiro, você precisa criar um objeto Range para cada área destacada. Range é uma API de longa data que representa uma seção contínua na árvore DOM—se você não estiver familiarizado com ela, precisará estudá-la.

const range = new Range();
range.setStart(someNode, startOffset);
range.setEnd(someNode, endOffset);

Então adicione-o a um objeto Highlight. Como o destaque pode ter múltiplas áreas não contíguas, um único objeto Highlight pode conter vários Ranges.

const highlight = new Highlight(range1, range2, ..., rangeN);

É similar a um objeto Set, então você pode usar métodos como add, delete, etc., para modificar os Ranges contidos.

CSS.highlights

Então adicione o objeto Highlight ao CSS.highlights. É similar a um objeto Map, com métodos para adicionar e remover membros como get, set, delete, etc., e os mesmos métodos de iteração.

Assim como um Map, ao adicionar um Highlight, você precisa dar-lhe uma chave como nome do highlight. Este nome é muito útil—como veremos abaixo, usamos este nome para definir o estilo de destaque, como um fundo verde. Então todos os destaques no mesmo objeto Highlight têm o mesmo estilo. Se você quiser destacar outro pedaço de texto em azul, precisará criar um novo highlight.

CSS.highlights.set("my-highlight", highlight);

Definindo o Pseudo-elemento ::highlight

A seguir, os estilos CSS entram em cena. Você pode definir estilos de destaque usando o pseudo-elemento ::highlight(nome-do-highlight).

::highlight(my-highlight) {
  background-color: yellow;
  color: black;
}

Nota: Apenas algumas propriedades CSS podem ser usadas, como background-color, color, cursor, etc. Veja a especificação para detalhes.

Modificando Dinamicamente os Intervalos de Destaque

CSS.highlights é como um Map com métodos similares para atualizar Highlights:

  • CSS.highlights.clear()
  • set(highlightName, Highlight)
  • delete(highlightName)

O objeto Highlight é como um Set com métodos similares para atualizar Ranges:

  • Highlight.add(range)
  • delete(range)

Modificando Estilos de Elementos de Texto

Alcance o destaque percorrendo o DOM para encontrar nós de texto alvo e modificando diretamente seus estilos de fundo.

  • Requer modificações do DOM, causando reflow do navegador com sobrecarga significativa de performance.
  • Implementar destaque entre elementos (onde o intervalo de destaque abrange múltiplos elementos) é bastante complexo. Highlights across elements
  • Adequado para cenários onde o conteúdo destacado é relativamente fixo e o intervalo é pequeno.

Sobrepondo Camadas Adicionais para Renderizar Destaques Sem Modificar o DOM do Texto

Crie uma camada de sobreposição transparente, calcule a posição na tela do texto alvo, então desenhe destaques semi-transparentes na sobreposição.

Posicionando Áreas de Destaque

  • Use Element.getClientRects() ou getBoundingClientRect() para obter coordenadas do texto na página.
  • Ao lidar com texto de múltiplas linhas, cada linha corresponde a uma área retangular que precisa de blocos de destaque separados.
  • Mudanças no tamanho da janela ou tamanho da fonte requerem recálculo das posições de destaque, o que pode impactar a performance.

Métodos de Desenho de Destaque

DIV como Sobreposição

Use contêineres pai com posicionamento absoluto e elementos filho com fundo semi-transparente para sobrepor texto. Por exemplo, o editor Monaco usa esta abordagem para implementar destaque de palavras iguais.

<div class="editor" style="position: relative;">
  <div class="overlay" style="position: absolute; height: 0;">
    <div
      class="highlight"
      style="top:0; left:57px; width:23px; background-color: rgba(173,214,255,0.15);"
    ></div>
    <!-- Adicionar mais áreas de highlight -->
  </div>
  <div class="content">
    <!-- Conteúdo de texto -->
  </div>
</div>
  • A posição do overlay é absolute, enquanto garante que o elemento pai não seja position: static, para que o posicionamento absoluto funcione. Isso permite que elementos de destaque internos sejam posicionados em qualquer lugar.
  • Para colocar acima do texto, simplesmente coloque o overlay antes do contêiner de texto no HTML. A altura do overlay é 0 para evitar afetar a interação com o texto abaixo.
  • Adicione elementos dentro, defina background-color para a cor de destaque semi-transparente, posicione na localização do texto destacado e defina a largura.
  • O editor Monaco (VSCode é baseado nele) usa este método. Veja a demo oficial. Após selecionar uma palavra-chave, as mesmas palavras-chave são destacadas. Olhando o HTML, você encontrará que essas palavras-chave não mudaram estilos, mas há um Overlay na interface do editor com cores de destaque semi-transparentes desenhadas dentro (veja a div com class="view-overlays").

SVG como Sobreposição

  • Defina overlay com as mesmas dimensões da página
  • Adicione <rect> dentro, então desenhe nas posições do texto destacado
  • foliate-js usa este método. Veja overlayer.js.

Usando Selection API e Pseudo-elemento ::selection — Destaque de Seleção de Texto Padrão do Navegador

Navegadores naturalmente destacam texto selecionado, então controlar a seleção pode indiretamente alcançar destaque. Estilos podem ser personalizados através do pseudo-elemento ::selection do CSS.

const range = new Range();
range.setStart(parentNode, startOffset);
range.setEnd(parentNode, endOffset);

// Definir seleção
const selection = document.getSelection();
selection.removeAllRanges();
selection.addRange(range);
::selection {
  background-color: #c3c2c2;
  color: white;
}

Este método é bastante inteligente, simples e tem amplo suporte do navegador, mas tem uma grande desvantagem: já que apenas uma seleção pode existir por vez, seleções programáticas e seleções reais do usuário entrarão em conflito e se sobrescreverão mutuamente. Portanto, é adequado apenas para cenários que atendem às seguintes condições:

  • Usuários não podem selecionar texto
  • Há apenas um segmento de texto destacado contínuo
  • Você precisa suportar navegadores mais antigos
  • Você quer ser preguiçoso e evitar outros métodos