Semantic Sass grid mixin

Nous allons étudier la création d'un simple mixin générateur de grille responsive sémantique en SASS.

…si vous ne savez pas trop de quoi on parle : bienvenue !

C'est quoi ?

Pour faire vite :

Nous parlons donc d'une fonction de quelques lignes de code qui permet de générer du CSS créant une grille responsive qui manipule le HTML. <!–more–>

On ‘gridifie’ les éléments de la page web en leur appliquant une simple fonction dans le CSS.

La plupart des frameworks existants tels ceux déjà cités comportent des grilles qui nécessitent de modifier le HTML en profondeur. Ces outils sont très solides et extrêmement utiles, mais sont souvent lourds et vous forcent à coder d'une certaine façon. On dit qu'ils sont ‘opinionated’.

Il y a aussi les grilles sémantiques telles SUSY qui sont formidables mais présentent le même inconvénient : elles veulent tout faire, sont lourdes et demandent un investissement conséquent en apprentissage.

Pour de petits projets, rien ne vaut la légèreté et la maniabilité du code que l'on produit soi-même.

La grille

Le mixin, nommé grid, génère des lignes qui contiennent des cellules (que beaucoup nomment colonnes).

Il ne comporte pas de fonctions avancées telles le nichage ou les marges automatiques : si vous voulez une fonction, il faut l'implémenter. Ce que fait ce mixin, c'est simple et formidable à la fois : il génère des lignes de cellules à volonté.

Exemple de SCSS :

article.news { @include grid(4,6); }
aside.nav { @include grid(2,6); }

Le HTML correspondant :

<article class="news">
    <h1>Les News du site</h1>
    <p>Whatever...</p>
</article>
<aside class="nav">
    <ul>
        <li>Menu 1</li>
        <li>Menu 2</li>
        <li>Menu 3</li>
    </ul>
</aside>

Le bloc avec la classe news occupera 4 cellules et le bloc avec la classe nav occupera 2 cellules, le tout dans une ligne de 6 cellules.

Ça marche aussi avec les id ou n'importe quel élément, tels div, section, etc.

Comment ça marche ?

Le mixin accepte les paramètres suivants : nombre de cellules, sur un nombre total de cellules, poussé de x cellules, avec ou sans marge droite.

Un appel au mixin tel que :

div.titre { @include grid(6,12,3,false); }

donnera au div de classe titre une largeur de 6 cellules décalées de 3 cellules vers la droite dans une ligne de 12 cellules sans marge ajoutée à droite : un bloc de la moitié de la fenêtre et centré !

Jetons maintenant un oeil au mixin :

@mixin grid($columns, $total-columns, $push: 0, $last-column: false) {
  $w: 100% * $columns / $total-columns;
  width: $w;
  float: left;
  @if $push == 0 {
    //rien
  }
  @else {
    $p: 100% * $push / $total-columns;
    margin-left: $p;
  }
  @if $last-column == true {
    padding-right: 0;
  }
  @else {
    padding-right: $pad;
  }
}

La largeur d'une cellule est simplement calculée par 100% x nombre de cellules demandées / nombre total de cellules dans la ligne. On flotte le tout à gauche, puis une condition regarde si on demande une valeur de poussée différent de zéro et dans ce cas applique une marge gauche égale à 100% x nombre de cellules de décalage / nombre total de celllules. La condition suivante est uniquement là pour régler certains cas de mauvais affichage de la dernière cellule.

Il est tout à fait envisageable de rajouter des fonctions et des paramètres selon ses besoins.

Idéalement le corps de la page contenant les grilles est lui-même un conteneur d'un seul bloc, de largeur prédéfinie mais de 100%, et centré.

On créé donc un mixin pour ça :

@mixin container($width: $sizeDesktop) {
  width: 100%;
  max-width: $width;
  margin: 0 auto;
  &:after {
    content: "";
    display: table;
    clear: both;
  }
}

