Link in grassetto dove nessuno ha mai aggiunto link prima: frammenti di testo

I frammenti di testo ti consentono di specificare uno snippet di testo nel frammento di URL. Quando si accede a un URL con un frammento di testo di questo tipo, il browser può evidenziarlo e portarlo all'attenzione dell'utente.

Identificatori di frammenti

Chrome 80 è stata una release importante. Conteneva una serie di funzionalità molto attese, come i moduli ECMAScript nei web worker, l'unione nullish, il concatenamento facoltativo e altro ancora. Come di consueto, la release è stata annunciata tramite un blog post sul blog di Chromium. Puoi vedere un estratto del blog post nello screenshot seguente.

Post del blog di Chromium con riquadri rossi attorno agli elementi con un attributo id.

Probabilmente ti starai chiedendo cosa significano tutte le caselle rosse. Sono il risultato dell'esecuzione del seguente snippet in DevTools. Evidenzia tutti gli elementi che hanno un attributo id.

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

Posso inserire un deep link a qualsiasi elemento evidenziato con un riquadro rosso grazie all'identificatore di frammento, che poi utilizzo nell'hash dell'URL della pagina. Supponiamo che io voglia creare un deep link alla casella Inviaci un feedback nei nostri forum dei prodotti nella sezione laterale. Potrei farlo creando manualmente l'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1. Come puoi vedere nel riquadro Elementi degli Strumenti per sviluppatori, l'elemento in questione ha un attributo id con il valore HTML1.

Strumenti per sviluppatori che mostrano l'id di un elemento.

Se analizzo questo URL con il costruttore URL() di JavaScript, vengono visualizzati i diversi componenti. Nota la proprietà hash con il valore #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: ""
}
*/

Tuttavia, il fatto che abbia dovuto aprire gli Strumenti per sviluppatori per trovare l'attributo id di un elemento la dice lunga sulla probabilità che l'autore del blog post volesse collegare questa particolare sezione della pagina.

Cosa succede se voglio creare un link a un elemento senza id? Supponiamo che io voglia creare un link all'intestazione Moduli ECMAScript nei web worker. Come puoi vedere nello screenshot seguente, l'elemento <h1> in questione non ha un attributo id, il che significa che non posso creare un link a questa intestazione. Questo è il problema che i frammenti di testo risolvono.

Strumenti per sviluppatori che mostrano un'intestazione senza un id.

Frammenti di testo

La proposta Frammenti di testo aggiunge il supporto per specificare uno snippet di testo nell'hash dell'URL. Quando si accede a un URL con un frammento di testo di questo tipo, lo user agent può evidenziarlo e portarlo all'attenzione dell'utente.

Compatibilità del browser

Browser Support

  • Chrome: 89.
  • Edge: 89.
  • Firefox: 131.
  • Safari: 18.2.

Source

Per motivi di sicurezza, la funzionalità richiede l'apertura dei link in un contesto noopener. Pertanto, assicurati di includere rel="noopener" nel tuo markup di ancoraggio <a> o di aggiungere noopener al tuo elenco Window.open() di funzionalità della finestra.

start

Nella sua forma più semplice, la sintassi dei frammenti di testo è la seguente: il simbolo cancelletto # seguito da :~:text= e infine start, che rappresenta il testo con codifica percentuale a cui voglio collegarmi.

#:~:text=start

Ad esempio, supponiamo che io voglia creare un link all'intestazione Moduli ECMAScript nei web worker nel blog post che annuncia le funzionalità di Chrome 80. In questo caso, l'URL sarebbe:

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

Il frammento di testo viene evidenziato in questo modo. Se fai clic sul link in un browser supportato come Chrome, il frammento di testo viene evidenziato e scorre fino a essere visualizzato:

Frammento di testo visualizzato e evidenziato.

start e end

Ora, cosa succede se voglio creare un link all'intera sezione intitolata Moduli ECMAScript nei web worker, non solo alla sua intestazione? La codifica percentuale dell'intero testo della sezione renderebbe l'URL risultante troppo lungo.

Fortunatamente, esiste un modo migliore. Anziché l'intero testo, posso inquadrare una parte specifica del testo con la sintassi start,end. Specifico un paio di parole con codifica percentuale all'inizio del frammento di testo e un paio di parole con codifica percentuale alla fine del frammento di testo, separate da una virgola.

Ecco un esempio:

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

Per start, ho ECMAScript%20Modules%20in%20Web%20Workers, poi una virgola, seguita da ES%20Modules%20in%20Web%20Workers. come end. Quando fai clic su un browser supportato come Chrome, l'intera sezione viene evidenziata e visualizzata:

Frammento di testo visualizzato e evidenziato.

