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ò enfatizzarlo e/o richiamarlo all'attenzione dell'utente.

Identificatori dei frammenti

Chrome 80 è stata una release importante. Conteneva una serie di funzionalità molto attese, come i moduli ECMAScript nei web worker, l'unione di valori null, la catenabilità facoltativa e altre ancora. Come di consueto, la release è stata annunciata tramite un post del blog sul blog di Chromium. Puoi vedere un estratto del post del blog nello screenshot di seguito.

Post del blog di Chromium con caselle rosse 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 link diretto a qualsiasi elemento evidenziato con una casella rossa grazie all'identificatore di frammento che poi utilizzo nell'hash dell'URL della pagina. Supponiamo che io voglia creare un link diretto alla casella Inviaci un feedback nei nostri forum dei prodotti nel riquadro a parte. Posso 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 il 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: ""
}
*/

Il fatto che sia stato necessario aprire gli Strumenti per sviluppatori per trovare l'elemento id di un elemento parla molto della probabilità che l'autore del post del blog avrebbe dovuto rimandare a questa particolare sezione della pagina.

Cosa succede se voglio fare un link a qualcosa senza un id? Supponiamo di voler collegare l'intestazione ECMAScript Modules in Web worker. Come puoi vedere nello screenshot di seguito, l'elemento <h1> in questione non ha un attributo id, il che significa che non posso fare un link a questa intestazione. Questo è il problema che viene risolto da Text Fragments.

DevTools mostra un'intestazione senza un id.

Frammenti di testo

La proposta Frammenti di testo aggiunge il supporto per la specifica di 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ò sottolinearlo e/o richiamarlo all'attenzione dell'utente.

Compatibilità del browser

Supporto dei browser

  • Chrome: 89.
  • Edge: 89.
  • Firefox: 131.
  • Safari Technology Preview: supportato.

Origine

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

start

Nella sua forma più semplice, la sintassi dei frammenti di testo è la seguente: il simbolo hash # seguito da :~:text= e infine start, che rappresenta il testo codificato in percentuale auquel voglio collegarmi.

#:~:text=start

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

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

Il frammento di testo viene enfatizzato in questo modo. Se fai clic sul link in un browser di supporto come Chrome, il frammento di testo viene evidenziato e scorre per visualizzarlo:

Il frammento di testo è stato visualizzato e evidenziato.

start e end

E se volessi collegare l'intera sezione intitolata ECMAScript Modules in Web worker, non solo l'intestazione? L'applicazione della codifica percentuale all'intero testo della sezione renderebbe l'URL risultante praticamente troppo lungo.

Per fortuna, c'è un modo migliore. Invece dell'intero testo, posso inquadrare il testo desiderato utilizzando la sintassi start,end. Pertanto, specifico un paio di parole con codifica percentuale all'inizio del testo desiderato e un paio di parole con codifica percentuale alla fine del testo desiderato, separati da una virgola ,.

Ecco come si presenta:

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 tramite scorrimento:

Il frammento di testo è stato 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 uso una sola parola sia per start che per end, puoi vedere che ho un problema. 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 desiderato inizialmente. L'evidenziazione si interrompe alla prima occorrenza della parola Workers., che è corretta, ma non è ciò che intendevo evidenziare. Il problema è che la sezione desiderata non è identificata in modo univoco dai valori start e end attuali di una sola parola:

Frammento di testo non intenzionale visualizzato e evidenziato.

prefix- e -suffix

Utilizzare valori sufficientemente lunghi per start e end è una soluzione per ottenere un link univoco. Tuttavia, in alcuni casi non è possibile. A proposito, perché ho scelto il post del blog relativo al rilascio di Chrome 80 come esempio? La risposta è che in questa release sono stati introdotti i frammenti di testo:

Testo del post del blog: frammenti di URL di testo. Ora gli utenti o gli autori possono creare un link 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 fa scorrere il frammento per visualizzarlo. Ad esempio, l&#39;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 post del blog relativo all'annuncio di Text Fragments.

Nello screenshot qui sopra, la parola "testo" appare quattro volte. La quarta occorrenza è scritta in un carattere di codice verde. Se volessi inserire un link a questa parola specifica, imposterei start su text. Poiché la parola "testo" è, in effetti, 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 viene associato alla prima occorrenza della parola "Testo" già presente nell'intestazione:

