I. Introduction

Il y a déjà quelques temps, en août 2003, j'ai écrit un court article intitulé CSS Frames, dans lequel j'ai décrit une technique permettant de simuler, en apparence, un cadre HTML avec du CSS. C'était il y a plus de trois ans, et je pense donc qu'il est temps de revoir et améliorer quelque peu la technique, d'autant plus que la page de démonstration d'origine pour les cadres CSS a reçu, récemment, de nombreuses visites.

J'ai seulement jeté un coup d'oeil rapide au code, et je peux affirmer qu'il date de quelques années. C'est parfois embarassant de se replonger du vieux code. La démo contient une liste des navigateurs avec lesquels j'avais fait mes essais, "Mozilla Firebird 0.61" y apparaît. Comme je le disais, il commence à dater, donc voilà la mise à jour.

La raison qui justifie la création d'une technique de cadres CSS est, bien sûr, la volonté d'abandonner l'utilisation des cadres HTML. Si vous n'en connaissez pas les raisons, lisez mon article Who framed the web: Frames and usability.

Maintenant, plongeons-nous dans la mise à jour de la technique des cadres CSS.

II. La mise en page : entête, corps de page pleine hauteur, pied de page

La disposition que je décris ici aura une entête fixe en haut de la page, une zone (au milieu) avec un contenu pouvant défiler, et un pied de page fixe en bas de page. Le concept peut être adapté à d'autres types de disposition en cadres, mais je vous le laisse en exercice.

Je me suis aussi assuré que le corps de la page prenne l'intégralité de la hauteur visible même s'il n'y a pas assez de contenu pour activer le défilement. Pour cela, j'ai utilisé la technique décrite par Peter-Paul Koch dans 100% height.

La mise en page repose sur trois blocs : #header, #content et #footer. L'effet de cadre se crée en deux étapes. Tout d'abord, on donne des positions fixes à #header et #footer, respectivement en haut et en bas de la page visible. Ensuite, on fixe des marges intérieures (padding) en haut et en bas de #content, afin qu'elles correspondent aux hauteurs de #header et #footer.

L'ensemble des trois blocs sont réunis dans un élément div ayant pour id #wrap, afin de faciliter le contrôle de la largeur d'affichage et du centrage horizontal. #content est inclus dans #content-wrap à cause de la technique des 100% en hauteur que j'utilise. Le bloc qui défile a besoin d'avoir une hauteur de 100%, mais a également un padding haut et bas. Cela devrait s'ajouter et faire plus de 100%, c'est pourquoi le padding est défini au niveau de #content à la place, étant donné que les deux ont le même arrière-plan.

III. Différentes largeurs

Selon que vous souhaitiez une mise en page qui s'ajuste à la largeur visible ou non, vous aurez besoin d'utiliser différentes largeurs pour les éléments #header et #footer. Les éléments qui ont la propriété position:fixed sont positionnés en respectant la fenêtre, donc le fait de mettre leur largeur à 100% (vous aurez besoin de fixer une largeur ou de les réduire pour coller à leur contenu) et ajuster la largeur de #wrap ne fonctionnera pas. Les blocs #header et #footer seraient toujours ajuster à la largeur de la fenêtre. À moins que l'on spécifie un left ou un right, leur coté gauche sera à gauche de #wrap, où ils seraient s'ils l'ont ne les avaient pas positionnés du tout.

J'ai préparé deux exemples pour montrer la différence. Dans le premier exemple, l'agencement est très fluide, et donc #header et #footer occupent toute la largeur. Dans le second exemple la largeur de la page est fixée à 40 em, et les largeurs de #header et #footer ont donc la même valeur.

IV. La feuille de style CSS

Voici le CSS que j'ai utilisée dans le premier exemple :

Code CSS
Sélectionnez

html, body 
{
  margin:0;
  padding:0;
  height:100%; /* 100 % en hauteur */
}
 
html>body #wrap {height:100%;} /* 100 % en hauteur */
 
#header 
{
   width:100%;
   height:5em;
}
 
html>body #header 
{
  position:fixed;
  z-index:10; /* empêche certains problèmes avec les élements de formulaire */
}
 
html>body #content-wrap {height:100%;} /* 100 % en hauteur */
 
html>body #content {padding:6em 1em;} /* 6em = hauteur de #header et #footer + 1em, 1em = donne au contenu un peu d'espace par rapport aux bords */
 