Ora potresti chiederti perché ho scelto start e end. In realtà, anche l'URL leggermente più breve https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules,Web%20Workers. con solo due parole su ciascun lato avrebbe funzionato. Confronta start e end con i valori precedenti.

Se faccio un ulteriore passo avanti e ora utilizzo una sola parola sia per start che per end, puoi vedere che sono in difficoltà. L'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript,Workers. ora è ancora più breve, ma il frammento di testo evidenziato non è più quello scelto originariamente. L'evidenziazione si interrompe alla prima occorrenza della parola Workers., il che è corretto, ma non è ciò che volevo evidenziare. Il problema è che la sezione scelta non è identificata in modo univoco dagli attuali valori start e end di una sola parola:

Frammento di testo non previsto visualizzato e messo in evidenza.

prefix- e -suffix

L'utilizzo di valori sufficientemente lunghi per start e end è una soluzione per ottenere un link univoco. In alcune situazioni, tuttavia, ciò non è possibile. A margine, perché ho scelto il blog post sulla release di Chrome 80 come esempio? La risposta è che in questa release sono stati introdotti i frammenti di testo:

Testo del blog post: Frammenti di URL di testo. Gli utenti o gli autori ora possono collegarsi a una parte specifica di una pagina utilizzando un frammento di testo fornito in un URL. Quando la pagina viene caricata, il browser evidenzia il testo e scorre fino al frammento. Ad esempio, l'URL riportato di seguito carica una pagina wiki per &quot;Gatto&quot; e scorre fino ai contenuti elencati nel parametro &quot;text&quot;.
Estratto del blog post di annuncio dei frammenti di testo.

Nota come nello screenshot sopra la parola "text" appare quattro volte. La quarta occorrenza è scritta in un carattere di codice verde. Se volessi creare un link a questa parola specifica, imposterei start su text. Poiché la parola "text" è, appunto, una sola parola, non può esserci un end. E ora? L'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text corrisponde alla prima occorrenza della parola "Text" già presente nell'intestazione:

Frammento di testo corrispondente alla prima occorrenza di "Testo".

Per fortuna, esiste una soluzione. In casi come questo, posso specificare un prefix- e un -suffix. La parola prima del testo verde con carattere di codice "text" è "the" e la parola dopo è "parameter". Nessuna delle altre tre occorrenze della parola "testo" ha le stesse parole circostanti. Con queste informazioni, posso modificare l'URL precedente e aggiungere prefix- e -suffix. Come gli altri parametri, anche questi devono essere codificati in percentuale e possono contenere più di una parola. https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=the-,text,-parameter. Per consentire al parser di identificare chiaramente prefix- e -suffix, questi devono essere separati da start e dall'elemento facoltativo end con un trattino -.

Frammento di testo corrispondente all'occorrenza scelta di "text".

La sintassi completa

Di seguito è riportata la sintassi completa dei frammenti di testo. Le parentesi quadre indicano un parametro facoltativo. I valori di tutti i parametri devono essere codificati in percentuale. Questo è particolarmente importante per i caratteri trattino -, e commerciale & e virgola ,, in modo che non vengano interpretati come parte della sintassi della direttiva di testo.

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

Ognuno dei valori prefix-, start, end e -suffix può corrispondere solo al testo all'interno di un singolo elemento a livello di blocco, ma gli intervalli start,end completi possono estendersi su più blocchi. Ad esempio, :~:text=The quick,lazy dog non trova corrispondenze nel seguente esempio, perché la stringa iniziale "The quick" non viene visualizzata all'interno di un singolo elemento a livello di blocco ininterrotto:

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

Tuttavia, corrisponde in questo esempio:

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

Creazione di URL di frammenti di testo con un'estensione del browser

La creazione manuale degli URL dei frammenti di testo è noiosa, soprattutto quando si tratta di assicurarsi che siano univoci. Se vuoi davvero farlo, la specifica contiene alcuni suggerimenti ed elenca i passaggi esatti per generare URL di frammenti di testo. Forniamo un'estensione del browser open source chiamata Link to Text Fragment che ti consente di creare un link a qualsiasi testo selezionandolo e poi facendo clic su "Copia link al testo selezionato" nel menu contestuale. Questa estensione è disponibile per i seguenti browser:

Link to Text Fragment browser extension.

Più frammenti di testo in un unico URL

Tieni presente che in un URL possono essere presenti più frammenti di testo. I singoli frammenti di testo devono essere separati da una e commerciale &. Ecco un esempio di link con tre frammenti di testo: 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.

Tre frammenti di testo in un URL.

Combinazione di elementi e frammenti di testo

