Olha só isso: finalmente dá pra estilizar qualquer texto

Sabe quando você quer destacar o resultado de uma busca na página e a única saída era sair injetando <span> ou <mark> no DOM? Pois é, essa era acabou. 🎉

A CSS Custom Highlight API chegou pra resolver exatamente isso. Combinada com pseudo-elementos como ::search-text, ::highlight(), ::target-text, ::spelling-error e ::grammar-error, você agora consegue estilizar ranges de texto que nunca foram envolvidos por nenhum elemento — só com CSS puro.

Isso muda o jogo pra ferramentas de busca, leitores de artigo, editores colaborativos e qualquer coisa que precise marcar texto sem mexer no DOM. Se você já escreveu aquele wrapper em cima do mark.js só pra pintar um resultado de busca, respira: tem caminho melhor. E se você quer entender como a plataforma vem evoluindo nessa direção, dá uma olhada nesse guia sobre CSS highlight pseudo-elements.

Developer inspecting CSS Custom Highlight API pseudo-elements in browser DevTools Algorithm Concept Visual

Os pseudo-elementos que você precisa conhecer

Segue o mapa da mina, do mais estável pro mais experimental:

Pseudo-elementoPra que serveSuporte
::selectionTexto selecionado pelo usuárioUniversal
::target-textTexto alvo via fragmento de URLChrome, Safari
::search-textAchados do "localizar na página"Chromium
::spelling-error / ::grammar-errorMarcadores nativos de ortografia/gramáticaChromium
::highlight(nome)Ranges customizados registrados via JSChrome 105+, Safari 17.2+

Estilizando o Ctrl+F do navegador

::search-text é aquele que a galera pede há uma década. Antes, o highlight do "localizar na página" era intocável. Agora não mais:

/* Destaque padrão dos resultados de busca */
::search-text {
  background: #ffe066;
  color: #1a1a1a;
}

/* O resultado atualmente focado (aquele que o Enter pula) */
::search-text:current {
  background: #ff7043;
  color: #fff;
  outline: 2px solid #ff7043;
}

Custom Highlight API na prática

O pulo do gato é registrar seus próprios ranges. Sem mutação de DOM, sem <mark> espalhado, sem reflow pesado em documentos grandes.

// 1. Encontre o range que você quer destacar
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
const ranges = [];
let node;
while ((node = walker.nextNode())) {
  const idx = node.textContent.indexOf('pseudo-elemento');
  if (idx !== -1) {
    const range = new Range();
    range.setStart(node, idx);
    range.setEnd(node, idx + 'pseudo-elemento'.length);
    ranges.push(range);
  }
}

// 2. Registre tudo sob um highlight nomeado
const highlight = new Highlight(...ranges);
CSS.highlights.set('termo-busca', highlight);
/* 3. Estilize o highlight nomeado */
::highlight(termo-busca) {
  background-color: #fff3a0;
  text-decoration: underline wavy #e67e22;
}

Pronto. Nenhum elemento wrapper, nenhuma limpeza quando o termo de busca muda — é só dar CSS.highlights.clear() e registrar de novo.

O padrão MicroLighter

Um truque bem legal que anda circulando: construir um syntax highlighter inteiro em cima da Custom Highlight API. Em vez de emitir <span class="keyword"> pra cada token, você tokeniza o texto, monta objetos Range e registra sob highlights como keyword, string, comment. O CSS faz a coloração. O DOM fica minúsculo e trocar de tema vira praticamente de graça.

Frontend engineer styling search-text highlight with CSS pseudo-elements on a code editor Software Concept Art

Cuidados, limites e o que ninguém te conta

Alguns pontos que os demos felizes esquecem de mencionar:

  • Só um subconjunto de CSS se aplica. Pseudo-elementos de highlight aceitam pouquíssimas propriedades: color, background-color, text-decoration e suas longhands, text-shadow e mais algumas. Você não consegue setar padding, border, font-size ou display. Se precisa de uma caixa em volta do match, essa não é a ferramenta.
  • Sem ::before / ::after. Não dá pra injetar conteúdo num highlight. É só estilização.
  • Ranges precisam estar vivos. Se o DOM mudar, seus ranges podem ficar inválidos e parar de renderizar silenciosamente. Re-registre em mutações se o conteúdo for dinâmico.
  • ::search-text é só Chromium por enquanto. Firefox e Safari ainda não entregaram. Faça feature-detect com CSS.supports('selector(::search-text)') e tenha fallback.
  • Acessibilidade: highlights são puramente visuais. Leitores de tela não anunciam. Se o destaque carrega significado (tipo resultado de busca), replique em regiões aria-live ou no nome acessível.

Receita de progressive enhancement

/* Baseline: funciona em todo lugar */
mark.search-hit {
  background: #ffe066;
}

/* Upgrade: sem wrapper no DOM */
@supports selector(::highlight(termo-busca)) {
  ::highlight(termo-busca) {
    background: #ffe066;
  }
}

Manda o fallback com <mark>, empilha o highlight por cima quando suportado, e apaga o fallback quando o Baseline alcançar. E se você curte histórias de como uma primitiva nova reescreve uma stack inteira, vale ler o caso de escala do WhatsApp com Rust — mesmo padrão de "API nova destrava arquitetura mais simples".

Pra onde ir agora

  1. Leia a spec da CSS Custom Highlight API — é curta e legível.
  2. Teste ::target-text pra highlight de deep-link em sites de documentação.
  3. Construa uma ferramentinha de anotação: pegue texto com window.getSelection(), converta em Range, registre o highlight. Você aprende a API inteira numa tarde.
  4. Fique de olho nas specs de ::search-text e ::spelling-error — conforme chegarem em mais engines, a era do "envelopa num span" oficialmente acaba.

Web developer reviewing MicroLighter syntax highlighter built with CSS Custom Highlight API System Abstract Visual

Fechando a conta

Pseudo-elementos de highlight do CSS são uma daquelas adições silenciosas que apagam categorias inteiras de JavaScript. Se seu codebase ainda injeta <mark> pra resultado de busca, ou carrega uma lib de 40KB só pra colorir token, a Custom Highlight API merece um olhar sério nesse trimestre.

Comece com ::highlight() pros seus próprios ranges, empilhe ::search-text e ::target-text onde houver suporte, e mantenha um fallback com <mark> pra cauda longa. O DOM que você não cria é o DOM que você não precisa limpar. 🚀

Este conteúdo foi elaborado com o auxílio de ferramentas de IA, com base em fontes confiáveis, e revisado pela nossa equipe editorial antes da publicação. Não substitui o aconselhamento de um profissional especializado.