Utilisation optimisée de Framework CSS comme Bootstrap avec Less

J'ai déjà abordé le sujet des Frameworks CSS qui surchargeaient le DOM HTML inutilement et allait à l'encontre de la philosophie du W3C (séparation du fond et de la forme) dans un précédent article où j'expliquais pourquoi, par exemple, Bootstrap est une régression pour un développement Front-end de qualité.

J'ai également expliqué comment reproduire l'équivalent de fonctionnalités utiles dans un Framework en respectant l'approche CSS-driven dans Grille CSS Responsive et Sémantique sans Framework.

Je vais ici vous démontrer que cette méthode CSS-driven peut non seulement être grandement simplifiée avec l'utilisation des préprocesseurs CSS comme Less, Sass ou Stylus, mais qu'elle permet également d'exploiter les Frameworks tel que Bootstrap de manière propre et conforme à la philosophie de séparation de la sémantique et du design.

Les approches HTML-driven et CSS-driven pour habiller une page Web

La différence est simple :

HTML-driven où l'habillage rapide et désolant

  • Les Frameworks CSS imposent une utilisation HTML-driven des sélecteurs CSS en demandant aux développeurs d'habiller une page web en la surchargeant de div et de class représentant l'habillage et la disposition graphique de la page.

HTML

<footer class="container">
    <div class="row">
        <div class="col-sm-4 col-sm-push-8">
            <div class="text-right hidden-xs">
                <a href="">Join us on Facebook !</a>
            </div>
            <div class="text-center visible-xs">
                <a href="">Join us on Facebook !</a>
            </div>
        </div>
        <div class="col-sm-8 col-sm-pull-4">
            All rights not reserved.
        </div>
    </div>
</footer>

CSS

/* Appel d'un Framework CSS. Lourd en poids et état de boite noire si on ne le connait pas. */

C'est malheureusement ce que l'on voit de plus en plus souvent sur les sites Internet et qui est selon moi « LA » régression pour un travail Front-end de qualité.

CSS-driven où le travail effectué avec l'évolution du HTML par le W3C

  • L'habillage CSS tel que défini par le W3C est lui CSS-driven. Il y a séparation du fond (la sémantique) et de la forme (la feuille de style) et rien de la disposition ou du design graphique ne doit transparaître dans le DOM HTML.

HTML

<footer>
        <div class="share">
                <a href="">Follow us on Google+ !</a>
        </div>
        <div class="copyright">
            All rights not reserved.
        </div>
</footer>

CSS

    .footer,
.container {
    max-width: 1200px;
    margin-left: auto;
    margin-right: auto;
    padding-left: 15px;
    padding-right: 15px;
}
    .footer
.no-gutter {
    padding-left: -15px;
    padding-right: -15px;
}
    .share,
    .copyright,
.col {
    float: left;
    width: 100%;
    padding-left: 15px;
    padding-right: 15px;
}
    .share,
    .copyright,
.relative { padding: relative; }
    .share,
.text-center { text-align: center; }

@media (min-width: 768px) {
    .copyright,
.col12-8 { width: 66.66666667%; }
    .share,
.col12-4 { width: 33.33333333%; }

    .copyright,
.push12-8 { left: 66.66666667%; }
    .share,
.pull12-4 { right: 33.33333333%; }

    .share,
.text-right { text-align: right; }
}

Et effectivement cela nécessite de savoir utiliser le CSS.

Pourquoi être HTML-driven est un réel problème ?

Prenons un exemple concret ; le « Footer » utilisé dans notre exemple précédent à les caractéristiques suivantes :

  • Sur mobile la partie de partage à son texte centré. Il en va de même pour la partie copyright.
  • Sur grand écran le copyright se trouve à gauche et prend 8/12ème de la place en largeur tandis que la partie de partage se trouve à droite et en prend 4/12ème. La partie de gauche a son texte aligné à gauche et la partie de droite a son texte aligné à droite.

Cependant les designers pensent que pour des raisons d'ergonomie il est préférable que sur la page d'accueil le bouton Facebook soit à gauche et prenne la moitié de la place et que le copyright soit à droite en prenant l'autre moitié. C'est donc à présent le copyright qui est aligné à droite sur grand écran.

Les trois choix aberrant faisable avec du développement HTML-driven

