Vous êtes ici : Accueil du blogCSS » Un gabarit de site à page unique (« One page layout ») sans javascript

Un gabarit de site à page unique (« One page layout ») sans javascript

Le but de cet article est de partager une technique de mise en page simple et efficace qui remplit les conditions suivantes :

  • Une rubrique (page) occupe tout l’espace du viewport,
  • Son contenu est centré verticalement,
  • Une hauteur de contenu supérieure à la hauteur du viewport ne doit pas pénaliser la mise en page,
  • Mise en page en CSS sans javascript,
  • Compatible IE8+

Voir la démo

<!DOCTYPE html>
<html>
	<head></head>
	<body>

		<ul class="menu">
			<li><a href="#page-1">Page1</a></li>
			<li><a href="#page-2">Page 2</a></li>
		</ul>

		<div id="page-1" class="sectionWrapper">
			<div class="contentWrapper">
				<!-- Contenu Page 1 -->
			</div><!-- /contentWrapper -->
		</div><!-- /sectionWrapper -->

		<div id="page-2" class="sectionWrapper">
			<div class="contentWrapper">
				<!-- Contenu Page 2 -->
			</div><!-- /contentWrapper -->
		</div><!-- /sectionWrapper -->

	</body>
</html>
html, body { height:100%; }
.sectionWrapper { display:table; height:100%; }
.contentWrapper { display:table-cell; vertical-align:middle; }

Un élément sur lequel on applique une valeur en pourcentage prendra comme hauteur référence celle de son parent. On remonte donc l’arborescence HTML en appliquant height:100% sur les éléments parents pour permettre aux rubriques d’occuper toute la hauteur du viewport.

Le centrage vertical du contenu est obtenu grâce à l’utilisation du vertical-align sur un conteneur de type table-cell.

Allez comme c’est bientôt noël, je laisse en cadeau pourri le fix IE7 :

.ie7 .sectionWrapper { height:auto; min-height:100%; }

Si vous voulez ajouter un effet de défilement à la navigation (de type « smooth scroll »), c’est par ici que ça se passe.

Et voilà, plus simple (et performant) que d’utiliser un script qui va calculer la dimension du viewport et adapter les tailles des conteneurs en conséquence, non ?

Cependant cette technique peut poser quelques soucis, notamment lorsqu’il s’agit d’afficher le contenu dans une colonne centrale. Heureusement nous allons voir que ce problème n’a rien d’insoluble.

Limites de la technique et solutions

Une colonne centrale

Supposons que l’on souhaite afficher le contenu de nos pages dans une colonne de largeur fixe centrée horizontalement et disposant d’un arrière-plan. Côté HTML/CSS, on est tenté de partir sur quelque chose comme ça :

<div id="global">

	<ul class="menu">[...]
	<div id="page-1" class="sectionWrapper">[...]
	<div id="page-2" class="sectionWrapper">[...]

</div><!-- /global -->
#global { width:990px; margin:0 auto; background:lightblue; }

Le centrage horizontal fonctionne bien, par contre on perd notre effet de mise en page full viewport pour les rubriques. Cela est logiquement dû au fait que nos conteneurs n’ont aucune référence de hauteur sur laquelle se baser (la hauteur de #global n’étant pas précisée). On va donc corriger cela :

#global { height:100%; [...] }

On constate que l’on retrouve bien l’effet de mise en page, mais on perd l’arrière-plan sur les pages secondaires. En limitant la hauteur de #global à 100%, on l’empêche également de s’adapter en hauteur aux éléments qu’il contient !

Et là, même en bidouillant les éléments avec du min-height, impossible d’obtenir quelque chose de convaincant. Il va donc falloir ruser au moyen d’une des feintes ci-dessous :

  • En appliquant l’arrière-plan sur les conteneurs des pages.

    .sectionWrapper {  background:lightblue; [...] }
    
  • En utilisant un conteneur en position fixe pour simuler l’arrière-plan (le code ci-dessous propose une solution à base de pseudo-élément mais rien ne vous empêche d’utiliser à la place un conteneur supplémentaire).

    #global:before {
    	content:'';
    	width:990px; height:100%;
    	position:fixed; top:0; left:50%;
    	margin-left:-495px; /* = width/2 */
    	z-index:-1;
    	background:lightblue;
    }
    
  • En utilisant une image sur <body> pour simuler la colonne.

    body {  background:url(colonne.png) repeat-y center; }
    

Centrer horizontalement et verticalement la page (sans colonne)

Mais peut-être souhaitez-vous limiter la hauteur d’une page à son contenu, en laissant libre l’espace (au dessus et en dessous) dégagé par le centrage vertical ?

Voir la démo

Un conteneur en table-cell reproduit le comportement standard d’une cellule de tableau (<td>), et occupe donc (en largeur et en hauteur) tout l’espace de son parent.

Pour appliquer un arrière-plan (qui n’occupe pas toute la surface disponible) à notre contenu, on devra donc utiliser un conteneur supplémentaire (dédié au centrage vertical) :

<div id="page-1" class="sectionWrapper">
	<div class="vAlignWrapper">
		<div class="contentWrapper">
			<!-- Contenu Page 1 -->
		</div><!-- /contentWrapper -->
	</div><!-- /vAlignWrapper -->
</div><!-- /sectionWrapper -->
html, body { height:100%; }
.sectionWrapper { display:table; height:100%; width:100%; }
.vAlignWrapper { display:table-cell; vertical-align:middle;  }
.contentWrapper { width:990px; margin:0 auto; background:lightblue; }

Dans cet exemple le centrage horizontal est réalisé directement sur .contentWrapper, mais on aurait pu également l’appliquer sur .sectionWrapper ou sur un conteneur global comme vu précédemment.

Voilà voilà. Si vous êtes confrontés à un autre problème ou si vous avez trouvé une feinte supplémentaire pour la colonne ou le centrage vertical, n’hésitez pas à partager via les commentaires !

Commentaires (2)

Lâcher un com'

  1. Paul
    16 mars 2015 à 13h48

    Bonjour,

    Je vous remercie pour cet article qui m’a permis de confirmer mon développement actuel.
    Par contre avec ces tables qui prennent toute la hauteur de l’écran, comment peut-on mettre un footer en bas de page ?
    Actuellement celui-ci se positionne juste après le #global qui fait 100% et non la taille réelle de l’ensemble des pages.

    Merci de votre aide.

    Paul

  2. BeliG
    16 mars 2015 à 19h48

    Bonjour Paul,

    Effectivement le positionnement du footer en bas de page peut être problématique, mais on peut y remédier en utilisant un peu de positionnement absolu :

    <div id="page-3" class="sectionWrapper">
       <div class="contentWrapper">[...]</div>
       <div id="footer">[...]</div>
    </div>

    #page-3 {
       position:relative;
    }
    #page-3 .contentWrapper {
       padding-bottom:100px; /* hauteur footer */
    }
    #footer {
       position:absolute; bottom:0; left:0;
       width:100%; height:100px;
    }

    (le footer doit être enfant de la dernière page, ici #page-3)

Laisser un commentaire

Balises HTML autorisées dans la rédaction du message :
<strong> <a> <code> <q>

Les champs marqués d'une étoile sont obligatoires.

Current month ye@r day *