Les fragments de texte vous permettent de spécifier un extrait de texte dans le fragment d'URL. Lorsque vous accédez à une URL contenant un tel fragment de texte, le navigateur peut le mettre en avant et/ou l'attirer l'attention de l'utilisateur.
Identifiants de fragment
Chrome 80 était une grande version. Elle contenait un certain nombre de fonctionnalités très attendues, comme les modules ECMAScript dans les Web Workers, la fusion des valeurs nulles, le chaînement facultatif, etc. Comme d'habitude, la version a été annoncée dans un article de blog sur le blog Chromium. Vous pouvez voir un extrait de l'article de blog dans la capture d'écran ci-dessous.
Vous vous demandez probablement ce que signifient toutes les cases rouges. Ils sont le résultat de l'exécution de l'extrait de code suivant dans DevTools. Elle met en surbrillance tous les éléments qui possèdent un attribut id
.
document.querySelectorAll('[id]').forEach((el) => {
el.style.border = 'solid 2px red';
});
Je peux placer un lien profond vers n'importe quel élément mis en surbrillance dans un cadre rouge grâce à l'identifiant de fragment que j'utilise ensuite dans le hachage de l'URL de la page. Si je voulais créer un lien profond vers le champ Envoyez-nous vos commentaires sur nos forums de produits dans le panneau latéral, je pourrais le faire en créant manuellement l'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1
.
Comme vous pouvez le voir dans le panneau "Éléments" des outils pour les développeurs, l'élément en question possède un attribut id
avec la valeur HTML1
.
Si j'analyse cette URL avec le constructeur URL()
de JavaScript, les différents composants sont révélés.
Notez la propriété hash
avec la valeur #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: ""
}
*/
Le fait que j'ai dû ouvrir les outils pour les développeurs pour trouver le id
d'un élément en dit long sur la probabilité que cette section particulière de la page ait été destinée à être associée par l'auteur du post.
Que se passe-t-il si je souhaite créer un lien vers un élément sans id
? Supposons que je souhaite créer un lien vers l'en-tête Modules ECMAScript dans les Web Workers. Comme vous pouvez le voir dans la capture d'écran ci-dessous, l'<h1>
en question ne comporte pas d'attribut id
, ce qui signifie que je ne peux pas créer de lien vers cet en-tête. C'est le problème que les fragments de texte résolvent.
Fragments de texte
La proposition Fragments de texte permet de spécifier un extrait de texte dans le hachage d'URL. Lorsqu'un utilisateur accède à une URL contenant un tel fragment de texte, l'agent utilisateur peut le mettre en avant et/ou l'attirer à l'attention de l'utilisateur.
Compatibilité du navigateur
Pour des raisons de sécurité, cette fonctionnalité nécessite que les liens soient ouverts dans un contexte noopener
.
Par conséquent, veillez à inclure rel="noopener"
dans votre balisage d'ancrage <a>
ou à ajouter noopener
à la liste des fonctionnalités de la fenêtre Window.open()
.
start
Dans sa forme la plus simple, la syntaxe des fragments de texte est la suivante: le symbole dièse #
suivi de :~:text=
, puis de start
, qui représente le texte encodé en pourcentage auquel je souhaite associer.
#:~:text=start
Par exemple, si je souhaite créer un lien vers l'en-tête Modules ECMAScript dans les Web Workers dans l'article de blog annonçant les fonctionnalités de Chrome 80, l'URL sera la suivante:
Le fragment de texte est mis en avant comme ceci. Si vous cliquez sur le lien dans un navigateur compatible, comme Chrome, le fragment de texte est mis en surbrillance et défile pour s'afficher:
start
et end
Que se passe-t-il si je souhaite créer un lien vers l'intégralité de la section intitulée Modules ECMAScript dans les Web Workers, et non seulement vers son titre ? Encodage en pourcentage de l'ensemble du texte de la section rendrait l'URL obtenue trop longue pour être pratique.
Heureusement, il existe une meilleure solution. Plutôt que de mettre en forme l'ensemble du texte, je peux encadrer le texte souhaité à l'aide de la syntaxe start,end
. Par conséquent, je spécifie quelques mots encodés en pourcentage au début du texte souhaité et quelques mots encodés en pourcentage à la fin du texte souhaité, séparés par une virgule ,
.
Voici à quoi cela ressemble:
Pour start
, j'ai ECMAScript%20Modules%20in%20Web%20Workers
, puis une virgule ,
suivie de ES%20Modules%20in%20Web%20Workers.
en tant que end
. Lorsque vous cliquez sur un navigateur compatible, comme Chrome, l'intégralité de la section est mise en surbrillance et défilée:
Vous vous demandez peut-être pourquoi j'ai choisi start
et end
. En fait, l'URL légèrement plus courte https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript%20Modules,Web%20Workers.
avec seulement deux mots de chaque côté aurait également fonctionné. Comparez start
et end
aux valeurs précédentes.
Si j'avance un peu plus loin et que j'utilise désormais un seul mot pour start
et end
, vous pouvez constater que je suis dans une situation délicate. L'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=ECMAScript,Workers.
est encore plus courte, mais le fragment de texte en surbrillance n'est plus celui souhaité à l'origine. La mise en surbrillance s'arrête à la première occurrence du mot Workers.
, ce qui est correct, mais ce n'est pas ce que je voulais mettre en surbrillance. Le problème est que la section souhaitée n'est pas identifiée de manière unique par les valeurs start
et end
d'un seul mot actuelles:
prefix-
et -suffix
Utiliser des valeurs suffisamment longues pour start
et end
est une solution pour obtenir un lien unique.
Toutefois, dans certains cas, cela n'est pas possible. À titre d'information, pourquoi ai-je choisi le post de blog sur la version Chrome 80 comme exemple ? La réponse est que les fragments de texte ont été introduits dans cette version:
Notez que dans la capture d'écran ci-dessus, le mot "text" (texte) apparaît quatre fois. La quatrième occurrence est écrite dans une police de code verte. Si je voulais créer un lien vers ce mot particulier, je définirais start
sur text
. Étant donné que le mot "texte" n'est qu'un seul mot, il ne peut pas y avoir de end
. Que se passe-t-il ensuite ? L'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=text
correspond à la première occurrence du mot "Texte" déjà présent dans l'en-tête:
Heureusement, il existe une solution. Dans ce cas, je peux spécifier un prefix-
et un -suffix
. Le mot avant la police de code verte "text" est "the", et le mot suivant est "parameter". Aucune des trois autres occurrences du mot "texte" n'a les mêmes mots environnants. Fort de ces informations, je peux modifier l'URL précédente et ajouter prefix-
et -suffix
. Comme les autres paramètres, ils doivent également être encodés en pourcentage et peuvent contenir plusieurs mots.
https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#:~:text=the-,text,-parameter
.
Pour permettre à l'analyseur d'identifier clairement les prefix-
et les -suffix
, ils doivent être séparés du start
et du end
facultatif par un tiret -
.
Syntaxe complète
La syntaxe complète des fragments de texte est présentée ci-dessous. (Les crochets indiquent un paramètre facultatif.)
Les valeurs de tous les paramètres doivent être encodées en pourcentage. Cela est particulièrement important pour les caractères tiret -
, esperluette &
et virgule ,
, afin qu'ils ne soient pas interprétés comme faisant partie de la syntaxe de la directive de texte.
#:~:text=[prefix-,]start[,end][,-suffix]
Chacun des éléments prefix-
, start
, end
et -suffix
ne correspond qu'au texte d'un seul élément au niveau du bloc, mais les plages start,end
complètes peuvent s'étendre sur plusieurs blocs. Par exemple, :~:text=The quick,lazy dog
ne correspondra pas dans l'exemple suivant, car la chaîne de départ "The quick" n'apparaît pas dans un seul élément de niveau bloc ininterrompu:
<div>
The
<div></div>
quick brown fox
</div>
<div>jumped over the lazy dog</div>
En revanche, il s'agit d'une correspondance dans cet exemple:
<div>The quick brown fox</div>
<div>jumped over the lazy dog</div>
Créer des URL de fragments de texte avec une extension de navigateur
Créer des URL de fragments de texte à la main est fastidieux, en particulier pour s'assurer qu'elles sont uniques. Si vous le souhaitez, la spécification contient des conseils et liste les étapes exactes pour générer des URL de fragment de texte. Nous fournissons une extension de navigateur Open Source appelée Link to Text Fragment (Lien vers un fragment de texte) qui vous permet de créer un lien vers n'importe quel texte en le sélectionnant, puis en cliquant sur "Copy Link to Selected Text" (Copier le lien vers le texte sélectionné) dans le menu contextuel. Cette extension est disponible pour les navigateurs suivants:
- Lien vers un fragment de texte pour Google Chrome
- Lien vers un fragment de texte pour Microsoft Edge
- Lien vers un fragment de texte pour Mozilla Firefox
- Lien vers un fragment de texte pour Apple Safari
Plusieurs fragments de texte dans une même URL
Notez que plusieurs fragments de texte peuvent apparaître dans une même URL. Les fragments de texte doivent être séparés par un caractère esperluette &
. Voici un exemple de lien avec trois fragments de texte :
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
.
Mélanger des fragments d'éléments et de texte
Les fragments d'éléments traditionnels peuvent être combinés à des fragments de texte. Vous pouvez tout à fait les placer dans la même URL, par exemple pour fournir une solution de remplacement appropriée si le texte d'origine de la page change, de sorte que le fragment de texte ne corresponde plus. L'URL https://blog.chromium.org/2019/12/chrome-80-content-indexing-es-modules.html#HTML1:~:text=Give%20us%20feedback%20in%20our%20Product%20Forums.
qui redirige vers la section Envoyez-nous vos commentaires sur nos forums sur les produits contient à la fois un fragment d'élément (HTML1
) et un fragment de texte (text=Give%20us%20feedback%20in%20our%20Product%20Forums.
):
Directive "fragment"
Il y a un élément de la syntaxe que je n'ai pas encore expliqué: la directive de fragment :~:
. Pour éviter les problèmes de compatibilité avec les fragments d'éléments d'URL existants, comme indiqué ci-dessus, la spécification des fragments de texte introduit la directive de fragment. La directive de fragment est une partie du fragment d'URL délimitée par la séquence de code :~:
. Il est réservé aux instructions de l'user-agent, telles que text=
, et est supprimé de l'URL lors du chargement afin que les scripts d'auteur ne puissent pas interagir directement avec lui. Les instructions de l'agent utilisateur sont également appelées directives. Dans le cas concret, text=
est donc appelé une directive de texte.
Détection de fonctionnalités
Pour détecter la prise en charge, recherchez la propriété fragmentDirective
en lecture seule sur document
. La directive de fragment est un mécanisme permettant aux URL de spécifier des instructions destinées au navigateur plutôt qu'au document. Il est destiné à éviter toute interaction directe avec le script de l'auteur afin que de futures instructions d'agent utilisateur puissent être ajoutées sans craindre d'introduire des modifications non compatibles avec le contenu existant. Les suggestions de traduction pourraient être un exemple de ces ajouts futurs.
if ('fragmentDirective' in document) {
// Text Fragments is supported.
}
La détection de fonctionnalités est principalement destinée aux cas où des liens sont générés de manière dynamique (par exemple, par les moteurs de recherche) pour éviter de diffuser des liens de fragments de texte vers des navigateurs qui ne les acceptent pas.
Appliquer un style aux fragments de texte
Par défaut, les navigateurs stylisent les fragments de texte de la même manière qu'ils stylisent mark
(généralement en noir sur jaune, les couleurs système CSS pour mark
). La feuille de style de l'user-agent contient du CSS qui se présente comme suit:
:root::target-text {
color: MarkText;
background: Mark;
}
Comme vous pouvez le constater, le navigateur expose un pseudo-sélecteur ::target-text
que vous pouvez utiliser pour personnaliser la mise en surbrillance appliquée. Par exemple, vous pouvez concevoir vos fragments de texte pour qu'ils soient en texte noir sur fond rouge. Comme toujours, veillez à vérifier le contraste des couleurs pour que votre style de remplacement ne pose pas de problèmes d'accessibilité. Assurez-vous également que la mise en surbrillance se démarque visuellement du reste du contenu.
:root::target-text {
color: black;
background-color: red;
}
Polyfillabilité
La fonctionnalité Fragments de texte peut être remplie dans une certaine mesure. Nous fournissons un polyfill, qui est utilisé en interne par l'extension, pour les navigateurs qui ne prennent pas en charge les fragments de texte intégrés lorsque la fonctionnalité est implémentée en JavaScript.
Génération de liens de fragments de texte programmatique
Le polyfill contient un fichier fragment-generation-utils.js
que vous pouvez importer et utiliser pour générer des liens de fragment de texte. Cela est illustré dans l'exemple de code ci-dessous:
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);
}
Obtenir des fragments de texte à des fins d'analyse
De nombreux sites utilisent le fragment pour le routage. C'est pourquoi les navigateurs suppriment les fragments de texte afin de ne pas endommager ces pages. Il existe un besoin reconnu d'exposer des liens vers des pages dans les fragments de texte, par exemple à des fins d'analyse, mais la solution proposée n'est pas encore implémentée. Pour le moment, vous pouvez utiliser le code ci-dessous pour extraire les informations souhaitées.
new URL(performance.getEntries().find(({ type }) => type === 'navigate').name).hash;
Sécurité
Les directives de fragment de texte ne sont appelées que pour les navigations complètes (hors même page) qui résultent d'une activation de l'utilisateur.
De plus, les navigations provenant d'une origine différente de la destination nécessiteront que la navigation se déroule dans un contexte noopener
, de sorte que la page de destination soit suffisamment isolée. Les directives de fragment de texte ne s'appliquent qu'au frame principal. Cela signifie que le texte ne sera pas recherché dans les iFrames, et que la navigation dans les iFrames n'appellera pas de fragment de texte.
Confidentialité
Il est important que les implémentations de la spécification des fragments de texte ne divulguent pas si un fragment de texte a été trouvé sur une page ou non. Bien que les fragments d'éléments soient entièrement sous le contrôle de l'auteur de la page d'origine, tout le monde peut créer des fragments de texte. N'oubliez pas que dans mon exemple ci-dessus, il n'était pas possible de créer un lien vers l'en-tête Modules ECMAScript dans les Web Workers, car <h1>
ne comportait pas de id
. En revanche, n'importe qui, y compris moi, pouvait créer un lien vers n'importe quel endroit en créant soigneusement le fragment de texte.
Imaginez que j'exploite un réseau publicitaire malveillant evil-ads.example.com
. Imaginons également que dans l'une de mes iFrames publicitaires, j'ai créé dynamiquement une iFrame inter-origine masquée vers dating.example.com
avec une URL de fragment de texte dating.example.com#:~:text=Log%20Out
une fois que l'utilisateur interagit avec l'annonce. Si le texte "Se déconnecter" est détecté, je sais que la victime est actuellement connectée à dating.example.com
, ce que je pourrais utiliser pour le profilage des utilisateurs. Étant donné qu'une implémentation naïve de Text Fragments peut décider qu'une correspondance réussie doit entraîner un changement de focus, sur evil-ads.example.com
, je peux écouter l'événement blur
et ainsi savoir quand une correspondance s'est produite. Dans Chrome, nous avons implémenté les fragments de texte de manière à éviter le scénario ci-dessus.
Une autre attaque consiste à exploiter le trafic réseau en fonction de la position de défilement. Supposons que j'ai accès aux journaux de trafic réseau de ma victime, comme l'administrateur d'un intranet d'entreprise. Imaginons qu'il existe un long document de ressources humaines intitulé Que faire si vous souffrez de…, suivi d'une liste de conditions telles que le surmenage, l'anxiété, etc. Je pourrais placer un pixel de suivi à côté de chaque élément de la liste. Si je détermine ensuite que le chargement du document coïncide avec le chargement du pixel de suivi à côté de l'élément burn out, je peux alors, en tant qu'administrateur de l'intranet, déterminer qu'un employé a cliqué sur un lien de fragment de texte avec :~:text=burn%20out
qu'il a peut-être supposé être confidentiel et non visible par quiconque. Cet exemple est quelque peu artificiel au départ, et son exploitation nécessite de remplir des conditions préalables très spécifiques. L'équipe de sécurité de Chrome a donc estimé que le risque d'implémenter le défilement lors de la navigation était gérable.
D'autres user-agents peuvent décider d'afficher un élément d'interface utilisateur de défilement manuel à la place.
Pour les sites qui souhaitent désactiver cette fonctionnalité, Chromium accepte une valeur d'en-tête Document Policy qu'ils peuvent envoyer afin que les agents utilisateur ne traitent pas les URL de fragments de texte.
Document-Policy: force-load-at-top
Désactiver les fragments de texte
Le moyen le plus simple de désactiver cette fonctionnalité consiste à utiliser une extension capable d'injecter des en-têtes de réponse HTTP, par exemple ModHeader (qui n'est pas un produit Google) pour insérer un en-tête de réponse (pas de requête) comme suit:
Document-Policy: force-load-at-top
Vous pouvez également désactiver cette fonctionnalité en utilisant le paramètre d'entreprise ScrollToTextFragmentEnabled
.
Pour ce faire sous macOS, collez la commande ci-dessous dans le terminal.
defaults write com.google.Chrome ScrollToTextFragmentEnabled -bool false
Sous Windows, suivez la documentation sur le site d'assistance Aide Google Chrome Enterprise.
Fragments de texte dans la recherche sur le Web
Pour certaines recherches, le moteur de recherche Google fournit une réponse rapide ou un résumé avec un extrait de contenu provenant d'un site Web pertinent. Ces extraits optimisés sont plus susceptibles d'apparaître lorsque vous lancez une recherche sous forme de question. Lorsque l'internaute clique sur un extrait optimisé, il accède directement au texte de l'extrait optimisé sur la page Web source. Cela fonctionne grâce aux URL de fragments de texte créées automatiquement.
Conclusion
L'URL des fragments de texte est une fonctionnalité puissante qui permet de créer un lien vers un texte arbitraire sur des pages Web. La communauté scientifique peut l'utiliser pour fournir des liens de citation ou de référence très précis. Les moteurs de recherche peuvent l'utiliser pour créer des liens profonds vers les résultats textuels sur les pages. Les sites de réseaux sociaux peuvent l'utiliser pour permettre aux utilisateurs de partager des passages spécifiques d'une page Web plutôt que des captures d'écran inaccessibles. J'espère que vous commencerez à utiliser les URL de fragment de texte et que vous les trouverez aussi utiles que moi. N'oubliez pas d'installer l'extension de navigateur Link to Text Fragment (Lien vers le fragment de texte).
Liens associés
- Brouillon de spécifications
- Examen du TAG
- Enregistrement de l'état de la plate-forme Chrome
- Bug de suivi Chrome
- Fil d'intent d'expédition
- Fil WebKit-Dev
- Fil de discussion sur la position de Mozilla concernant les normes
Remerciements
Les fragments de texte ont été implémentés et spécifiés par Nick Burris et David Bokan, avec la contribution de Grant Wang. Merci à Joe Medley pour avoir examiné attentivement cet article. Image héros de Greg Rakozy sur Unsplash.