I frammenti di elementi tradizionali possono essere combinati con i frammenti di testo. È perfettamente accettabile avere entrambi nello stesso URL, ad esempio per fornire un fallback significativo nel caso in cui il testo originale della pagina cambi, in modo che il frammento di testo non corrisponda più. L'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1:~:text=Give%20us%20feedback%20in%20our%20Product%20Forums. che rimanda alla sezione Inviaci un feedback nei nostri forum di prodotto contiene sia un frammento di elemento (HTML1) sia un frammento di testo (text=Give%20us%20feedback%20in%20our%20Product%20Forums.):

Collegamento con frammento di elemento e frammento di testo.

La direttiva del frammento

C'è un elemento della sintassi che non ho ancora spiegato: l'istruzione del frammento :~:. Per evitare problemi di compatibilità con i frammenti di elementi URL esistenti, come mostrato, la specifica dei frammenti di testo introduce l'istruzione del frammento. L'istruzione del frammento è una parte del frammento di URL delimitata dalla sequenza di codice :~:. È riservato alle istruzioni dello user agent, come text=, e viene rimosso dall'URL durante il caricamento in modo che gli script dell'autore non possano interagire direttamente con questo. Le istruzioni per gli user agent vengono anche chiamate istruzioni. Nel caso concreto, text= è quindi chiamato direttiva di testo.

Rilevamento delle caratteristiche

Per rilevare il supporto, verifica la proprietà di sola lettura fragmentDirective su document. La direttiva del frammento è un meccanismo che consente agli URL di specificare istruzioni indirizzate al browser anziché al documento. Lo scopo è evitare l'interazione diretta con lo script dell'autore, in modo che le istruzioni future dello user agent possano essere aggiunte senza il timore di introdurre modifiche che provocano un errore ai contenuti esistenti. Un potenziale esempio di queste aggiunte future potrebbe essere rappresentato dai suggerimenti di traduzione.

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

Il rilevamento delle funzionalità è destinato principalmente ai casi in cui i link vengono generati dinamicamente (ad esempio dai motori di ricerca) per evitare di pubblicare link di frammenti di testo nei browser che non li supportano.

Stile dei frammenti di testo

Per impostazione predefinita, i browser applicano lo stile ai frammenti di testo nello stesso modo in cui applicano lo stile a mark (in genere nero su giallo, i colori di sistema CSS per mark). Il foglio di stile dello user agent contiene CSS simile al seguente:

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

Come puoi vedere, il browser espone uno pseudoselettore ::target-text che puoi utilizzare per personalizzare l'evidenziazione applicata. Ad esempio, potresti progettare i frammenti di testo in modo che siano neri su sfondo rosso. Come sempre, assicurati di controllare il contrasto dei colori in modo che lo stile di override non causi problemi di accessibilità e assicurati che l'evidenziazione si distingua visivamente dal resto dei contenuti.

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

Polyfill

La funzionalità Frammenti di testo può essere sottoposta a polyfill in una certa misura. Forniamo un polyfill, utilizzato internamente dall'estensione, per i browser che non forniscono il supporto integrato per i frammenti di testo in cui la funzionalità è implementata in JavaScript.

Il polyfill contiene un file fragment-generation-utils.js che puoi importare e utilizzare per generare link ai frammenti di testo. Questo è descritto nell'esempio di codice:

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);
}

Ottenere frammenti di testo a scopo di analisi

Molti siti utilizzano il frammento per il routing, motivo per cui i browser rimuovono i frammenti di testo per non interrompere queste pagine. È stata riconosciuta la necessità di esporre i link dei frammenti di testo alle pagine, ad esempio per scopi di analisi, ma la soluzione proposta non è ancora stata implementata. Come soluzione alternativa, puoi utilizzare il seguente codice per estrarre le informazioni.

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

Sicurezza

Le istruzioni dei frammenti di testo vengono richiamate solo nelle navigazioni complete (non nella stessa pagina) che sono il risultato di un'attivazione utente. Inoltre, le navigazioni che provengono da un'origine diversa dalla destinazione richiedono che la navigazione avvenga in un contesto noopener, in modo che la pagina di destinazione sia sufficientemente isolata. Le istruzioni dei frammenti di testo vengono applicate solo al frame principale. Ciò significa che il testo non viene cercato all'interno degli iframe e la navigazione nell'iframe non richiama un frammento di testo.

Privacy

È importante che le implementazioni della specifica Text Fragments non rivelino se un frammento di testo è stato trovato o meno in una pagina. Mentre i frammenti di elementi sono completamente sotto il controllo dell'autore della pagina originale, i frammenti di testo possono essere creati da chiunque. Ricordi come nel mio esempio non c'era modo di creare un link all'intestazione ECMAScript Modules in Web Workers, poiché l'elemento <h1> non aveva un id, ma come chiunque, me compreso, poteva semplicemente creare un link a qualsiasi punto creando con cura il frammento di testo?

