arneoio / rgaa-checker

A browser extension to check compliance with the RGAA standard
https://www.arneo.io
Apache License 2.0
54 stars 1 forks source link

Images - Amélioration de la fonctionnalité Highlight #8

Open PhilippeVay opened 5 months ago

PhilippeVay commented 5 months ago

Description du problème

La fonctionnalité highlight tente de distinguer les éléments audités par un critère du reste du contenu en ajoutant une opacité de 0.2 au reste du contenu mais pas aux éléments audités (ex: "les images" ou "les tableaux"). Pour les images, certains nœuds texte ne sont pas correctement estompés : les nœuds texte ayant un parent commun avec une image ne deviennent pas translucides et il n'est pas possible de leur ajouter une opacité à moins de les encapsuler dans un span (pas une bonne idée quand on ne connait rien de la page) ou d'également rendre translucide l'image en l'ajoutant sur le parent. Sur https://www.alsacreations.fr, les 4 images HTML5, etc sont estompées mais pas les p ou li ayant un span avec du texte.

image

Pistes...

Après avoir passé une journée à développer une solution JS, SVG et mask-image, je viens d'en (re)trouver une autre en pur CSS ou presque...
On peut en effet :

Pour la spécificité, j'avais remonté chez ffoodd ce que permettait @layer (snippet d'exemple et lien vers l'article de référence de bram.us) avec 1 seule limitation bien rare.[^1]

Solution proposée (CSS et JS) ⬇️

Placer le at-layer le plus tôt possible (JS) Placer notre `@layer` nommé le plus tôt possible dans la page. Pas essentiel à moins de devoir écraser d'autres styles eux aussi dans un `@layer` et avec `!important`, ça fait beaucoup de conditions... ```js (function () { let e = document.createElement("style"); e.prepend("@layer rgaac-hl-img;"); document.head.querySelector("title").after(e); })() ```
Highlight les images d'une page (CSS) ```css /* Highlight "images" in a page */ @layer rgaac-hl-img { * { filter: none !important; /* Images may have weird filters */ } /* Everything except images */ *:not(:where( img, [role="img"], area, svg, :where(input, object, embed)[type="image"])) { color: rgba(0, 0, 0, 0.2) !important; background: transparent !important; border-color: transparent !important; outline-color: transparent !important; text-shadow: none !important; } /* All type of images and then SVG. TODO: */ :where( img, /* includes [ismap] */ [role="img"], area, :where(input, object, embed)[type="image"]) { outline: 2px dashed green !important; outline-offset: -2px !important; box-shadow: 4px 0 0 -2px darkred, 0 4px 0 -2px blue !important; } svg { border: 3px solid green !important; outline: 3px dashed white !important; outline-offset: -3px !important; } /* Pseudo-elements are not valid in the selector list for :is() or :where() */ *::before, *::after { color: rgba(0, 0, 0, 0.2) !important; background: transparent !important; border-color: transparent !important; outline-color: transparent !important; text-shadow: none !important; } /* Detect and flag : inline styles with !important are more specific than any @layer :( (for now, all properties are selected even if commented) */ body:has( [style*="!important"] )::before { content: "Page contains inline style with !important" !important; position: relative !important; z-index: 987654 !important; display: block !important; margin-bottom: 1rem !important; padding: 1rem !important; color: white !important; background: darkred !important; } } ```

Tests

URLs de test :

Vu ailleurs

Du côté de la concurrence 🕵️‍♂️ :

[^1]: Cela écrase bien aussi les styles inline mais je viens de me rendre compte (ou bien j'avais oublié depuis) qu'un style inline avec !important aura toujours plus de spécificité que n'importe quel @layer. Mmh si j'en ai rencontré une fois, c'était il y a 10 ans dans du GG Maps embedded ou du temps d'IE6 et ça a disparu il y a bien longtemps. Bref c'est plus que rare et ça se détecte en CSS.

jonathan-vallet commented 5 months ago

Merci beaucoup pour le retour très complet!

Effectivement avec la méthode qu'on a utilisé il y a quelques nodes texte qui peuvent passer au travers. On n'était pas vraiment dans l'optique de masquer complètement le reste quand on active le "highlight" (plus tard on proposera à chacun de régler l'opacité comme il le souhaite dans des paramètres), mais l'idée est de conserver le contexte autour des éléments. À terme si les performances ne sont pas trop impactées, l'idée serait d'avoir un canvas par dessus la page avec un masque, et de "faire des trous" dedans aux emplacement de chaque éléments mis en avant. comme ça déjà on n'aurait plus du tout d'adhérence à modifier le style de la page (ce qui peut être problématique puisqu'on peut révéler des éléments qui étaient en "opacity: 0". Et ça peut être très performant puisqu'on peut trouer juste les éléments qui sont visibles dans le viewport plutot que toute la page, et ainsi mettre à jour le masque en temps réel au scroll/resize par exemple.

On a également une feature qui devrait arriver prochainement permettant de trouver un élément spécifique dans la page :)

On va creuser les idées suggérées en tout cas en attendant

PhilippeVay commented 5 months ago

La version avec un grand masque SVG par dessus la page et d'autres transparents (1 par image, pile par dessus) est ce que j'avais préparé initialement (ou 1 seul masque avec 1 gris foncé et plein de blancs par dessus les images, le résultat est le même). Code : https://gist.github.com/PhilippeVay/9ed5dc541f7c51f2b30924ee7b292b99

Inconvénient de cette méthode : ça fait chauffer le CPU dans de longues pages, ce que ne fait pas la version rgba(). Cet article fait passer un Ryzen 5 mobile 3xxx de 4% à 100% pendant le scroll au lieu de ~20% sans les masques.

Pour revenir au Highlight actuel, il y a aussi des images qui sont masquées (faux négatifs), cf. capture d'écran ci-dessus, ce qui est plus embêtant que quelques faux positifs.