Volver al Centro de conocimiento
Plataforma

CSS Highlight API: pintura y accesibilidad

Usa resaltados personalizados con texto semántico, rangos limitados, foco de teclado, contraste y una alternativa accesible.

BotBrowser Team

Documentación

Quieres la documentación estructurada de Plataforma?

Este artículo forma parte de la biblioteca editorial. Para pasos de configuración, material de referencia y actualizaciones continuas, entra en la sección de docs.

CSS Highlight API puede dar estilo a coincidencias de búsqueda, anotaciones y selecciones sin cambiar el DOM, pero un resaltado es presentación, no significado. BotBrowser puede repetir un fixture de resaltado propio de la página e inspeccionar estados de reserva visibles; no puede certificar el habla de tecnologías de asistencia, la intención de lectura de una persona ni la implementación completa de pintura del navegador. Mantén el contrato acotado: expón el texto en el DOM, registra rangos limitados, pinta una capa distinguible y conserva una alternativa semántica y operable con teclado.

CSS Highlight API convierte texto DOM en rangos acotados y una capa pintada, manteniendo foco de teclado, colores forzados y alternativa DOM

TL;DR

  • CSS.highlights.set('search-hit', new Highlight(range)) aplica estilo a un Range; no añade texto, etiquetas ni semántica accesible.
  • Un pseudo-elemento de resaltado como ::highlight(search-hit) debe usar un par de colores con contraste seguro y nunca ser la única señal.
  • Conserva el texto fuente y un contador de resultados anunciado en el DOM; prueba por separado el foco de teclado, la selección, los colores forzados, el zoom y la reducción de movimiento.
  • Reconstruye los rangos tras cambios de contenido, limita su cantidad y longitud y elimina entradas obsoletas con CSS.highlights.delete(name).
  • BotBrowser puede comprobar el estado propio de la página y la alternativa, pero este artículo reúne orientación basada en fuentes y no declara una ejecución de BotBrowser.

Contenido

Conserva el significado en el DOM

La API de resaltado cambia cómo se pinta el texto existente. Un Range apunta a nodos ya presentes, por lo que un lector de pantalla, una copia, la búsqueda de texto y el renderizado sin CSS necesitan el mismo contenido fuente. Coloca el contador de resultados en una región aria-live="polite", conserva la consulta en un campo etiquetado y muestra una lista o párrafo normal para las anotaciones. No codifiques una advertencia solo con un fondo amarillo o un efecto de pintura personalizado.

La API es independiente de la Selection API. Una selección del usuario puede verse mediante ::selection; un resaltado personalizado con nombre es un objeto Highlight propiedad de la aplicación. Da a cada estado un nombre estable como search-hit o current-hit y elimínalo cuando la consulta esté vacía. El nombre es un hook de CSS, no una etiqueta que una tecnología de asistencia vaya a anunciar.

Para un límite relacionado con la identidad visual, gestión del color CSS y accesibilidad de pantalla explica cómo separar un resultado de estilo visible en el navegador de una afirmación de capacidad. Para la interacción de teclado, localización y privacidad de Keyboard Layout API muestra por qué una etiqueta visual no debe convertirse en una inferencia sobre quien la usa. La revisión de compatibilidad de Web Components añade una matriz para separar detección de funciones y promesas al lector.

Registra rangos limitados

Crea rangos a partir de nodos de texto renderizados, no de una cadena HTML no confiable. Un fixture sencillo puede recorrer nodos de texto, buscar una consulta con plegado de mayúsculas y llamar a range.setStart() y range.setEnd() para cada coincidencia. Limita MAX_HIGHLIGHTS y MAX_MATCH_CHARS; la página debe seguir respondiendo cuando la consulta coincide con miles de palabras.

const MAX_HIGHLIGHTS = 100;
const MAX_MATCH_CHARS = 120;

function showMatches(root, query) {
  CSS.highlights.delete('search-hit');
  if (!query || !window.Highlight) return 0;
  const ranges = [];
  for (const node of root.querySelectorAll('[data-search-text]')) {
    const text = node.textContent || '';
    let offset = 0;
    while (offset < text.length && ranges.length < MAX_HIGHLIGHTS) {
      const start = text.toLocaleLowerCase().indexOf(query.toLocaleLowerCase(), offset);
      if (start < 0) break;
      if (query.length <= MAX_MATCH_CHARS) {
        const range = new Range();
        range.setStart(node.firstChild, start);
        range.setEnd(node.firstChild, start + query.length);
        ranges.push(range);
      }
      offset = start + Math.max(query.length, 1);
    }
  }
  CSS.highlights.set('search-hit', new Highlight(...ranges));
  return ranges.length;
}

El fixture exacto depende de los límites de los nodos de texto; el código de producción debe gestionar con seguridad nodos anidados y un firstChild vacío. Recalcula después de renderizar, localizar, filtrar o reciclar una lista virtual. Un rango que apunta a contenido eliminado es estado obsoleto, no una razón para mantener vivo un objeto de resaltado antiguo.

Pinta una capa visible y accesible

Usa el pseudo-elemento ::highlight(search-hit) para la capa con nombre y mantén pequeñas las declaraciones. El estilo de CSS Highlight API está limitado intencionadamente frente a los elementos normales; el navegador puede ignorar propiedades no compatibles. Elige un primer plano y fondo que cumplan el objetivo de contraste del producto y añade una señal no cromática, como un contorno, icono o contador de resultados en la interfaz cercana.

::highlight(search-hit) {
  color: #111827;
  background-color: #fde68a;
  text-decoration: underline 0.12em solid #92400e;
}

