Vínculo en negrita donde nadie se vinculó antes: Fragmentos de texto

Los fragmentos de texto te permiten especificar un fragmento de texto en el fragmento de URL. Cuando navegas a una URL con ese fragmento de texto, el navegador puede enfatizarlo o llamar la atención del usuario.

Identificadores de fragmentos

Chrome 80 fue un gran lanzamiento. Contenía una serie de funciones muy esperadas, como los módulos de ECMAScript en Web Workers, la combinación nula, el encadenamiento opcional y mucho más. Como de costumbre, la versión se anunció a través de una entrada de blog en el blog de Chromium. Puedes ver un extracto de la entrada de blog en la captura de pantalla a continuación.

Entrada de blog de Chromium con cuadros rojos alrededor de elementos con un atributo id.

Probablemente te estés preguntando qué significan todos los cuadros rojos. Son el resultado de la ejecución del siguiente fragmento en Herramientas para desarrolladores. Destaca todos los elementos que tienen un atributo id.

document.querySelectorAll('[id]').forEach((el) => {
  el.style.border = 'solid 2px red';
});

Puedo colocar un vínculo directo a cualquier elemento destacado con un cuadro rojo gracias al identificador de fragmento que luego uso en el hash de la URL de la página. Si quería agregar un vínculo directo al cuadro Envíanos tus comentarios en nuestro Foro de productos que se encuentra al lado, puedo hacerlo creando la URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1. Como puedes ver en el panel Elementos de las Herramientas para desarrolladores, el elemento en cuestión tiene un atributo id con el valor HTML1.

Herramientas para desarrolladores que muestra el id de un elemento

Si analizo esta URL con el constructor URL() de JavaScript, se revelan los diferentes componentes. Observa la propiedad hash con el valor #HTML1.

new URL('https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1');
/* Creates a new `URL` object
URL {
  hash: "#HTML1"
  host: "blog.chromium.org"
  hostname: "blog.chromium.org"
  href: "https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1"
  origin: "https://blog.chromium.org"
  password: ""
  pathname: "/2019/12/chrome-80-content-indexing-es-modules.html"
  port: ""
  protocol: "https:"
  search: ""
  searchParams: URLSearchParams {}
  username: ""
}
*/

Sin embargo, el hecho de que tuve que abrir las herramientas para desarrolladores a fin de encontrar el id de un elemento dice mucho sobre la probabilidad de que el autor de la entrada de blog debería vincular esta sección en particular de la página.

¿Qué sucede si quiero un vínculo a algo sin id? Supongamos que quiero vincular el encabezado Módulos de ECMAScript en Web Workers. Como puedes ver en la siguiente captura de pantalla, el elemento <h1> en cuestión no tiene un atributo id, lo que significa que no hay manera de establecer un vínculo a este encabezado. Este es el problema que resuelven los fragmentos de texto.

Las Herramientas para desarrolladores muestran un encabezado sin id.

Fragmentos de texto

La propuesta de Fragmentos de texto agrega compatibilidad para especificar un fragmento de texto en el hash de URL. Cuando navega a una URL con este fragmento de texto, el usuario-agente puede enfatizar o llamar la atención del usuario.

Compatibilidad del navegador

Navegadores compatibles

  • 89
  • 89
  • x
  • x

Origen

Por motivos de seguridad, la función requiere que los vínculos se abran en un contexto noopener. Por lo tanto, asegúrate de incluir rel="noopener" en tu lenguaje de marcado de anclaje de <a> o de agregar noopener a tu lista de Window.open() de funciones de funcionalidad de ventana.

start

En su forma más simple, la sintaxis de los fragmentos de texto es la siguiente: el símbolo de hash # seguido de :~:text= y, por último, start, que representa el texto codificado por porcentaje con el que quiero vincularme.

#:~:text=start

Por ejemplo, supongamos que quiero vincular al encabezado Módulos de ECMAScript en trabajadores web de la entrada de blog en la que se anuncian funciones en Chrome 80. En este caso, la URL sería la siguiente:

https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules%20in%20Web%20Workers