Corrispondenza del frammento di testo alla prima occorrenza di "Testo".

Fortunatamente, esiste una soluzione. In casi come questo, posso specificare un prefix​- e un -suffix. La parola prima del carattere in codice verde "text" è "the" e quella successiva è "parameter". Nessuna delle altre tre occorrenze della parola "testo" ha le stesse parole circostanti. Grazie a queste informazioni, posso modificare l'URL precedente e aggiungere prefix- e -suffix. Come per 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 elementi devono essere separati da start e dall'elemento facoltativo end con un trattino -.

Corrispondenza del frammento di testo nell'occorrenza di "text" desiderata.

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. Ciò è particolarmente importante per i caratteri -, E commerciale & e virgola ,, quindi non vengono interpretati come parte della sintassi delle istruzioni di testo.

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

Ognuno di prefix-, start, end e -suffix corrisponderà 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 corrisponderà nell'esempio seguente, perché la stringa iniziale "The quick" non viene visualizzata all'interno di un singolo elemento senza interruzioni a livello di blocco:

<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

Creare manualmente URL di frammenti di testo è noioso, soprattutto quando si tratta di assicurarsi che siano univoci. Se vuoi, la specifica include alcuni suggerimenti ed elenca i passaggi esatti per la generazione di URL di frammenti di testo. Forniamo un'estensione per browser open source chiamata Link a frammento di testo che ti consente di collegare a qualsiasi testo selezionandolo e facendo clic su "Copia link nel testo selezionato" nel menu contestuale. Questa estensione è disponibile per i seguenti browser:

Link al frammento di testo del browser.

Più frammenti di testo in un URL

Tieni presente che in un URL possono essere visualizzati più frammenti di testo. I singoli frammenti di testo devono essere separati da un carattere 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 frammenti di testo. È perfetto avere entrambi nello stesso URL, ad esempio per fornire una riserva significativa nel caso in cui il testo originale nella 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: la direttiva del frammento :~:. Per evitare problemi di compatibilità con i frammenti di elementi URL esistenti, come mostrato sopra, la specifica dei frammenti di testo introduce la direttiva fragment. La direttiva 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 esso. Le istruzioni dell'user agent vengono anche chiamate istruzioni. Nel caso specifico, text= è quindi chiamata direttiva di testo.

Rilevamento di funzionalità

Per rilevare il supporto, esegui un test per la proprietà fragmentDirective di sola lettura su document. La direttiva fragment è un meccanismo per gli URL per specificare istruzioni rivolte al browser anziché al documento. Ha lo scopo di evitare l'interazione diretta con lo script dell'autore, in modo che le future istruzioni dell'agente utente possano essere aggiunte senza il timore di introdurre modifiche che comportino l'interruzione dei contenuti esistenti. Un potenziale esempio di queste aggiunte future potrebbe essere i 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 con frammenti di testo a browser non supportati.

Applicazione di stili ai frammenti di testo

Per impostazione predefinita, i browser applicano gli stili ai frammenti di testo nello stesso modo in cui li applicano 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 un pseudo selettore ::target-text che puoi utilizzare per personalizzare l'evidenziazione applicata. Ad esempio, puoi progettare i frammenti di testo in modo che siano di colore nero su sfondo rosso. Come sempre, assicurati di controllare il contrasto di colore in modo che lo stile di sostituzione non causi problemi di accessibilità e assicurati che l'evidenziazione risalti visivamente dal resto dei contenuti.

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

Policompilabilità

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 supporto integrato per frammenti di testo in cui la funzionalità è implementata in JavaScript.

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

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 eliminano i frammenti di testo per non interrompere le pagine. Esiste un bisogno riconosciuto di esporre i link ai frammenti di testo alle pagine, ad esempio per scopi di analisi, ma la soluzione proposta non è ancora stata implementata. Come soluzione alternativa per il momento, puoi utilizzare il codice riportato di seguito per estrarre le informazioni desiderate.

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

Sicurezza

Le direttive dei frammenti di testo vengono richiamate solo per le navigazioni complete (non nella stessa pagina) che sono il risultato di un'attivazione dell'utente. Inoltre, le navigazioni provenienti da un'origine diversa da quella di destinazione richiedono che la navigazione venga eseguita in un contesto noopener, in modo che la pagina di destinazione sia nota per essere sufficientemente isolata. Le istruzioni sui frammenti di testo vengono applicate soltanto al frame principale. Ciò significa che il testo non verrà cercato all'interno degli iframe e la navigazione negli iframe non attiverà un frammento di testo.

