blog

Vestiges d’un CSS Guru

Billet

Colonnes, marges et nth-child en CSS 3

Mail d’une amie :

J’ai une colle pour toi :

1 – 4 colonnes de 240px => largeur totale 960px
2 – je rajoute un margin-right de 5px et soustrais 5px de la largeur de la colonne => largeur totale 960px
Et pourtant dans le 2ème cas, visuellement la largeur totale est inférieure à 960px.
How is it possible ?

Elle n’était vraisemblablement pas bien réveillée parce qu’elle connaissait la réponse, mais je vais développer la méthode ici pour ceux qui auraient des soucis.

Largeur totale ≠ largeur utilisée

Si vous avez un espace total de 480 pixels de large et que vous y mettez, côte à côte, 4 colonnes de 120px de large, alors tout l’espace horizontal est rempli.

Maintenant, si l’on diminue la largeur des colonnes jusqu’à 90px mais qu’on rajoute à leur droite 30px de marge, le compte total ne va pas changer.

Le souci, c’est la dernière marge à droite. Elle rentre dans le calcul des 480px de large, mais visuellement, c’est du vide.

n colonnes, n-1 marges

Quel que soit le nombre de colonnes, le nombre de marges sera toujours inférieur de 1.
Pour n colonnes on a bien n-1 marges.

Ce que l’on veut : supprimer la dernière marge à droite. 1

nth child : le sélecteur providentiel

Au lieu d’appliquer une classe à la dernière colonne de chaque ligne, on va utiliser la fabuleuse pseudo-classe CSS 3 :nth-child.

Dans mon exemple, on veut virer la marge de chaque colonne multiple de 4.
Il faut faire :

.column:nth-child(4n){ margin-right:0;}

En fait, le nombre n correspond à un nombre qui va incrémenter indéfiniment, en commençant par 1. Donc on a :

  • 4*1 = 4 (la 4e colonne)
  • 4*2 = 8 (la 8e colonne)
  • 4*3…

Il permet donc de sélectionner toutes les colonnes multiples de 4.

Etant donné que nth-child n’est pas supporté par IE6, IE7 et IE8, il vous sera sans doute nécessaire d’utiliser plutôt une classe “last” sur la dernière colonne de chaque ligne.

Calcul des largeurs optimales

Comment être sûr d’occuper totalement l’espace horizontal disponible ? En d’autres termes, comment faire en sorte que :

largeur totale des colonnes
+ largeur totale des marges
= largeur totale du conteneur

Ici, je veux que que mes 4 colonnes fassent 90px de large.
Largeur totale des colonnes = 90*4 = 360px.
Il reste donc 480-360 = 120px pour 3 marges.
Chaque marge fera donc 120/3 = 40px de large.

Ici, le compte est bon, j’ai envie de dire.
Toutes les colonnes ont la même largeur, et les marges aussi, et la largeur utilisée est égale à la largeur totale.
L’utilisation de l’espace est donc optimale.

Trouver facilement les valeurs optimales

Imaginons des colonnes qui font 85px de large.

  • Largeur totale des colonnes = 85*4 = 340px
  • Largeur restante pour les marges = 480 – 340 = 140px
  • Largeur de chaque marge = 140/3 = 46,6666666666666666666667

Le drame ! Bien sûr, on pourrait essayer de trouver la solution en tâtonnant, en testant 86, puis 84, puis 87… Quelle perte de temps !

Pour calculer la largeur optimale, voici la règle :

La marge gagnée sur chaque colonne doit être un multiple du nombre de marges.

Ok. Alors, repartons au début. On avait 4 colonnes à 120px de large et 0px de marge.
On a 3 marges, donc faut procéder par palier de 3px :

  • 120 – 0 = 120px
  • 120 – 3 = 117px (de large pour une colonne)
  • 120 – 6 = 114px
  • 120 – 30 = 90px (notre exemple)
  • 120 – 33  = 87px
  • 120 – 36 = 84px

Du coup, on voit bien que 85px de large pour une colonne, c’est pas bon. Il faut choisir soit 87px ou bien 84px.

Prenons 84px qui est le plus proche :

  • colonnes = 84*4 = 336px
  • marge totale = 480-336 = 144px
  • chaque marge = 144/3 = 48px

Avec des colonnes à 84px de large et des marges à 48px de large, l’espace horizontal de 480px est utilisé en entier.

  1. Il est très rare d’utiliser des marges à gauche et de supprimer la première de chaque ligne, et ce, pour 2 raisons :
    1) dans la logique, on veut espacer le 1er élément du 2ème, et non pas espacer le 1er élément du bord gauche
    2) le margin-left pose des soucis à IE6 et IE7 (le fameux “double margin”) mais pas le margin-right