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/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.
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
.
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 Strumenti per sviluppatori per trovare il id
di un elemento è molto indicativo della probabilità che questa particolare sezione della pagina fosse destinata a essere collegata dall'autore del post del blog.
Cosa succede se voglio fare un link a qualcosa senza un id
? Supponiamo che io voglia aggiungere un link all'intestazione Moduli ECMAScript
nei worker web. Come puoi vedere nello screenshot di seguito, l'elemento <h1>
in questione non ha un attributo id
, il che significa che non posso collegarmi a questa intestazione. Questo è il problema che viene risolto da Text Fragments.
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
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 da 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à:
Il frammento di testo è sottolineato come questo. Se fai clic sul link in un browser supportato come Chrome, il frammento di testo viene evidenziato e visualizzato scorrendo:
start
e end
Ora, cosa succede se voglio collegarmi all'intera sezione intitolata Moduli ECMAScript nei worker web, non solo alla sua intestazione? L'applicazione della codifica percentuale all'intero testo della sezione renderebbe l'URL risultante praticamente troppo lungo.
Fortunatamente, esiste 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:
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:
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:
prefix-
e -suffix
L'utilizzo di 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:
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:
Fortunatamente, esiste una soluzione. In casi come questo, posso specificare un prefix-
e un -suffix
. La parola prima del carattere "text" del codice verde è "the" e la parola dopo è "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 devono essere separati da start
e dall'eventuale end
con un trattino -
.
La sintassi completa
La sintassi completa dei frammenti di testo è riportata di seguito. 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 text.
#:~: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 "Il rapido" non compare 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
Creare manualmente gli URL dei frammenti di testo è un'operazione tediosa, soprattutto per assicurarsi che siano unici. Se proprio vuoi, la specifica contiene alcuni suggerimenti e elenca i passaggi esatti per generare gli URL dei frammenti di testo. Forniamo un'estensione del browser open source chiamata Link to Text Fragment (Collega a frammento di testo) che ti consente di collegarti a qualsiasi testo selezionandolo e facendo clic su "Copia link al testo selezionato" nel menu contestuale. Questa estensione è disponibile per i seguenti browser:
- Eseguire il collegamento a un frammento di testo per Google Chrome
- Eseguire il collegamento a un frammento di testo per Microsoft Edge
- Eseguire il collegamento a un frammento di testo per Mozilla Firefox
- Eseguire il collegamento a un frammento di testo per Apple Safari
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
.
Combinazione di elementi e frammenti di testo
I frammenti di elementi tradizionali possono essere combinati con i frammenti di testo. È perfettamente possibile avere entrambi
nello stesso URL, ad esempio per fornire un'opzione di riserva significativa nel caso in cui il testo originale sulla pagina
vari, 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.
):
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, verifica la presenza della proprietà fragmentDirective
di sola lettura in document
. La direttiva frammento è 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à è pensato principalmente per i casi in cui i link vengono generati dinamicamente (ad esempio dai motori di ricerca) per evitare di pubblicare link a frammenti di testo per i browser che non li supportano.
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 dei colori in modo che lo stile sostitutivo non causi problemi di accessibilità e assicurati che l'evidenziazione risalti visivamente rispetto al resto dei contenuti.
:root::target-text {
color: black;
background-color: red;
}
Polyfillability
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.
Generazione di link ai frammenti di testo programmatici
Il polyfill contiene un filefragment-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 rimuovono i frammenti di testo per non interrompere queste 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 implementata. Come soluzione alternativa, per il momento puoi utilizzare il codice riportato di seguito per estrarre le informazioni che ti interessano.
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 direttive dei frammenti di testo vengono applicate solo 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. I frammenti di elementi sono completamente sotto il controllo dell'autore della pagina originale, mentre i frammenti di testo possono essere creati da chiunque. Ricordi come nell'esempio riportato sopra
non era possibile fare un link all'intestazione Moduli ECMAScript nei worker web, poiché <h1>
non aveva un id
, ma come chiunque, incluso me, poteva semplicemente fare un link a qualsiasi pagina creando con cura 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 che lo scenario precedente 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 poi stabilisco che il caricamento del documento avviene contemporaneamente al caricamento del pixel di monitoraggio accanto, ad esempio, all'elemento burn out, posso stabilire, in qualità di amministratore dell'intranet, che un dipendente ha fatto clic su un link a un frammento di testo con :~:text=burn%20out
che il dipendente potrebbe aver assunto essere 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.
Frammenti di testo nella ricerca sul web
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.
Conclusione
L'URL dei frammenti di testo è una funzionalità potente per creare link a testo arbitrario nelle pagine web. La comunità accademica può utilizzarlo per fornire citazioni o link di riferimento estremamente precisi. I motori di ricerca possono utilizzarlo per creare link diretti ai risultati di testo nelle pagine. I siti di social network possono utilizzarlo per consentire agli utenti di condividere passaggi specifici di una pagina web anziché screenshot non accessibili. 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.
Link correlati
- Bozza delle specifiche
- Revisione del TAG
- Voce dello stato della piattaforma Chrome
- Bug di monitoraggio di Chrome
- Thread Intent to Ship
- Thread WebKit-Dev
- Thread sulla posizione degli standard di Mozilla
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.