Enfoques Principales para Resaltar Texto

Enfoques Principales para Resaltar Texto


Resaltar texto puede parecer simple a primera vista—solo cambiar el fondo a amarillo—pero en realidad es bastante complejo. Toma este ejemplo de abajo, donde la parte resaltada abarca múltiples elementos y contiene texto parcial de elementos inferiores.

Highlights across elements

A continuación, recorreré varios enfoques comunes para implementar el resaltado de texto, discutiendo sus pros y contras junto con casos de uso prácticos para delinear las soluciones técnicas principales.

CSS Highlight API — Resaltado de Texto Moderno y Eficiente

Esta es actualmente la mejor opción para implementar el resaltado de texto, siendo simple de usar y eficiente. La única desventaja es que los navegadores necesitan versiones relativamente recientes para el soporte, aunque para 2025 todos los navegadores principales lo soportan.

Objeto Highlight

Primero, necesitas crear un objeto Range para cada área resaltada. Range es una API de larga data que representa una sección continua en el árbol DOM—si no estás familiarizado con ella, necesitarás repasarla.

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

Luego agrégalo a un objeto Highlight. Como el resaltado puede tener múltiples áreas no contiguas, un solo objeto Highlight puede contener varios Ranges.

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

Es similar a un objeto Set, por lo que puedes usar métodos como add, delete, etc., para modificar los Ranges contenidos.

CSS.highlights

Luego agrega el objeto Highlight a CSS.highlights. Es similar a un objeto Map, con métodos para agregar y eliminar miembros como get, set, delete, etc., y los mismos métodos de iteración.

Al igual que un Map, al agregar un Highlight, necesitas darle una clave como nombre del highlight. Este nombre es muy útil—como veremos a continuación, usamos este nombre para establecer el estilo de resaltado, como un fondo verde. Entonces todos los resaltados en el mismo objeto Highlight tienen el mismo estilo. Si quieres resaltar otro fragmento de texto en azul, necesitarás crear un nuevo highlight.

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

Definir el Pseudo-elemento ::highlight

A continuación, los estilos CSS toman el escenario. Puedes definir estilos de resaltado usando el pseudo-elemento ::highlight(nombre-del-highlight).

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

Nota: Solo se pueden usar algunas propiedades CSS, como background-color, color, cursor, etc. Consulta la especificación para más detalles.

Modificar Dinámicamente los Rangos de Resaltado

CSS.highlights es como un Map con métodos similares para actualizar Highlights:

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

El objeto Highlight es como un Set con métodos similares para actualizar Ranges:

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

Modificar Estilos de Elementos de Texto

Logra el resaltado recorriendo el DOM para encontrar nodos de texto objetivo y modificando directamente sus estilos de fondo.

  • Requiere modificaciones del DOM, causando reflow del navegador con sobrecarga significativa de rendimiento.
  • Implementar resaltado entre elementos (donde el rango de resaltado abarca múltiples elementos) es bastante complejo. Highlights across elements
  • Adecuado para escenarios donde el contenido resaltado es relativamente fijo y el rango es pequeño.

Superponer Capas Adicionales para Renderizar Resaltados Sin Modificar el DOM del Texto

Crea una capa superpuesta transparente, calcula la posición en pantalla del texto objetivo, luego dibuja resaltados semi-transparentes en la superposición.

Posicionar Áreas de Resaltado

  • Usa Element.getClientRects() o getBoundingClientRect() para obtener las coordenadas del texto en la página.
  • Al manejar texto de múltiples líneas, cada línea corresponde a un área rectangular que necesita bloques de resaltado separados.
  • Los cambios en el tamaño de la ventana o el tamaño de la fuente requieren recalcular las posiciones de resaltado, lo que puede afectar el rendimiento.

Métodos de Dibujo de Resaltado

DIV como Superposición

Usa contenedores padre con posicionamiento absoluto y elementos hijo con fondo semi-transparente para superponer texto. Por ejemplo, el editor Monaco usa este enfoque para implementar el resaltado de palabras iguales.

<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>
    <!-- Agregar más áreas de highlight -->
  </div>
  <div class="content">
    <!-- Contenido de texto -->
  </div>
</div>
  • La posición del overlay es absolute, mientras se asegura que el elemento padre no sea position: static, para que el posicionamiento absoluto funcione. Esto permite que los elementos de resaltado internos se posicionen en cualquier lugar.
  • Para colocar encima del texto, simplemente pon el overlay antes del contenedor de texto en HTML. La altura del overlay es 0 para evitar afectar la interacción con el texto de abajo.
  • Agrega elementos dentro, establece background-color al color de resaltado semi-transparente, posiciona en la ubicación del texto resaltado y establece el ancho.
  • El editor Monaco (VSCode está basado en él) usa este método. Ve la demo oficial. Después de seleccionar una palabra clave, las mismas palabras clave se resaltan. Mirando el HTML, encontrarás que estas palabras clave no han cambiado estilos, pero hay un Overlay en la interfaz del editor con colores de resaltado semi-transparentes dibujados dentro (ve el div con class="view-overlays").

SVG como Superposición

  • Establece overlay con las mismas dimensiones que la página
  • Agrega <rect> dentro, luego dibuja en las posiciones del texto resaltado
  • foliate-js usa este método. Ve overlayer.js.

Usar Selection API y Pseudo-elemento ::selection — Resaltado de Selección de Texto Predeterminado del Navegador

Los navegadores naturalmente resaltan el texto seleccionado, por lo que controlar la selección puede lograr indirectamente el resaltado. Los estilos se pueden personalizar a través del pseudo-elemento ::selection de CSS.

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

// Establecer selección
const selection = document.getSelection();
selection.removeAllRanges();
selection.addRange(range);
::selection {
  background-color: #c3c2c2;
  color: white;
}

Este método es bastante inteligente, simple y tiene amplio soporte del navegador, pero tiene un defecto importante: ya que solo puede existir una selección a la vez, las selecciones programáticas y las selecciones reales del usuario entrarán en conflicto y se sobrescribirán entre sí. Por lo tanto, solo es adecuado para escenarios que cumplan las siguientes condiciones:

  • Los usuarios no pueden seleccionar texto
  • Solo hay un segmento de texto resaltado continuo
  • Necesitas soportar navegadores más antiguos
  • Quieres ser perezoso y evitar otros métodos