#footer 
{
   width:100%;
   height:5em;
}
 
html>body #footer 
{
  position:fixed;
  bottom:0;
  z-index:10; /* empêche certains problèmes avec les élements de formulaire */
}
            

Et maintenant, voici comment fonctionne le second exemple :

Code CSS
Sélectionnez

html, body 
{
   margin:0;
   padding:0;
   height:100%; /* 100 % en hauteur */
}
 
html>body #wrap {height:100%;} /* 100 % en hauteur */
 
#wrap 
{
   width:40em;
   margin:0 auto;
}
 
#header 
{
   width:40em;
   height:5em;
}
 
html>body #header 
{
   position:fixed;
   z-index:10; /* empêche certains problèmes avec les élements de formulaire */
}
 
html>body #content-wrap {height:100%;} /* 100 % height */
 
html>body #content {padding:6em 1em;} /* 6em = hauteur de #header et #footer + 1em, 1em = donne au contenu un peu d'espace par rapport aux bords */
 
#footer 
{
   width:40em;
   height:5em;
}
 
html>body #footer 
{
   position:fixed;
   bottom:0;
   z-index:10; /* empêche certains problèmes avec les élements de formulaire */
}
            

V. Les ajustements pour Internet Explorer (IE)

Malheureusement, Internet Explorer sous Windows dans des versions inférieures ou égales à 6 ne supportent pas la propriété CSS position:fixed. Comme il est utilisé par trop de monde, on ne peut l'ignorer, et il est nécessaire de placer quelques rustines. Etonnement, elles sont inutiles sous IE7, ça fonctionne tel quel ! Toutefois, pour IE5 et 6, il faudra ajouter quelques règles supplémentaires à l'aide d'un commentaire conditionnel :

Code (X)HTML
Sélectionnez

<!--[if lt IE 7]>
<link rel="stylesheet" href="ie.css" type="text/css">
<![endif]-->
            

Le fichier ie.css contient le code CSS qui suit :

Code CSS
Sélectionnez

html, body {background:url(foo) fixed;}
 
#header, #footer 
{
   position:absolute;
   z-index:10;
}
#header 
{
    top:expression(eval(document.compatMode && document.compatMode=='CSS1Compat') ? documentElement.scrollTop : document.body.scrollTop)
}
 
#wrap, #content-wrap {height:100%;}
 
#content {padding:6em 1em;}
 
#footer 
{
    top:expression(eval(document.compatMode && document.compatMode=='CSS1Compat') ? 
    documentElement.scrollTop +(documentElement.clientHeight-this.clientHeight) : 
    document.body.scrollTop +(document.body.clientHeight-this.clientHeight));
}
            

Ceci fonctionne avec IE 5, 5.5 et 6, bien que je ne me sois pas embêté à recentrer horizontalement sous IE 5.* ; en effet, il est temps d'abandonner les IE 5.*

Le défilement est quelque peu instable, mais il fonctionne. Étant donné que les expressions font appel à du JavaScript, cela ne fontionnera pas s'il est désactivé. Heureusement, dans de tels cas, cela entrainera juste le défilement de toute la page, et aucun contenu sera caché.

VI. Améliorations progressives et jolies dégradations

Dans les navigateurs ne supportant pas position:fixed (à l'exception de IE5-6), la page entière défilera, ce qui est un défaut tout à fait acceptable. J'utilise un "sélecteur enfant" afin de permettre uniquement aux navigateurs le supportant de voir les déclarations position:fixed. Vouloir laisser les navigateurs ne supportant pas le positionnement fixe (à l'exception de IE5-6 sous Windows) voir l'ensemble des propriétés CSS constitue un autre problème.

La technique fonctionne sur tous les navigateurs modernes qui sont passés entre mes mains, à une exception. L'astuce utilisée pour ajuster la zone de contenu sur l'intégralité de la hauteur de la fenêtre provoque un comportement étrange avec les navigateurs ICab et Internet Explorer pour Mac. Ce sont des problèmes esthétiques d'une gravité assez faible, je pense donc qu'il est possible d'y survivre.

À part cela, je ne suis pas conscient d'autres problèmes. Cependant cela ne signifie pas qu'il n'y en ait pas, donc je vous remercie de m'avertir si vous trouvez des bugs, ou si vous souhaitez proposer quelques améliorations supplémentaires.

VII. Remerciements

Tous mes remerciements à troumad pour sa relecture.