Envoyer un mail à l’auteur
xavier at ultra-fluide.com

Ressources

Portes coulissantes en CSS (Sliding Doors of CSS).

par Douglas Bowman en octobre 2003, traduit en français par Xavier Boully.
L'article original publié en anglais sur A List Apart, a été traduit en français avec l'autorisation de l'auteur Douglas Bowman et de Jeffrey Zeldman au nom de A List Apart.

Une des possibilités méconnue de CSS repose sur la possibilité d'attacher des images à des calques, et ce faisant, de leur permettre de glisser les unes sur les autres pour la création d'effets particuliers. En l'état actuel de CSS2, ce mécanisme requière un élément HTML distinct pour chaque image. Mais dans bien des cas, le code introduit pour représenter les composants classiques de l'interface fournit déjà les éléments que nous pouvons exploiter pour cet usage.

La navigation par onglets en est un bon exemple. Il est temps en effet de revenir aux onglets dont la popularité va croissante pour la navigation principale. Puisque CSS est maintenant largement supporté, nous pouvons l'utiliser pour améliorer significativement la qualité et l'apparence des onglets sur nos sites web. Vous savez probablement que CSS permet de contrôler des listes simples. Vous avez probablement déjà vu de telles listes présentées sous forme d'onglets dans ce genre :

Onglets classiques en CSS, couleurs unies et coins carrés

Et si l'on prenait les mêmes balises HTML pour les transformer de cette façon :

Onglets stylisés avec coins arrondis et ombres pour effet de relief

Où se cache l'innovation ?

Beaucoup d'onglets basés sur CSS souffrent de ce même design un peu simple : rectangles de couleur unie, encadrement, bordure qui disparaît pour signifier l'onglet courant, et un changement de couleur au survol de la souris. Est-ce tout ce que CSS peut nous apporter ? Un simple assemblage de rectangles et de couleurs unies ?

On a vu beaucoup d'innovation sur le plan du design de la navigation web, avant même que CSS ne soit répandue. Formes créatives, combinaisons et dégradés de couleurs, imitation d'interfaces du monde réel. Cependant ces designs reposent souvent sur des images incrustant des contenus textuels et positionnées à l'aide de tableaux imbriqués. L'édition du texte ou la simple modification de l'ordre des onglets relèvent du tour de force, tout comme leur changement de dimension est impossible ou problématique pour la mise en page.

Un système de navigation en texte pur est bien plus facile à maintenir et se charge rapidement en comparaison de son équivalent sous forme d'images. Par ailleurs, même si nous pouvons utiliser l'attribut alt sur chaque image, le simple texte reste plus accessible puisqu'il peut être agrandi par les utilisateurs malvoyants. Il en résulte un retour des menus texte CSS pour le design web. Mais jusqu'à maintenant, les onglets en CSS ne sont pas sur le plan visuel aussi aboutis que ce qu'on a pu voir avant, et on ne souhaiterait pas forcement les proposer pour présenter les références d'un créatif ou d'un designer. Une technologie récente comme CSS devrait permettre de créer quelque chose de mieux, sans perdre sur la qualité du design par rapport à ce que l'on avait avec les images et les tableaux.

La technique de la "porte coulissante"

Une interface flexible, adaptable à la taille du texte, peut être créée en utilisant simplement deux images en arrière-plan. Pensez à ces deux images comme à deux battants coulissants (l'une pour la gauche l'autre pour la droite) formant ensemble une porte d'entrée. Les battants glissent ensemble, soit il se chevauchent largement et couvrent un espace étroit, soit au contraire ils se chevauchent à peine pour couvrir une surface plus importante. Le rectangle foncé du schéma indique la zone de recouvrement :

Le diagramme montre 2 ensembles de portes. Le premier, voit les 2 portes superposés sur une large bande pour prendre moins de place. Dans le second,les portes sont superposés sur une zone plus limitée et couvrent ainsi une plus grande largeur.

Les deux images ne sont pas identiques puisque chacune reprend une partie spécifique de l'onglet : droite du visuel pour l'une et gauche pour l'autre. L'image qui se trouve dessus ne doit pas cacher les parties spécifiques de l'autre image. Pour l'éviter l'image de dessus, celle de gauche dans notre exemple, sera la plus étroite possible pour ne reprendre que la partie spécifique gauche du visuel. En supposant par exemple qu'il s'agisse d'un onglet aux angles arrondis, l'image de gauche n'est pas plus large que la zone arrondie de l'angle gauche :

