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

Ressources

Template CSS 2 : modèle 3 colonnes auto adaptable.

Ajout fin 2004.

L'article ci-dessous a été écrit en 2003, il a beaucoup vieilli, et compte tenu de nouvelles astuces découvertes depuis, le modèle présenté pourrait être grandement simplifié.
Il mériterait d'être réécrit, en attendant, vous trouverez sur cette autre page quelques hacks CSS récents qui pourront simplifier le travaille du webmaster.

Sommaire.

Nous présentons dans cette rubrique un template de page web classique. Ce template reste simple, mais il supporte d'être étendu pour une présentation plus sophistiquée. Nous respectons complètement CSS 2 et XHTML strict pour construire ce modèle.
Nous illustrons sur cet exemple les difficultés de mise au point d'une page web compte tenu des nombreux défauts (bugs et non respect des standards) des principaux navigateurs. A cette occasion, vous y trouverez également les moyens de contourner chacun des problèmes rencontrés.
La compatibilité de ce template est assurée avec Internet Explorer 5 et 6 sur PC, Internet Explorer 5 sur Mac, Mozilla 1.4, Netscape Navigator 7, Safari 1.0.

Cette rubrique constitue donc un bon tutorial pour se lancer dans la mise en page web avec CSS. Ressources disponibles :

Présentation du modèle

Notre page web va se diviser en cinq zones :

Nous souhaitons schématiquement obtenir ceci :

schema template tutorial CSS2

Nous posons en plus les contraintes suivantes :

L'objectif est de bâtir sur ces contraintes un modèle CSS qui fonctionne sur l'ensemble des pages d'un site web, donc si possible quelles que soient la taille du contenu ou la largeur de la fenêtre du navigateur (si ces paramètres restent à des valeurs raisonnables).

Explications et commentaires concernant le code

Nos commentaires s'appuient sur ce code.

Organisation générale de la page

Un coup d'oeil sur la partie XHTML (balise body) informe rapidement sur la mise en page générale. Au plus haut niveau de l'arbre XHTML, notre page se compose de deux éléments: l'entête .header et un élément principal .main.
L'élément principal .main va hériter d'une hauteur adéquate provenant de l'élément fils .central. .main va transmettre cette hauteur aux autres éléments fils qui lui sont asservis : .menus et .notes.
Enfin, la hauteur de .central résulte de la somme des hauteurs des éléments qu'il contient : .corps et .pied. La hauteur de .pied est fixe, alors que .corps s'adapte à la taille de son contenu.

L'arbre des éléments est schématiquement celui-ci :

Pour terminer ce tour d'horizon, une remarque utile à l'optimisation du référencement : .header, .menus, .notes ont un positionnement absolu par rapport à leurs parents. Cela signifie que la situation de ces éléments dans le code est indifférente. Le webmaster est donc libre de choisir l'ordre d'apparition de ces objets pour placer le contenu le plus significatif en tête. Généralement on place .main devant .header, et .central devant .menus et .notes.

Largeur de la page

Pour notre modèle nous avons choisi d'adapter la page à la largeur de la fenêtre du navigateur. La balise body porte donc l'attribut width=100%. .header et .main sont également à 100% de leur parent body pour occuper toute la largeur.