C'est là que l'utilisation d'un Framework va forcer les développeurs à faire de mauvais choix de développement puisque cette modification ne devrait impacter que les intégrateurs Front-end, cependant...

  1. Le plus simple sera de dire aux designers ou au client que cette modification n'est pas possible. Le « Footer » doit rester consistant et étant utilisé sur toutes les pages du site il n'est pas possible d'avoir un « Footer » spécifique. Des raisons techniques seront avancées comme des contraintes Bootstrap, etc.

  2. Un composant alternatif va être crée part les développeur Back-end afin de répondre à cette demande. Une condition sera mise en place pour que le composant du Footer alternatif soit injecté sur l'accueil et uniquement sur l'accueil. Cela forcera également de dupliquer du code qu'il faudra maintenir en double en cas de changement.

    <footer class="container">
     <div class="row">
         <div class="col-sm-6">
             <div class="hidden-xs">
                 <a href="">Join us on Facebook !</a>
             </div>
             <div class="text-center visible-xs">
                 <a href="">Join us on Facebook !</a>
             </div>
         </div>
         <div class="col-sm-6">
             <div class="text-right hidden-xs">
                 All rights not reserved.
             </div>
             <div class="visible-xs">
                 All rights not reserved.
             </div>
         </div>
     </div>
    </footer>
    
  3. Dans un cas extrême il serait même envisagé de faire travailler les Content Filler en plaçant les classes dans des variations de contenu par page de manière à ne pas injecter les mêmes classes en fonction de la page appelée avec un code comme celui ci-dessous... le summum de l'aberrance.

    <footer class="container">
     <div class="row">
         <div class="<column-left>">
             <div class="<mobile>">
                 <a href="">Join us on Facebook !</a>
             </div>
             <div class="<desktop>">
                 <a href="">Join us on Facebook !</a>
             </div>
         </div>
         <div class="<column-right>">
             <div class="<mobile>">
                 All rights not reserved.
             </div>
             <div class="<desktop>">
                 All rights not reserved.
             </div>
         </div>
     </div>
    </footer>
    

La solution logique de l'approche CSS-driven

Le HTML n'aurait absolument pas besoin de changer puisque la demande concerne le design. C'est donc bien le développeur Front-end qui doit s'occuper de cette tâche et en assurer l'évolution et la maintenance. Cela signifie simplement que si le « Footer » est injecté sur un layout comportant la classe .home en amont (sur le <body> par exemple). Il suffit alors d'ajouter à la fin de la feuille CSS les règles suivantes :

@media (min-width: 768px) {
    .home .copyright,
    .home .share,
.col12-6 { width: 50%; }

    .home .copyright,
    .home .share,
.push-pull-reset { left: 0; right: 0; }

    .home .share,
.text-left { text-align: left; }

    .home .copyright,
.text-right { text-align: right; }
}

Profiter des avantages d'un Framework CSS tout en respectant les bonnes pratiques

C'est ici qu'intervient le préprocesseur Less. Sans être un grand expert dans ce languages on peut très facilement tirer parti des avantages d'un Framework CSS comme Bootstrap sans surcharger d'une seule ligne son DOM.