Ce diagramme montre une image gauche étroite qui isole l'angle arrondi gauche de l'onglet, puis cette même image en situation avec sa compagne de droite.

Si l'objet grossit au delà de ce qui est montré au dessus, du fait d'un changement de texte ou de taille de police, les images vont être repoussée et laisser apparaître un espace disgracieux. Nous devons donc gérer cette variation de taille. Dans quelle proportion notre objet peut-il grossir quand un texte est agrandi dans un navigateur ? Il parait réaliste de compter sur accroissement maximum de 300 % du texte de l'onglet. Nous devons donc étendre nos images de fond pour absorber cette variation. Pour revenir à notre exemple, nous ferons l'image de dessous (celle de droite) en 400x150 pixels et celle de devant en 9x150 pixels.

Gardons à l'esprit que la partie visible d'une image de fond correspond à la taille (contenu + padding) de l'élément à laquelle elle s'applique. Nos deux images sont ancrées aux coins extérieurs de leur élément respectif. Donc l'effet visible devrait être un onglet comme ceci :

Voici les 2 images superposées dont la taille présente une marge de sécurité dans le sens de la hauteur, et en largeur pour l'image de droite. Seule la partie visible prend forme pour représenter l'onglet.

Si l'onglet vient à s'agrandir, nos images glissent pour remplir une fenêtre visible plus étendue, une partie plus importante des images étant alors utilisée :

La partie visible présente cette fois un onglet plus grand pour lequel le glissement et la taille des images permettent une parfaite adaptation.

Les onglets personnalisés présentés au début de l'article ont été créés avec Photoshop pour obtenir un léger effet de relief. Nous représentons l'onglet sélectionné par un remplissage éclairci, et un bord plus foncé. Etant donnée la technique exposée précédemment, l'image doit ensuite être étendue en largeur et hauteur puis coupée en deux pour définir les parties gauche et droite :

Images droite et gauche pour notre onglet réel.

Il faut refaire la même chose avec l'image éclaircie de l'onglet courant. Lorsque nous avons les quatre images (1,2,3,4), nous pouvons passer au codage HTML et CSS de nos onglets.

Création de l'onglet

Si vous vous intéressez à la création de listes horizontales en CSS, vous remarquerez certainement au moins deux méthodes pour ranger un groupe d'items sur une ligne. Chacun a ses avantages et inconvénients. Mais les deux font intervenir certains aspects cachés de CSS qui peuvent rapidement devenir complexes. L'une de ces méthodes repose sur les boîtes en ligne, et l'autre sur les éléments flottants.

La première méthode, certainement la plus utilisée, revient à affecter à la propriété display de chaque item de liste la valeur "inline". Ce procédé est séduisant par sa simplicité. Appliqué à la technique des portes coulissantes, il fait malheureusement apparaître quelques problèmes de rendu sous certains navigateurs. Nous allons plutôt utiliser la propriété float des items de liste pour les placer en ligne, même si les éléments flottants peuvent aussi être frustrant, lorsque certains comportements étranges se manifestent ostensiblement en marge du bon sens. Pourtant une compréhension simplifiée de la gestion des éléments flottants multiples permet d'obtenir les effets souhaités.

Nous allons imbriquer une série d'éléments flottants dans un autre élément flottant servant de container. Cela permet d'encadrer complètement les items flottants, et de cette façon, de pouvoir ajouter une couleur de fond ou une image dernière nos onglets. Nous devons prendre garde à ce que l'élément qui suit nos onglets interrompe le flottement par la valeur "clear" de sa propriété float. Cela évitera ainsi aux onglets flottants d'affecter la position d'éventuels autres éléments de la page.

Commençons par le code HTML suivant :

<div id="header">
    <ul>
      <li><a href="#">Home</a></li>
      <li id="current"><a href="#">News</a></li>
      <li><a href="#">Produits</a></li>
      <li><a href="#">A propos</a></li>
    </ul>
</div>

Dans la pratique, la div #header peut aussi contenir bien d'autres choses telles qu'un logo ou un formulaire de recherche. Pour notre exemple la valeur de l'attribut href se réduira à # même si évidemment elle devrait représenter un fichier ou un répertoire en fonctionnement normal.

