Fork me on GitHub

Construire une grille fluide avec float

Afficher/Masquer les propositions de solutions

Principes abordés : Responsive Web Design

Prérequis :

Acte 1

Nous allons construire ensemble une grille fluide, c'est-à-dire une CSS définissant une collection de classes qui nous permettront d'organiser, au sein d'un certain bloc, le contenu en colonnes et en gouttières. L'idée est de pouvoir très simplement définir que tel contenu occupe ½, ⅓, ⅙… de la largeur disponible, quelle que soit la largeur du viewport.

Notre grille n'occupera pas nécessairement tout l'espace, mais peut-être qu'une partie du site. Nous allons donc l'embarquer dans un élément de type bloc, un container, dont nous considérerons qu'il est "large à 100%", il sera la base de notre grille. Notez que si cet élément est le seul élément du body, alors tout se passera comme si la grille occupait toute la largeur disponible car, par défaut, cet élément de type bloc occupera véritablement toute la largeur.

Nous allons partir du code HTML suivant :

<div class="grille">
	<!-- 100% large -->
</div>
Mettez en place deux colonnes de contenu. Le contenu principal occupe ⅔ de la largeur disponible, le contenu latéral, ⅓.
<div class="grille">
	<div class="col-2-3">
		<p>Contenu principal</p>
	</div>
	<div class="col-1-3">
		<p>Contenu latéral</p>
	</div>
</div>

Pour faire en sorte d'afficher les deux zones l'une à côté de l'autre, il faut les faire flotter et leur appliquer des largeurs…

Essayer de distinguer ce qui s'applique véritablement à un élément affichant une certaine classe (par exemple, .col-1-3) de ce qui s'appliquera à l'ensemble des classes de type .col-{quelque chose}. Comment adresser l'ensemble de ces classes avec une seule règle CSS ?

Proposition de solution :

[class*='col-'] {
	float: left;
}

.col-2-3 {
	width: 66.66%;
}

.col-1-3 {
	width: 33.33%;
}
		

Acte 2

Si vous remplacez les contenus par du Lorem Ipsum [1], par exemple, vous allez vite vous rendre compte d'un problème : le texte d'un élément continue jusqu'au contenu suivant, ce qui n'est pas très agréable à l'oeil. Nous allons donc mettre en place des gouttières de 20px, qui permettront d'aérer le contenu.

Définissez des gouttières de 20px de large entre les contenus. Attention, les gouttières ne sont qu'entre les contenus… ni à gauche, ni à droite de la grille.

Vous rencontrez des problèmes pour faire rentrer vos contenus en largeur ? C'est normal, c'est à cause du modèle de boîtes par défaut. Pour simplifier la mise en place, appliquez à l'ensemble des éléments la règle box-sizing: border-box; [2] afin que la largeur définie d'un contenu soit véritablement sa largeur, indépendamment des padding et des border appliqués.

Description visuelle de l'impact de box-sizing: border-box;
Avec box-sizing: border-box; les bordures et les paddings sont dessinés à l'intérieur de la largeur de contenu définie. Les marges sont dessinées à l'extérieur. Original par Adam Kaplan
.

Proposition de solution pour la mise en place de box-sizing: border-box; [3]:

html {
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;
}
*, *:before, *:after {
	box-sizing: inherit;
}
		

Puis pour la mise en place des gouttières :

[class*='col-'] {
	padding-right: 20px;
}
[class*='col-']:last-of-type {
	padding-right: 0;
}
		

Acte 3

Nous voudrions pouvoir nous laisser une option sur les gouttières extérieures, sous la forme d'une classe CSS supplémentaire que nous pourons utiliser, ou non, pour activer ces gouttières. Implémentez cette classe .grille-espace en CSS (n'oubliez pas de modifier votre HTML pour l'utiliser).
<div class="grille grille-espace">
	<div class="col-2-3">
		<p>Contenu principal</p>
	</div>
	<div class="col-1-3">
		<p>Contenu latéral</p>
	</div>
</div>
	

Ajoutons d'abord le padding à gauche :

.grille-espace {
	padding-left: 20px;
}
		

Puis nous restorons éventuellement la gouttière de droite que nous avons supprimé précédemment :

.grille-espace > [class*='col-']:last-of-type {
	padding-right: 20px;
}
		

Acte 4

Nous voudrions également pouvoir nous laisser une option sur l'alignement, afin de pouvoir caler des contenu sur la droite, par exemple, même si aucun contenu ne le précède à gauche. Implémentez en CSS une classe .oppose (n'oubliez pas de modifier votre HTML pour l'utiliser).
<div class="grille">
	<div class="col-1-3 oppose">
		<p>Contenu calé à droite</p>
	</div>
</div>
	

Proposition de solution :

.oppose {
	float: right;
}
		

Acte 5

Nous avançons bien mais il est parfois difficile de voir où nous en sommes, faute de mise en forme.

Utilisez le code CSS suivant pour y voir plus clair (adaptez à votre code) :
body{
	background-color: #446CB3;
	color: #FFF;
}

.grille {
	border: 2px dashed rgba(255,255,255,0.3);
}

[class*='col-'] p {
	background: rgba(225,255,255,0.1);
	border: 2px solid rgba(255,255,255,0.2);
	display:block;
	padding: 1rem;
	margin: 1rem 0;
	font-size: 0.9rem;
	font-weight: 600;
}
	

Que se passe-t-il ? Pouvez-vous l'expliquer et comment résoudre ce problème ?

Nous allons ajouter une notion à notre code HTML, celle de ligne :

