Ajouter un lien en gras lorsque personne n'a encore associé de lien: fragments de texte

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 le signaler à l'utilisateur.

Identifiants de fragment

Chrome 80 était une grande version. Il contenait un certain nombre de fonctionnalités très attendues, telles que les modules ECMAScript dans les nœuds de calcul Web, le coalescing nullish, les chaînages facultatifs, etc. Comme d'habitude, la version a été annoncée via 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.

Article de blog Chromium avec des rectangles rouges autour des éléments avec un attribut id.

Vous vous demandez probablement ce que tous les cadres rouges signifient. 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 comportent 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. Supposons que je veuille créer un lien profond vers le champ Envoyez-nous vos commentaires sur nos forums de produits dans le panneau latéral. Pour ce faire, je peux créer 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 "Elements" (Éléments) des outils pour les développeurs, l'élément en question comporte un attribut id avec la valeur HTML1.

Outils de développement affichant l'id d'un élément.

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 ECMAScript Modules in Web Workers (Modules ECMAScript dans Web Workers). Comme vous pouvez le voir dans la capture d'écran ci-dessous, le <h1> en question n'a pas d'attribut id. Je ne peux donc pas créer de lien vers cet en-tête. C'est le problème que les fragments de texte résolvent.

Outils pour les développeurs affichant un titre sans id.

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

Navigateurs pris en charge

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

Source

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 à votre liste Window.open() des fonctionnalités de la fenêtre.

start

Dans sa forme la plus simple, la syntaxe des fragments de texte est la suivante: le symbole de hachage #, suivi de :~:text= et enfin start, qui représente le texte encodé en pourcentage vers lequel je souhaite créer un lien.

#:~:text=start

Par exemple, supposons que je souhaite créer un lien vers l'en-tête ECMAScript Modules in Web Workers (Modules ECMAScript dans les workers Web) de l'article de blog annonçant les fonctionnalités dans Chrome 80. Dans ce cas, l'URL serait la suivante:

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

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 s'affiche à l'écran :

Fragment de texte affiché et mis en surbrillance.

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 ? Si vous encodez l'intégralité du texte de la section en pourcentage, l'URL obtenue serait incroyablement longue.

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 :

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

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, toute la section est mise en surbrillance et fait défiler l'écran pour l'afficher:

Fragment de texte affiché en surbrillance et mis en surbrillance.

Vous vous interrogez peut-être sur mon choix concernant 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. ne contenant que 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 actuelles, qui ne contiennent qu'un seul mot :

Fragment de texte non intentionnel affiché et mis en surbrillance.

prefix- et -suffix

L'utilisation de valeurs suffisamment longues pour start et end constitue une solution pour obtenir un lien unique. Toutefois, dans certains cas, cela n'est pas possible. Pourquoi ai-je choisi l'article de blog de la version Chrome 80 comme exemple ? La réponse est que les fragments de texte ont été introduits dans cette version :

Texte de l&#39;article de blog : Fragments d&#39;URL textuels. Les utilisateurs ou les auteurs peuvent désormais créer un lien vers une partie spécifique d&#39;une page à l&#39;aide d&#39;un fragment de texte fourni dans une URL. Lorsque la page est chargée, le navigateur met en surbrillance le texte et fait défiler le fragment pour qu&#39;il s&#39;affiche. Par exemple, l&#39;URL ci-dessous charge une page Wiki pour &quot;Chat&quot; et fait défiler le contenu indiqué dans le paramètre &quot;text&quot;.
Extrait de l'article de blog annonçant les fragments de texte.

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 avec code vert. Pour créer un lien vers ce mot spécifique, définissez 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 :

Fragment de texte correspondant à la première occurrence de "Text".

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 après 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 prefix- et -suffix, ils doivent être séparés du start et du end facultatif par un tiret -.

Fragment de texte correspondant à l'occurrence souhaitée de "text".

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>

Cependant, il correspond 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 le fragment de texte extension du navigateur.

Plusieurs fragments de texte dans une même URL

Notez que plusieurs fragments de texte peuvent apparaître dans une même URL. Ces fragments de texte doivent être séparés par une 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.

Trois fragments de texte dans une seule URL.

Mélanger des fragments d'éléments et de texte

Les fragments d'éléments traditionnels peuvent être associé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.) :

Association avec un fragment d'élément et un fragment de texte.

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'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 :~:. Elle est réservée aux instructions de user-agent, telles que text=. Elle est supprimée de l'URL lors du chargement afin que les scripts d'auteur ne puissent pas interagir directement avec elle. Les instructions relatives au user-agent sont également appelées instructions. Dans le cas concret, text= est donc appelé une directive de texte.

Détection de caractéristiques

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 conçu pour éviter toute interaction directe avec le script de l'auteur, afin que les futures instructions du user-agent puissent être ajoutées sans craindre d'apporter des modifications destructives au contenu existant. Les indications de traduction constituent un exemple potentiel d'ajouts de ce type.

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 dynamiquement (par exemple par des moteurs de recherche) pour éviter de diffuser des fragments de texte dans 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 voir, 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 en tant que texte noir sur fond rouge. Comme toujours, veillez à vérifier le contraste des couleurs pour que votre style de forçage 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 émulée 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 nativement les fragments de texte, où la fonctionnalité est implémentée en JavaScript.

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 les liens des fragments de texte vers les pages, 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 sont appliquées qu'au cadre 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 "Log Out" (Déconnexion) s'affiche, cela signifie que la victime est actuellement connectée à dating.example.com, 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 constate ensuite que le chargement du document coïncide temporairement avec le chargement du pixel de suivi à côté de l'élément burn out, par exemple, je peux, 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 supposé être confidentiel et n'est visible par personne. 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 le souhaitent, Chromium accepte une valeur d'en-tête Document Policy qu'ils peuvent envoyer afin que les user-agents 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 effectuer cette opération 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 Google Chrome Enterprise Help.

Pour certaines recherches, le moteur de recherche Google fournit une réponse rapide ou un résumé avec un extrait de contenu d'un site Web pertinent. Ces extraits optimisés sont plus susceptibles de s'afficher lorsqu'une recherche prend la forme d'une 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.

Page de résultats du moteur de recherche Google affichant un extrait enrichi. La barre d'état affiche l'URL des fragments de texte.
Une fois que vous avez cliqué sur l'URL, la section appropriée de la page s'affiche à l'écran.

Conclusion

L'URL de 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 des URL de fragments de texte et que vous les trouverez aussi utiles que moi. N'oubliez pas d'installer l'extension de navigateur Lien vers le fragment de texte.

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.