I frammenti di testo 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ò mettere in evidenza e/o portarlo all'attenzione dell'utente.
Identificatori di frammenti
Chrome 80 è stato un successo. Conteneva una serie di funzionalità molto attese, come i moduli ECMAScript nei web worker, la coalescenza nullish, il concatenamento opzionale e altro ancora. Come di consueto, il rilascio è stato annunciato tramite un post del blog sul blog di Chromium. Puoi vedere un estratto del post del blog nel seguente screenshot.
Probabilmente ti stai chiedendo cosa significano tutte le caselle rosse. Questi tag 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 utilizzo nell'hash dell'URL della pagina. Supponendo di voler aggiungere un link diretto al riquadro Forniscici feedback nel nostro Forum dei prodotti a parte, potrei farlo creando l'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1
a mano.
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 mostrati i diversi componenti.
Osserva 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 il id
di un elemento indica la probabilità che l'autore del post del blog dovesse prevedere un link a questa particolare sezione della pagina.
Cosa devo fare se voglio collegarmi a qualcosa senza id
? Supponiamo di voler creare un link all'intestazione ECMAScript Modules
in Web Workers (Moduli ECMAScript nei web worker). Come puoi vedere nello screenshot di seguito, l'<h1>
in questione non ha un attributo id
, il che significa che non c'è modo di creare un link a questo titolo. Questo è il problema dei frammenti di testo.
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ò mettere in risalto e/o portarlo 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
al tuo elenco Window.open()
di funzionalità relative alle funzionalità delle finestre.
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 con codifica percentuale a cui voglio collegarti.
#:~:text=start
Ad esempio, supponiamo di voler creare un link all'intestazione Moduli ECMAScript nei web worker nel post del blog che annuncia le funzionalità di Chrome 80. In questo caso, l'URL sarà:
Il frammento di testo è enfatizzato in questo modo. Se fai clic sul link in un browser che supporta il browser come Chrome, viene evidenziato il frammento di testo e viene reso visibile lo scorrimento:
start
e end
E se volessi creare un link all'intera sezione intitolata Moduli ECMAScript nei web worker, non solo al titolo? La codifica percentuale dell'intero testo della sezione renderebbe l'URL risultante incredibilmente lungo.
Per fortuna c'è un modo migliore. Anziché sull'intero testo, posso inquadrare il testo desiderato utilizzando la
sintassi start,end
. Pertanto, indico 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, separate da una virgola ,
.
Ecco come:
Per start
, ho ECMAScript%20Modules%20in%20Web%20Workers
, seguito da una virgola ,
seguita da ES%20Modules%20in%20Web%20Workers.
come end
. Quando fai clic su un browser che supporta
Chrome come Chrome, viene evidenziata e visualizzata l'intera sezione tramite scorrimento:
Ora potresti chiederti qual è la mia scelta di start
e end
. In realtà, avrebbe funzionato 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. Confronta start
e end
con i
valori precedenti.
Se faccio un ulteriore passo in avanti e ora utilizzo una sola parola sia per start
che per end
, vedrai che sono nei guai. 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 originariamente desiderato. 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 correnti di una parola start
e end
:
prefix-
e -suffix
L'utilizzo di valori sufficientemente lunghi per start
e end
è una soluzione per ottenere un link univoco.
In alcuni casi, tuttavia, ciò non è possibile. Inoltre, perché ho scelto il post
del blog sul rilascio di Chrome 80 come esempio? In questa versione sono stati introdotti
i frammenti di testo:
Osserva come nello screenshot sopra la parola "testo" appare quattro volte. La quarta occorrenza
è scritta con un carattere di codice verde. Se volessi collegare questa parola specifica, imposterò start
su text
. Poiché la parola "testo" è, beh, è solo una parola, non può esserci un end
. Che cosa succede ora? L'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text
corrisponde 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 che precede il carattere del codice verde "text" è "the" e la parola che segue è "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 gli altri
parametri, anche questi devono essere codificati a 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 da end
facoltativo con un trattino -
.
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 del trattino -
, della e commerciale &
e della virgola ,
, in modo che non vengano interpretati come parte della sintassi delle direttive del testo.
#:~:text=[prefix-,]start[,end][,-suffix]
Ciascun elemento prefix-
, start
, end
e -suffix
corrisponderà al testo all'interno di un solo
elemento a livello di blocco,
ma gli intervalli completi di start,end
possono coprire più blocchi. Ad esempio,
:~:text=The quick,lazy dog
non corrisponderà nell'esempio seguente, perché la stringa
iniziale "Il rapido" non appare all'interno di un singolo elemento a livello di blocco senza interruzioni:
<div>
The
<div></div>
quick brown fox
</div>
<div>jumped over the lazy dog</div>
Tuttavia, in questo esempio corrisponde:
<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 URL di frammenti di testo manualmente è noioso, soprattutto quando si tratta di assicurarsi che siano univoci. Se vuoi, la specifica offre alcuni suggerimenti ed elenca i passaggi esatti per generare URL di frammenti di testo. Forniamo un'estensione del browser open source denominata Link al frammento di testo che ti consente di collegare qualsiasi testo selezionandolo e poi facendo clic su "Copia link al testo selezionato" nel menu contestuale. Questa estensione è disponibile per i seguenti browser:
- Link al frammento di testo per Google Chrome
- Link al frammento di testo per Microsoft Edge
- Link al frammento di testo per Mozilla Firefox
- Link al frammento di testo per Apple Safari
Più frammenti di testo in un URL
Tieni presente che in un URL possono essere presenti più frammenti di testo. I frammenti di testo specifici devono essere separati
dalla e commerciale &
. Ecco un link di esempio 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 inserire entrambi i valori nello stesso URL, ad esempio per fornire un elemento di riserva significativo nel caso in cui il testo originale nella pagina cambi e 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 Forniscici un feedback nella nostra sezione Forum dei prodotti contiene sia un frammento di elemento (HTML1
) sia un frammento di testo (text=Give%20us%20feedback%20in%20our%20Product%20Forums.
):
L'istruzione fragment
C'è un elemento della sintassi che non ho ancora spiegato: l'istruzione fragment :~:
. Per evitare problemi di compatibilità con i frammenti di elementi URL esistenti, come mostrato sopra, la specifica Fragmenti di testo introduce l'istruzione relativa ai frammenti. L'istruzione di frammento è una parte del frammento URL delimitato 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 l'URL. Le istruzioni dello user agent sono
chiamate anche istruzioni. Nel caso concreto, text=
viene quindi chiamata istruzione di testo.
Rilevamento delle funzionalità
Per rilevare il supporto, esegui il test per la proprietà fragmentDirective
di sola lettura su document
. L'istruzione relativa al frammento è un meccanismo che consente agli URL di specificare le istruzioni indirizzate al browser anziché al documento. Il suo scopo è evitare l'interazione diretta con lo script dell'autore, in modo che le istruzioni future dello user agent possano essere aggiunte senza timore di introdurre modifiche che provocano un errore nei contenuti esistenti. Un
potenziale esempio di queste aggiunte future potrebbe essere costituito 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 la pubblicazione di frammenti di testo e link a browser che non li supportano.
Applicare uno stile ai frammenti di testo
Per impostazione predefinita, i frammenti di testo nello stile dei browser hanno lo stesso stile utilizzato per mark
(in genere, nero su giallo, i colori di sistema CSS per mark
). Il foglio di stile user-agent contiene codice CSS simile al seguente:
:root::target-text {
color: MarkText;
background: Mark;
}
Come puoi vedere, il browser mostra uno pseudo-selettore ::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 di colore in modo che lo stile di override non causi problemi di accessibilità e che l'evidenziazione risalti effettivamente visivamente dal resto dei contenuti.
:root::target-text {
color: black;
background-color: red;
}
Policompilabilità
La funzionalità Frammenti di testo può essere eseguita in polyfill in una certa misura. Forniamo un polyfill, che viene utilizzato internamente dall'estensione, per i browser che non forniscono supporto integrato per i frammenti di testo in cui la funzionalità è implementata in JavaScript.
Generazione del link al frammento di testo programmatico
Il polyfill contiene un file
fragment-generation-utils.js
che puoi importare e utilizzare per generare link a frammenti di testo. come descritto 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 per scopi di analisi
Molti siti utilizzano il frammento per il routing, motivo per cui i browser escludono i frammenti di testo in modo da non interrompere le pagine. È accertata necessità di esporre i link ai frammenti di testo alle pagine, ad esempio a scopo di analisi, ma la soluzione proposta non è ancora implementata. 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 istruzioni relative ai frammenti di testo vengono richiamate solo in navigazioni complete (non-same-page) che sono il risultato di
un'attivazione utente.
Inoltre, le navigazioni provenienti da un'origine diversa da quella di destinazione richiedono che la navigazione avvenga in un contesto noopener
, in modo che la pagina di destinazione sia nota essere sufficientemente isolata. Le istruzioni relative ai frammenti di testo
vengono applicate solo al frame principale. Ciò significa che il testo non verrà cercato all'interno di iframe e la navigazione nell'iframe
non richiamerà un frammento di testo.
Privacy
È importante che le implementazioni della specifica dei frammenti di testo non facciano trapelare se un frammento di testo è stato trovato su una pagina o meno. Mentre l'autore della pagina originale è sotto il pieno controllo dei frammenti di elementi, i frammenti di testo possono essere creati da chiunque. Ricordi come nell'esempio precedente non c'era un modo per creare un link all'intestazione Moduli ECMAScript nei web worker, dato che <h1>
non aveva un id
, ma come chiunque, incluso me, potesse creare un link a qualsiasi luogo creando con attenzione il frammento di testo?
Immagina di gestire una rete pubblicitaria malevola evil-ads.example.com
. Immagina inoltre che in uno degli iframe dell'annuncio abbia creato dinamicamente un iframe multiorigine nascosto in dating.example.com
con un URL di frammento di testodating.example.com#:~:text=Log%20Out
dopo che l'utente ha interagito con l'annuncio. Se viene trovato il testo "Esci", so che la vittima ha eseguito l'accesso a dating.example.com
, che potrei utilizzare per la profilazione dell'utente. Poiché un'implementazione ingenua di Frammenti di testo potrebbe decidere che una corrispondenza riuscita debba causare un'opzione di impostazione dello 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 tale che lo scenario descritto sopra non si verifichi.
Un altro attacco potrebbe essere lo sfruttamento del traffico di rete in base alla posizione di scorrimento. Supponiamo di avere accesso ai registri
del traffico di rete della mia vittima, ad esempio come amministratore dell'intranet di un'azienda. Ora immagina che esistesse un lungo documento sulle risorse umane What to Do If You Sffer From... e poi un elenco di condizioni come burn out, anxiety e così via. Potrei posizionare un pixel di monitoraggio accanto a ogni elemento dell'elenco. Se poi stabilisco che il caricamento del documento avviene temporaneamente e avviene insieme al caricamento del pixel di monitoraggio accanto, ad esempio, all'elemento burnout, posso determinare, in qualità di amministratore dell'intranet, che un dipendente ha fatto clic su un link di frammento di testo con :~:text=burn%20out
che il dipendente potrebbe aver ritenuto riservato e non visibile a nessuno. Poiché questo esempio è in qualche modo inventato all'inizio e poiché il suo sfruttamento richiede il rispetto di precondizioni molto specifiche, 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 invece un elemento UI di scorrimento manuale.
Per i siti che vogliono disattivare questa opzione, Chromium supporta un valore di intestazione Criterio documento che può inviare in modo che gli user agent non elaborino gli URL di frammenti di testo.
Document-Policy: force-load-at-top
Disabilitazione dei frammenti di testo
Il modo più semplice per disabilitare la funzionalità consiste nell'utilizzare un'estensione in grado di inserire intestazioni di risposta HTTP, ad esempio ModHeader (non un prodotto Google), per inserire un'intestazione di risposta (non di richiesta) come segue:
Document-Policy: force-load-at-top
Un altro modo più coinvolgente per fare la disattivazione è utilizzare l'impostazione aziendale
ScrollToTextFragmentEnabled
.
Per farlo su macOS, incolla il comando seguente 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 web
Per alcune ricerche, il motore di ricerca Google fornisce una risposta o un riepilogo rapido con uno snippet di contenuti di un sito web pertinente. Questi snippet in primo piano vengono visualizzati con maggiore probabilità quando una ricerca è sotto forma di domanda. Facendo clic su uno snippet in primo piano, l'utente viene indirizzato direttamente al testo dello snippet in primo piano sulla pagina web di origine. Questo grazie agli URL di frammenti di testo creati automaticamente.
Conclusione
L'URL frammenti di testo è una potente funzionalità che consente di inserire link a testo arbitrario nelle pagine web. La comunità accademica può utilizzarlo per fornire link con citazioni o riferimenti molto precisi. I motori di ricerca possono usarla per creare link diretti ai risultati testuali sulle pagine. I siti di social network la possono usare per consentire agli utenti di condividere passaggi specifici di una pagina web anziché screenshot inaccessibili. Spero che inizi a utilizzare gli URL di frammenti di testo e che tu li trovi utili quanto me. Assicurati di installare l'estensione del browser Link to Text Fragment.
Link correlati
- Bozza delle specifiche
- Revisione TAG
- Voce Stato della piattaforma Chrome
- Bug di monitoraggio di Chrome
- Thread intenzione di spedire
- Thread WebKit-Dev
- Thread della posizione standard di Mozilla
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 articolo. Immagine hero di Greg Rakozy su Unsplash.