El fragmento de texto se enfatiza de esta manera. Si haces clic en el vínculo en un navegador compatible, como Chrome, se destaca el fragmento de texto y se muestra lo siguiente:

El fragmento de texto se desplazó hasta la vista y se destaca.

start y end

¿Qué sucede si quiero incluir un vínculo a toda la sección titulada ECMAScript Modules in Web Workers, y no solo al encabezado? La codificación en porcentaje de todo el texto de la sección haría que la URL resultante sea poco práctica.

Por suerte, hay una mejor manera. En lugar del texto completo, puedo enmarcar el texto deseado con la sintaxis start,end. Por lo tanto, especifico un par de palabras con codificación porcentual al comienzo del texto deseado y un par de palabras con codificación porcentual al final de este, separadas por una coma ,.

Así se ve:

https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules%20in%20Web%20Workers,ES%20Modules%20in%20Web%20Workers..

Para start, tengo ECMAScript%20Modules%20in%20Web%20Workers, luego una coma , seguida de ES%20Modules%20in%20Web%20Workers. como end. Cuando haces clic en un navegador compatible, como Chrome, se destaca toda la sección y se desplaza hasta que sea visible:

El fragmento de texto se desplazó hasta la vista y se destaca.

Es posible que te preguntes qué tan diferente es start y end. En realidad, la URL un poco más corta https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules,Web%20Workers. con solo dos palabras a cada lado habría funcionado. Compara start y end con los valores anteriores.

Si vamos un paso más allá y ahora uso solo una palabra para start y end, puedes ver que estoy en problemas. La URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript,Workers. ahora es aún más corta, pero el fragmento de texto destacado ya no es el que se buscaba originalmente. El resaltado se detiene en la primera aparición de la palabra Workers., lo cual es correcto, pero no es lo que pretendía destacar. El problema es que los valores actuales start y end de una palabra no identifican de forma única la sección deseada:

Fragmento de texto no deseado que se desplazó hasta la vista y se destaca.

prefix- y -suffix

Usar valores lo suficientemente largos para start y end es una solución a fin de obtener un vínculo único. Sin embargo, en algunos casos esto no es posible. Como nota al margen, ¿por qué elegí la entrada de blog de la versión de Chrome 80 como mi ejemplo? La respuesta es que, en esta versión, se presentaron los fragmentos de texto:

Texto de la entrada de blog: Fragmentos de URL de texto. Ahora, los usuarios o autores pueden vincular a una parte específica de una página usando un fragmento de texto proporcionado en una URL. Cuando se carga la página, el navegador destaca el texto y desplaza el fragmento hasta que quede visible. Por ejemplo, la siguiente URL carga una página de wiki para &#39;Gato&#39; y se desplaza hasta el contenido que aparece en el parámetro `text`.
Extracto de la entrada de blog sobre el anuncio de Text Fragments

Observa cómo en la captura de pantalla anterior la palabra "texto" aparece cuatro veces. El cuarto caso se escribe con una fuente de código verde. Si quiero establecer un vínculo a esta palabra en particular, establecería start como text. Como la palabra "texto" es, bueno, solo una palabra, no puede haber una end. ¿Qué debes hacer ahora? La URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text coincide con la primera aparición de la palabra "Text" en el encabezado:

Fragmento de texto que coincide en la primera instancia de "Text".

Por suerte, hay una solución. En casos como este, puedo especificar un prefix​- y una -suffix. La palabra antes de la fuente del código verde "text" es "the" y la palabra siguiente es "parameter". Ninguna de las otras tres ocurrencias de la palabra "texto" tiene las mismas palabras circundantes. Con este conocimiento, puedo modificar la URL anterior y agregar prefix- y -suffix. Al igual que los otros parámetros, estos también deben estar codificados en porcentajes y pueden contener más de una palabra. https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=the-,text,-parameter. Para permitir que el analizador identifique claramente el prefix- y el -suffix, deben separarse de start y el end opcional con un guion -.

Fragmento de texto que coincide en el caso deseado de "text".

La sintaxis completa