Nous commençons à introduire la présentation en rendant #header flottant. Ainsi nous serons certain que le container de la liste d'items sera flottant. Dès lors que cet élément est flottant, nous devons lui assigner une largeur à 100%. Nous ajoutons un fond jaune temporaire pour nous assurer que ce container s'étend suffisamment pour occuper l'arrière-plan des onglets. Nous proposons également des propriétés textuelles par défaut pour rendre la présentation uniforme :

#header {
    float:left;
    width:100%;
    background:yellow;
    font-size:93%;
    line-height:normal;
    }

Pour l'instant nous mettons également les propriétés margin/padding de la liste et des items à 0, et retirons la puce. Chaque item flotte à gauche :

#header ul {
    margin:0;
    padding:0;
    list-style:none;
    }
#header li {
    float:left;
    margin:0;
    padding:0;
    }

Nous mettons les liens en tant qu'éléments block, de façon à oublier les ennuis des boîtes en ligne.

#header a {
    display:block;
    }

Puis nous ajoutons l'image droite en arrière-plan de l'élément li (les modifications sont en gras)

 #header li {
    float:left;
    background:url("norm_right.gif")
      no-repeat right top;
    margin:0;
    padding:0;
    }

Avant de continuer avec l'image gauche, regardons ce que cela donne avec l'exemple 1. (Les règles CSS appliquées à l'élément body de l'exemple sont sans importance. Elles fixent simplement des valeurs génériques pour les marges, padding, couleurs et polices).

- - -

Nous pouvons maintenant placer l'image de gauche par dessus celle de droite en l'appliquant en arrière-plan de l'élément a (lien imbriqué dans chaque item). Nous rajoutons des padding pour élargir l'onglet et séparer le texte des bordures :

 #header a {
    display:block;
    background:url("norm_left.gif")
      no-repeat left top;
    padding:5px 15px;
    }

Cela conduit à l'exemple 2. L'onglet prend forme maintenant. Mais j'entends d'ici les utilisateurs de IE5/Mac qui se demande, "Que se passe-t-il ? Les onglets sont empilés verticalement et s'étendent pour occuper l'écran entier." Ne vous inquiétez pas nous y reviendrons sous peu. Pour l'instant, faites de votre mieux pour suivre, ou changez de navigateur momentanément si vous en avez un à porté de main, soyez sur que nous allons régler votre problème.

- - -

Nous avons nos onglets en place, il nous reste maintenant à modifier les images pour l'onglet sélectionné. Ciblons simplement un item et son lien avec id="current". Comme nous n'avons rien d'autre à modifier concernant l'arrière-plan, nous utilisons la propriété background-image :

 #header #current {
    background-image:url("norm_right_on.gif");
    }
 #header #current a {
    background-image:url("norm_left_on.gif");
    }

Nous avons besoin d'une bordure en bas de nos onglets. Cependant, appliquer la propriété border au container parent #header ne produirait pas l'effet voulu : nous souhaitons que l'onglet sélectionné se dégage des autres en passant par dessus la bordure. Nous créons donc une image supplémentaire avec cette bordure, et pendant que nous y sommes, nous ajoutons un léger dégradé pour obtenir ceci :

Bordure de bas de barre d'onglet

Nous appliquons cette image en arrière-plan du container #header (à la place de la couleur jaune) en la positionnant en bas de l'élément, et nous complétons avec une couleur d'arrière-plan qui se fond avec la couleur du haut de la nouvelle image. En même temps nous retirons le padding de l'élément body, et appliquons un padding de 10 pixels à gauche, à droite et en haut de la liste :

 #header {
    float:left;
    width:100%;
    background:#DAE0D2 url("bg.gif")
      repeat-x bottom;
    font-size:93%;
    line-height:normal;
    }
  #header ul {
    margin:0;
    padding:10px 10px 0;
    list-style:none;
    }

Pour compléter l'effet, il faut que l'onglet sélectionné passe par dessus la bordure. Vous penserez peut-être que nous allons appliquer une bordure à nos onglets qui correspond à la couleur de notre nouvelle image installée dans #header, puis changer la couleur de la bordure en blanc pour l'onglet sélectionné ? Mais cette méthode créerait "une marche" de 1 pixel que de bon yeux interprèteraient comme un défaut. Nous préférons décaler le padding de l'élément a pour obtenir un angle parfait sur l'onglet sélectionné qui apparaîtra ainsi :

