Fait dire aux boutons repliables s'ils sont ouverts ou fermés

« aria-expanded="@_ouvert" » ne rend pas « true » ou « false » : Blazor y voit
un attribut de présence, comme disabled. Vrai donnait aria-expanded="", faux
retirait l'attribut — dans les deux cas, un lecteur d'écran n'apprenait rien,
et un bouton replié ne s'annonçait plus comme repliable.

Le défaut valait pour les six boutons de l'application. Une fonction nommée
remplace le booléen nu, qui se relisait comme correct.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mathieu
2026-08-22 01:39:28 +02:00
co-authored by Claude Opus 5
parent e85867014c
commit c168959e12
8 changed files with 63 additions and 13 deletions
+1 -1
View File
@@ -16,7 +16,7 @@
<div class="arbre-ligne">
@if (Enfants.Count > 0)
{
<button type="button" class="arbre-plier" aria-expanded="@Deplie"
<button type="button" class="arbre-plier" aria-expanded="@Aria.Etat(Deplie)"
aria-label="@($"{(Deplie ? "Replier" : "Déplier")} « {Serie.Titre} »")"
@onclick="Basculer">
<span aria-hidden="true">@(Deplie ? "▾" : "▸")</span>
@@ -13,10 +13,9 @@
*@
<li class="groupe-serie" @key="Entree.Serie!.Id">
<div class="groupe-serie-entete">
@* ⚠️ « aria-expanded="@Deplie" » ne marche PAS : Blazor traite un booléen comme un attribut
de présence et rend « aria-expanded="" ». L'état doit être écrit en toutes lettres. *@
@* ⚠️ Aria.Etat, et non le booléen nu : voir la mise en garde qu'il porte. *@
<button type="button" class="groupe-serie-plier"
aria-expanded="@(Deplie ? "true" : "false")"
aria-expanded="@Aria.Etat(Deplie)"
aria-label="@($"{(Deplie ? "Replier" : "Déplier")} « {Entree.Serie!.Titre} »")"
@onclick="Basculer">
<span aria-hidden="true">@(Deplie ? "▾" : "▸")</span>
+1 -1
View File
@@ -61,7 +61,7 @@
}
<button type="button" class="bandeau-icone bandeau-bascule" @onclick="BasculerMenu"
aria-expanded="@_menuOuvert" aria-controls="menu-principal"
aria-expanded="@Aria.Etat(_menuOuvert)" aria-controls="menu-principal"
aria-label="@(_menuOuvert ? "Fermer le menu" : "Ouvrir le menu")">
<span aria-hidden="true">@(_menuOuvert ? "\u2715" : "\u2630")</span>
</button>
+2 -2
View File
@@ -165,7 +165,7 @@ else if (_bibliographie is { } biblio)
<div class="actions-formulaire">
<button type="button" class="bouton bouton-discret"
@onclick="() => _filtresOuverts = !_filtresOuverts"
aria-expanded="@_filtresOuverts">
aria-expanded="@Aria.Etat(_filtresOuverts)">
Filtrer (@NombreFiltres)
</button>
@@ -302,7 +302,7 @@ else if (_bibliographie is { } biblio)
{
<button type="button" class="carte-titre oeuvre-titre-bouton"
@onclick="() => BasculerOeuvre(oeuvre.Titre)"
aria-expanded="@_oeuvresOuvertes.Contains(oeuvre.Titre)">
aria-expanded="@Aria.Etat(_oeuvresOuvertes.Contains(oeuvre.Titre))">
@oeuvre.Titre
</button>
}
+1 -1
View File
@@ -15,7 +15,7 @@
<h1 class="titre-page">Catalogue</h1>
<button type="button" class="bouton bouton-discret bouton-compact"
aria-expanded="@_filtresOuverts" aria-controls="filtres-catalogue"
aria-expanded="@Aria.Etat(_filtresOuverts)" aria-controls="filtres-catalogue"
@onclick="() => _filtresOuverts = !_filtresOuverts">
Filtrer@(FiltresActifs > 0 ? $" ({FiltresActifs})" : "")
</button>
+22
View File
@@ -0,0 +1,22 @@
namespace MaBibli.Client.Services;
/// <summary>
/// Les états ARIA, écrits en toutes lettres.
/// </summary>
/// <remarks>
/// ⚠️ <b><c>aria-expanded="@_ouvert"</c> ne fait pas ce qu'on croit.</b> Blazor traite un booléen
/// comme un attribut de <i>présence</i> — à la manière de <c>disabled</c> ou <c>hidden</c> : vrai
/// rend <c>aria-expanded=""</c>, faux <b>retire l'attribut</b>. Or ARIA attend les chaînes
/// « true » et « false », et un lecteur d'écran ne sait lire ni l'une ni l'autre de ces deux
/// formes : replié, le bouton ne s'annonce plus comme repliable du tout.
/// <para>
/// Le défaut est passé inaperçu cinq fois (2026-08-22) parce qu'il ne se voit pas à l'écran et
/// qu'aucun test ne rend de balisage. D'où cette fonction : elle se remarque à la relecture là
/// où un booléen nu se lit comme correct.
/// </para>
/// </remarks>
public static class Aria
{
/// <summary>« true » ou « false », jamais un attribut de présence.</summary>
public static string Etat(bool valeur) => valeur ? "true" : "false";
}