A continuación, se muestra la sintaxis completa de Text Fragments. (Los corchetes indican un parámetro opcional). Los valores de todos los parámetros deben estar codificados en porcentajes. Esto es muy importante para los caracteres -, & y , de coma, por lo que no se interpretan como parte de la sintaxis directiva de texto.

#:~:text=[prefix-,]start[,end][,-suffix]

Cada uno de los valores prefix-, start, end y -suffix solo coincidirá con el texto dentro de un único elemento a nivel de bloque, pero los rangos start,end completos pueden abarcar varios bloques. Por ejemplo, :~:text=The quick,lazy dog no coincidirá en el siguiente ejemplo debido a que la cadena inicial "The fast" no aparece dentro de un único elemento sin interrupciones a nivel de bloque:

<div>
  The
  <div></div>
  quick brown fox
</div>
<div>jumped over the lazy dog</div>

Sin embargo, coincide con este ejemplo:

<div>The quick brown fox</div>
<div>jumped over the lazy dog</div>

Cómo crear URLs de Text Fragment con una extensión de navegador

Crear URLs de fragmentos de texto a mano es tedioso, en especial cuando se trata de asegurarse de que sean únicas. Si realmente quieres hacerlo, la especificación tiene algunas sugerencias y enumera los pasos exactos para generar URLs de fragmento de texto. Proporcionamos una extensión de navegador de código abierto llamada Link to Text Fragment que te permite vincular cualquier texto seleccionándolo y, luego, haciendo clic en "Copy Link to Selected Text" en el menú contextual. Esta extensión está disponible para los siguientes navegadores:

Extensión del navegador de vínculo a Text Fragment .

Varios fragmentos de texto en una URL

Ten en cuenta que pueden aparecer varios fragmentos de texto en una URL. Los fragmentos de texto específicos deben estar separados por un carácter et &. A continuación, se incluye un vínculo de ejemplo con tres fragmentos de texto: https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=Text%20URL%20Fragments&text=text,-parameter&text=:~:text=On%20islands,%20birds%20can%20contribute%20as%20much%20as%2060%25%20of%20a%20cat's%20diet.

Tres fragmentos de texto en una URL.

Cómo combinar elementos y fragmentos de texto

Los fragmentos de elementos tradicionales se pueden combinar con fragmentos de texto. Está bien tener ambos en la misma URL, por ejemplo, para proporcionar un resguardo significativo en caso de que cambie el texto original en la página, de modo que el fragmento de texto ya no coincida. La URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1:~:text=Give%20us%20feedback%20in%20our%20Product%20Forums. que vincula a la sección Envíanos comentarios en nuestros Foros de productos contiene un fragmento de elemento (HTML1) y un fragmento de texto (text=Give%20us%20feedback%20in%20our%20Product%20Forums.):

Vinculación tanto con el fragmento de elemento como con el fragmento de texto.

La directiva de fragmento

Hay un elemento de la sintaxis que aún no expliqué: la directiva de fragmento :~:. Para evitar problemas de compatibilidad con fragmentos de elementos de URL existentes, como se muestra más arriba, la especificación de fragmentos de texto presenta la directiva del fragmento. La directiva de fragmento es una parte del fragmento de URL delimitado por la secuencia de código :~:. Se reserva para las instrucciones de usuario-agente, como text=, y se quita de la URL durante la carga para que las secuencias de comandos de autor no puedan interactuar directamente con ella. Las instrucciones del usuario-agente también se denominan directivas. Por lo tanto, en el caso concreto, text= se denomina directiva de texto.

Detección de funciones

Para detectar compatibilidad, prueba la propiedad fragmentDirective de solo lectura en document. La directiva del fragmento es un mecanismo para que las URLs especifiquen instrucciones dirigidas al navegador en lugar del documento. Su objetivo es evitar la interacción directa con la secuencia de comandos del autor, de modo que se puedan agregar futuras instrucciones de usuario-agente sin temor a introducir cambios rotundos en el contenido existente. Un posible ejemplo de estas incorporaciones futuras podrían ser las sugerencias de traducción.

if ('fragmentDirective' in document) {
  // Text Fragments is supported.
}