Immagina che io gestisca una rete pubblicitaria dannosa evil-ads.example.com. Immagina inoltre che in uno degli iframe del mio annuncio abbia creato dinamicamente un iframe multiorigine nascosto per dating.example.com con un URL di frammento di testo dating.example.com#:~:text=Log%20Out una volta che l'utente interagisce con l'annuncio. Se trovo il testo "Esci", so che la vittima ha eseguito l'accesso a dating.example.com, che potrei utilizzare per la profilazione utente. Poiché un'implementazione ingenua dei frammenti di testo potrebbe decidere che una corrispondenza riuscita deve causare un cambio di stato attivo, su evil-ads.example.com potrei ascoltare l'evento blur e quindi sapere quando si è verificata una corrispondenza. In Chrome, abbiamo implementato i frammenti di testo in modo che questo scenario non possa verificarsi.

Un altro attacco potrebbe essere quello di sfruttare il traffico di rete in base alla posizione di scorrimento. Supponiamo che io abbia accesso ai log del traffico di rete della mia vittima, ad esempio come amministratore di una rete intranet aziendale. Ora immagina che esista un lungo documento delle risorse umane intitolato Cosa fare se soffri di…, seguito da un elenco di condizioni come burnout, ansia e così via. Potrei inserire un pixel di monitoraggio accanto a ogni elemento dell'elenco. Se poi stabilisco che il caricamento del documento avviene contemporaneamente al caricamento del pixel di monitoraggio accanto, ad esempio, alla voce burnout, posso, in qualità di amministratore della rete intranet, determinare che un dipendente ha fatto clic su un link di un frammento di testo con :~:text=burn%20out che il dipendente potrebbe aver ritenuto riservato e non visibile a nessuno. Poiché questo esempio è un po' artificioso e poiché il suo sfruttamento richiede il rispetto di precondizioni molto specifiche, il team di sicurezza di Chrome ha valutato che il rischio di implementare lo scorrimento durante la navigazione è gestibile. Altri user agent potrebbero decidere di mostrare un elemento UI di scorrimento manuale.

Per i siti che vogliono disattivare questa funzionalità, Chromium supporta un valore di intestazione Document Policy che possono inviare in modo che gli user agent non elaborino gli URL dei frammenti di testo.

Document-Policy: force-load-at-top

Disattivazione dei frammenti di testo

Il modo più semplice per disattivare la funzionalità è utilizzare un'estensione che può inserire intestazioni della risposta HTTP, ad esempio ModHeader (non un prodotto Google), per inserire un'intestazione della risposta (non della richiesta) come segue:

Document-Policy: force-load-at-top

Un altro modo, più complesso, per disattivare la funzionalità è utilizzare l'impostazione aziendale ScrollToTextFragmentEnabled. Per farlo su macOS, incolla il seguente comando nel terminale.

defaults write com.google.Chrome ScrollToTextFragmentEnabled -bool false

Su Windows, segui la documentazione sul sito di assistenza della Guida di Google Chrome Enterprise.

Per alcune ricerche, il motore di ricerca Google fornisce una risposta rapida o un riepilogo con uno snippet di contenuti di un sito web pertinente. È più probabile che questi snippet in primo piano vengano visualizzati quando una ricerca è sotto forma di domanda. Quando l'utente fa clic su uno snippet in primo piano, viene indirizzato direttamente al testo dello snippet in primo piano nella pagina web di origine. Ciò è possibile grazie agli URL dei frammenti di testo creati automaticamente.

Pagina dei risultati di ricerca di Google che mostra uno snippet in primo piano. La barra di stato mostra l'URL dei frammenti di testo.
Dopo aver fatto clic, viene visualizzata la sezione pertinente della pagina.

Conclusione

L'URL dei frammenti di testo è una funzionalità efficace per creare link a testo arbitrario nelle pagine web. La comunità accademica può utilizzarlo per fornire link di citazione o link referenti molto precisi. I motori di ricerca possono utilizzarlo per creare deep link ai risultati di testo nelle pagine. I siti di social networking possono utilizzarla per consentire agli utenti di condividere passaggi specifici di una pagina web anziché screenshot inaccessibili. Spero che inizierai a utilizzare gli URL dei frammenti di testo e che li troverai utili quanto me. Assicurati di installare l'estensione del browser Link to Text Fragment.

Ringraziamenti

I frammenti di testo sono stati implementati e specificati da Nick Burris e David Bokan, con il contributo di Grant Wang. Grazie a Joe Medley per la revisione approfondita di questo documento.