Menu déroulant horizontal
Extrait de code pour un menu déroulant, horizontal et adaptatif avec bouton dit « hamburger ».
Règles d’implémentation pour l’accessibilité
- L’exemple présenté ici est celui d’un menu hamburger avec menu déroulant (rubriques parentes et sous-rubriques).
- La page affichée est celle correspondant au lien 3 de la rubrique 2.
- Le bouton hamburger est une icône : il est donc masqué aux logiciels de synthèse vocale par l’attribut aria
aria-hidden="true"
et un texte significatif est proposé pour ces logiciels mais caché à la vue via le style csssr-only
. - Le bouton de rubrique parente permettant d’afficher le sous-menu correspondant :
- porte l’attribut aria
aria-controls
qui fera référence à l’ìd
posé sur la liste contenant le sous-menu ; - porte l’attribut aria
aria-haspopup="true"
pour signifier aux technologies d’assistance qu’un sous-menu est présent ; - porte l’attribut aria
aria-expanded
qui prend la valeurtrue
si le sous-menu est affiché,false
si le sous-menu n’est pas affiché.
- porte l’attribut aria
- Pour que ce menu fonctionne, du code javascript sera nécessaire. Le script gère :
- le changement d’état
aria-expanded
; l’affichage/disparition du sous-menu est alors géré en CSS ; - la disparition du sous-menu quand l’utilisateur appuie sur la touche “Echap” ou clique n’importe où dans la page. De plus, le focus revient sur le bouton à l’origine de l’action.
- le changement d’état
Visuel du menu proposé
Le menu proposé est celui du site “Sofève Concept”
-
Menu replié en vue supérieure à 1200px de large
-
Menu déplié en vue supérieure à 1200px de large
-
Menu replié en vue responsive (largeur d’écran inférieure à 1200px)
-
Menu déplié en vue responsive (largeur d’écran inférieure à 1200px)
Extraits de code
Code HTML
<nav role='navigation' class="navbar" aria-label="Menu principal">
<button aria-haspopup="true" aria-expanded="false" id="hamburger" aria-controls="menu">
<span class="sr-only">Menu</span></button>
<ul id="menu">
<li class="home"><a href="xxx">
<i class="fa fa-home" aria-hidden="true"></i>
<span class="responsive">Accueil</span></a>
</li>
<li>
<button aria-haspopup="true" aria-expanded="false" aria-controls="menu-1">Première rubrique</button>
<ul id="menu-1">
<li><a href="xxx">Veniam nulla sunt ullamco commodo</a></li>
<li><a href="xxx">commodo nostrud consectetur</a></li>
<li><a href="xxx">Elit do ex commodo culpa tempor</a></li>
</ul>
</li>
<li><button aria-haspopup="true" aria-expanded="false" aria-controls="menu-2" aria-current="true">Deuxième rubrique</button>
<ul id="menu-2">
<li><a href="xxx">Veniam nulla sunt ullamco commodo</a></li>
<li><a href="xxx">commodo nostrud consectetur</a></li>
<li><a href="xxx" aria-current="page">La page active</a></li>
<li><a href="xxx">Elit do ex commodo culpa tempor</a></li>
<li><a href="xxx">voluptate qui mollit do cillum id</a></li>
</ul>
</li>
<li><button aria-haspopup="true" aria-expanded="false" aria-controls="menu-3">Troisième rubrique</button>
<ul id="menu-3">
<li><a href="xxx">Veniam nulla sunt ullamco commodo</a></li>
<li><a href="xxx">commodo nostrud consectetur</a></li>
<li><a href="xxx">voluptate qui mollit do cillum id</a></li>
<li><a href="xxx">Exercitation nisi labore laborum</a></li>
</ul>
</li>
</ul>
</nav>
Code CSS
Pour adapter la couleur de la barre de navigation et des liens, modifier les codes couleurs dans la déclaration :root
.
:root {
--FONT-FAMILY-texte: Arial, Helvetica, sans-serif;
--FONT-FAMILY-titre: Arial, Helvetica, sans-serif;
--CADRATIN-base: 1em;
--WHITE-color: #FFFFFF;
--WHITE-TRANSPARENT-color: rgba(255, 255, 255, 0.8);
--BLACK-color: #000000;
--BLACK-TRANSPARENT-color: rgba(0, 0, 0, 0.8);
--BANDEAU-color: #474747;
--BANDEAU-ACTIVE-color: #87c300;
--BANDEAU-ACTIVE-CONTRAST-color: #000;
--BANDEAU-TRANSPARENT-color: rgb(71, 71, 71, 0.8);
--LINK-color: #4A6B00;
--OUTLINE-color: 3px solid #588000;
--BORDER-color: #575757;
--SHADOW: 0 0.5rem 1rem #757575 !important;
}
/** Navbar - Barre de navigation horizontale principale et menu déroulant */
.sr-only {
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px) !important;
-webkit-clip-path: inset(50%) !important;
clip-path: inset(50%) !important;
height: 1px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
width: 1px !important;
white-space: nowrap !important;
}
nav[role="navigation"].navbar {
background-color: var(--BANDEAU-color);
color: var(--WHITE-color);
min-height: 2.5em;
}
nav[role="navigation"].navbar .responsive {
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
nav[role="navigation"].navbar button#hamburger {
display: none;
}
nav[role="navigation"].navbar button#hamburger::before {
font-family: 'FontAwesome';
content: "\f0c9";
}
nav[role="navigation"].navbar ul {
margin: 0;
padding: 0;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
list-style: none;
}
nav[role="navigation"].navbar ul button[aria-expanded='false']+ul {
display: none;
}
nav[role="navigation"].navbar ul li {
text-align: center;
border-right: 1px solid var(--WHITE-color);
}
nav[role="navigation"].navbar ul li a[aria-current="page"],
nav[role="navigation"].navbar ul li a,
nav[role="navigation"].navbar ul li button {
padding: 0.75rem 1.5rem .5rem 1.5rem;
font-family: var(--FONT-FAMILY-texte);
font-size: 1rem;
line-height: 1em;
color: var(--WHITE-color);
}
nav[role="navigation"].navbar ul li a[aria-current="page"],
nav[role="navigation"].navbar ul li button[aria-current="true"] {
background: var(--BANDEAU-ACTIVE-color);
color: var(--BANDEAU-ACTIVE-CONTRAST-color);
font-weight: bold;
}
nav[role="navigation"].navbar ul li a {
display: block;
text-align: left;
text-decoration: none;
}
nav[role="navigation"].navbar ul li button {
background-color: transparent;
border: 0;
cursor: pointer;
width: 100%;
text-align: left;
}
nav[role="navigation"].navbar ul li button::after {
font-family: 'FontAwesome';
content: "\f078";
float: right;
padding-left: .5em;
}
nav[role="navigation"].navbar ul li a:hover,
nav[role="navigation"].navbar ul li a:focus,
nav[role="navigation"].navbar ul li button:hover,
nav[role="navigation"].navbar ul li button:focus,
nav[role="navigation"].navbar ul li button[aria-expanded='true'] {
background: var(--BANDEAU-ACTIVE-color);
color: var(--BANDEAU-ACTIVE-CONTRAST-color);
text-decoration: underline;
}
nav[role="navigation"].navbar ul li button[aria-expanded="true"]::after {
transform: rotate(-180deg);
}
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul {
display: block;
box-shadow: var(--SHADOW);
background-color: white;
position: absolute;
margin-top: 0;
z-index: 1030;
}
/*si on veut un triangle vers le bas*/
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul::before {
content: "";
display: block;
border: 0.5em solid var(--WHITE-color);
border-top-color: var(--BANDEAU-ACTIVE-color);
position: absolute;
top: 0;
left: 0.25em;
}
/** style pour les sous-menus */
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul {
padding-bottom: .5em;
}
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul li:first-of-type {
padding-top: .5em;
}
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul li a[aria-current="page"],
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul li a {
color: var(--LINK-color);
background: transparent;
}
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul li a:hover,
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul li a:focus {
text-decoration: underline;
background-color: transparent;
}
nav[role="navigation"].navbar ul button[aria-expanded='true'] + ul li a[aria-current="page"] {
font-weight: bold;
}
nav[role="navigation"].navbar ul button[aria-expanded='true'] + ul li a[aria-current="page"]::before{
content: "";
float: left;
height: 1em;
margin-left: -.5em;
margin-right: .25em;
width: 3px;
background-color: var(--LINK-color);
}
nav[role="navigation"].navbar ul button[aria-expanded='true'] + ul li a[aria-current="page"]:first-of-type a{
padding-top: .75em;
}
/** Responsive */
@media screen and (max-width: 1200px) {
nav[role="navigation"].navbar button#hamburger {
display: block;
background-color: transparent;
border:0;
color: var(--WHITE-color);
font-size: 1.2em;
font-weight: bold;
padding: 0.25em 1em 0.5em 1em;;
cursor: pointer;
}
nav[role="navigation"].navbar button#hamburger:hover {
background: #B0AEAE;
color: #191A1A;
}
nav[role="navigation"].navbar button[aria-expanded=false]#hamburger + ul {
display: none;
}
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul::before {
content: none;
}
nav[role="navigation"].navbar ul {
flex-direction: column;
}
nav[role="navigation"].navbar ul li {
text-align: left;
border: 0;
}
nav[role="navigation"].navbar ul li:not(:last-child) {
border-bottom: 1px solid var(--WHITE-color);
}
nav[role="navigation"].navbar .icon-home {
display: none;
}
nav[role="navigation"].navbar .responsive {
position: static;
width: auto;
height: auto;
overflow: visible;
clip: auto;
white-space: normal;
}
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul {
display: block;
box-shadow: none;
background-color: var(--WHITE-TRANSPARENT-color);
position: static;
margin-top: 0;
z-index: 1000;
}
nav[role="navigation"].navbar button[aria-expanded='true'] + ul li ul li:not(:last-child){
border-bottom:1px solid var(--WHITE-color);
}
nav[role="navigation"].navbar ul button[aria-expanded='true']+ul li {
border: 0;
}
}
Code javascript
Le script ci-dessous sera intégré dans la page HTML via l’écriture suivante :
<script src="/js/script.js"></script>
Fichier js/script.js
/**
* Fonction pour afficher le sous-menu au clic de souris
*/
function hamburger() {
var buttonHamburger = document.getElementById("hamburger");
// Au clic sur le bouton, on modifie la valeur de l'attribut aria-expanded (true ou false)
// L'affichage/disparition du sous-menu est ensuite géré en CSS.
buttonHamburger.addEventListener('click', function (e) {
let state = buttonHamburger.getAttribute('aria-expanded');
state === 'false' ? buttonHamburger.setAttribute('aria-expanded', 'true') : buttonHamburger.setAttribute('aria-expanded', 'false');
});
// On gère la disparition du sous-menu quand l'utilisateur appuie sur le bouton "Echap" de son clavier.
// On s'assure que le focus clavier revient bien sur le bouton "Hamburger".
document.addEventListener('keydown', evt => {
var isEchap = false;
if ("key" in evt) {
isEchap = (evt.key === "Escape" || evt.key === "Esc");
} else {
isEchap = (evt.keyCode === 27);
}
if (isEchap) {
buttonHamburger.setAttribute('aria-expanded', 'false')
buttonHamburger.focus()
}
});
}
hamburger()
// Le menu et sous-menu
function menuEtSousMenuDeroulant() {
var theButtons = document.querySelectorAll('.navbar button[aria-expanded]:not(#hamburger)');
for (i = 0; i < theButtons.length; i++) {
// apparition/disparition du sous-menu au clic
// L'affichage/disparition du sous-menu est ensuite géré en CSS.
theButtons[i].addEventListener('click', function (e) {
var thisButton = e.target;
for (j = 0; j < theButtons.length; j++) {
if (thisButton !== theButtons[j])
theButtons[j].setAttribute('aria-expanded', 'false')
}
var stateButton = thisButton.getAttribute('aria-expanded') === 'false' ? true : false;
thisButton.setAttribute('aria-expanded', stateButton);
});
// disparition des sous-menu quand changement de focus sur bouton
theButtons[i].addEventListener('focus', function (e) {
var thisButton = e.target;
for (j = 0; j < theButtons.length; j++) {
if (thisButton !== theButtons[j])
theButtons[j].setAttribute('aria-expanded', 'false')
}
});
}
// disparition du sous-menu et focus sur le bouton correspondant au sous-menu quand l'utilisateur appuie sur le bouton "Echap" de son clavier.
document.addEventListener('keydown', evt => {
var isEchap = false;
if ("key" in evt) {
isEchap = (evt.key === "Escape" || evt.key === "Esc");
} else {
isEchap = (evt.keyCode === 27);
}
if (isEchap) {
for (j = 0; j < theButtons.length; j++) {
if (theButtons[j].getAttribute('aria-expanded') === 'true') {
theButtons[j].setAttribute('aria-expanded', 'false');
theButtons[j].focus()
}
}
}
});
}
menuEtSousMenuDeroulant()
// Fermeture de tous les sous-menus via clic dans le body
function fermerMenuViaClicBody(event) {
var theButtons = document.querySelectorAll('.navbar button[aria-expanded]');
if (!event.target.matches('.navbar button[aria-expanded]')) {
for (i = 0; i < theButtons.length; i++) {
theButtons[i].setAttribute('aria-expanded', 'false');
}
}
}
document.body.addEventListener('click', fermerMenuViaClicBody, false);