La detección de funciones está destinada principalmente a casos en los que se generan vínculos de forma dinámica (por ejemplo, en los motores de búsqueda) para evitar entregar vínculos de fragmentos de texto a navegadores que no los admiten.

Cómo aplicar estilo a fragmentos de texto

De forma predeterminada, los navegadores diseñan los fragmentos de texto de la misma manera en que diseñan mark (por lo general, negro sobre amarillo, los colores del sistema de CSS para mark). La hoja de estilo del usuario-agente contiene CSS que se ve de la siguiente manera:

:root::target-text {
  color: MarkText;
  background: Mark;
}

Como puedes ver, el navegador expone un pseudoselector ::target-text que puedes usar para personalizar el resaltado aplicado. Por ejemplo, puedes diseñar tus fragmentos de texto para que sean texto negro sobre un fondo rojo. Como siempre, asegúrate de verificar el contraste de color para que tu estilo de anulación no cause problemas de accesibilidad y asegúrate de que el elemento destacado se destaque visualmente del resto del contenido.

:root::target-text {
  color: black;
  background-color: red;
}

Capacidad de polifill

La función Text Fragments puede aplicarse a través de polyfills hasta cierto punto. Proporcionamos un polyfill, que se usa internamente en la extensión, para los navegadores que no ofrecen compatibilidad integrada con fragmentos de texto en los que la funcionalidad se implementa en JavaScript.

El polyfill contiene un archivo fragment-generation-utils.js que puedes importar y usar para generar vínculos de Text Fragment. Esto se describe en la siguiente muestra de código:

const { generateFragment } = await import('https://unpkg.com/text-fragments-polyfill/dist/fragment-generation-utils.js');
const result = generateFragment(window.getSelection());
if (result.status === 0) {
  let url = `${location.origin}${location.pathname}${location.search}`;
  const fragment = result.fragment;
  const prefix = fragment.prefix ?
    `${encodeURIComponent(fragment.prefix)}-,` :
    '';
  const suffix = fragment.suffix ?
    `,-${encodeURIComponent(fragment.suffix)}` :
    '';
  const start = encodeURIComponent(fragment.textStart);
  const end = fragment.textEnd ?
    `,${encodeURIComponent(fragment.textEnd)}` :
    '';
  url += `#:~:text=${prefix}${start}${end}${suffix}`;
  console.log(url);
}

Cómo obtener fragmentos de texto con fines estadísticos

Muchos sitios usan el fragmento para el enrutamiento, por lo que los navegadores quitan los fragmentos de texto para no dañar esas páginas. Existe una necesidad reconocida de exponer vínculos de fragmentos de texto a páginas, por ejemplo, con fines estadísticos, pero aún no se implementó la solución propuesta. Como solución alternativa, por ahora, puedes usar el siguiente código para extraer la información deseada.

new URL(performance.getEntries().find(({ type }) => type === 'navigate').name).hash;

Seguridad

Las directivas de fragmentos de texto solo se invocan en navegaciones completas (que no son de la misma página) que son el resultado de una activación del usuario. Además, las navegaciones que se originen en un origen diferente al destino requerirán que la navegación se realice en un contexto noopener, de modo que se sepa que la página de destino está lo suficientemente aislada. Las directivas de fragmentos de texto solo se aplican al marco principal. Eso significa que no se buscará texto dentro de iframes, y la navegación de iframe no invocará un fragmento de texto.

Privacidad

Es importante que las implementaciones de la especificación de fragmentos de texto no filtren si un fragmento de texto se encontró en una página o no. Si bien los fragmentos de elementos están completamente bajo el control del autor de la página original, cualquiera puede crear fragmentos de texto. ¿Recuerdas que en mi ejemplo anterior no había forma de vincular al encabezado Módulos de ECMAScript en Web Workers, ya que <h1> no tenía un id, pero cómo cualquier persona, incluido yo, podía establecer un vínculo a cualquier lugar creando cuidadosamente el fragmento de texto.