Agrandissement de 2 versions d'onglets. La première montrant un défaut d'1 pixel en utilisant une bordure basse, la seconde montrant un angle à 90 degré sans défaut.

Nous diminuons le padding du bas des liens normaux de 1 pixels (5px - 1px = 4px), tout en maintenant ce pixel pour le lien de l'onglet sélectionné :

 #header a {
    display:block;
    background:url("norm_left.gif")
      no-repeat left top;
    padding:5px 15px 4px;
    }
  #header #current a {
    background-image:url("norm_left_on.gif");
    padding-bottom:5px;
    }

Ce changement permet à la bordure du bas d'être visible sous les onglets normaux, et cachée sous l'onglet sélectionné. Nous arrivons ainsi à l'exemple 3.

Finitions

Vous avez peut-être remarqué dans l'exemple précédent les coins blancs en haut des onglets. Ces coins opaques évitent que l'image de dessous n'apparaisse au travers de celle qui la couvre. En théorie nous devrions faire en sorte que ces coins se confondent avec l'arrière-plan. Mais nos onglets sont susceptibles de varier en taille et donc la couleur d'arrière-plan peut également varier. Finalement nous préférons changer les images pour leur donner des coins transparents. Il y a lieu si les courbes sont anti-aliasées d'introduire un contour dont la couleur est une moyenne de celle de l'arrière-plan.

Maintenant que les coins sont transparents, un bout de l'image de droite apparaît à l'angle gauche. Pour corriger ce défaut, nous introduisons un padding gauche à l'élément item équivalent à la largeur de l'image de gauche (9px). Il faut également soustraire cette même valeur sur l'élément a si l'on souhaite conserver le texte centré (15px - 9px = 6px) :

 #header li {
    float:left;
    background:url("right.gif")
      no-repeat right top;
    margin:0;
    padding:0 0 0 9px;
    }
  #header a {
    display:block;
    background:url("left.gif")
      no-repeat left top;
    padding:5px 15px 4px 6px;
    }

Cependant, nous ne pouvons pas laisser les choses en l'état puisque l'image gauche est maintenant repoussée à 9 pixels du bord gauche de l'onglet. Mais comme nous avons maintenant les bords des deux images exactement l'un contre l'autre, il n'est plus nécessaire de garder l'image de gauche au-dessus. Nous pouvons donc inverser l'ordre des images et échanger les éléments auxquels elles sont affectées. Cette inversion vaut également pour les images de l'onglet sélectionné.

  #header li {
    float:left;
    background:url("left.gif")
      no-repeat left top;
    margin:0;
    padding:0 0 0 9px;
    }
  #header a, #header strong, #header span {
    display:block;
    background:url("right.gif")
      no-repeat right top;
    padding:5px 15px 4px 6px;
    }
  #header #current {
    background-image:url("left_on.gif");
    }
  #header #current a {
    background-image:url("right_on.gif");
    padding-bottom:5px;
    }

On arrive ainsi à l'exemple 4. Notons que l'ajustement fait pour obtenir les coins transparents conduit à la présence d'une petite zone insensible à la souris sur la gauche de l'onglet. Cette zone est en dehors du texte et se remarque à peine. Utiliser des images transparentes n'est pas strictement obligatoire. Pour ceux qui préfèrent éviter la zone non cliquable, il est toujours possible de revenir à une couleur de fond sur les angles, et à une couleur unie pour l'arrière-plan. Nous conserverons dans la suite nos coins transparents.

- - -

Nous ferons les derniers ajustements d'un coup : texte en gras, couleur de texte en marron pour les onglets normaux, couleur de texte gris foncé pour l'onglet sélectionné, suppression du soulignement des liens et changement de couleur du texte au survol de la souris. Et voici maintenant l'exemple 5.

Hack pour la compatibilité

Après l'exemple 2, nous avons soulevé un problème avec IE5/Mac pour qui chaque onglet prend la largeur entière du navigateur, forçant ainsi le menu à s'empiler verticalement. Ce n'est pas vraiment ce que nous attendions.