Less vous permet d'utiliser des variables dans votre CSS ainsi que des raccourcis de classe à la place de retaper toutes vos propriétés CSS. En sortie, c'est bien un fichier CSS qui est généré mais, vous n'avez pas besoin de vous en pré-occuper :

  • Vous n'avez qu'à maintenir le .less dans vos fichiers et le .css est automatiquement généré. Un fichier .css.map permet également à votre navigateur de vous indiquer pour un élément HTML ciblé dans votre débogueur F12 quelles lignes du fichier .less sont utilisées (C'est le cas pour Google Chrome sans aucune intervention de votre part).
  • Pour maintenir non plus un fichier .css, mais un fichier .less, il va vous falloir un logiciel qui va exécuter pour vous votre fichier test.less avant le renvoi de la réponse au client quand le fichier test.css est demandé.
  • Une fois en environnement de production on active aucunement Less et c'est bien test.css qui sera renvoyé sans calcule supplémentaire quand une requête pour test.css sera effectuée par le client.

Pour ma part, j'utilise le moteur de sites web Node.js : NodeAtlas. Il permet d'activer Less facilement dans un environnement de développement pour travailler dans les règles de l'art avec les versions Less de vos Frameworks préférés !

Étude d'un exemple avec Bootstrap

Il vous faudra :

Sources

Explications

Nous allons habiller la structure HTML suivante avec Bootstrap ; notez qu'aucune classe Bootstrap ne vient polluer le DOM HTML :

HTML

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Less Example with Bootstrap</title>
    </head>
    <body>
        <header>
            <div class="brand">

                <div class="logo component">
                    <h3>Bruno Lesieur</h3>
                </div>

            </div>
            <div class="slogan">

                <div class="markdown component">
                    <p>Some #ID with lot of .CLASS</p>
                </div>

            </div>
            <div class="title">

                <div class="logo component">
                    <h1>Quelque #ID et beaucoup de .CLASS</h1>
                </div>  

            </div>
            <nav class="main-nav">

                <div class="navigation component">
                    <ul>
                        <li><a href="">Home</a></li>
                        <li><a href="">Section A</a></li>
                        <li><a href="">Section B</a></li>
                        <li><a href="">Section C</a></li>
                    </ul>
                </div>      

            </nav>
        </header>
        <div class="content">
            <section class="overview">

                <div class="carousel component">
                    <h1>Slide 1</h1>
                    <p>Bla bla bla</p>
                </div>  

            </section>
            <nav class="anchor-nav">

                <div class="navigation component">
                    <h2>Summary</h2>
                    <ul>
                        <li>
                            <a href="#h1-title">H1 Title</a>
                            <ul>
                                <li>
                                    <a href="#h2-title">H2 Title</a>
                                    <ul>
                                        <li><a href="#h3-title-1">H3 Title 1</a></li>
                                        <li><a href="#h3-title-2">H3 Title 1</a></li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </div>

            </nav>
            <article class="main">
                <div class="article">

                    <div class="markdown component">
                        <header>
                            <h1 id="h1-title">H1 Title</h1>
                            <p>This is a leading text for my article</p>
                        </header>

                        <h2 id="h2-title">H2 Title</h2>
                        <p>Bla bla bla</p>

                        <h3 id="h3-title-1">H3 Title 1</h3>
                        <p>Bla bla bla</p>

                        <h3 id="h3-title-2">H3 Title 2</h3>
                        <p>Bla bla bla</p>

                        <header>
                            <footer>
                                <p>by <a href="">MachinisteWeb</a></p>
                                <p>date, etc</a></p>
                            </footer>
                        </header>
                    </div>

                </div>
                <ul class="step-list">
                    <li class="step">

                        <div class="markdown component">
                            <h3>H3 Step</h3>
                            <p>Bla bla bla</p>
                        </div>

                    </li>
                    <li class="step">

                        <div class="markdown component">
                            <h3>H3 Step</h3>
                            <p>Bla bla bla</p>
                        </div>

                    </li>
                    <li class="step">

                        <div class="markdown component">
                            <h3>H3 Step</h3>
                            <p>Bla bla bla</p>
                        </div>

                    </li>
                </ul>
            </article>
            <ul class="call-to-action-list">
                <li class="call-to-action">

                    <div class="markdown component">
                        <h2>H2 Action</h2>
                        <p>Bla bla bla</p>
                    </div>

                </li>
                <li class="call-to-action">

                    <div class="markdown component">
                        <h2>H2 Action</h2>
                        <p>Bla bla bla</p>
                    </div>          

                </li>
                <li class="call-to-action">

                    <div class="markdown component">
                        <h2>H2 Action</h2>
                        <p>Bla bla bla</p>
                    </div>          

                </li>
            </ul>
        </div>
        <footer>
            <nav class="secondary-nav">

                <div class="navigation component">
                    <ul>
                        <li>
                            <a href="">Contact us</a>
                        </li>
                    </ul>
                </div>

            </nav>
            <div class="utils">

                <div class="markdown component">
                    <p>Join us on Google+</p>
                </div>  

            </div>
            <div class="legals">

                <div class="markdown component">
                    <p>©All Right not reserved at all</p>
                </div>  

            </div>
        </footer>
    <body>
</html>

Et voici le fichier Less expliqué :

Less

/*------------------------------------*\
    $SUMMARY
\*------------------------------------*/

/**
 * SUMMARY.................C'est moi !
 * RESET...................Même rendu pour tous les navigateurs.
 * IMPORT..................Les fichiers Less nécessaire de Bootstrap.
 * TESTS...................Des règles CSS activables et désactivables pour les tests.
 * GRID....................Habillage de la grille.
 */





/*------------------------------------*\
    $RESET
\*------------------------------------*/

/* On inclut le padding à la taille. */
* {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}

/* On évite les marges. */
body {
  margin: 0;
  padding: 0;
}





/*------------------------------------*\
    $IMPORT
\*------------------------------------*/

/* On importe les variables du Framework. */
@import 'bootstrap/variables';

/* On importe le système de grille. */
@import 'bootstrap/grid';
@import 'bootstrap/mixins/grid';
@import 'bootstrap/mixins/grid-framework';

/* On importe le système de responsivité. */
@import 'bootstrap/responsive-utilities';
@import 'bootstrap/mixins/responsive-visibility';

/* À titre d'exemple, voici tout ce qu'il faudrait importer pour utiliser `.text-center` et `.text-right`. Il n'est parfois pas toujours judicieux d'importer des parties de Framework quand on a besoin que d'une classe. Nous créerons notre propre alignement plus bas. */
/*
@import 'bootstrap/type';
@import 'bootstrap/mixins/text-overflow.less';
@import 'bootstrap/mixins/text-emphasis.less';
@import 'bootstrap/mixins/background-variant.less';
*/





/*------------------------------------*\
    $TESTS
\*------------------------------------*/

/* Afficher les zones plus facilement dans la page HTML pour déboguer l'affichage. */
.brand:before,
.slogan:before,
.title:before,
.main-nav:before,
.overview:before,
.anchor-nav:before,
.main:before,
.call-to-action:before,
.secondary-nav:before,
.legals:before,
.utils:before {
   width: 100%;
   display: inline-block;
}

.brand:before {
    content: "Brand";
   background-color: rgba(0, 0, 150, 0.5);
}
.slogan:before {
   content: "Slogan";
   background-color: rgba(150, 150, 0, 0.5);
}
.title:before {
   content: "Title";
   background-color: rgba(255, 0, 0, 0.2);
}
.main-nav:before {
   content: "Nav";
   background-color: rgba(0, 255, 0, 0.2);
}
.overview:before {
   content: "Overview";
   background-color: rgba(150, 0, 0, 0.5);
}
.anchor-nav:before {
   content: "Anchor nav";
   background-color: rgba(0, 0, 255, 0.2);
}
.main:before {
   content: "Main";
   background-color: rgba(255, 255, 0, 0.2);
}
.call-to-action:before {
   content: "Call to action";
   background-color: rgba(255, 0, 255, 0.2);
}
.secondary-nav:before {
   content: "Secondary nav";
   background-color: rgba(0, 150, 0, 0.5);
}
.legals:before {
   content: "Legals";
   background-color: rgba(0, 255, 255, 0.2);
}
.utils:before {
   content: "Utils";
   background-color: rgba(150, 0, 150, 0.5);
}
.main:before {
  content: none;
}
.article:before {
  content: "Article";
  background-color: rgba(255, 255, 0, 0.2);
  width: 100%;
  display: inline-block;
}
.step:before {
  content: "Step";
  background-color: rgba(0, 255, 0, 0.2);
  width: 100%;
  display: inline-block;
}




/*------------------------------------*\
    $GRID
\*------------------------------------*/

/* Normalement, Bootsrap utilise la classe `.row` sur un élément enfant pour annuler le padding inutile en vu d'injecter des colonnes. Nous n'allons pas surcharger le DOM pour cela aussi nous créons une nouvelle classe qui s'applique directement sur le `.container` et qui à la même fonction. */
.padding-reset {
    margin-left: auto;
    margin-right: auto;
    padding-left: 0;
    padding-right: 0;
}

/* Nous allons manager nous même les `.row` sans nécessairement ajouter des éléments dans le DOM. */
.clear-left {
    clear: left;    
}

/* Nous allons utiliser les listes pour définir des éléments de liste et non des `div` comme Bootstrap le fait habituellement. */
.ul-reset {
    padding: 0;
    margin: 0;
    list-style: none;
}

/* Affin de ne pas importer du code inutile, nous allons nous même recréer les trois classes nécessaire pour l'alignement des textes. */
.text-right {
  text-align: right;
}
.text-left {
  text-align: left;
}
.text-center {
  text-align: center;
}





/* À partir d'ici, on habille notre grille avec les raccourcis propre à Less.
- `&:extend(<class>);` rajoute la classe courante à la liste des classes du sélecteur `<class>` à la ligne ou elle est définie.
- `<class>;` ajoute l'intégralité des sélecteurs de la classe <class> à ceux de la classe courante. */

/* Ainsi on ajoute
- `body > header, .content, body > footer` aux classes `.container` et `.padding-reset`
ce qui donnera en sortie
- `body > header, .content, body > footer, .container {}` et 
- `body > header, .content, body > footer, .padding-reset {}` */
body > header,
.content,
body > footer {
    &:extend(.container, .padding-reset);
}

/* Ici on ajoute les mécanismes des colonnes Bootstrap. */
.brand {
    .make-sm-column(2);
    .make-sm-column-push(10);
}
.slogan {
    .make-sm-column(10);
    .make-sm-column-pull(2);
}
/* On créer manuellement un retour à la ligne sous cette colonne, peut importe son contenu. */
.title {
    &:extend(.clear-left);
    .make-sm-column(2);
}
.main-nav {
    .make-sm-column(10);
}
.overview {
    .make-sm-column(12);
}
.anchor-nav {
    .make-sm-column(3);    
}
.main {
    .make-sm-column(9);    
}
.call-to-action-list {
    &:extend(.ul-reset);
}
.call-to-action {
    .make-sm-column(6);
    .make-md-column(4);
}
.call-to-action:nth-child(1) {
    .make-lg-column-offset(2);
}

/* On cache le troisième élément `.call-to-action` en fonction de la taille de l'écran représenté par les variables : `@screen-sm-min`, `@screen-md-min` et `@screen-lg-min`. */
@media (min-width: @screen-sm-min) {
    .call-to-action:nth-child(n+3) {
        display: none;
    }
}
@media (min-width: @screen-md-min) {
    .call-to-action:nth-child(n+3) {
        display: block;
    }
}
@media (min-width: @screen-lg-min) {
    .call-to-action:nth-child(n+3) {
        display: none;
    }
}
.secondary-nav {
    .make-sm-column(12);
}
.utils {
    .make-sm-column(3);
    .make-sm-column-push(9);
}
.legals {
    .make-sm-column(9);
    .make-sm-column-pull(3);
}
/* Cette fois on utilise bien `.row` pour annuler le padding de l'élément englobant afin de ré-aligner la grille interne. */
.step-list {
    &:extend(.ul-reset);
    .row;
}
.step {
    .hidden-xs;
    .make-sm-column(4);
}
.legals,
.brand {
  .text-left;
}
.utils {
  .text-center;
}
@media (min-width: @screen-sm-min) {
  .utils,
  .brand {
    .text-right;
  }
  .legals {
    .text-left
  }
}

Étude d'un exemple sans Framework

Il vous faudra :

Sources

Explications

Nous allons habiller la même structure HTML que précédemment mais à la main sans aucun Framework :

HTML

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Less Example with Bootstrap</title>
    </head>
    <body>
        <header>
            <div class="brand">

                <div class="logo component">
                    <h3>Bruno Lesieur</h3>
                </div>

            </div>
            <div class="slogan">

                <div class="markdown component">
                    <p>Some #ID with lot of .CLASS</p>
                </div>

            </div>
            <div class="title">

                <div class="logo component">
                    <h1>Quelque #ID et beaucoup de .CLASS</h1>
                </div>  

            </div>
            <nav class="main-nav">

                <div class="navigation component">
                    <ul>
                        <li><a href="">Home</a></li>
                        <li><a href="">Section A</a></li>
                        <li><a href="">Section B</a></li>
                        <li><a href="">Section C</a></li>
                    </ul>
                </div>      

            </nav>
        </header>
        <div class="content">
            <section class="overview">

                <div class="carousel component">
                    <h1>Slide 1</h1>
                    <p>Bla bla bla</p>
                </div>  

            </section>
            <nav class="anchor-nav">

                <div class="navigation component">
                    <h2>Summary</h2>
                    <ul>
                        <li>
                            <a href="#h1-title">H1 Title</a>
                            <ul>
                                <li>
                                    <a href="#h2-title">H2 Title</a>
                                    <ul>
                                        <li><a href="#h3-title-1">H3 Title 1</a></li>
                                        <li><a href="#h3-title-2">H3 Title 1</a></li>
                                    </ul>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </div>

            </nav>
            <article class="main">
                <div class="article">

                    <div class="markdown component">
                        <header>
                            <h1 id="h1-title">H1 Title</h1>
                            <p>This is a leading text for my article</p>
                        </header>

                        <h2 id="h2-title">H2 Title</h2>
                        <p>Bla bla bla</p>

                        <h3 id="h3-title-1">H3 Title 1</h3>
                        <p>Bla bla bla</p>

                        <h3 id="h3-title-2">H3 Title 2</h3>
                        <p>Bla bla bla</p>

                        <header>
                            <footer>
                                <p>by <a href="">MachinisteWeb</a></p>
                                <p>date, etc</a></p>
                            </footer>
                        </header>
                    </div>

                </div>
                <ul class="step-list">
                    <li class="step">

                        <div class="markdown component">
                            <h3>H3 Step</h3>
                            <p>Bla bla bla</p>
                        </div>

                    </li>
                    <li class="step">

                        <div class="markdown component">
                            <h3>H3 Step</h3>
                            <p>Bla bla bla</p>
                        </div>

                    </li>
                    <li class="step">

                        <div class="markdown component">
                            <h3>H3 Step</h3>
                            <p>Bla bla bla</p>
                        </div>

                    </li>
                </ul>
            </article>
            <ul class="call-to-action-list">
                <li class="call-to-action">

                    <div class="markdown component">
                        <h2>H2 Action</h2>
                        <p>Bla bla bla</p>
                    </div>

                </li>
                <li class="call-to-action">

                    <div class="markdown component">
                        <h2>H2 Action</h2>
                        <p>Bla bla bla</p>
                    </div>          

                </li>
                <li class="call-to-action">

                    <div class="markdown component">
                        <h2>H2 Action</h2>
                        <p>Bla bla bla</p>
                    </div>          

                </li>
            </ul>
        </div>
        <footer>
            <nav class="secondary-nav">

                <div class="navigation component">
                    <ul>
                        <li>
                            <a href="">Contact us</a>
                        </li>
                    </ul>
                </div>

            </nav>
            <div class="utils">

                <div class="markdown component">
                    <p>Join us on Google+</p>
                </div>  

            </div>
            <div class="legals">

                <div class="markdown component">
                    <p>©All Right not reserved at all</p>
                </div>  

            </div>
        </footer>
    <body>
</html>

Et voici le fichier Less expliqué :

Less

/*------------------------------------*\
        $SUMMARY
\*------------------------------------*/

/**
 * SUMMARY.................C'est moi !
 * VARIABLES...............Valeurs réutilisables.
 * RESET...................Même rendu pour tous les navigateurs.
 * TESTS...................Des règles CSS activables et désactivables pour les tests.
 * GRID....................Grille de base à 12 colonnes.
 * ALIGNMENT...............Alignement du contenu des colonnes.
 * VISTIBLE / HIDDEN.......Cacher / Afficher les colonnes.
 * UI......................Appliquer la CSS sur les éléments.
 */





/*------------------------------------*\
    $VARIABLES
\*------------------------------------*/

/* Les valeurs qui vont nous servir de gap pour l'affichage responsive des éléments. */
@screen-xs-max: 763px;
@screen-sm-min: 764px;
@screen-sm-max: 991px;
@screen-md-min: 992px;
@screen-md-max: 1199px;
@screen-lg-min: 1200px;





/*------------------------------------*\
    $RESET
\*------------------------------------*/

/* On inclut le padding à la taille. */
* {
    -webkit-box-sizing: border-box;
       -moz-box-sizing: border-box;
            box-sizing: border-box;
}

/* On évite les marges. */
body {
    margin: 0;
    padding: 0;
}





/*------------------------------------*\
    $TESTS
\*------------------------------------*/

/* Afficher les zones plus facilement dans la page HTML pour déboguer l'affichage. */
.brand:before,
.slogan:before,
.title:before,
.main-nav:before,
.overview:before,
.anchor-nav:before,
.main:before,
.call-to-action:before,
.secondary-nav:before,
.legals:before,
.utils:before {
    width: 100%;
    display: inline-block;
}

.brand:before {
    content: "Brand";
    background-color: rgba(0, 0, 150, 0.5);
}
.slogan:before {
    content: "Slogan";
    background-color: rgba(150, 150, 0, 0.5);
}
.title:before {
    content: "Title";
    background-color: rgba(255, 0, 0, 0.2);
}
.main-nav:before {
    content: "Nav";
    background-color: rgba(0, 255, 0, 0.2);
}
.overview:before {
    content: "Overview";
    background-color: rgba(150, 0, 0, 0.5);
}
.anchor-nav:before {
    content: "Anchor nav";
    background-color: rgba(0, 0, 255, 0.2);
}
.main:before {
    content: "Main";
    background-color: rgba(255, 255, 0, 0.2);
}
.call-to-action:before {
    content: "Call to action";
    background-color: rgba(255, 0, 255, 0.2);
}
.secondary-nav:before {
    content: "Secondary nav";
    background-color: rgba(0, 150, 0, 0.5);
}
.legals:before {
    content: "Legals";
    background-color: rgba(0, 255, 255, 0.2);
}
.utils:before {
    content: "Utils";
    background-color: rgba(150, 0, 150, 0.5);
}
.main:before {
    content: none;
}
.article:before {
    content: "Article";
    background-color: rgba(255, 255, 0, 0.2);
    width: 100%;
    display: inline-block;
}
.step:before {
    content: "Step";
    background-color: rgba(0, 255, 0, 0.2);
    width: 100%;
    display: inline-block;
}





/*------------------------------------*\
    $GRID
\*------------------------------------*/

/* On crée une grille sur 12 colonnes en affectant les valeurs. */
.span12-12 { width: 100%; }
.span12-11 { width: 91.66666667%; }
.span12-10 { width: 83.33333333%; }
.span12-9 { width: 75%; }
.span12-8 { width: 66.66666667%; }
.span12-7 { width: 58.33333333%; }
.span12-6 { width: 50%; }
.span12-5 { width: 41.66666667%; }
.span12-4 { width: 33.33333333%; }
.span12-3 { width: 25%; }
.span12-2 { width: 16.66666667%; }
.span12-1 { width: 8.33333333%; }

/* On crée de quoi déplacer les colonnes vers la droite. */
.pull12-12 { right: 100%; }
.pull12-11 { right: 91.66666667%; }
.pull12-10 { right: 83.33333333%; }
.pull12-9 { right: 75%; }
.pull12-8 { right: 66.66666667%; }
.pull12-7 { right: 58.33333333%; }
.pull12-6 { right: 50%; }
.pull12-5 { right: 41.66666667%; }
.pull12-4 { right: 33.33333333%; }
.pull12-3 { right: 25%; }
.pull12-2 { right: 16.66666667%; }
.pull12-1 { right: 8.33333333%; }
.pull12-0 { right: 0; }

/* On crée de quoi déplacer les colonnes vers la gauche. */
.push12-12 { left: 100%; }
.push12-11 { left: 91.66666667%; }
.push12-10 { left: 83.33333333%; }
.push12-9 { left: 75%; }
.push12-8 { left: 66.66666667%; }
.push12-7 { left: 58.33333333%; }
.push12-6 { left: 50%; }
.push12-5 { left: 41.66666667%; }
.push12-4 { left: 33.33333333%; }
.push12-3 { left: 25%; }
.push12-2 { left: 16.66666667%; }
.push12-1 { left: 8.33333333%; }
.push12-0 { left: 0; }

/* On crée de quoi déplacer les colonnes vers la gauche en créant des espaces vides. */
.prepend12-12 { margin-left: 100%; }
.prepend12-11 { margin-left: 91.66666667%; }
.prepend12-10 { margin-left: 83.33333333%; }
.prepend12-9 { margin-left: 75%; }
.prepend12-8 { margin-left: 66.66666667%; }
.prepend12-7 { margin-left: 58.33333333%; }
.prepend12-6 { margin-left: 50%; }
.prepend12-5 { margin-left: 41.66666667%; }
.prepend12-4 { margin-left: 33.33333333%; }
.prepend12-3 { margin-left: 25%; }
.prepend12-2 { margin-left: 16.66666667%; }
.prepend12-1 { margin-left: 8.33333333%; }
.prepend12-0 { margin-left: 0; }

/* On crée de quoi déplacer les colonnes vers la droite en créant des espaces vides. */
.append12-12 { margin-right: 100%; }
.append12-11 { margin-right: 91.66666667%; }
.append12-10 { margin-right: 83.33333333%; }
.append12-9 { margin-right: 75%; }
.append12-8 { margin-right: 66.66666667%; }
.append12-7 { margin-right: 58.33333333%; }
.append12-6 { margin-right: 50%; }
.append12-5 { margin-right: 41.66666667%; }
.append12-4 { margin-right: 33.33333333%; }
.append12-3 { margin-right: 25%; }
.append12-2 { margin-right: 16.66666667%; }
.append12-1 { margin-right: 8.33333333%; }
.append12-0 { margin-right: 0; }

/* On crée de quoi appliquer les états définis au dessus sur nos colonnes. */
.pull-push { position: relative; }
.pull-push-reset { position: static; }

/* On crée de quoi gérer les paddings. */
.gutter { padding-left: 16px; padding-right: 16px; }
.gutter-reset { padding-left: 0; padding-right: 0; }

/* On crée de quoi gérer les listes et les retours à la ligne. */
.list-reset { margin: 0;padding: 0;list-style-type: none; }
.clearfix { clear: both; }

/* On crée nos éléments unitaires. */
.grid { max-width: 1200px; margin-left:auto; margin-right:auto; }
.grid:after { content: ""; clear: both; display: block; }
.column { float: left; width: 100%; }





/*------------------------------------*\
        $ALIGMENT
\*------------------------------------*/

/* Gestion de l'alignement du contenu. */
.text-left { text-align: left; }
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-justify { text-align: justify; }





/*------------------------------------*\
        $VISTIBLE / HIDDEN
\*------------------------------------*/

/* Gestion de la visibilité du contenu. */
.display-block { display: block; }
.display-inline { display: inline-block; }
.display-inline-block { display: inline-block; }
.display-none { display: none; }





/*------------------------------------*\
    $UI
\*------------------------------------*/

/* Habillage Mobile et Petite Tablette. */
/* Comme on n'utilise pas de Media Queries dans les prochaines définitions, on peut utiliser `&:extend` qui va ajouter la classe courante au sélecteur dans `&:extend` au niveau de la définition du sélecteur plus haut, cela pour alléger la feuille CSS qui sera générées. */
body > header,
body > footer,
.content {
    &:extend(.grid);
}

body > header:after,
body > footer:after,
.content:after {
    &:extend(.grid:after);  
}

.brand,
.slogan,
.title,
.main-nav,
.overview,
.anchor-nav,
.main,
.article,
.step,
.call-to-action,
.secondary-nav,
.utils,
.legals {
    &:extend(.column);   
}

.brand,
.slogan,
.title,
.main-nav,
.overview,
.anchor-nav,
 .article,
.step,
.call-to-action,
.secondary-nav,
.utils,
.legals {
    &:extend(.gutter);
}

.step-list,
.call-to-action-list {
    &:extend(.list-reset);
}

.title {
    &:extend(.clearfix);
}

.legals,
.utils {
    &:extend(.text-center);  
}

.step {
    &:extend(.display-none);    
}

/* Tablette / Petit Écran 
On utilise nos variables `@screen-sm-min`, `@screen-md-min` et `@screen-lg-min`  pour garder toujours la même valeur dans la zone de @media.
*/

@media (min-width: @screen-sm-min) {

/* En ce qui concerne les classes dans des zones de Media Queries, il ne faut pas utiliser `&:extend` mais simplement le nom des classes de manière à dupliquer les sélecteurs de ces classes à l'intérieur de la classe que vous venez de déclarer et donc à l'intérieur des Media Queries. */
    .brand,
    .title {
        .span12-2;
    }
    .anchor-nav,
    .utils {
        .span12-3;
    }
    .step {
        .span12-4;
    }
    .call-to-action {
        .span12-6;
    }
    .legals,
    .main {
        .span12-9;
    }
    .main-nav,
    .slogan {
        .span12-10;
    }

    .utils,
    .legals,
    .brand,
    .slogan {
        .pull-push;
    }

    .utils {
        .push12-9;
    }
    .brand {
        .push12-10;
    }
    .slogan {
        .pull12-2;
    }
    .legals {
        .pull12-3;
    }
    .legals {
        .text-left;
    }
    .brand,
    .utils {
        .text-right;
    }
    .step {
        .display-block;
    }
    .call-to-action:nth-child(n + 3) {
        .display-none;
    }
}

/* Écran Standard */
@media (min-width: @screen-md-min) {
    .anchor-nav,  
    .call-to-action {
        .span12-4;
    }
    .main {
        .span12-8;
    }
    .call-to-action:nth-child(n + 3) {
        .display-block;
    }
}

/* Grand Écran */
@media (min-width: @screen-lg-min) {
    .anchor-nav {
        .span12-3;
    }
    .call-to-action {
        .span12-4;
    }
    .main {
        .span12-9;
    }
    .call-to-action:nth-child(odd) {
        .prepend12-2;
    }
    .call-to-action:nth-child(even) {
        .append12-2;
    }
    .call-to-action:nth-child(n + 3) {
        .display-none;
    }
}

De l'utilité d'un Framework

Ce que l'on peut constater facilement en étudiant les deux exemples précédents c'est que la connaissance du Framework, afin de l'utiliser judicieusement, n'est pas bien plus utile/difficile à appliquer que de créer son propre jeu de classe CSS. Les Frameworks CSS sont donc de très bonnes sources d'inspiration et l'étude de leurs mécanismes améliorera grandement vos aptitudes en CSS mais leur utilisation ne vous dispense pas de réfléchir.

Lire dans une autre langue