Imagina que publico una red de publicidad malvada evil-ads.example.com. Imagina además que, en uno de mis iframes de anuncios, creé de forma dinámica un iframe de origen cruzado oculto en dating.example.com con una URL de fragmento de texto dating.example.com#:~:text=Log%20Out una vez que el usuario interactúa con el anuncio. Si se encuentra el texto "Log Out", significa que la víctima accedió a dating.example.com, que podría usar para la generación de perfiles del usuario. Dado que una implementación básica de Text Fragments podría decidir que una coincidencia correcta debe generar un cambio de enfoque, en evil-ads.example.com podía escuchar el evento blur y, por lo tanto, saber cuándo se produjo una coincidencia. En Chrome, implementamos Text Fragments de tal manera que la situación anterior no puede suceder.

Otro ataque podría ser explotar el tráfico de red según la posición de desplazamiento. Supongamos que tengo acceso a los registros del tráfico de red de mi víctima, como administrador de la intranet de una empresa. Ahora, imagina que existía un documento extenso de recursos humanos llamado What to Do if you Suffer From... y, luego, una lista de condiciones como agotamiento, ansiedad, etc. Podría colocar un píxel de seguimiento junto a cada elemento de la lista. Si, luego, determino que la carga del documento ocurre temporalmente junto con la carga del píxel de seguimiento junto al elemento burn out, puedo determinar, como administrador de la intranet, que un empleado hizo clic en un vínculo de fragmento de texto con :~:text=burn%20out que el empleado supuso que era confidencial y que no estaba visible para nadie. Dado que este ejemplo es un poco forzado al principio y debido a que su explotación requiere que se cumplan condiciones previas muy específicas, el equipo de seguridad de Chrome evaluó el riesgo de implementar el desplazamiento en la navegación para que sea administrable. Otros usuarios-agentes pueden decidir mostrar un elemento de IU de desplazamiento manual en su lugar.

En el caso de los sitios que lo desean, Chromium admite un valor de encabezado de Política del documento que pueden enviar para que los usuarios-agentes no procesen las URLs de fragmentos de texto.

Document-Policy: force-load-at-top

Inhabilita fragmentos de texto

La forma más fácil de inhabilitar la función es usar una extensión que pueda insertar encabezados de respuesta HTTP, por ejemplo, ModHeader (no un producto de Google), para insertar un encabezado de respuesta (no una solicitud) de la siguiente manera:

Document-Policy: force-load-at-top

Otra forma más compleja de inhabilitar esta opción es usar la configuración empresarial ScrollToTextFragmentEnabled. Para hacer esto en macOS, pega el siguiente comando en la terminal.

defaults write com.google.Chrome ScrollToTextFragmentEnabled -bool false

En Windows, sigue la documentación del sitio de asistencia de Ayuda de Google Chrome Enterprise.

Para algunas búsquedas, el motor de búsqueda de Google proporciona una respuesta rápida o un resumen con un fragmento de contenido de un sitio web relevante. Es más probable que estos fragmentos destacados aparezcan cuando una búsqueda en forma de pregunta. Cuando un usuario hace clic en un fragmento destacado, se lo dirige directamente al texto correspondiente en la página web de origen. Esto funciona gracias a las URLs de Text Fragments creadas automáticamente.

La página de resultados del motor de búsqueda de Google que muestra un fragmento destacado. La barra de estado muestra la URL de Text Fragments.
Después de hacer clic, se desplaza hasta ver la sección relevante de la página.

Conclusión

Text Fragments URL es una potente función para establecer vínculos a texto arbitrario en páginas web. La comunidad académica puede usarlo para proporcionar vínculos de citas o referencia de alta precisión. Los motores de búsqueda pueden usarlo para establecer vínculos directos con los resultados de texto en las páginas. Los sitios de redes sociales pueden usarlo para permitir que los usuarios compartan fragmentos específicos de una página web en lugar de capturas de pantalla inaccesibles. Espero que empieces a usar las URLs de Text Fragment y que te resulten tan útiles como yo. Asegúrate de instalar la extensión del navegador Link to Text Fragment.

Agradecimientos

Nick Burris y David Bokan implementaron y especificaron los fragmentos de texto, con contribuciones de Grant Wang. Agradecemos a Joe Medley por la revisión exhaustiva de este artículo. Hero image de Greg Rakozy en Unsplash.