Pour ceux qui seraient tentés par une page de largeur fixe centrée dans la fenêtre du navigateur nous indiquons au passage le fragment de code correspondant (testé sur les navigateurs listés au début de l'article) :
.ApplyToBody {position:relative;margin:0px;text-align:center;background-color:#e7e7e7}
.ApplyToFrame {position:relative;width:760px;margin-left:auto;margin-right:auto}

Ce code donne un cadre de 760 pixels de large centré sur un fond gris.

Deux astuces spécifiques à Internet Explorer.

Contourner les bugs consiste parfois à donner des directives différentes à chaque navigateur en fonction de leur comportement propre. Certains défauts bien spécifiques, correctement exploités, permettent d'atteindre cet objectif.

Prenons par exemple le sélecteur * html .main
Il désigne normalement toute balise portant l'attribut class=main, fille d'une balise html, elle-même fille d'une balise quelconque de plus haut niveau. Pour un navigateur normalement constitué, ce sélecteur désigne un ensemble vide de balise puisque, selon le standard, la balise html est balise de plus haut niveau et ne peut être fille d'une autre balise. En revanche Internet Explorer (toute version) "oublie" l'astérisque. Grâce à ce bug il devient donc possible de donner des directives reconnues uniquement de IE.

Il existe un autre bug bien pratique. Le caractère \ désigne dans le contexte des expressions régulières le caractère d'échappement. Les différentes versions de Internet Explorer Mac (et uniquement Mac) considèrent le caractère \ comme un caractère d'échappement partout dans le code. On exploite ainsi ce défaut :

/* commentaire qui finit au bout de cette ligne sauf pour IE Mac \*/
ligne visible par tout navigateur sauf IE Mac
/* fin de code invisible pour IE Mac */

Pour IE Mac, l'astérisque est échappé, donc le commentaire se poursuit sur trois lignes. Il devient donc possible de masquer du code à IE Mac. Dans la pratique on commence par écrire des directives spécifiques à IE Mac, puis on les surcharge par les commandes destinées aux autres navigateurs, cette surcharge restant invisible à IE Mac.

Nous utilisons ces deux artifices à plusieurs reprises dans notre feuille de style.

 

Revue des difficultés

Hauteur de .main.
Nous souhaitons que .main hérite sa hauteur de .central. Selon le standard ceci est possible si .central est positionné en relatif, et si .main a sa propriété height à auto (valeur par défaut donc implicite dans notre code).
Sous IE PC height=auto est un problème pour .notes et .menus. En effet ces derniers doivent hériter leur hauteur de celle de .main, et ce n'est possible avec IE PC qu'à condition de fixer explicitement la hauteur du parent .main. Nous avons choisi arbitrairement height=0px. Heureusement, même si ce n'est pas standard, sur IE PC cette valeur fixe ne fige pas la hauteur de l'élément .main : IE PC réagit un peu comme si height désignait en fait une hauteur minimum.
IE Mac cumule de son coté tous les ennuis : comme pour IE PC height=auto entrave l'héritage de la hauteur, mais comme le standard une hauteur fixe fige la hauteur qui ne s'adapte plus au contenu. Pour IE Mac, height=100% conduit à un compromis qui nous semble acceptable (cependant voir ci-dessous le paragraphe concernant les défauts non résolus). Etrangement avec cette valeur, .main s'adapte à la hauteur de son contenu et les fils .notes et .menus héritent des 100%. Ce choix induit cependant de nouveaux problèmes car ces 100% représentent la hauteur de la fenêtre. Pour un .main dont la taille est inférieure à la fenêtre, les .menus et .notes dépassent. Nous corrigeons cet effet involontaire avec overflow:hidden.
Enfin, nous terminons en précisant que IE 5 sur PC ne gère pas correctement overflow:hidden donc nous positionnons pour IE PC overflow:visible.

Le cadre central.
Selon le standard, ce cadre .central doit être positionné en relatif (position:relative) car seul ce type de contenu impose au parent (.main) de s'adapter pour le contenir. Malheureusement sous IE Mac, les cadres positionnés en relatif ont des propriétés right et left qui sont figées (valeur héritée de celle du parent). Dans notre cas ces valeurs sont left=0px et right=0px fixées explicitement ou implicitement sur .main. Le positionnement horizontal de .central se fait donc avec des marges : margin-left:170px et margin-right:100px.

Le contenu utile .corps.
C'est cet élément qui prend soit la hauteur de son contenu, soit une hauteur minimum si ce contenu est petit. Le standard propose une solution simple pour cette fonctionnalité avec min-height : height:auto (valeur par défaut) et min-height=300px, pour une hauteur minimum de 300 pixels.
IE ne reconnaît pas min-height. Cependant IE PC qui traite mal l'overflow a une propriété height qui se comporte comme min-height. On définit donc pour IE height=300px. Sur IE PC .corps aura une hauteur de 300 pixels ou plus selon le contenu.
Sur IE Mac les choses sont différentes, puisque ce navigateur gère correctement l'overflow, le contenu débordera de .corps. En revanche ce contenu va imposer sa hauteur à .central parent de .corps. Finalement le résultat sera le même pour les deux versions de IE au niveau de .central.
C'est encore différent pour Safari. Safari respecte bien le standard sans toutefois reconnaître min-height. Nous introduisons donc deux éléments vides, l'un flottant, de largeur 0, de hauteur 300px, l'autre de hauteur nulle placé sous l'élément flottant. Ainsi .corps dont la hauteur vaut auto pour Safari va s'adapter à son contenu, notamment à la hauteur de l'objet flottant.

Positionner .menus et .notes.
Ces éléments ont un positionnement absolu. Le standard propose trois manières pour définir la situation de ces éléments sur l'axe vertical. Il suffit de choisir deux attributs parmi top, bottom et height. Cependant IE n'accepte pas que top et bottom soient utilisés en même temps. Nous avons donc opté pour top=0px et height=100%. Cela fonctionne pour adapter la hauteur de ces éléments à la hauteur de .main.

Remarques

Présence récurrente de margin=0px dans notre code.
La valeur par défaut de la marge varie d'un navigateur à l'autre, elle ne vaut pas systématiquement zéro. Il est donc préférable de la fixer explicitement. C'est en particulier le cas de Mozilla et Netscape. Par ailleurs ces navigateurs respectent le standard concernant le modèle d'élément block : la marge n'intervient pas pour définir la dimension du block qui vaut simplement padding + contenu. Cette combinaison conduit parfois à un effet surprenant : lorsqu'un élément parent s'adapte à la taille de ses fils et que un ou des fils ont une marge, alors cette marge peut déborder du parent. Nous préférons donc souvent imposer une marge nulle et gérer les espacements avec le padding.

Utilisation de padding-top=10px
Comme indiqué dans la précédente remarque, padding convient pour définir l'espace entre un contenu et le bord de son contenant. Mais l'utilisation de ce padding en haut plutôt qu'en bas n'est pas un hasard. IE Mac présente un bug retors : un élément, parent d'éléments <p> et positionné en relatif, "retro hérite" des margin-bottom, padding-bottom, border-bottom du dernier élément <p>. Dans notre cas, nous souhaitons que .pied soit exactement en bas de .central, il est donc important de vérifier que les éléments <p> de .pied ont des margin-bottom, padding-bottom, border-bottom à 0, explicitement ou implicitement.

Utilisation de right:15px; margin-right:-15px;
Tous les éléments positionnés à droite à une distance du bord inférieure à 15 pixels font l'objet de cet étrange traitement. Il s'agit une fois encore de contourner un bug IE MAC. Ce navigateur introduit une marge cachée de 15 pixels sur tous les éléments. Pour les objets proches du bord, cette marge cachée dépasse et impose la présence d'une barre de défilement horizontale, que l'astuce décrite évite.

Défauts non résolus

Les problèmes listés dans ce paragraphe concernent IE MAC et uniquement ce navigateur.

Barre de défilement verticale.
Les contenus devant s'adapter à la largeur de la fenêtre (width=100%) ne prennent pas en compte la présence d'une barre de défilement verticale (cas d'une page de grand contenu). Ce contenu "glisse" sous cette barre de défilement, et impose donc la présence d'une barre de défilement horizontale pour le découvrir.

Overflow:hidden.
overflow:hidden rend invisible un contenu qui dépasse, mais ne le supprime pas. Dans notre modèle cela conduit à une zone blanche sous la page, voir à une barre de défilement verticale.

Hauteur des .menu et .notes.
Pour les pages très longues les éléments .menu et .notes sont trop courts pour atteindre le bas de la page. il est possible de remplacer pour .main height=100% par une valeur en pixel dont on sait qu'elle est supérieure à la taille de toutes les pages à traiter.

Textes positionnés en bas de .menu et .notes.
Ces textes sont coupés par overflow:hidden. D'une façon générale, la résolution des problèmes de hauteur sur IE Mac pour .menu et .notes nécessiterait la superposition pour chaque colonne de 3 objets : l'un pour le fond qui sera tronqué par overflow:hidden, l'autre pour les textes en bas positionné avec bottom, l'autre pour les textes en haut positionné avec top (nous n'avons pas implémenté cette solution pour éviter une trop grande complexité du code).
Il faut se souvenir que sous IE, il n'est malheureusement pas possible d'utiliser simultanément top et bottom. Cela suppose donc souvent la création de plusieurs objets distincts là ou un seul suffit selon le standard. Sous IE Mac s'ajoute le fait qu'il n'est pas possible de définir la hauteur exacte, d'ou la solution d'une hauteur excessive tronquée.


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