<div class="grille grille-espace">
	<div class="ligne">
		<div class="col-2-3">
			<p>Contenu principal</p>
		</div>
		<div class="col-1-3">
			<p>Contenu latéral</p>
		</div>
	</div>
	<div class="ligne">
		<div class="col-2-3 oppose">
			<p>Contenu latéral</p>
		</div>
	</div>
</div>
	

Reste à expliquer aux éléments quel espace considérer. Une solution parmi d'autres est d'ajouter un pseudo élément à la fin de chaque ligne, de type block (par défaut, le type d'un pseudo-élément est inline). Cela va permettre au navigateur de considérer la valeur renseignée comme un bloc : nous aurons donc, avant et après chaque ligne, deux blocs invisibles attachés. Ensuite, sur ces blocs, on peut appliquer un clear: both;, qui dégage ces blocs du flux flottant.

.ligne:before,
.ligne:after {
	content:" ";
	display: block;
	clear: both;
}
	

Acte 6

Notre grille est bien partie, mais il faut désormais ajouter d'autres types de largeurs d'éléments pour rendre notre mise-en-page flexible aux besoins.

Ajoutez des classes pour mettre en forme des contenu occupant ½, ¼ ou ⅙ de la largeur disponible. Pensez aussi aux contenus occupant ⅔, ¾, ⅚… N'hésitez pas à modifier votre code HTML pour réaliser vos tests.

On essaie souvent d'avoir des systèmes de grilles fluides permettant aux contenus d'occuper des moitiés, des quarts ou des sixièmes de la largeur disponible. Dans ce contexte, notre nommage de classes est-il pertinent, n'entrainera-t-il pas des ambiguïtés ? Que pourrait-on proposer de mieux ?

Proposition de solution :

.col-1-2 {
	width: 50%;
}
.col-1-4 {
	width: 25%;
}
.col-1-6 {
	width: 16,66%;
}
		

Le nommage séparant les ½, ¼ ou ⅙ n'est en effet pas pertinent, car il existe alors plusieurs manières d'écrire la même chose. Par exemple, "la moitié de la largeur" peut être à la fois un demi, mais également trois sixièmes… C'est pour cette raison que vous trouverez de nombreuses grilles organisées sur le PGCD de 2, 3 et 6 : 12.

Acte 7

Notre grille est prête, mais bien que flexible au sens RWD, elle ne l'est pas énormément en termes de maintenance…

Que se passerait-il demain si nous voulions modifier la largeur de nos gouttières ? Proposez une solution pour rendre la maintenance de ce paramètre plus simple. Quels impacts sur le processus de développement ?

Il existe, dans le monde du développement CSS, la notion de pré ou de post-processeurs. Peuvent-ils aider ? Comment ? Est-ce lourd à mettre en place et que cela change-t-il dans un projet en termes de maintenance et de facilité de lecture ?

Les pré et post processeur CSS permettent de réaliser des opérations amenant à du CSS (à partir d'un autre langage) ou étendant le CSS après son écriture. Leur utilisation n'est ni bonne, ni mauvaise : elle dépend du contexte. En revanche, elle implique de travailler au sein d'une équipe parfaitement consciente des usages et qui maitrise ces outils. La courbe d'apprentissage, pour un nouvel arrivant, sera plus importante que s'il n'y avait pas ces outils : il faut donc s'assurer qu'en contre-partie, le temps gagné à l'usage est supérieur.

Proposition de solution en SCSS (voir la démo) :

/* Gestion du modèle de boite */
/* Bonnes pratiques : http://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/ */
html {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

*, *:before, *:after {
	box-sizing: inherit;
}

/* Taille des gouttières */
$gouttiere: 20px;

/* Règles pour la mise en forme */
body {
	background-color: #446CB3;
	color: #FFF;

	.grille {
		border: 2px dashed rgb(255, 255, 255);
		border: 2px dashed rgba(255, 255, 255, 0.3);
	}

	[class*='col-'] p {
		background: rgba(225, 255, 255, 0.1);
		border: 2px solid rgb(255, 255, 255);
		border: 2px solid rgba(255, 255, 255, 0.2);
		display: block;
		padding: 1rem;
		margin: 1rem 0;
		font-size: 0.9rem;
		font-weight: 600;
	}
}

.grille {
	[class*='col-'] {
		float: left;

		&.oppose {
			float: right;
		}
	}

	/* Sur 12 colonnes */
	@for $i from 1 through 11 {
		.col-#{$i}-12 {
			width: (100% / 12) * $i;
		}
	}

	/* Sur 3 colonnes */
	@for $i from 1 through 2 {
		.col-#{$i}-3 {
			width: (100% / 3) * $i;
		}
	}

	[class*='col-'] {
		padding-right: $gouttiere;
	}
	[class*='col-']:last-of-type {
		padding-right: 0;
	}

	.ligne {
		&:before,
		&:after {
			content: " ";
			display: block;
			clear: both;
		}
	}

	/* Espaces extérieur */
	&.grille-espace {
		padding-left: $gouttiere;

		[class*='col-']:last-of-type {
			padding-right: $gouttiere;
		}
	}
}

Acte 8

Nous disposons désormais d'une grille efficace. Mettons-là en condition réelles.

Voici un schéma présentant les contenus de notre site.
Exemple de mise en page sur grille à 12 colonnes

Commencez par critiquer la mise-en-forme fournie. Vous semble-t-elle cohérente par rapport à la grille sur laquelle elle se repose ?

Utilisez une grille fluide pour mettre en forme votre mise-en-page corrigée.