Privacy

È importante che le implementazioni della specifica dei frammenti di testo non lascino intendere se un frammento di testo è stato trovato o meno in una pagina. Mentre i frammenti di elemento sono completamente sotto il controllo dell'autore della pagina originale, i frammenti di testo possono essere creati da chiunque. Ricordi come, nell'esempio precedente, non c'era modo di collegare l'intestazione ECMAScript Modules in Web worker, dato che <h1> non aveva un id, ma come chiunque, incluso me, poteva collegarsi a qualsiasi punto creando con attenzione il frammento di testo?

Immagina che io gestisca una rete pubblicitaria malvagia evil-ads.example.com. Immagina inoltre che in uno dei miei iframe annunci abbia creato dinamicamente un iframe cross-origin nascosto per dating.example.com con un URL Text Fragment dating.example.com#:~:text=Log%20Out non appena l'utente interagisce con l'annuncio. Se viene trovato il testo "Uscire", so che la vittima ha attualmente eseguito l'accesso a dating.example.com, che potrei utilizzare per il profilo dell'utente. Poiché un'implementazione ingenua di TextFragments potrebbe decidere che una corrispondenza riuscita debba causare un trasferimento dell'attenzione, 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 tale che lo scenario descritto sopra non possa verificarsi.

Un altro attacco potrebbe consistere nell'exploitare il traffico di rete in base alla posizione dello scorrimento. Supponiamo che io abbia accesso ai log del traffico di rete della mia vittima, ad esempio come amministratore dell'intranet di un'azienda. Ora immagina che esista un lungo documento delle risorse umane Che cosa fare se soffri di… e poi un elenco di condizioni come burn out, ansia e così via. Potrei inserire un pixel di monitoraggio accanto a ogni voce dell'elenco. Se stabilisco che il caricamento del documento coincide temporaneamente con il caricamento del pixel di monitoraggio accanto, ad esempio, all'elemento burn-out, posso, in qualità di amministratore dell'intranet, determinare che un dipendente ha fatto clic su un link con frammento di testo con :~:text=burn%20out che il dipendente potrebbe aver considerato riservato e non visibile a nessuno. Poiché questo esempio è in qualche modo artificioso e poiché il suo sfruttamento richiede il rispetto di prerequisiti molto specifici, il team di sicurezza di Chrome ha valutato il rischio di implementare lo scorrimento durante la navigazione come gestibile. Altri user agent potrebbero decidere di mostrare un elemento dell'interfaccia utente di scorrimento manuale.

Per i siti che non vogliono partecipare, Chromium supporta un valore dell'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

Disattivare i frammenti di testo

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

Document-Policy: force-load-at-top

Un altro modo, più complesso, per disattivare questa funzionalità è utilizzare l'impostazione Enterprise ScrollToTextFragmentEnabled. Per farlo su macOS, incolla il comando riportato di seguito 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 mostrati quando una ricerca viene formulata sotto forma di domanda. Se fa clic su uno snippet in primo piano, l'utente viene indirizzato direttamente al testo dello snippet in primo piano nella pagina web di origine. Questo funziona grazie agli URL dei frammenti di testo creati automaticamente.

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

Conclusione

L'URL dei frammenti di testo è una funzionalità potente per creare link a testo arbitrario nelle pagine web. La community accademica può utilizzarlo per fornire link di riferimento o citazioni molto precisi. I motori di ricerca possono utilizzarlo per creare link diretti ai risultati di testo nelle pagine. I siti di social network possono utilizzarla per consentire agli utenti di condividere passaggi specifici di una pagina web anziché screenshot inaccessibili. Spero che tu inizi a utilizzare gli URL dei frammenti di testo e che li trovi utili come me. Assicurati di installare l'estensione del browser Link to Text Fragment.

Ringraziamenti

Text Fragments è stato implementato e specificato da Nick Burris e David Bokan, con il contributo di Grant Wang. Grazie a Joe Medley per la revisione approfondita di questo articolo. Immagine hero di Greg Rakozy su Unsplash.