Le pseudo-élément after permet d'éviter à l'élément qui contient des objets flottants de s'éffondrer (“collapse”). C'est une amélioration du truc dit “clearfix”.

Pour éviter les problèmes tels la modification de la taille des objets si on leur ajoute du padding ou une bordure, on utilise le modèle “border-box” qui permet de s'affranchir de ces considérations. Avec cette astuce, les paddings et bordures sont inclus à l'intérieur des objets et n'en poussent plus les frontières.

*, *:before, *:after {
  @include box-sizing(border-box);
}

J'utilise le raccourci fourni par Compass mais vous pourriez tout aussi bien tout écrire à la main.

Pour finir on va créer un mixin qui annule la grille et affiche les éléments sous formes de blocs pour l'affichage sur petits écrans :

@mixin pad {
  width: 100% !important;
  float: none !important;
  margin-left: 0;
}

J'oubliais l'appel à Compass et quelques variables en début de fichier :

@import 'compass'
$sizeBigDesktop: 1600px;
$sizeDesktop: 1200px;
$sizeTablet: 1024px;
$sizePortrait: 768px;
$sizeMobile: 480px;
$pad: 1%;

pour faciliter la manipulation et les tests.

Responsive

La grille est déjà fluide car elle utilise des pourcentages et pas des pixels. Elle s'adapte à la taille de la fenêtre en réduisant ou maximisant les cellules proportionnellement.

Il faut pourtant compléter cela en prévoyant des “breakpoints”, des zones de délimitation où l'affichage va changer.

Par exemple, grille normale de infini jusqu'à 1024 pixels de large, puis affichage simplifié jusqu'à 480 pixels, et affichage dépouillé en dessous.

Ou tout simplement pour viser certains appareils, tels l'iPad, en paysage ou en portrait. Chaque “media query” contient du CSS qui ne sera utilisé que lorsque les conditions seront remplies.

Par exemple :

@media screen and (max-width: $sizeTablet) {
  body {
    margin-top: 0.5em;
  }
  article.rouge {
    @include grid(1, 4);
    background-color: red;
  }
  article.vert {
    @include grid(3, 4);
    background-color: green;
  }
  img.nature {
    @include grid(1, 2);
    margin-bottom: $pad;
  }
}

@media screen and (max-width: $sizePortrait) {
  article, nav, .center {
    @include pad;
  }
  img.nature {
    @include pad;
    margin-bottom: $pad;
  }
}

Astuces

A noter que si vous avez par exemple une liste dans votre HTML d'une centaine d'images de la forme :

<li><img src="img1.jpg"></li>
<li><img src="img2.jpg"></li>
...
<li><img src="img42.jpg"></li>
...

une seule ligne de SCSS, avec notre fonction, suffit à remplir une page avec les images formant une superbe grille :

li img { @include grid(1,5); }

Dans cet exemple les images formeront des lignes de 5, sur tous les éléments de la liste.

On peut également mélanger joyeusement les types de grille dans la page :

div.bloc1 { @include grid(7,24); }
div.bloc2 { @include grid(10,24,3); }
div.bloc3 { @include grid(4,24,0,true); }
div.bloc4 { @include grid(3,9); }
div.bloc5 { @include grid(5,9,1); }

On aura bien noté que les paramètres de push et de dernière colonne sont optionnels. En revanche, en cas d'utilisation du dernier paramètre alors que l'on ne souhaite pas pousser, il faut indiquer 0, comme dans l'exemple au-dessus, ligne 3.

Conclusion

Avec des formules d'écolier et un peu de logique apportée à CSS grâce à SASS, on peut facilement et rapidement se créer un outil très puissant et totalement configurable.

Je vous invite à le manipuler vous-même si vous le souhaitez, sur Github :

KKGrid

Téléchargez le zip ou encore mieux, clonez le projet où vous le souhaitez :

git clone https://github.com/galaakk/KKGrid.git monProjet
Auteur: Eric Dejonckheere