Effet de vague sur une liste d'items

Le bling-bling sévit partout, y-compris dans le développement web. Exemple : les items de liste du pied-de-page du blog {Sciences²} (dont la lecture est par ailleurs fortement recommandée). Autant j'aime l'effet rendu, autant la manière de l'obtenir me laisse, comment dire, perplexe...

Jetons d'abord un oeil au code HTML d'un item de liste :

<li class="monthly-archive">
    <a href="http://sciences.blogs.liberation.fr/home/2010/10/index.html">
        <span class="monthly-archive-out">octobre 2010</span>
        <span class="monthly-archive-over" style="width: 0px; padding-left: 0px; display: block;">
            <span class="texte_over">octobre 2010</span>
            <img width="19px" height="15px" class="image_over" src="/test/images/fleche_noir.gif" alt="fleche">
        </span>
    </a>
</li>
Item de liste du pied-de-page du site {sciences²}.

Ouch ! Plutôt compliqué comme code, bourré d'éléments « artificels » (avec duplication de contenu !!!) qui n'ont qu'un seul but : pouvoir rendre l'effet. Effet qui doit être ensuite géré en javascript (mais le code artificel est présent « en dur » ; on se demande pourquoi !), avec JQuery et YUI semble-t-il (je n'ai pas cherché plus loin). Bref, une bonne grosse usine à gaz curieusement agencée(1).

Tâchons de voir comment implémenter quelque chose de plus simple et de plus propre ! Je me suis contenté d'une reproduction approximative mais suffisamment fidèle de l'effet, écrite en moins de 10 minutes, sans trop se faire de noeuds au cerveau et basée sur une fonctionnalité des CSS 3 : les transitions.

Voyons d'abord le code HTML. Au risque d'enfoncer des portes ouvertes, rappelons quelques évidences (car cela n'est apparemment pas encore compris par tout le monde) : le HTML est un langage de balisage qui permet de structurer un document web. Dans l'absolu, le document web ne devrait être constitué que du code HTML utile à organiser son contenu (titres, paragraphes, listes, etc.), la présentation et l'interaction étant ensuite pris en charge par les CSS et le javascript. Dans la pratique, il est parfois nécessaire de surcharger le code pour obtenir l'effet ou la présentation escompté(e), mais toujours en essayant de limiter au strict nécessaire ces ajouts et si possible sans mettre à mal le contenu(2).

Dans le cas qui nous occupe ici, nous travaillons sur une liste d'items faisant office de menu de navigation. Inutile d'ajouter des span et que sais-je d'autres, une liste à puces et des liens feront amplement l'affaire. Nous définissons juste une classe à la liste pour y appliquer des styles spécifiques (mais même cela pourrait être omis) :

<ul class="wave">
    <li><a href="#">Item 1</a></li>
    <li><a href="#">Item 2</a></li>
    <li><a href="#">Item 3</a></li>
    <li><a href="#">Item 4</a></li>
    <li><a href="#">Item 5</a></li>
    <li><a href="#">Item 6</a></li>
    <li><a href="#">Item 7</a></li>
    <li><a href="#">Item 8</a></li>
    <li><a href="#">Item 9</a></li>
    <li><a href="#">Item 10</a></li>
</ul>
Code HTML simplifié d'un item.

Voyons ensuite la présentation : nous allons jouer sur la variation de la largeur du lien pour simuler l'effet ; les pseudo-éléments nous permettront par ailleurs la flèche terminale.

/*
    Effect de vague sur une liste d'items
    2011-09-16, Rui Nibau
    http://omacronides.com/notes/2011-09-16/
*/
.wave {
    text-align: left;
    background: #333;
    margin: 0 auto;
    padding: 0 2px;
    width: 150px;
    border: 1px solid #000;
}

.wave li {
    position: relative;
    list-style: none;
    margin: 2px 0;
    background-color: #191919;
}

.wave a {
    text-decoration: none;
    display: inline-block;
    padding: 0;
    color: #fff;
    background-color: #fff;
    white-space: pre;
    width: 0;
    -webkit-transition: color 0.5s, width 0.5s;
       -moz-transition: color 0.5s, width 0.5s;
         -o-transition: color 0.5s, width 0.5s;
            transition: color 0.5s, width 0.5s;
}
.wave a:hover {
    text-decoration: none;
}

.wave a:focus,
.wave li:hover > a {
    color: #191919;
    width: 150px;
    -webkit-transition: width 0.1s;
       -moz-transition: width 0.1s;
         -o-transition: width 0.1s;
            transition: width 0.1s;
}

.wave a:before {
    display: inline-block;
    content:"";
    width: 5px;
}

.wave a:after {
    position: absolute;
    right: 5px;
    color: #191919;
    padding: 0 0 0 5px;
    border-left: 1px solid #191919;
    content: "\279c";
}
Code CSS pour simuler l'effet.

Et le résultat : Démonstration

Quelques remarques sur ce code, testé sous Firefox 6.02, Opera 11.51 et Chromium 12 :

  • Il y a évidemment bien d'autres manières de faire : j'avais par exemple commencé par faire varier la position d'une image de fond blanche au lieu de jouer sur la largeur.
  • Nous appliquons l'effet non seulement quand on passe la souris au-dessus des items mais aussi quand les liens ont le focus, pour pouvoir facilement naviguer dans le menu au clavier.
  • Cette solution a un défaut : comme elle utilise les transitions CSS, l'effet dynamique ne sera pas rendu sous IE ou avec d'anciennes versions des autres navigateurs web (mais le menu sera utilisable). 10 minutes de plus, une dizaine de lignes javascript et une image de fond peuvent facilement réctifier cette faiblesse !

CSS transitions. Mozilla Developer Network,

OLSSON, Tommy. Visual Vs. Structural. Accessites.org, . Une petite leçon de rattrapage.