Dans la plus part des navigateurs, rendre un élément flottant agit sur cet élément en ajustant sa taille à la taille minimum requise pour contenir son contenu. Si par exemple un élément flottant contient (ou est lui même) une image sa largeur va s'adapter à la largeur de l'image. S'il contient simplement du texte, la largeur de l'élément flottant va prendre la longueur de la plus longue ligne insécable.

Un grain de sable perturbe ce schéma avec IE5/Mac lorsqu'un élément block de largeur automatique est introduit dans un élément flottant. Les autres navigateurs vont réduire le flottant autant que possible sans se soucier de l'élément block qu'il contient. Mais IE5/Mac n'adapte pas la largeur du flottant dans cette circonstance. Au contraire il étend le flottant et l'élément block à la largeur maximale disponible. Pour contourner ce problème nous devons rendre les liens flottants pour IE/Mac à l'exclusion des autres navigateurs. Nous utilisons le hack de l'antislash commenté pour différentier la règle servie à IE/Mac :

  #header a {
    float:left;
    display:block;
    background:url("right.gif")
      no-repeat right top;
    padding:5px 15px 4px 6px;
    text-decoration:none;
    font-weight:bold;
    color:#765;
    }
  /* Le hack de l'antislash commenté
     cache cette règle à IE5-Mac \*/
  #header a {float:none;}
  /* End IE5-Mac hack */

Note du traducteur : le hack contraposé eut été légèrement plus simple :

  #header a {
    /* Pour IE Mac uniquement \*//*/   
    float:left;
    /**/
    display:block;
    background:url("right.gif")
      no-repeat right top;
    padding:5px 15px 4px 6px;
    text-decoration:none;
    font-weight:bold;
    color:#765;
    }

Les navigateurs IE5/Mac doivent maintenant afficher correctement les onglets de notre exemple 6. Rien n'a changé pour les autres navigateurs. Notons également que IE5.0/Mac présente de nombreux bogues qui ont été corrigés dans la version IE5.1/Mac. La technique des portes coulissantes souffre tellement avec la version 5.0 que des contournements ne peuvent plus être envisagés. Cependant la version IE5.1/Mac est disponible depuis bien longtemps, donc le pourcentage de Macs OS 9 utilisant IE5.0 doit être quasiment nul.

Variations

Nous venons de parcourir la technique des "portes coulissantes" afin de créer une navigation par onglets basée sur une simple liste de liens au style légèrement personnalisé. Le menu ainsi obtenu est simple à maintenir, son chargement en est rapide et la taille du texte peut être modifiée sans casser le design. Est-il encore nécessaire de mentionner combien ce procédé est souple et s'adapte quelque soit la sophistication du design envisagé ?

Cette technique n'a pas de limite hormis celles que notre imagination pourrait introduire. Notre dernier exemple ne présente qu'une possibilité, mais cela ne doit pas nous restreindre.

Par exemple, il n'y a pas d'obligation à ce que les onglets soient symétriques. J'ai rapidement créé une version 2 qui remplace l'effet de relief par des couleurs unies, introduit des bordures anguleuses et nettement plus travaillées sur le coté gauche. Il est même possible d'échanger l'ordre droite/gauche des images comme le montre cette version 3. Avec un peu d'attention lors de la création des images, il est même possible d'abandonner la bordure du bas au profit d'un ajustement des images de l'onglet et de l'arrière-plan comme présenté dans cette version 3 d'inspiration Art-Déco. Si votre navigateur permet le changement de feuille de style CSS, vous pourrez examiner ces 3 versions sur ce document principal.

Il est possible d'obtenir d'autres effets au-delà de ce qui a été démontré ici. Dans nos exemples, la couleur du texte change au survol de la souris, mais l'intégralité des images pourraient être modifiées pour obtenir des effets de rollover. Dès lors que deux éléments imbriqués sont présents dans le code HTML, CSS peut être utilisée pour introduire des images en arrière-plan et obtenir des effets que nous n'avons même pas commencé à imaginer. Nous avons réalisé des onglets horizontaux, mais les portes coulissantes peuvent être introduites dans plein d'autres situations. Que pourriez-vous en faire de votre coté ?


Agence de communication Ultra-Fluide : 01 47 70 23 32 - contact at ultra-fluide.com - 44 rue Richer 75009 Paris.