Ressources · Développeurs
Patterns FSE avancés pour l'accessibilité
Cinq patterns WordPress Full Site Editing prêts à copier, pour traiter les critères RGAA que les blocs natifs seuls ne couvrent pas.
Les encarts des fiches critères couvrent l'usage courant des blocs natifs. Cette page
va plus loin : cinq patterns complets, prêts à copier, pour les cas où l'éditeur
de site seul ne suffit pas. Chaque pattern pousse theme.json
et les template parts jusqu'à leur limite utile.
Public visé : développeurs et prestataires qui construisent des thèmes FSE pour le secteur public, et chargés de communication qui veulent comprendre ce que leur prestataire peut mettre en place.
Compatibilité : WordPress 6.3 minimum. Les ajouts apportés par WordPress 7.0 (sortie prévue le 20 mai 2026) sont signalés quand ils simplifient un pattern.
Sommaire des 5 patterns
Lien d'évitement intégré à theme.json
Le lien d'évitement est le premier pattern à traiter parce qu'aucun bloc natif
ne le propose clé en main. L'encart du critère 12.7 donne une version avec CSS
dans une feuille de style séparée. Ce pattern va un cran plus loin : tout se pilote
depuis theme.json, sans feuille CSS additionnelle.
Principe
Le lien d'évitement est un bouton placé en première position dans le template part
Header. Il utilise une classe CSS personnalisée lien-evitement.
Les styles de masquage et d'apparition au focus sont déclarés dans theme.json
via la section styles.css au niveau racine.
Template part Header
Créez parts/header.html avec le bloc Bouton en toute première position.
<!-- wp:buttons {"className":"lien-evitement","layout":{"type":"flex","justifyContent":"left"}} -->
<div class="wp-block-buttons lien-evitement">
<!-- wp:button {"className":"is-style-outline"} -->
<div class="wp-block-button is-style-outline">
<a class="wp-block-button__link wp-element-button" href="#contenu-principal">
Aller au contenu principal
</a>
</div>
<!-- /wp:button -->
</div>
<!-- /wp:buttons -->
<!-- wp:site-title /-->
<!-- wp:navigation /--> Template Page
Dans templates/page.html, encapsulez le contenu
dans un bloc Groupe avec l'ancre contenu-principal
et la balise sémantique main.
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","anchor":"contenu-principal","layout":{"type":"constrained"}} -->
<main id="contenu-principal" class="wp-block-group">
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-content /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
Styles dans theme.json
Le champ styles.css accepte du CSS brut depuis
WordPress 6.2. Placez-y les règles de masquage du lien d'évitement.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"styles": {
"css": ".lien-evitement .wp-block-button__link { position: absolute; left: -9999px; top: 0; z-index: 100; } .lien-evitement .wp-block-button__link:focus { left: 1rem; top: 1rem; }"
}
} Pourquoi cette approche
Tout le thème est autodescriptible : pas de style.css
à maintenir, pas de dépendance à un build. Un autre prestataire qui reprend le thème
comprend immédiatement où se trouvent les styles d'accessibilité. Le lien reste invisible
pour les utilisateurs voyants et parfaitement fonctionnel au clavier.
Vérification : ouvrez la page sur le site. Appuyez sur Tab immédiatement après le chargement. Le bouton doit apparaître en haut à gauche avec un contraste visible. Appuyez sur Entrée : le focus doit sauter sur la zone de contenu principal.
Palette WCAG AAA verrouillée avec style variations
Le critère 3.3 demande un contraste AA minimum. Ce pattern livre une palette AAA (ratio 7:1 pour le texte standard, 4.5:1 pour le texte large), avec une variante sombre incluse. La saisie de couleurs libres est bloquée pour empêcher les rédacteurs de contourner la palette.
Palette principale dans theme.json
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"settings": {
"color": {
"custom": false,
"customDuotone": false,
"customGradient": false,
"defaultPalette": false,
"defaultGradients": false,
"defaultDuotone": false,
"palette": [
{ "slug": "fond", "color": "#ffffff", "name": "Fond" },
{ "slug": "texte", "color": "#1a1a1a", "name": "Texte (ratio 16.9:1)" },
{ "slug": "texte-secondaire", "color": "#4a4a4a", "name": "Texte secondaire (ratio 8.9:1)" },
{ "slug": "accent", "color": "#0052a3", "name": "Accent (ratio 8.6:1)" },
{ "slug": "accent-fond", "color": "#e8f0fa", "name": "Fond accent clair" },
{ "slug": "alerte", "color": "#a00000", "name": "Alerte (ratio 7.5:1)" }
]
}
}
}
Les trois options custom, customDuotone,
customGradient à false
bloquent la saisie libre. Les trois options defaultPalette,
defaultGradients, defaultDuotone
à false retirent les couleurs par défaut de WordPress,
qui ne sont pas toutes conformes.
Variante sombre dans styles/sombre.json
Une style variation sombre qui conserve les mêmes ratios.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"title": "Sombre",
"settings": {
"color": {
"palette": [
{ "slug": "fond", "color": "#0f0f0f", "name": "Fond" },
{ "slug": "texte", "color": "#f5f5f5", "name": "Texte (ratio 16.1:1)" },
{ "slug": "texte-secondaire", "color": "#c0c0c0", "name": "Texte secondaire (ratio 9.0:1)" },
{ "slug": "accent", "color": "#7eb3f0", "name": "Accent (ratio 8.9:1)" },
{ "slug": "accent-fond", "color": "#1a2e42", "name": "Fond accent sombre" },
{ "slug": "alerte", "color": "#ff8080", "name": "Alerte (ratio 7.2:1)" }
]
}
},
"styles": {
"color": {
"background": "var(--wp--preset--color--fond)",
"text": "var(--wp--preset--color--texte)"
}
}
}
Les slugs sont identiques à la palette principale. Quand un utilisateur bascule sur
la variante sombre depuis Apparence puis Éditeur puis Styles, tous les blocs qui
utilisent var(--wp--preset--color--accent) se
recolorent automatiquement.
Pourquoi cette approche
Un rédacteur qui insère un bloc Paragraphe ne peut littéralement pas choisir une couleur hors palette. La conformité est verrouillée à la source du thème, sans dépendre de la vigilance humaine à chaque publication. Les variations offrent un choix visuel sans compromis sur l'accessibilité.
Pour un travail rapide sur plusieurs combinaisons, L'Atelier WP génère des palettes
AAA déterministes directement exploitables dans theme.json :
latelier-wp.com
(lien externe qui s'ouvre dans un nouvel onglet)
Focus styles pilotés par theme.json
Le critère 10.7 demande un indicateur de focus visible et contrasté. Ce pattern utilise
les pseudo-classes supportées par theme.json depuis
WordPress 6.3 pour les éléments, et les pseudo-states des blocs élargis avec WordPress 7.0.
Focus sur les éléments globaux (WordPress 6.3+)
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"styles": {
"elements": {
"link": {
":focus": {
"outline": {
"style": "solid",
"width": "2px",
"color": "var(--wp--preset--color--accent)",
"offset": "2px"
}
},
":focus-visible": {
"outline": {
"style": "solid",
"width": "3px",
"color": "var(--wp--preset--color--accent)",
"offset": "3px"
}
}
},
"button": {
":focus": {
"outline": {
"style": "solid",
"width": "3px",
"color": "var(--wp--preset--color--accent)",
"offset": "2px"
}
}
}
}
}
}
La pseudo-classe :focus-visible permet de ne montrer
l'indicateur qu'au focus clavier, pas au clic souris. Les navigateurs modernes la
supportent tous.
Focus sur le bloc Bouton
WordPress 7.0 étend les pseudo-classes aux blocs eux-mêmes, pas seulement aux éléments. Le bloc Bouton peut désormais être stylé sur tous ses états.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"styles": {
"blocks": {
"core/button": {
"color": {
"background": "var(--wp--preset--color--accent)",
"text": "var(--wp--preset--color--fond)"
},
":hover": {
"color": { "background": "var(--wp--preset--color--texte)" }
},
":focus": {
"color": { "background": "var(--wp--preset--color--texte)" },
"outline": {
"style": "solid",
"width": "3px",
"color": "var(--wp--preset--color--alerte)",
"offset": "3px"
}
}
}
}
}
}
La couleur de l'outline utilise alerte pour maximiser
le contraste avec le fond du bouton, qui est déjà coloré. C'est une astuce souvent
oubliée : le focus ring d'un bouton doit contraster avec le bouton lui-même, pas avec
le fond de la page.
Pourquoi cette approche
Les focus styles survivent aux mises à jour du thème et des blocs. Un développeur qui modifie le CSS global ne peut pas casser accidentellement l'indicateur de focus, puisqu'il est défini au niveau du thème. Les pseudo-états 7.0 permettent de piloter hover, focus et active avec la même cohérence.
Navigation complète avec fil d'Ariane et landmarks
Ce pattern assemble le template part Header complet d'un site public conforme : lien d'évitement, fil d'Ariane, navigation principale, recherche. Il combine plusieurs critères dans une structure cohérente.
Template part Header complet
<!-- wp:buttons {"className":"lien-evitement"} -->
<div class="wp-block-buttons lien-evitement">
<!-- wp:button -->
<div class="wp-block-button">
<a class="wp-block-button__link wp-element-button" href="#contenu-principal">
Aller au contenu principal
</a>
</div>
<!-- /wp:button -->
</div>
<!-- /wp:buttons -->
<!-- wp:group {"tagName":"div","className":"header-top","layout":{"type":"flex","justifyContent":"space-between","flexWrap":"wrap"}} -->
<div class="wp-block-group header-top">
<!-- wp:site-title {"level":0} /-->
<!-- wp:search {"label":"Rechercher sur le site","showLabel":false,"buttonText":"Rechercher","buttonPosition":"button-inside"} /-->
</div>
<!-- /wp:group -->
<!-- wp:navigation {"ariaLabel":"Navigation principale"} /--> Template Page avec fil d'Ariane
WordPress 7.0 introduit un bloc Breadcrumbs natif qui génère automatiquement le fil d'Ariane sémantique correct.
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<!-- wp:group {"tagName":"main","anchor":"contenu-principal","layout":{"type":"constrained"}} -->
<main id="contenu-principal" class="wp-block-group">
<!-- wp:breadcrumbs {"showCurrentAsLink":false} /-->
<!-- wp:post-title {"level":1} /-->
<!-- wp:post-content /-->
</main>
<!-- /wp:group -->
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
Sur WordPress 6.x, le bloc Breadcrumbs n'existe pas. Le fil d'Ariane se construit alors
à la main avec un bloc Groupe balisé nav
et un attribut aria-label, ou avec une extension comme
Yoast SEO qui fournit son propre bloc fil d'Ariane.
Structure sémantique finale
Le rendu HTML produit respecte tous les landmarks attendus en audit.
<header>
<!-- lien d'évitement -->
<!-- site-title + search -->
<nav aria-label="Navigation principale">...</nav>
</header>
<main id="contenu-principal">
<nav aria-label="Vous êtes ici">...</nav>
<h1>...</h1>
<!-- contenu -->
</main>
<footer>...</footer> Vérification
Un audit automatique (axe-core, WAVE, pa11y) valide cette structure sans remonter d'erreur sur les landmarks. L'extension Landmarks du navigateur permet de visualiser les zones une par une.
Typographie fluide et respect des préférences système
Ce pattern combine trois exigences : la typographie fluide du critère 10.11, les règles
d'espacement du 10.12, et le respect de prefers-reduced-motion
du critère 13.8.
Typographie fluide complète
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"settings": {
"typography": {
"fluid": true,
"fontSizes": [
{ "slug": "xs", "size": "0.875rem",
"fluid": { "min": "0.875rem", "max": "1rem" }, "name": "Petit" },
{ "slug": "base", "size": "1rem",
"fluid": { "min": "1rem", "max": "1.125rem" }, "name": "Normal" },
{ "slug": "lg", "size": "1.25rem",
"fluid": { "min": "1.125rem", "max": "1.5rem" }, "name": "Grand" },
{ "slug": "xl", "size": "1.75rem",
"fluid": { "min": "1.5rem", "max": "2.25rem" }, "name": "Très grand" },
{ "slug": "2xl", "size": "2.5rem",
"fluid": { "min": "2rem", "max": "3.5rem" }, "name": "Titre" }
]
}
},
"styles": {
"typography": {
"fontSize": "var(--wp--preset--font-size--base)",
"lineHeight": "1.6"
},
"elements": {
"h1": { "typography": { "fontSize": "var(--wp--preset--font-size--2xl)", "lineHeight": "1.2" } },
"h2": { "typography": { "fontSize": "var(--wp--preset--font-size--xl)", "lineHeight": "1.3" } },
"h3": { "typography": { "fontSize": "var(--wp--preset--font-size--lg)", "lineHeight": "1.4" } }
}
}
}
La valeur lineHeight à 1.6 pour le corps de texte couvre
largement l'exigence du critère 10.12 (1.5 minimum quand un utilisateur force l'espacement).
Les hiérarchies de titres conservent une interligne plus serrée pour rester lisibles.
Respect de prefers-reduced-motion via styles.css
WordPress 6.2 a ouvert la section styles.css au CSS
brut. C'est le bon endroit pour les media queries d'accessibilité.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"styles": {
"css": "@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } }"
}
}
Cette règle neutralise toute animation ou transition pour les utilisateurs ayant configuré
cette préférence dans leur système. La directive !important
est nécessaire parce que cette règle doit l'emporter sur les animations définies par les
blocs et les extensions.
Pourquoi cette approche
L'utilisateur final contrôle sa préférence de mouvement au niveau de son système d'exploitation. Votre thème respecte ce choix sans qu'aucune action supplémentaire ne soit demandée au rédacteur. La typographie s'adapte à la largeur de l'écran sans débordement sur mobile, ni texte trop petit sur grand écran.
Pour aller plus loin
Ces cinq patterns couvrent les cas où theme.json
apporte une valeur systémique à l'accessibilité. Certains critères restent hors de
leur portée : les formulaires complexes au-delà du bloc Recherche, les médias avec
sous-titres, les composants interactifs custom. Ces sujets relèvent d'extensions dédiées
ou de développement spécifique.
-
Fiches critères RGAA de Boussole
Chaque fiche inclut un encart de mise en œuvre WordPress FSE quand un bloc natif ou un réglage y répond directement.
-
WordPress 7.0 Source of Truth (lien externe qui s'ouvre dans un nouvel onglet)
Documentation complète des nouveautés attendues le 20 mai 2026, dont plusieurs simplifient les patterns décrits ici.