@media (forced-colors: active) {
  ::highlight(search-hit) {
    color: CanvasText;
    background-color: Highlight;
    text-decoration: underline;
  }
}

No supongas que un resaltado personalizado se pinta igual en todos los motores o contextos incrustados. Detecta CSS.highlights, Highlight y el selector que uses; después muestra la clase de reserva o el marcador en línea si falta algún requisito. Un resultado de pintura visible en el navegador no demuestra que un lector de pantalla anuncie «coincidencia» ni que un modo de alto contraste conserve tus colores.

Gestiona selección, foco y alternativa

La búsqueda debe mover el foco a un control de resultado real, no a un rango pintado. Ofrece botones Anterior y Siguiente con un nombre accesible, conserva la consulta en el campo y desplaza el resultado seleccionado a la vista sin atrapar el foco del teclado. Si el usuario selecciona texto, no sobrescribas ::selection con el resaltado de búsqueda; las dos capas expresan estados distintos.

Cuando los resaltados no sean compatibles, añade un elemento mark temporal o una clase CSS alrededor de un nodo de texto confiable y expón el mismo contador y navegación. Elimina esa alternativa antes de aplicar una consulta nueva para que no se acumulen envoltorios anidados. Para anotaciones de solo lectura, una nota adyacente con aria-describedby es más segura que depender de un parche de color que desaparece al imprimir o con colores forzados.

Comprueba el zoom al 200 %, el espaciado del texto, la navegación solo con teclado, prefers-reduced-motion y un lector de pantalla. El resaltado no debe ocultar los contornos de foco, recortar los trazos descendentes ni crear una animación que parpadee para cada resultado. Si la consulta está vacía o no hay coincidencias, borra el resaltado nombrado y anuncia «0 resultados» en la región activa.

Clasifica resultados con una tabla de decisión

Observed stageWhat it establishesSafe next action
CSS.highlights or Highlight absentNamed highlights cannot start in this contextUse semantic mark or plain text and keep navigation usable
API present, query emptyThere is no range to paintDelete search-hit, announce the cleared state, and retain focus
Ranges created, paint visibleThe page applied one browser-visible style layerVerify contrast, focus, forced colors, and accessible result text
Content or locale changedExisting offsets may be staleRebuild ranges from current text nodes and discard the old object
Match count exceeds 100The fixture hit its bounded workloadShow a capped result state and offer narrower search, not unbounded work
Forced colors or print differsPresentation changed by user agent or mediumKeep the DOM result and a non-color cue as the source of meaning

Cada fila describe una condición observable, no una promesa universal. Registra el estado visible, la longitud de la consulta, el número de rangos y la rama de reserva; no guardes el documento completo ni infieras el comportamiento de lectura.

Punto de controlRegistroLo que no demuestra
Detección de APICSS.highlights=true, Highlight=trueQue un lector de pantalla anuncie la pintura
Ciclo del rangorangeCount=3, longitud y nodosQue el texto pertenezca a una identidad
Alternativafallback=mark y motivoQue el motor tenga un fallo de accesibilidad
FocofocusTarget=result-2 y orden de tecladoLa intención de la persona
Limpiezase elimina el resaltado antiguoQue se borró estado remoto
ComprobaciónRegistro mínimoNo inferir
Compatibilidad APIwindow.CSS, CSS.highlights, window.HighlightQue todas las propiedades CSS estén soportadas
Límites de consultaMAX_HIGHLIGHTS=100, MAX_MATCH_CHARS=120Que el documento completo sea seguro de guardar
Rango actualnodo fuente y rangeCountQue el texto tenga relación con una identidad
FocofocusTarget=result-2Que la persona quiera leer ese resultado
Modo visualnormal, colores forzados o impresiónQue la pantalla física use los mismos colores
Limpiezanombre eliminado antes de volver a renderizarQue se haya borrado un estado remoto

Capacidad y limitación de BotBrowser

BotBrowser puede ejecutar un fixture de página autorizado y comprobar el contador DOM, el número de rangos y la rama de reserva. No puede certificar la lectura de un lector de pantalla ni garantizar que cada motor pinte ::highlight() igual.

{
  "api": "CSS.highlights",
  "highlightName": "search-hit",
  "rangeCount": 3,
  "maxHighlights": 100,
  "domResultText": "3 matches",
  "assistiveTechnologySpeech": "not-asserted"
}

Repite el fixture tras una versión del navegador, un cambio de localización, una lista virtual o un nuevo token de contraste. Compara la primera diferencia visible y conserva la alternativa DOM en el registro de aceptación.

Fuentes

Conclusión práctica

Usa la pintura personalizada de CSS Highlight API para enfatizar texto que ya tiene significado semántico. Limita y reconstruye los rangos, conserva el estado y la navegación en el DOM y ofrece una alternativa sin color con contraste seguro. Trata la salida de BotBrowser como evidencia de la página, no como prueba de voz asistiva ni de la interpretación de una persona. BotBrowser puede repetir un fixture autorizado que registra rangos Highlight, aplica ::highlight() y comprueba la alternativa visible; este artículo no afirma una ejecución de BotBrowser y no puede certificar la voz de un lector de pantalla ni la percepción del color.

#CSS Highlight API#CSS Custom Highlight API#Accessibility#CSS Painting#BotBrowser

Este artículo forma parte de la guía: Superficies de la plataforma web: mapa de revisión

Lleva BotBrowser de la investigación a producción

Usa estas guías para entender el modelo y después avanzar hacia validación multiplataforma, contextos aislados y despliegue de navegador preparado para escalar.