Vous êtes sur la page 1sur 301

Sass

& Compass
avancé
Optimiser ses feuilles de styles CSS

Mehdi Kabab

Préface de Raphaël Goetter


Sass & Compass
avancé
Grâce à Sass et à son framework CSS3 Compass, les intégrateurs et développeurs web professionnels Mehdi Kabab
confrontés à des impératifs de productivité et de maintenabilité disposent enfin d’outils libres pour écrire Expert front-end pour
de façon cohérente leurs feuilles de styles CSS. le cabinet d’expertises
Clever Age (Lyon), Mehdi
Sass, un must pour optimiser l’écriture des feuilles de styles CSS Kabab est aussi développeur
web. Son expertise l’amène
Porté par une communauté très active, le préprocesseur libre Sass offre un arsenal de fonctions pour la productivité à intervenir sur tout type
du développeur front-end : code CSS allégé et simplifié lors de la phase de développement, variables, mixins, fonctions, de projet : de l’intégration
placeholders, concaténation, validation de code à la volée… Facilitant la mise en œuvre des principes DRY et KISS, l’outil one shot jusqu’aux solutions
permet de concevoir des arborescences de projets extrêmement robustes. L’organisation logique en plusieurs fichiers permet CMS complexes. Auteur
un travail d’équipe efficace, à condition de s’assurer que tous les protagonistes se dotent de versions identiques des outils. d’un ouvrage sur Gimp,
il attache une attention
Compass, le framework CSS3 pour Sass, permet d’assurer la compatibilité du site, quel que soit le navigateur, marquant particulière au partage
la fin des longues sessions de débogage sous Internet Explorer. Il embarque un générateur d’images de sprites CSS auquel des connaissances, et fut
tout un chapitre est dédié : la génération d’images de sprites haute définition n’aura jamais été aussi simple ! chargé pendant deux ans
du cours de graphisme libre
Une référence méthodologique pour l’intégrateur web de la licence professionnelle
Communication, logiciels libres
Écrit par l’un des pionniers de l’utilisation de Sass/Compass et préfacé par Raphaël Goetter, fondateur d’Alsacreations.fr, et sources ouvertes (CoLibre)
cet ouvrage est un must pour l’intégrateur web qui souhaite acquérir les meilleures pratiques d’écriture CSS et les à l’université Lumière Lyon 2.
compétences en programmation nécessaires à la maîtrise de Sass. Retrouvez-le sur Twitter
@piouPiouM !

Au sommaire
Installation de Sass et Compass • Installer Sass, Compass… et Ruby ? • Environnements graphiques disponibles • Pre-
mière conversion d’un fichier Sass en feuille CSS • Syntaxes de Sass • Deux choix de syntaxe : Sass et SCSS • Imbriquer
les règles • Différents niveaux de commentaires • Variables • Diviser et être plus efficace • Réutiliser son code :
introduction aux mixins • Passage d’un bloc de contenu à un mixin • Héritage avec @extend • Maîtriser l’héritage avec
les placeholders • Support des Media Queries • Pièges à éviter • Développer avec Sass • Sass et les données • Des
mathématiques dans vos CSS • Directives de contrôle • Manipulations avancées avec les fonctions • Premier projet Sass
et contraintes de production • Initialiser l’arborescence du projet • Compiler un projet Sass • Utiliser des bibliothèques
Sass • Initialisation de projet facile avec Compass • Compass centralise la configuration du projet • Compiler un projet
Compass • Utiliser des bibliothèques Sass dans un projet Compass • Compass, votre futur meilleur ami • Accès simplifié
aux ressources statiques • Une boîte à outils DRY • Un framework CSS3 • Support multinavigateur (cross browser) •
Création de sprites CSS avec Compass • Qu’est-ce qu’un sprite CSS ? • Les sprites, une nécessité • La magie de Compass
pour la génération de sprites • Maîtriser les sélecteurs • Optimiser ses sprites • En finir avec des compilations trop
longues • Gérer un projet Compass : un peu de méthodologie • De la bonne gestion des versions de Sass et Compass •
Déboguer un projet Sass • Travailler en équipe • Configuration avancée avec Compass • Maintenir un casseur de cache
personnalisé • Afficher des notifications Growl sous Mac OS X • Partager des fichiers entre plusieurs projets • Guide
de survie de l’interface en ligne de commande • L’invite de commandes • Lister les fichiers • Se déplacer dans le système
de fichiers • Manipuler les fichiers • Motifs de remplacements.

ISBN : 978-2-212-13677-7
À qui s’adresse cet ouvrage ?

Conception : Nord Compo


– Au développeur-intégrateur qui cherche à s’approprier le préprocesseur CSS Sass et son framework CSS3 Compass ; Code éditeur : G13677
– À l’intégrateur expérimenté qui souhaite optimiser sa méthode de travail pour garantir la maintenabilité de ses sites ;
– Au chef de projet qui cherche à s’assurer que tous les intervenants d’un projet travaillent avec les mêmes outils.

@
Téléchargez le code source des exemples
sur le site d’accompagnement du livre
http://www.editions-eyrolles.com
Sass
& Compass
avancé
Optimiser ses feuilles de style CSS
Chez le même éditeur

Dans la collection Design web

Dans la collection A Book Apart

Dans la collection Mémento

Retrouvez aussi nos livres numériques sur


http://izibook.eyrolles.com

pII_Kabab.indd 1 30/09/13 09:25


Sass
& Compass
avancé
Optimiser ses feuilles de style CSS

Mehdi Kabab

Préface de Raphaël Goetter


ÉDITIONS EYROLLES
61, bd Saint-Germain
75240 Paris Cedex 05
www.editions-eyrolles.com

En application de la loi du 11 mars 1957, il est interdit de reproduire intégralement ou partiellement le présent ouvrage,
sur quelque support que ce soit, sans l’autorisation de l’Éditeur ou du Centre Français d’exploitation du droit de copie,
20, rue des Grands Augustins, 75006 Paris.
© Groupe Eyrolles, 2013, ISBN : 978-2-212-13677-7

Copyright_Kabab.indd 1 30/09/13 09:26


Préface
de Raphaël Goetter

Quand les spécifications CSS sont nées en 1996, durant la préhistoire du Web, elles
étaient volontairement élaborées pour un public de designers web, avec pour directive
de constituer un langage aussi simple et intuitif que possible. Cet impératif de sim-
plicité a également été cause de leurs principales lacunes : pas de variables, pas de
boucles, pas de fonctions ni de conditions en CSS.
Mais ça, c’était avant.
Le Web a beaucoup évolué depuis les années 1990, les méthodes et les outils de pro-
duction ont progressé pour s’adapter à des contraintes nouvelles. Mon métier d’inté-
grateur HTML, soumis lui aussi à cette implacable sélection darwinienne, fluctue
petit à petit pour devenir le métier plus polyvalent de développeur front-end.
Même le simpliste CSS s’est complexifié au cours de ses versions 3 et 4 en brouillon :
amusez-vous à produire des matrices et perspectives au sein des transformations et
rotations CSS 3D, et vous comprendrez ce que je veux dire.
Durant ces dernières années est apparu un panel impressionnant d’outils permettant
de faciliter et d’accélérer notre travail quotidien d’intégrateur, notre fameux
workflow : des gestionnaires de contenu (CMS), des frameworks JavaScript et CSS,
des éditeurs de texte de plus en plus sophistiqués, et surtout des préprocesseurs CSS
– codes produisant du code – destinés à pallier les faiblesses du langage CSS.
Je suis pour ainsi dire un adepte de CSS de la première heure. Un dinosaure en quelque
sorte. En tant que tel, ma première réaction envers les préprocesseurs fut celle de la
méfiance. Je leur prêtais moult inconvénients : ce n’est pas du vrai CSS ; pire, ça déna-
ture CSS (oui, moi je fais du vrai CSS), ça produit une « soupe » de code, ça rajoute un
niveau de complexité, etc.
Sass et Compass
VI

Ajoutez à cela que je ne supporte guère la lecture des règles imbriquées dans les prépro-
cesseurs (je trouve ça bien plus fastidieux à lire), que je suis allergique à la ligne de com-
mande et… que je suis parfois de mauvaise foi !
Pour autant, il faut parfois savoir prendre du recul et se rendre à l’évidence : si ces
outils existent et se démocratisent, c’est bien qu’ils répondent à un besoin. Et ce
besoin est simple : contourner certaines contraintes modernes de délais et de rende-
ment sans perdre en qualité de production.
De nombreuses idées reçues (et fausses) circulent autour des préprocesseurs CSS. J’ai
appris à en surmonter quelques-unes à partir du moment où j’ai assimilé trois points
essentiels les concernant :
1 Un préprocesseur n’est ni du CSS ni une extension de CSS, il produit simplement
du CSS.
2 Un préprocesseur ne produit pas forcément du code sale, il ne fait que ce que vous
lui dites de faire.
3 (Corollaire du 2.) Si vous ne connaissez pas bien CSS, un préprocesseur produira
du code sale.
Nul doute que chacun de nous sache s’adapter au changement et pratique sa veille quo-
tidienne. Les préprocesseurs CSS, bien employés, peuvent devenir redoutablement
efficaces une fois intégrés dans notre flux de production moderne. Et si, en plus, l’un
d’eux parvient à me construire des sprites CSS automatiquement sans que j’aie à
m’arracher un seul cheveu, comme le fait déjà Compass, c’est à moitié gagné pour moi !
Le livre de Kaelig (Deloumeau-Prigent) m’a donné envie de tester des préprocesseurs
et de jouer avec ; celui de Mehdi m’a ouvert les yeux sur l’évidence de les employer
régulièrement dans mon travail d’intégrateur.
Sass et Compass sont aujourd’hui des produits mûrs portés par une communauté très
riche, et leurs bénéfices vont – comme à moi – vous paraître évidents : code CSS extrê-
mement allégé et simplifié lors de la phase de développement, variables, fonctions, pré-
fixes, concaténation, correction et validation de code à la volée… Autant de fonctionna-
lités désormais automatisées qui ne perturberont plus votre routine journalière de travail.
Je suis heureux que l’ouvrage de Mehdi soit publié et m’en apprenne plus sur ces
outils inévitablement appelés à devenir les compagnons fidèles de notre quotidien.

Raphaël Goetter
www.goetter.fr
fondateur d’Alsacréations
Table des matières

Avant-propos ................................................................................. 1
Pourquoi ce livre ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
À qui s’adresse cet ouvrage ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Structure de l’ouvrage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Remerciements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

CHAPITRE 1
Installation de Sass et Compass................................................... 5
Installer Sass, Compass… et Ruby ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Installation sous Mac OS X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Ouvrir le terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Mettre à jour les paquets Ruby (RubyGems) . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Installer Sass et Compass depuis RubyGems . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
En cas de problème sous Mac OS X. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Installation sous Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Ouvrir l’invite de commandes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Installer Ruby. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Installer Sass et Compass depuis RubyGems . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Installation sous Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Environnements graphiques disponibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
L’environnement Compass.app pour Linux, Windows et OS X . . . . . . . . . . . . 15
Le compilateur Scout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Prepros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
CodeKit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Mixture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Première conversion d’un fichier Sass en feuille CSS . . . . . . . . . . . . . . . . . . . . . . 17
Session interactive de Sass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Sass et Compass
VIII

CHAPITRE 2
Une syntaxe de Sass .................................................................... 21
Deux choix de syntaxe : Sass et SCSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
De CSS à SCSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Imbriquer les règles, une révolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Sélecteur parent & . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Imbriquer les groupes de sélecteurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Sélecteurs avancés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Les propriétés imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Différents niveaux de commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Les commentaires silencieux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Conserver les commentaires de licence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Les variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Déclarer et utiliser une variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Portée d’une variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Portée locale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Variable globale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Écraser une variable globale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
Variable globale ou locale ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Interpoler une variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Diviser et être plus efficace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Les feuilles de styles partielles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Mise en pratique des feuilles de styles partielles . . . . . . . . . . . . . . . . . . . . . . . . . 46
Importations imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Limites de l’instruction @import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Définir des variables par défaut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Réutiliser son code : introduction aux mixins . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Définir un mixin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Appeler un mixin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Règles CSS dans les mixins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Passage d’arguments à un mixin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Arguments par défaut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Liste d’arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
Passage d’un bloc de contenu à un mixin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Héritage avec @extend . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Utiliser l’héritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
Du bon usage de l’héritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Implications pour les règles imbriquées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Création de sélecteurs nuisibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Maîtriser l’héritage avec les placeholders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Table des matières
IX

Usage avancé des placeholders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76


Support des Media Queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Imbriquer les Media Queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Des variables pour être lisible . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Media Queries avancées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Les pièges à éviter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Syndrome de l’imbrication aiguë . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
La règle de l’inception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Héritages complexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Consolider à tort un héritage par placeholder . . . . . . . . . . . . . . . . . . . . . . . . . 89
Ordre d’apparition des placeholders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

CHAPITRE 3
Développer avec Sass.................................................................. 93
Sass et les données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Les principaux types de données . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Les chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
Les valeurs numériques. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Les couleurs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Les booléens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Les listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Connaître le type d’une donnée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Le cas particulier de la valeur nulle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Des mathématiques dans vos CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
Comparaison de valeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Opérations numériques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
Opérations avec des unités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Opérations sur les chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Opérations sur les couleurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Opérations booléennes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Les directives de contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Les tests conditionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Les boucles @for et @while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Les itérations de listes avec @each . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Manipulations avancées avec les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Fonctions sur les chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Fonctions numériques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Fonctions sur les couleurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
Fonctions RGB. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
Sass et Compass
X

Fonctions HSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116


Fonctions d’opacité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Autres fonctions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Fonctions sur les listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
Fonctions d’introspection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
Fonctions utilitaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Fonctions personnalisées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

CHAPITRE 4
Premier projet Sass et contraintes de production.................. 123
Initialiser l’arborescence du projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Arborescence type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Initialisation rapide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Le cas des mixins tierce partie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Renforcer la structure du projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Penser « modulaire » : l’exemple de SMACSS . . . . . . . . . . . . . . . . . . . . . . . . 134
Principe de fonctionnement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
SMACSS appliqué à Sass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
Compiler un projet Sass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Compilation manuelle. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Compilation automatique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Utiliser des bibliothèques Sass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Initialisation de projet facile avec Compass . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Créer un nouveau projet Compass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
Transformer un projet existant en projet Compass . . . . . . . . . . . . . . . . . . . . 148
S’appuyer sur un fichier de configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Compass centralise la configuration du projet . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Anatomie d’un fichier de configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Options disponibles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
Fichier de configuration type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
Compiler un projet Compass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Compilation manuelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Compilation automatique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
Utiliser des bibliothèques Sass dans un projet Compass . . . . . . . . . . . . . . . . . . . 158
En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
Table des matières
XI

CHAPITRE 5
Compass, votre futur meilleur ami.......................................... 159
Accès simplifié aux ressources statiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Ne perdez plus vos images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
Récupérer les dimensions d'une image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
Embarquer des images dans la feuille de styles . . . . . . . . . . . . . . . . . . . . . . . 164
Compass, une boîte à outils DRY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Une documentation riche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Déterminer quels fichiers importer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Compass, un framework CSS3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
La guerre des préfixes, un lointain souvenir . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Les grands classiques de CSS3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Coins arrondis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Ombres portée. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
@font-face facile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Un module d'image très complet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
Un support cross-browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Un outil à l'écoute du marché . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
Un support cross-browser paramétrable . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
Compass, ou comment oublier Internet Explorer . . . . . . . . . . . . . . . . . . . . . 182
Génération automatique de hacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Désactiver le support d’Internet Explorer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

CHAPITRE 6
Création de sprites CSS avec Compass .................................... 185
Qu'est-ce qu'un sprite CSS ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
Les sprites, une nécessité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
Accélérer le chargement de la page web . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
Créer une sprite map n'est pas une sinécure . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Compass, ce super-héros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
La magie de Compass pour la génération de sprites . . . . . . . . . . . . . . . . . . . . . . 189
Créer une sprite map CSS avec Compass . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
Générer les sprites CSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
Paramétrer une sprite map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Augmenter l'espace autour des sprites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Préciser les dimensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
Configurer la position. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Des positions exprimées en pourcentages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
Répéter un sprite horizontalement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
Sass et Compass
XII

Configurer le nom de la classe de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200


Choisir l'agencement optimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
Ordonner les images dans la sprite map. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
Intégrer la sprite map via Data-URI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
Gestion automatique des pseudo-classes CSS . . . . . . . . . . . . . . . . . . . . . . . . 203
Maîtriser les sélecteurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204
Des sprites aux petits oignons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 209
Exemple 1 : personnaliser les sélecteurs des sprites . . . . . . . . . . . . . . . . . . . . 213
Exemple 2 : supprimer la répétition des dimensions . . . . . . . . . . . . . . . . . . . 214
Exemple 3 : des sprites CSS en haute définition . . . . . . . . . . . . . . . . . . . . . . 217
Exemple 4 : déclarer les dimensions des sprites par taille d’image . . . . . . . . . . 221
En finir avec des compilations trop longues . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Origine du problème . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227

CHAPITRE 7
Gérer un projet Compass :
un peu de méthodologie .......................................................... 229
De la bonne gestion des versions de Sass et Compass . . . . . . . . . . . . . . . . . . . . 230
Problèmes rencontrés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
Le gestionnaire de paquets Bundler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Déclarer les gems d’un projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
Installation de Bundler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Installer les gems propres au projet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233
Cycle de vie des gems d’un projet avec Bundler . . . . . . . . . . . . . . . . . . . . . . . 236
Partager son projet géré par Bundler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
Déboguer un projet Sass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
Exploiter les informations de débogage de Sass . . . . . . . . . . . . . . . . . . . . . . . 239
Focus sur une solution en devenir : Source Maps . . . . . . . . . . . . . . . . . . . . . . 242
Activer le support de Source Maps dans Sass . . . . . . . . . . . . . . . . . . . . . . . . . . 243
Activer le support de Source Maps dans Compass . . . . . . . . . . . . . . . . . . . . . . 244
Activer le support de Source Maps dans le navigateur . . . . . . . . . . . . . . . . . . . 245
Exploiter les Source Maps du préprocesseur dans le navigateur . . . . . . . . . . . . 247
Travailler en équipe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
Stratégies de gestion des styles CSS générés . . . . . . . . . . . . . . . . . . . . . . . . . 252
Stratégie 1 : versionner les styles CSS compressés . . . . . . . . . . . . . . . . . . . . . 252
Ciel, un conflit ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Stratégie 2 : utiliser un script de déploiement . . . . . . . . . . . . . . . . . . . . . . . . 254
Documentez ! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
En résumé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
Table des matières
XIII

ANNEXE A
Configuration avancée avec Compass ..................................... 259
Maintenir un casseur de cache personnalisé . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
Afficher des notifications Growl sous Mac OS X . . . . . . . . . . . . . . . . . . . . . . . 262
Partager des fichiers entre plusieurs projets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
Mise en œuvre avec Sass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Mise en œuvre avec Compass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267

ANNEXE B
Guide de survie de l’interface en ligne de commande .......... 269
L’invite de commandes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Lister les fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
Faciliter la lecture de la liste de fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
Afficher les fichiers cachés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Se déplacer dans le système de fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Revenir dans son répertoire personnel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
Remonter dans l’arborescence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Alterner entre deux emplacements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
Manipuler les fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Créer un fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Créer un répertoire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Copier des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
Déplacer des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
Supprimer des fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
Motifs de remplacements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279

Index........................................................................................... 281
Avant-propos

Sass est un préprocesseur CSS dont le but est d’épargner bien du labeur à ceux qui
doivent produire des feuilles de styles.
Tel était en tout cas l’objectif de Hampton Catlin (http://www.hamptoncatlin.com/) lorsqu’il
l’a développé en 2006. Hampton Catlin est connu notamment pour avoir créé les
sites et les applications mobiles de la fondation Wikimedia. Aidé de Nathan
Weizenbaum (http://nex-3.com/), ils ont doté Sass de mécanismes similaires à ceux
trouvés dans des langages de développement tels que Ruby, PHP ou Python. Un pari
réussi en demi-teinte à l’époque. En effet, la syntaxe fortement inspirée de celle du
langage Ruby en faisait un outil peu accessible pour les intégrateurs web.
Le préprocesseur connaît un regain d’intérêt en 2008 lorsque Chris Eppstein (http://
chriseppstein.github.io/) rejoint l’équipe de développement. Avec Nathan, devenu entre-
temps leader du projet, ils font évoluer la syntaxe du préprocesseur pour qu’elle soit
compatible avec CSS. La version 2.2.0 paraît mi-2009. Cette fois, l’objectif est
atteint : en rapprochant la syntaxe de Sass de celle de CSS, la prise en main de l’outil
devient plus facile et permet de réduire les temps de développement, y compris pour
le débutant. L’adoption du préprocesseur se démocratise alors dès l’année 2010.
C’est aussi en 2008 que Chris Eppstein développe Compass, le premier framework
pour Sass. Véritable boîte à outils CSS3, Compass se rend rapidement indispensable
à ceux qui l’utilisent, grâce à des fonctionnalités puissantes telles qu’un générateur de
sprites CSS.
Sass est devenu si populaire que d’importantes équipes de développement, telle celle
de Google Chrome, contribuent au projet. C’est ainsi que le support de Source Maps
(voir chapitre 7) a récemment été ajouté à Sass.
Le préprocesseur et son framework CSS3 jouent désormais un rôle important dans la
création de feuilles de styles. À tel point que le réseau social professionnel LinkedIn a
embauché Chris Eppstein pour lui donner, entre autres missions, celle de maintenir
Sass et Compass.
Sass et Compass
2

Il est toujours difficile de choisir une solution technique. Sans verser dans le prosély-
tisme aveugle, rappeler brièvement la genèse d’un projet aide à en évaluer la maturité.
Sass est déjà vieux de sept années bien remplies, et à l’abri du soupçon d’effet de
mode. Le nombre de ses contributeurs va grandissant. Sa pérennité est assurée.
N’ayez crainte, vous avez fait le bon choix !

Pourquoi ce livre ?
Les préprocesseurs CSS tels que Sass séduisent de plus en plus d’acteurs du Web. Mais
force est de constater que l’outil et son framework CSS3 Compass sont souvent mal
utilisés, faute d’ouvrages et d’articles de référence. Ces usages maladroits conduisent à
des feuilles de styles excessivement complexes, lorsqu’elles ne vont pas jusqu’à rendre
impossible toute évolution d’un projet à cause d’une cascade CSS mal maîtrisée.
Ayant intégré dès 2010 Sass et Compass à ma boîte à outils de développeur front-
end, j’ai eu l’occasion de les utiliser dans de nombreux projets. Le travail dans une
agence web comme Clever Age m’a permis d’exploiter ces deux outils dans des cir-
constances diverses et variées, allant du simple site statique à la création de plusieurs
thèmes complexes pour des sites multilingues propulsés par Drupal.
Fort de ces expériences, et des enseignements que j’ai pu tirer de mes erreurs, je vous
propose dans cet ouvrage de partager mon savoir-faire, afin je l’espère de vous aider à
tirer le meilleur de Sass et Compass, pour produire un code maintenable et éviter les
pièges de certaines fonctionnalités à double tranchant, que sont l’imbrication ou
l’héritage des règles CSS.

Clever Age

Clever Age est un cabinet d’expertises qui se positionne sur l'ensemble de la chaîne
de production web depuis plus de 10 ans. Cette couverture 100% digitale, ainsi que
ses références, en font un prestataire majeur du marché francophone. La société pri-
vilégie un usage pragmatique des technologies du Web, appliquant les bonnes prati-
ques techniques et méthodologiques sur les standards, l'ergonomie et l'accessibilité,
la performance, la capitalisation.
B http://www.clever-age.com/
Avant-propos
3

À qui s’adresse cet ouvrage ?


Le soin apporté à ce livre le rendra accessible aux débutants, auxquels on explique les
premières étapes d’installation et de prise en main, mais il s’adresse surtout :
• au développeur-intégrateur qui cherche à s’approprier le préprocesseur CSS et
son framework CSS3 ;
• à l’intégrateur expérimenté qui souhaite optimiser sa méthode de travail ;
• au chef de projet qui cherche à s’assurer que tous les intervenants d’un projet tra-
vaillent avec les mêmes outils.

Structure de l’ouvrage
Le livre est découpé en sept chapitres.
• Tout d’abord, le chapitre 1 présente la démarche d’installation de Sass et de Com-
pass en fonction des différents systèmes d’exploitation que sont Mac OS X, Linux
ou encore Windows. Des alternatives graphiques sont également proposées. L’ins-
tallation est suivie d’une première prise de contact avec le préprocesseur CSS.
• Le chapitre 2 est dédié à la syntaxe de Sass, dont on découvrira la richesse : nota-
tion imbriquée des règles, placeholders, etc.
• Le chapitre 3 traite du développement avec Sass. En effet, le préprocesseur
apporte son lot d’instructions qui l’élèvent au statut de langage de programma-
tion. Apprenez à manipuler efficacement les différents types de données de Sass
pour aborder vos projets avec une approche systématique de non-redondance
(DRY, Don't Repeat Yourself).
• Le chapitre 4 explique comment créer un premier projet Sass, et surtout com-
ment penser une arborescence robuste pour minimiser ses temps de maintenance.
On y introduira Compass, le framework CSS3 pour Sass, et son fichier de confi-
guration qui facilite la vie d’un projet.
• Le chapitre 5 est dédié à la présentation du framework Compass. De la capacité à
gérer l’accès aux ressources statiques au support multinavigateur, Compass
apporte son lot non négligeable de commodités.
• Le chapitre 6 s’étend sur un outil particulièrement utile alors que les performan-
ces des sites sont de plus en plus critiques : le générateur de sprites CSS de Com-
pass – la manipulation des sprites map n’aura plus de secret pour vous et maintenir
des sprites haute définition n’aura jamais été aussi simple.
• Enfin, le chapitre 7 donne des pistes pour organiser et maintenir un projet Sass
ou Compass… en équipe ! Il y sera aussi question de débogage, notamment avec
l’introduction du support de Source Maps dans Sass.
Sass et Compass
4

Il nous a paru utile de compléter ces chapitres avec deux annexes.


• L’annexe A propose des éléments de configuration avancée pour vos projets
Compass.
• L’annexe B, quant à elle, présente les bases de la manipulation de l’interface en
ligne de commande, outil indispensable pour qui voudrait exploiter efficacement
Sass et Compass.

RESSOURCES Code source des exemples du livre


Le code source des exemples du livre peut être téléchargé depuis le site dédié à
l’ouvrage. Les mises à jour de code sont disponibles depuis le dépôt GitHub.
B http://livre-sass-compass.fr
B https://github.com/piouPiouM/livre-sass-compass-avance/

Remerciements
Mes remerciements vont tout d’abord aux développeurs de Sass et de Compass qui ont
littéralement révolutionné mes méthodes de travail. Merci à Hampton Catlin, Nathan
Weizenbaum et Chris Eppstein et à tous les contributeurs pour votre formidable travail !
Je remercie Kaelig Deloumeau-Prigent pour m’avoir intégré à l’équipe de relecteurs
de son ouvrage CSS maintenables avec Sass & Compass (publié aux éditions Eyrolles).
Cette expérience fut le déclic qu’il me manquait pour me lancer dans la rédaction
d’un ouvrage dédié à Sass et Compass.
Muriel, des éditions Eyrolles, pour avoir cru en moi et pour sa bonne humeur et
toute l’équipe : Sophie, Géraldine, Laurène et Gaël.
Je n’oublie pas mes collègues de Clever Age Lyon qui ont intégré Sass et Compass à
leur boîte à outils, après que je leur ai présentés à mon arrivée dans l’agence en 2010.
Ils ont ainsi pu confirmer mon choix technique de l’époque.
Pour terminer, je remercie les relectrices Marie Guillaumet et Corinne Schillinger
qui ont habilement usé de la Force pour corriger mon élocution à la Yoda mais, sur-
tout, mis à contribution leur expertise pour améliorer cet ouvrage. Et merci à
Raphaël Goetter pour la préface !
Bien sûr, je n’oublie pas les amis de Yelp Lyon qui ont su comment booster ma moti-
vation (vous avez dit glaces ?).
Enfin, merci à Marie, mon rayon de soleil permanent qui a illuminé mes séances de
travail et qui a assumé mes longs mois d’indisponibilité.
Mehdi Kabab
http://pioupioum.fr/
1
Installation de Sass et Compass

L’installation de Sass et Compass ne pose aucune difficulté – y compris pour


ceux qui sont peu habitués aux outils en ligne de commande, à condition qu’ils
ne se laissent pas impressionner.

SOMMAIRE
B Installer Sass et Compass en ligne de commande
B Choisir une alternative graphique
B Transformer un fichier Sass en fichier CSS
Sass et Compass
6

Ce chapitre vous guidera pas à pas dans l’installation en ligne de commande du pré-
processeur Sass et de son framework CSS3. Une fois Sass installé, vous verrez com-
ment transformer très simplement un premier fichier Sass en feuille de styles depuis
le terminal.

Installer Sass, Compass… et Ruby ?


PERFORMANCES Sass et Compass : alternatives graphiques versus ligne de commande
Qu’on se le tienne pour dit, c’est lorsqu’ils sont exécutés en ligne de commande (depuis un terminal ou
shell) que Sass et Compass donnent le maximum d’eux-mêmes. Si vous appréhendez cette facette de
l’outil, n’ayez crainte, des alternatives graphiques seront tout de même proposées plus loin.

Sass et Compass sont des outils en ligne de commande écrits en Ruby et construits
au-dessus de ce langage de programmation. Pour en tirer toute la puissance, Ruby
doit être installé sur votre machine.

REMARQUE Sass sans Compass ?


Avant de poursuivre, je tiens à préciser que si vous n’êtes intéressé que par Sass, et non par Compass, ce
dernier n’est pas obligatoire pour utiliser le préprocesseur. Et pour cause, Compass n’est qu’un fra-
mework qui existe grâce à Sass.

VERSION Sass 3.2.x et Compass 0.12.x et nouveautés des 3.3 et 0.13 (respectivement)
Les versions de Sass et de Compass utilisées dans cet ouvrage sont celles qui sont stables et disponibles
au moment de l’écriture, à savoir :
• la version 3.2.10 pour Sass ;
• la version 0.12.2 pour Compass.
Nous présentons cependant certaines fonctionnalités qui n’en sont encore qu’à l’état de développement
ou qui sont déjà intégrées à la version de développement des deux outils. Dans ce cas, les versions utili-
sées sont les suivantes :
• la version 3.3.0.alpha.229 pour Sass ;
• la version 0.13.alpha.4 pour Compass.

Installation sous Mac OS X


Ruby est intégré dans Mac OS X, inutile donc de l’installer. Vous pouvez directe-
ment passer à l’installation de Sass et de Compass.
Installation de Sass et Compass
7
CHAPITRE 1

Ouvrir le terminal
Pour commencer, ouvrez un terminal depuis le Finder. Pour ce faire, double-cliquez
sur l’icône Terminal située dans le dossier Applications>Utilitaires.

Figure 1–1
Lancer l’application Terminal

ALLER PLUS LOIN Se familiariser avec la ligne de commande


Si vous n’êtes pas à l’aise avec la ligne de commande, consultez l’annexe B qui présente les commandes
essentielles à un usage quotidien. Nous recommandons également l’ouvrage avancé sur Mac OS X com-
portant une annexe sur l’utilisation de la ligne de commande :
R Guillaume Gète, OS X Mountain Lion efficace, Eyrolles, 2013

Mettre à jour les paquets Ruby (RubyGems)


Si vous ne l’avez jamais fait, il serait bon de mettre à jour RubyGems, le gestionnaire
de paquets (gems) pour Ruby. Pour ce faire, exécutez dans le terminal la commande
suivante.
Mise à jour de RubyGems

$ sudo gem update --system

B http://rubygems.org/
Sass et Compass
8

Installer Sass et Compass depuis RubyGems


Sass et Compass sont eux aussi livrés sous la forme de paquets, ou gems. Issue du
projet RubyGems, l’installation d’une gem nommée <name> est simple :

$ gem install <name>

B.A.-BA Faut-il saisir le caractère « $ » ?


Tout au long de cet ouvrage, nous rappelons en début de chaque ligne de commande saisie par l’utilisa-
teur le symbole dollar $, pour deux raisons :
1. Pour tous les systèmes de type *nix — comme Linux, Unix, Mac OS X — il est internationalement con-
venu de différencier les commandes lancées par l’utilisateur courant de celles qui sont exécutées en
ayant obtenu les privilèges du super-utilisateur de la machine, j’ai nommé root. Dès lors, le caractère
dollar $ identifie l’utilisateur courant (vous) et le caractère dièse # le super-utilisateur (ce même carac-
tère utilisé pour écrire un hashtag sur les réseaux sociaux).
2. La présence du symbole facilite la lecture des sessions de travail dans le terminal. Grâce à lui, les com-
mandes saisies se détachent visuellement des messages produits.
La réponse est donc non, il ne faut pas saisir le symbole $, sous peine de voir s’afficher le message :
bash: $: command not found.

Installation de Sass

$ gem install sass


Fetching: sass-3.2.10.gem (100%)
ERROR: While executing gem ... (Gem::FilePermissionError)
You don't have write permissions into the
/Library/Ruby/Gems/1.8 directory.

Comme dans l’exemple ci-dessus, il peut cependant arriver que la commande échoue,
suite à un problème de permissions d’écriture dans le dossier où sont stockées les gems
du système. Si tel est le cas, préfixez simplement la commande avec l’instruction sudo.
Votre mot de passe utilisateur vous sera alors demandé (invite Password:).
Je ne préciserai jamais l’instruction sudo car il faut l’utiliser avec parcimonie, par
exemple lorsque l’outil n’a pas suffisamment de droits de lecture ou d’écriture. Mal-
heureusement, beaucoup d’utilisateurs y ont recours à tort et à travers, au point de
rendre leur système instable.
Installation de Sass et Compass
9
CHAPITRE 1

Figure 1–2
Installation de Sass et Compass
depuis le terminal

Ainsi, l’installation de Sass et de Compass devient (voir figure 1-2) :


Installation de Sass et Compass

$ sudo gem install sass


Password:
Fetching: sass-3.2.10.gem (100%)
Successfully installed sass-3.2.10
1 gem installed
Installing ri documentation for sass-3.1.0...
Installing RDoc documentation for sass-3.1.0...

$ sudo gem install compass


Fetching: compass-0.12.2.gem (100%)
Successfully installed compass-0.12.2
1 gem installed
Installing ri documentation for compass-0.12.2...
Installing RDoc documentation for compass-0.12.2...

RubyGems est capable de gérer les dépendances entre gems. L’installation de Com-
pass, qui dépend du préprocesseur Sass, peut donc se résumer à une seule commande.
Installation de Compass et de ses dépendances, comme Sass

$ gem install compass

Il faut maintenant vérifier la bonne installation du préprocesseur et de son fra-


mework CSS3, en affichant leurs versions respectives (voir figure 1-3).
Sass et Compass
10

ASTUCE Arrêter l’installation des documentations


L’installation d’une gem s’accompagne parfois de l’installation de sa documentation aux formats ri et
RDoc. Rarement utiles pour les non-développeurs, vous pouvez indiquer une bonne fois pour toutes à
RubyGems que vous ne souhaitez pas les installer.
Pour cela, éditez ou créez le fichier .gemrc situé à la racine de votre répertoire utilisateur et ajoutez-y la
ligne gem: --no-ri --no-rdoc. Cela peut se faire facilement depuis le terminal :
$ echo "gem: --no-ri --no-rdoc" >> ~/.gemrc

Les deux gems sont bien installées

$ sass -v
Sass 3.2.10 (Media Mark)

$ compass version
Compass 0.12.2 (Alnilam)
Copyright (c) 2008-2013 Chris Eppstein
Released under the MIT License.
Compass is charityware.
Please make a tax deductable donation for a worthy cause:
http://umdf.org/compass

Figure 1–3
Sass et Compass sont installés,
le travail peut commencer !

En cas de problème sous Mac OS X


Il arrivera peut-être que certaines installations de gems échouent, notamment dans le
cas où une gem cherche à être compilée en tant qu’extension native, plus perfor-
mante. Cette étape nécessite la présence d’outils de développement, fournis avec
l’application Xcode d’Apple, sur votre système.
Voici les étapes à suivre pour les installer.
1 Rendez-vous dans l’App Store (Menu>App Store…).
2 Recherchez Xcode et cliquez sur le bouton Installer.
3 Une fois le téléchargement achevé, installez Xcode en exécutant Install Xcode situé
dans le dossier Applications.
Installation de Sass et Compass
11
CHAPITRE 1

Figure 1–4
Xcode dans l’App Store

4 Lancez Xcode depuis le dossier Applications.


5 Allez dans le menu Xcode>Preferences, puis dans l’onglet Downloads (Télécharge-
ments).
6 Cliquez sur le bouton Install de la ligne Command Line Tools pour lancer l’installa-
tion.

Figure 1–5
Installation des outils
de développement de Xcode
Sass et Compass
12

Installation sous Windows


Windows n’est pas livré par défaut avec Ruby. Vous devez dans un premier temps
l’installer.

Ouvrir l’invite de commandes


Pour cela, commencez par ouvrir une invite de commandes via le menu
Démarrer>Tous les programmes>Accessoires>Invite de commandes (sous Windows 7).
Vous pouvez aussi le lancer par le menu Démarrer>Rechercher les programmes et
fichiers et lancer la recherche du terme cmd (pour command).
À tout hasard, vous pouvez tester la présence de Ruby à l’aide de la commande ruby -
v. Si un message d’erreur s’affiche comme dans la figure 1-6, alors Ruby est bien
absent de votre système. Sinon la version de Ruby s’afficherait et son installation
serait de fait inutile.

Figure 1–6
Ruby est absent du système.

Installer Ruby

Figure 1–7
Télécharger l’installateur Ruby
Installation de Sass et Compass
13
CHAPITRE 1

Votre système est dépourvu de Ruby, installez-le.


1 Rendez-vous à l’adresse http://rubyinstaller.org/.
2 Cliquez sur le bouton de téléchargement intitulé Download.
3 Sur la nouvelle page (voir figure 1-7), téléchargez le paquet dont la version est
supérieure ou égale à 1.8.7 (j’opte pour le paquet Ruby 1.9.3, voir page 448 dans
l’exemple).
4 Le téléchargement terminé, lancez l’installateur.
5 Dans la fenêtre Installation Destination and Optional Tasks (« Destination de l’ins-
tallation et tâches optionnelles »), veillez bien à cocher les deux options Add Ruby
executables to your PATH (« Ajouter les exécutables Ruby dans votre PATH ») et
Associate .rb and .rbw files with this Ruby installation (« Associer les fichiers .rb et
.rbw avec cette installation de Ruby »).
6 Continuez l’installation jusqu’au bout.

Figure 1–8
Bien configurer l’installateur
Ruby

L’installation terminée, fermez l’invite de commandes précédemment ouverte, puis


relancez-la. Vérifiez la bonne installation de Ruby en affichant sa version (voir figure 1-9).
Sass et Compass
14

Figure 1–9
Ruby est correctement installé.

Installer Sass et Compass depuis RubyGems


Comme pour Mac OS X, Ruby est fourni avec le système de paquets RubyGems. La
procédure d’installation est donc identique, à l’exception que vous n’aurez jamais à
saisir l’instruction sudo sous Windows.
Installation de Sass et Compass

C:\Users\mehdi> gem install sass


C:\Users\mehdi> gem install compass

NOTE L’invite de commandes (prompt) de Windows


Dans le reste de l’ouvrage, je ne renseignerai pas l’invite de prompt de Windows, à savoir la chaîne de
caractères C:\Users\mehdi>. À la place, j’utiliserai le symbole dollar $, comme expliqué dans l’encart
« Faut-il saisir le caractère “ $ “ ? ».

Installation sous Linux


Si vous êtes sous une distribution Unix ou Linux, vous savez probablement lancer le
terminal. Vérifiez que Ruby soit bien installé sur votre système à l’aide de la com-
mande ruby -v. Si vous obtenez la réponse bash: ruby: command not found, alors il
faut l’installer.
Pour cela, recourez au système d’installation de logiciels disponible sur votre distri-
bution.

B http://fr.wikipedia.org/wiki/Gestionnaire_de_paquets
Installation de Sass et Compass
15
CHAPITRE 1

Tout est en ordre, reportez-vous aux étapes de mise à jour de RubyGems et d’instal-
lation de Sass et Compass sous Mac OS X. Les procédures sont identiques.

ALLER PLUS LOIN Se familiariser avec GNU/Linux


R Kiki Novak, Linux aux petits oignons, Eyrolles, 2009 (version ebook)
R Kiki Novak, Bien débuter avec GNU/Linux, Eyrolles, à paraître
R Raphaël Hertzog et Roland Mas, Debian Squeeze GNU/Linux, Eyrolles, 2012

Environnements graphiques disponibles


Parce que le terminal peut rebuter plus d’un utilisateur non initié à la ligne de com-
mande, des outils graphiques ont vu le jour. Tous ces outils ont la particularité
d’embarquer Sass, Compass et parfois certaines extensions pour les deux outils.
Ainsi, l’utilisateur n’a rien à installer en plus de l’outil graphique retenu.
En revanche, ces outils imposent une version de Sass et Compass pour tous vos
projets : celle qui est embarquée dans le logiciel et non forcément la dernière dispo-
nible en date. Ainsi, la technique de gestion avancée des versions des gems abordée
dans le chapitre 7 est impossible à mettre en œuvre avec un outil graphique. De
même, la mise à jour de la version embarquée se fait parfois avec plusieurs mois de
retard par rapport à sa disponibilité en ligne de commande.
Si vous préférerez y recourir, nous présentons ci-après six d’entre eux : Compass.app,
Scout, Prepros, CodeKit et Mixture. Mais rappelons encore qu’en cas de problème
avec l’un de ces outils, il est toujours temps de s’initier à la ligne de commande pour
profiter de toute la puissance du préprocesseur !

L’environnement Compass.app pour Linux, Windows et OS X


Multi-plates-formes (Windows, Mac OS X et Linux), Compass.app fut la première
interface graphique pour Sass et Compass. Complet, l’outil :
• propose le support de la version stable et de la version en développement de Sass
et Compass ;
• supporte les notifications Growl sous Mac OS X ;
• fournit le support à LiveReload pour permettre de rafraîchir automatiquement la
page du navigateur ;
• embarque un serveur web.
Sass et Compass
16

Un tutoriel vidéo est proposé pour guider les nouveaux arrivants. Payant (10 $),
sachez que 30 % seront reversés à une fondation à but non lucratif américaine spécia-
lisée dans les maladies mitochondriales.

B http://compass.handlino.com/

Le compilateur Scout
Scout est une application gratuite pour Windows et Mac OS X qui permet de com-
piler à la volée les fichiers Sass et vos projets Compass. Son interface est simple et ne
nécessite que peu de configuration.

B http://mhs.github.io/scout-app/

Prepros
Nouveau venu dans la famille des interfaces graphiques pour Sass et Compass, Prepos
fournit aussi un support à d’autres préprocesseurs CSS comme LESS ou Stylus.
Gratuit et disponible pour Windows et Mac OS X, ses fonctionnalités sont simi-
laires à celles de Compass.app. Il propose en plus des utilitaires d’optimisation des
images, de concaténation et de minification des fichiers JavaScript.

B http://alphapixels.com/prepros/

CodeKit
Produit semblable à Prepros, CodeKit est exclusivement destiné au système d’exploi-
tation Mac OS X. C’est l’outil le plus onéreux du panel présenté ici (25 €).

B http://incident57.com/codekit/

Mixture
Projet prometteur, Mixture est un outil de prototypage et de création rapide de sites
statiques. Son support de Sass et Compass est bon, et permet même d’utiliser l’envi-
ronnement Ruby et RubyGems de votre système.

B http://mixture.io/
Installation de Sass et Compass
17
CHAPITRE 1

Première conversion d’un fichier Sass en feuille CSS


Sass est fraîchement installé sur votre système, que diriez-vous de transformer un
premier fichier Sass en feuille de styles ?
Créez un fichier style.scss et renseignez-y les lignes qui suivent.
styles.scss

.nav {
h2 {
margin-bottom: 8px;
}
li {
margin-bottom: 1px;
}
a {
display: block;
&:hover, &:focus {
color: royalblue;
}
&:active {
color: royalblue;
}
}
}

Dans un terminal, déplacez-vous à l’endroit où est enregistré le fichier style.scss (à


l’aide de la commande cd <chemin> – voir annexe B), puis lancez la compilation du
fichier en feuille de styles styles.css à l’aide de la commande sass <entrée> <sortie>
où <entrée> est un fichier Sass et <sortie> un fichier CSS.
Transformation par Sass du fichier en feuille de styles

$ sass styles.scss style.css

Le fichier généré montre que Sass a automatiquement résolu les différentes imbrica-
tions des sélecteurs en sélecteurs CSS valides.
styles.css

.nav h2 {
margin-bottom: 8px; }
.nav li {
margin-bottom: 1px; }
Sass et Compass
18

.nav a {
display: block; }
.nav a:hover, .nav a:focus {
color: royalblue; }
.nav a:active {
color: royalblue; }

Si vous n’aimez pas le format de sortie des règles CSS et souhaitez quelque chose de
plus traditionnel, relancez la compilation en ajoutant l’option -t expanded à la
commande :

$ sass -t expanded styles.scss style.css

styles.css en format étendu

.nav h2 {
margin-bottom: 8px;
}
.nav li {
margin-bottom: 1px;
}
.nav a {
display: block;
}
.nav a:hover, .nav a:focus {
color: royalblue;
}
.nav a:active {
color: royalblue;
}

Notez que si vous ne précisez pas de fichier de sortie (styles.css ici), Sass affichera la
transformation directement dans le terminal.
La transformation Sass en CSS s’affiche dans le terminal

$ sass -t expanded styles.scss


.nav h2 {
margin-bottom: 8px;
}
.nav li {
margin-bottom: 1px;
}
.nav a {
display: block;
}
Installation de Sass et Compass
19
CHAPITRE 1

.nav a:hover, .nav a:focus {


color: royalblue;
}
.nav a:active {
color: royalblue;
}

Pour en savoir plus sur la syntaxe de Sass, rendez-vous au chapitre suivant !

Session interactive de Sass


Comme nous le verrons au chapitre 3, Sass supporte un éventail conséquent d’ins-
tructions de programmation. Il peut parfois être préférable de tester rapidement un
calcul ou une syntaxe au lieu de lancer la compilation de tout un projet pour valider
son hypothèse.
C’est pourquoi Sass s’accompagne d’un outil de session dite interactive. Dans un ter-
minal, lancez la commande sass -i pour initialiser la session. Une invite de com-
mandes symbolisée par deux chevrons indique qu’elle attend vos instructions.
Vous pouvez par exemple demander la valeur de la composante bleue de la couleur
#ff1493 (ou deeppink) à l’aide de la fonction blue() (voir chapitre 3) ou assigner des
variables (voir chapitre 2) et les utiliser.
La session interactive de Sass en action

$ sass -i
>> blue(#ff1493)
147
>> blue(deeppink)
147
>> $gutter: 8px
8px
>> $gutter / 2
4px
>> 1em + 1px
SyntaxError: Incompatible units: 'px' and 'em'.

Pour quitter une session interactive, utilisez la combinaison de touches Ctrl + D, quel
que soit votre système d’exploitation (oui, même sous Mac OS X).
Pratique, il est toutefois important de retenir qu’elle n’accepte pas de CSS et qu’elle
n’en génère pas. En effet, son but est de tester des instructions Sass (encore appelées
SassScript) et en aucun cas des transformations CSS. Si vous souhaitez absolument
tester des transformations CSS depuis la ligne de commande, la syntaxe est la sui-
Sass et Compass
20

vante (excepté pour les utilisateurs de Windows dont le shell limité ne supporte pas
cette syntaxe).
Transformation CSS en saisie directe dans le terminal

$ sass --scss -s <<"EOF"


> .clever {
> font-weight: bold;
> .age { font-variant: small-caps; }
> }
> EOF
.clever {
font-weight: bold; }
.clever .age {
font-variant: small-caps; }

L’argument --scss indique explicitement à Sass que vous utilisez la syntaxe SCSS
(voir chapitre 2). L’option -s permet à Sass de lire les données en provenance du ter-
minal. La saisie multiligne se fait grâce à la syntaxe <<"EOF". Attention, n’oubliez pas
les guillemets sans quoi Sass générera une erreur. Après avoir appuyé sur la touche
Entrée, chaque ligne est préfixée par un chevron. Écrivez normalement vos styles
Sass. Une fois terminé, renseignez sur une ligne vide le mot indiqué précédemment
entre guillemets (soit EOF dans l’exemple) et appuyez sur Entrée. Sass réalise alors la
transformation de votre saisie en CSS.
Vous retrouverez de nombreux exemples d’usages de la session interactive au gré de
votre lecture des prochains chapitres.

OUTIL Session interactive de Compass


Compass propose lui aussi une commande pour ouvrir une session interactive : compass
interactive. Attention, elle donne accès aux fonctions de Compass mais en aucun cas à ses mixins
(voir chapitres 2 et 5). Comme avec la session interactive de Sass, la session se quitte grâce à Ctrl + D.

En résumé
Ce premier contact avec Sass a peut-être éveillé votre curiosité. Entre les règles
imbriquées, l’utilisation de variables et cette énigmatique esperluette (le caractère &),
Sass paraît plein de mystères.
Le prochain chapitre vous propose de découvrir la richesse syntaxique offerte par
Sass.
2
Une syntaxe de Sass

La force de Sass est d’introduire de nouveaux concepts pour rationnaliser


l’écriture des feuilles de styles. Quels sont-ils ? Une chose est sûre, ils changeront
votre manière de travailler.

SOMMAIRE
B Découvrir les bases de la syntaxe
B Simplifier la maintenance des feuilles de styles
B Optimiser ses feuilles de styles
B Éviter les pièges de Sass
Sass et Compass
22

Sass est l’un des préprocesseurs CSS les plus populaires. Il doit sa renommée à sa
syntaxe qui enrichit celle de son grand-frère CSS. Découvrez dans ce chapitre ce que
peut apporter cette nouvelle syntaxe à votre productivité, sans pour autant sacrifier
vos acquis, car Sass s’efforce d’être compatible avec CSS.

Deux choix de syntaxe : Sass et SCSS


Historiquement, le projet Sass était intégré au projet Haml (http://haml.info), un moteur
de gabarit HTML (ou template) écrit en Ruby. À l’instar de Python ou de Yaml,
l’indentation y joue un rôle crucial : elle permet la fermeture automatique des balises.
De fait, la forme indentée de Sass hérite de cette syntaxe tout en espaces, où les acco-
lades et autres points-virgules n’ont pas leur place.
Si vous souhaitez utiliser cette syntaxe, donnez simplement à votre fichier l’extension
.sass.

Attirante par sa concision et son gain apparent en temps de saisie, il existe une alter-
native à la syntaxe Sass : la syntaxe SCSS, ou Sassy CSS. Introduite en 2010 avec
Sass 3.0, la syntaxe SCSS est une extension de CSS3 qui évite à l’intégrateur
l’apprentissage d’un énième langage.

La syntaxe SCSS, plus naturelle pour Sass, une syntaxe indentée


l’intégrateur
.navigation { .navigation
background-color: #000; background-color: #000
color: #fff; color: #fff
}

À moins de venir du monde Ruby/Haml ou Python, la syntaxe indentée est moins


accessible au débutant et plus contraignante : une erreur d’indentation pourra trans-
former une règle en une autre. Pire, l’insertion par habitude d’un point-virgule fera
échouer la compilation.

De CSS à SCSS
Qui parle d’extension de CSS3 parle d’héritage de la syntaxe classique des feuilles de
styles. C’est pourquoi transformer un fichier CSS en un fichier SCSS est d’une faci-
lité déconcertante : renommez l’extension .css en .scss et le tour est joué !
Une syntaxe de Sass
23
CHAPITRE 2

La syntaxe SCSS sera à l’honneur dans tout l’ouvrage, car elle est plus facile d’accès
mais aussi parce qu’elle est désormais largement adoptée par la communauté. Elle est
utilisée dans la majorité des exemples et autres ressources d’aide disponibles en ligne.
Bien évidemment, si SCSS se limitait à renommer une extension de fichier, le pré-
processeur Sass n’aurait pas lieu d’être. Comme nous le verrons dans les prochaines
sections, SCSS apporte son lot d’enrichissements de la syntaxe CSS.

Imbriquer les règles, une révolution


Qu’on se le tienne pour dit, aucun développeur n’aime saisir 20 fois les mêmes sélec-
teurs pour décrire un ensemble de règles CSS. Tous rêvaient secrètement de pouvoir
les imbriquer : c’est désormais possible avec Sass.
Prenons l’exemple classique du menu de navigation constitué d’une liste non
ordonnée à représenter sous la forme d’un menu horizontal.
ch02-001.html

<ul class="menu">
<li><a href="/">Accueil</a></li>
<li><a href="/references">Nos références</a></li>
<li><a href="/a-propos">L’agence</a></li>
</ul>

Nous pourrions écrire la feuille de styles associée suivante.


Des définitions CSS redondantes

.menu {
list-style: none;
overflow: hidden;
}
.menu li {
float: left;
}
.menu li + li {
margin-left: 1em;
}
.menu a {
text-decoration: none;
}
Sass et Compass
24

L’exemple est fort simple, mais il a tout de même fallu saisir le sélecteur .menu quatre
fois et le sélecteur .menu li à deux reprises. Sur cet exemple simpliste, la situation
n’est certes pas dramatique. Mais, transposée dans le cadre d’un réel projet, le temps
perdu à répéter inlassablement les sélecteurs devient cauchemardesque.
Sass offre donc une syntaxe dite « imbriquée », qui permet de se soustraire à ces
interminables et rébarbatives répétitions. Voyez par vous-même.
ch02-001.scss

.menu {
list-style: none;
overflow: hidden;
li {
float: left;
+ li {
margin-left: 1em;
}
}
a {
text-decoration: none;
}
}

L’imbrication des sélecteurs est redoutable d’efficacité. Finie la répétition des


sélecteurs ! La lecture du code est elle aussi simplifiée.

RAPPEL Compiler un fichier Sass


Dans un terminal, déplacez-vous dans le répertoire contenant le fichier à compiler, puis lancez la com-
mande sass, en précisant le nom du fichier à traiter et éventuellement le nom du fichier CSS de sortie.
$ sass ch02-001.scss ch02-001.css

Dans un premier temps, Sass lit le premier niveau .menu (le parent) et crée une règle
si des styles le concernent, ce qui est le cas dans l’exemple présent. Ensuite, il ajoute
ce parent en préfixe à chacun de ses enfants directs li et a.
SCSS, étape transitoire

.menu {
list-style: none;
overflow: hidden;
}
.menu li {
float: left;
Une syntaxe de Sass
25
CHAPITRE 2

+ li {
margin-left: 1em;
}
}
.menu a {
text-decoration: none;
}

Sass répète ces étapes jusqu’à avoir traversé l’intégralité des niveaux enfants. Ici, le
sélecteur parent .menu li possède pour enfant le sélecteur + li. Sass génère donc un
nouveau sélecteur .menu li + li, créant ainsi la feuille de styles attendue.
CSS compilée

.menu {
list-style: none;
overflow: hidden;
}
.menu li {
float: left;
}
.menu li + li {
margin-left: 1em;
}
.menu a {
text-decoration: none;
}

Sélecteur parent &


Les sélecteurs imbriqués sont une véritable révolution dans le travail quotidien du
développeur front-end ou de l’intégrateur. Mais il est des cas où l’usage strict de
l’imbrication des règles est insuffisant et où il est nécessaire de répéter les sélecteurs.
C’est le cas des pseudo-classes.
Reprenons notre exemple de menu et, pour des raisons évidentes d’ergonomie, ajou-
tons un effet de survol sur les liens. Afin d’être compatible avec la navigation au cla-
vier, forçons également le trait lors de leur prise de focus. Un premier réflexe est
d’écrire nos pseudo-classes comme enfants du sélecteur a.
Sass et Compass
26

ch02-002.scss

.menu {
list-style: none;
overflow: hidden;
li {
float: left;
+ li {
margin-left: 1em;
}
}
a {
text-decoration: none;
:hover {
text-decoration: underline;
}
:focus {
text-decoration: underline;
}
}
}

La compilation de la feuille de styles ne retourne aucune erreur, mais le résultat n’est pas
celui escompté. En effet, les pseudo-classes générées ne s’appliquent pas aux liens.
Extrait de ch02-002.css

.menu a {
text-decoration: none;
}
.menu a :hover {
text-decoration: underline;
}
.menu a :focus {
text-decoration: underline;
}

Comme nous l’avions vu lors du traitement des piles de sélecteurs, Sass lie le parent
(.menu a) à ses enfants (:hover et :focus) en les séparant par une espace (.menu a
:hover).

Les développeurs de Sass conscients du problème ont introduit un nouveau sélecteur,


le sélecteur parent &. Son rôle est d’interférer avec la création des sélecteurs descen-
dants pour référencer le sélecteur parent lui-même.
Lorsqu’il rencontrera un sélecteur parent &, Sass le remplacera par la combinaison des
sélecteurs imbriqués jusqu’alors rencontrés.
Une syntaxe de Sass
27
CHAPITRE 2

ch02-003.scss

.menu {
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
&:focus {
text-decoration: underline;
}
}
}

Ainsi, dans l’exemple ch02-003.scss, lorsque Sass rencontre le sélecteur &:hover, il


aura déjà parcouru les deux niveaux d’imbrication .menu et a, les combinant en un
sélecteur .menu a. C’est notre sélecteur parent &. Le résultat final sera donc l’écriture
du sélecteur .menu a:hover.
ch02-003.css

.menu a {
text-decoration: none;
}
.menu a:hover {
text-decoration: underline;
}
.menu a:focus {
text-decoration: underline;
}

Puisque le sélecteur & est remplacé par le parent calculé par Sass, il peut être utilisé
pour préfixer une classe CSS, afin de créer un sélecteur plus spécifique.

SCSS CSS
.alert { .alert {
border: 1px solid #fbeed5; border: 1px solid #fbeed5;
&.error { }
border-color: #eed3d7; .alert.error {
} border-color: #eed3d7;
} }

Le sélecteur parent est aussi d’une grande aide pour simplifier l’écriture d’un style
alternatif en fonction d’une classe appliquée sur un élément parent. Prenez l’exemple
de l’identification de la version d’Internet Explorer par l’ajout d’une classe .ie ou
Sass et Compass
28

.ie7 sur la balise body ou html. L’écriture de la version spécifique à IE7 des styles de
l’élément d’identifiant #navigation devient la suivante.

SCSS CSS
#navigation { #navigation {
top: 0; top: 0;
.ie7 & { }
top: 2px; .ie7 #navigation {
} top: 2px;
} }

Une seule limite est imposée dans l’usage du sélecteur parent &. Ce dernier devra tou-
jours être précédé par un caractère blanc (une espace ou un retour à la ligne).
Il est donc interdit d’écrire un sélecteur comme div&.

Étrange au premier abord, ce comportement est pleinement justifié : Sass n’a aucune
connaissance du contexte de votre projet.
En effet, bien qu’il soit séduisant de vouloir appliquer en une seule passe un style
global (.error) et un style plus précis (textarea.error), si Sass autorisait l’écriture du
sélecteur qui suit :
.error {
/* … */
textarea& {
color: red;
}
}

L’inverse serait également permis :


textarea {
/* … */
.error& {
color: red;
}
}

Auquel cas, un nouveau sélecteur .errortextarea serait généré :


.errortextarea {
color: red;
}

Et si cette classe existait déjà dans votre projet ? Rien de tel que des surcharges non
désirées pour nuire à votre journée de travail.
Une syntaxe de Sass
29
CHAPITRE 2

Imbriquer les groupes de sélecteurs


Le langage CSS permet de regrouper plusieurs sélecteurs dans une même règle. Le
sélecteur h1, h2, h3 capture les éléments h1, les éléments h2 et les éléments h3 de la
page. Chacun des sélecteurs de ce groupe peut éventuellement être enfant d’un autre
sélecteur (.resume).
CSS

.resume h1, .resume h2, .resume h3 {


color: pink;
}

Le sélecteur parent est répété autant de fois qu’il y a d’éléments à capturer dans le
groupe de sélecteurs. L’imbrication des règles permise par Sass va une nouvelle fois
nous permettre d’économiser un précieux temps de saisie.
SCSS

.resume {
h1, h2, h3 {
color: pink;
}
}

Lors de son analyse du code, Sass découpe le groupe de sélecteurs pour les préfixer
individuellement par le sélecteur parent. Il combine .resume et h1, puis .resume et h2,
suivi par .resume et h3. Finalement, il associe les trois combinaisons dans un nouveau
groupe, générant ainsi le code répétitif vu plus haut.
Évidemment, ce mécanisme fonctionne aussi pour une règle imbriquée dans un
groupe de sélecteurs.
SCSS

.resume, .footer {
a {
text-decoration: none;
}
}

Sass va en premier lieu combiner .resume et a, puis .footer et a pour finalement ras-
sembler les deux groupes en un nouveau.
Sass et Compass
30

CSS

.resume a, .footer a {
text-decoration: none;
}

Nous n’avons jusqu’ici croisé que des imbrications d’un seul niveau de profondeur.
Sass n’impose pas de limite en la matière, vous pouvez donc tout à fait écrire le code
qui suit, économisant ainsi de nombreuses saisies.
ch02-004.scss

nav, .menu {
background-color: #fefefe;
ul, ol {
list-style: none;
padding: 0;
margin: 0;
li {
a, .link {
color: blue;
}
}
}
}

ch02-004.css

nav, .menu {
background-color: #fefefe;
}
nav ul, nav ol, .menu ul, .menu ol {
list-style: none;
padding: 0;
margin: 0;
}
nav ul li a, nav ul li .link, nav ol li a, nav ol li .link, .menu ul li a, .menu
ul li .link, .menu ol li a, .menu ol li .link {
color: blue;
}

ATTENTION Niveaux d’imbrication


Pour un meilleur contrôle de vos styles, il est important de limiter le nombre d’imbri-
cations dans votre code. Pour en savoir plus, reportez-vous à la section « Syndrome
de l’imbrication aiguë ».
Une syntaxe de Sass
31
CHAPITRE 2

Sélecteurs avancés
De nombreux sélecteurs CSS permettent de cibler plus précisément un élément de la
structure du document. Parmi les plus connus : le sélecteur d’enfant direct >, encore
appelé combinateur filial, le sélecteur d’éléments adjacents + (ou combinateur d’adja-
cence directe) et le combinateur d’adjacence indirecte ~.
Ces trois sélecteurs bénéficient de la notation imbriquée qu’offre Sass, c’est donc
naturellement que vous écrirez le sélecteur h1 ~ pre de la manière suivante.
Support du combinateur d’adjacence indirecte

h1 {
~ pre {
margin-top: .5em;
}
}

Nul besoin de précéder le combinateur ~ par le sélecteur parent &, la compilation des
sélecteurs est établie par la concaténation, niveau par niveau, des sélecteurs enfants
séparés par une espace.

SE DOCUMENTER Sélecteurs CSS


Retrouvez la spécification complète des sélecteurs CSS disponibles dans le document de la spécification :
B http://www.w3.org/TR/css3-selectors/

La totalité des pseudo-classes CSS (de niveau 1 à 3) sont supportées par Sass. Pour
les exploiter dans le style d’écriture imbriquée, préfixez-les du sélecteur parent &,
comme vu dans l’exemple ch02-005.scss.
ch02-005.scss : une lettrine en SCSS

p {
font: 1em/1.5 sans-serif;
&:first-letter {
float: left;
font-size: 3em;
line-height: 1;
margin-right: .2em;
}
}
Sass et Compass
32

ch02-005.css

p {
font: 1em/1.5 sans-serif;
}
p:first-letter {
float: left;
font-size: 3em;
line-height: 1;
margin-right: .2em;
}

Les propriétés imbriquées


L’enrichissement de la notation CSS par l’imbrication des sélecteurs est étendu aux
propriétés composites comme background-image, background-position, etc. N’avez-
vous jamais songé à une syntaxe CSS dépourvue de la répétition des préfixes que sont
background-, border-, font-, padding- ou encore margin- ? Sass répond à votre attente.

Imbrication des propriétés en Sass

.baseline {
font: {
family: Arial, sans-serif;
size: 1em;
weight: bold;
variant: small-caps;
}
}

Dans cet exemple, le préfixe font- est remplacé par font: (avec un deux-points) pour
créer une nouvelle règle dont les différentes variantes sont écrites comme de simples
propriétés, dépourvues de leur préfixe. En plus de l’économie de la saisie de 3 font-,
la lecture de la règle gagne en clarté.
Cependant, préférez la saisie de la version raccourcie de vos propriétés si vous le
pouvez. Tout aussi claire, vous économiserez le transfert de quelques octets.
Version raccourcie de l’exemple précédent

.baseline {
font: small-caps bold 1em Arial, sans-serif;
}
Une syntaxe de Sass
33
CHAPITRE 2

Différents niveaux de commentaires


CSS ne connaît qu’un format de commentaire :

/* Un simple commentaire */
.button { … }

Commode pour expliciter ses choix à l’attention du prochain intervenant sur le projet –
ou pour soi-même quelques mois après, la présence des commentaires dans les feuilles
de styles accessibles aux yeux de tous peut être un frein à leur généralisation. En outre,
leur présence alourdit inutilement le poids des données envoyées aux navigateurs, à
l’heure où le moindre octet économisé est important dans les contextes mobiles. C’est
pourquoi CSS est l’un des langages web les moins commentés qui existe.
Or, les commentaires sont indispensables dans le corps de métier qu’est l’intégration
web, qui relève parfois du mysticisme lorsqu’il faut conjuguer avec les susceptibilités
des différents navigateurs du marché.

RAPPEL Commentaires CSS et mode Sass compressé


Sass offre quatre formats de sortie du CSS compilé, allant de la version la plus verbeuse de rédaction des
styles (expanded) à une version réduisant au maximum le nombre de caractères générés (compressed).
Ce dernier mode supprimera jusqu’aux commentaires traditionnels CSS ! Au moment de la compilation,
précisez le format de sortie au moyen du paramètre --style (ou -t) :
$ sass --style compressed styles.scss

Les commentaires silencieux


Forts de ce constat, les développeurs de Sass ont agrémenté SCSS d’un nouveau
format de commentaires qui ne sera pas interprété par le moteur de compilation, et
donc absent de la sortie CSS : les commentaires silencieux.
Un commentaire silencieux de Sass

// Un commentaire silencieux Sass, ignoré à l'étape de compilation


#sidebar { … }

Finie l’application de propriétés z-index hasardeuses, du moins du point de vue du


relecteur :

.slider {
position: relative;
.slide {
Sass et Compass
34


}
+ .aside {
// On s'assure que la zone latérale du carrousel s'affiche au-dessus
// des slides. La valeur de z-index maximale d'une slide est égale
// au nombre de slides du carrousel. Il est improbable qu'un
// carrousel soit composé de plus de 50 slides.
z-index: 50;
}
}

Le précédent commentaire n’est pas avare en détails et n’a nécessité qu’une poignée
de secondes pour le rédiger. Il se révélera salutaire lorsqu’une demande d’évolution
ou un bogue sera reporté par le client.

Conserver les commentaires de licence


Supprimer tout commentaire de la sortie générée est louable lorsqu’il est question de
performances front-end, mais il existe certains cas où la présence d’un commentaire
est obligatoire : celui du rappel d’une licence de diffusion et d’utilisation.

RESSOURCE Richard Stallman et la révolution du logiciel libre


R Richard M. Stallman, Sam Williams et Christophe Masutti, Richard Stallman et la révolution du
logiciel libre – Une biographie autorisée, Eyrolles, 2013

Ce cas de figure est prévu par Sass grâce à la syntaxe [astérisque-point d’exclama-
tion] (star-bang)/*! … */. L’ajout d’un point d’exclamation à la borne ouvrante d’un
commentaire CSS oblige Sass à conserver le commentaire en l’état. Aucune suppres-
sion ne sera appliquée au contenu du commentaire.
Exemple d’en-tête de fichier SCSS pourvu de la licence MIT

/*!
* Copyright (c) 2013 Mehdi Kabab
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
Une syntaxe de Sass
35
CHAPITRE 2

* The above copyright notice and this permission notice shall be


* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
.my_project {

}

Dans ce commentaire important (loud comment en anglais) embarquant la licence


MIT, de multiples astérisques sont répétés en début de ligne. Leur présence est pure-
ment esthétique ; ils n’ont aucune incidence sur le fonctionnement des commentaires
importants.

HISTORIQUE Évolution des commentaires importants


Introduits dans Sass 3, les commentaires importants pouvaient s’écrire en conjugaison des commentaires
silencieux (//!). Cette syntaxe a été dépréciée dans la version 3.1.9 de Sass pour n’autoriser que la nota-
tion star-bang qui s’est imposée comme une convention d’écriture auprès des autres préprocesseurs CSS.
B http://sass-lang.com/docs/yardoc/file.SASS_CHANGELOG.html#319

Les variables
Au gré des évolutions d’une maquette ou des désirs du client, il est devenu courant de
devoir appliquer tour à tour diverses couleurs de fond sur un élément. Chacune de
ces couleurs se retrouve déjà dans le projet mais, par la sacro-sainte manie du « au cas
où », nous écrivons dans nos feuilles de styles CSS l’horreur suivante.
Itérations par les commentaires

.block {
// Tour à tour sont testées trois couleurs. À chaque test, l’ancienne
// couleur est commentée.
background-color: /*#f00*//*#eaeaea*/#ffc;
}
Sass et Compass
36

L’absence d’un système de variables encourage à commenter les anciennes valeurs


pour les retrouver plus tard, « au cas où » on en aurait besoin ailleurs.

T Variable

Une variable est un pointeur nommé vers un espace mémoire qui permet de stocker une donnée et d’y
accéder à tout moment en l’appelant par son nom.

L’un des progrès majeurs apporté par Sass est l’introduction d’un système de varia-
bles dans CSS ! Si vous pratiquez le langage PHP, l’écriture de variables telle que
Sass l’a implémentée vous sera familière.
Comme en PHP, Sass utilise le caractère $ pour distinguer les variables des propriétés
CSS : $highlight-color. En plus d’être facilement identifiable dans un fichier CSS, la
notation choisie n’entre pas en conflit avec les syntaxes actuelles et futures de CSS. Car
ne l’oublions pas, Sass a pour finalité d’enrichir CSS et non de le remplacer. Il est donc
vital qu’aucun conflit de syntaxe ne soit introduit par le préprocesseur.

HISTORIQUE Évolution de la syntaxe des variables


Alors que Sass 2 avait recours au point d’exclamation pour noter les variables, il a été décidé dès la ver-
sion 3.0.0 de Sass d’opter pour le caractère $ pour des raisons esthétiques mais surtout pour faciliter la
lecture du code. La lecture d’une variable comme !last-child pouvait être difficile selon la police
d’écriture utilisée par l’éditeur de code.
De la même manière, vous pourrez lire dans d’anciens articles disponibles sur la toile que la déclaration
des variables s’effectue à l’aide du signe d’égalité =. Sachez qu’il fut effectivement utilisé du temps de
Sass dans sa version 2 et inférieure mais que son usage est désormais proscrit, en faveur de la notation
native des propriétés de CSS.

Déclarer et utiliser une variable


Une variable Sass se déclare comme une propriété CSS :

$highlight-color: #ff7100;

Ci-dessus, nous déclarons la variable $highlight-color et nous lui assignons la valeur


#ff7100.

Les noms de variables obéissent aux mêmes contraintes que les noms de propriétés.
Ainsi, une variable Sass :
• ne peut pas débuter par un chiffre ;
• peut commencer par un tiret - optionnel (et un seul) ;
• peut débuter par tout caractère alphanumérique ([a-z1-9]) et le caractère tiret bas _ ;
Une syntaxe de Sass
37
CHAPITRE 2

• peut être composée par tout caractère alphanumérique ([a-z1-9]) plus les caractè-
res tiret bas _ et tiret -.

SYNTAXE Nom de variable : trait d’union ou souligné ?


Sass ne fait pas de distinction entre le trait d’union (-) et le tiret bas (_) dans les noms de variables. Ainsi,
une variable déclarée sous le nom $ma-couleur-de-fond pourra être indifféremment appelée par
$ma_couleur_de_fond ou encore $ma_couleur-de_fond.

Les noms de variables qui suivent sont donc valides : $-valid, $_valid, $v4l1d, $a-
valid_name, $__valid. Toutefois, je vous déconseille d’user de ce genre de variables qui
est le meilleur moyen pour se faite détester par ses collègues !
Les prochaines variables sont invalides et lèveront une erreur lors de la compilation :
$9nvalid, $--invalid, $#invalid.

Il est bien sûr dans votre intérêt de déclarer des variables aux noms explicites et si
possible sémantiques, comme $link-color ou $base-font_size.

NORME Support d’Unicode


Si le sujet vous intéresse, je vous conseille de vous reporter à la spécification CSS 2.1 qui détaille les con-
ventions de nommage des propriétés et autres classes CSS. Vous remarquerez alors que j’ai sciemment
passé sous silence le support des caractères de la norme ISO 10646.
En effet, le manque de lisibilité introduit par des déclarations comme $ : black; - dont la version
échappée est $\260F: black; – et les possibles incompatibilités suivant l’encodage du fichier margi-
nalisent son usage.
Voyez la spécification du W3C et la page Wikipedia sur la norme ISO 10646 :
B http://www.w3.org/TR/CSS21/syndata.html#characters
B http://fr.wikipedia.org/wiki/ISO/CEI_10646
Les types de données supportées par Sass sont plus longuement détaillés dans le chapitre 3.

Tout appel à une variable sera remplacé par sa valeur lors de la phase de compilation
par Sass. Sa définition est quant à elle absente de la sortie CSS.
Déclarer et utiliser une variable Sass

.warning {
// Déclaration de la variable $highlight-color.
$highlight-color: #ff7100;
// La variable est ensuite utilisée à deux reprises :
color: $highlight-color;
border: 1px solid $highlight-color;
}
Sass et Compass
38

CSS compilée

.warning {
color: #ff7100;
border: 1px solid #ff7100;
}

Une variable Sass peut contenir différents types de données :


• une couleur en notation hexadécimale : #ff7100 ;
• un mot-clé : red ;
• des valeurs métriques : 2px ou 2em ou 2rem, 2, etc. ;
• de multiples valeurs séparées par des espaces : 1px solid #fcc ;
• de multiples valeurs séparées par des virgules : Arial, Verdana, sans-serif ;
• plus généralement, n’importe quelle liste de valeurs.
Une unique différence avec la déclaration de propriété CSS subsiste. Contrairement
à son homologue, une variable peut être déclarée en dehors d’une règle CSS.
Déclarer une variable Sass à l’extérieur d’une règle CSS

$highlight-color: #ff7100;
.warning {
color: $highlight-color;
border: 1px solid $highlight-color;
}

CSS compilée, le résultat est identique

.warning {
color: #ff7100;
border: 1px solid #ff7100;
}

Ce qui nous amène à nous pencher davantage sur la portée des variables Sass.

Portée d’une variable


Au premier abord, l’emplacement de la déclaration d’une variable importe peu.
Celle-ci sera disponible en toute part de notre feuille de styles Sass. Cette déduction
est partiellement fausse.
En effet, chaque règle crée ce que l’on appelle un contexte de travail délimitant
chacun une portée maximale pour les variables.
Une syntaxe de Sass
39
CHAPITRE 2

Portée locale
Déclarer une variable au sein d’une règle CSS ne l’affichera qu’à l’intérieur de cette
règle et de ses enfants imbriqués.
Déclarer une variable au sein d’une règle CSS

.warning {
$highlight-color: #ff7100;
color: $highlight-color;
h3 {
color: #fff;
background-color: $highlight-color;
}
}

Résultat de la compilation

.warning {
color: #ff7100;
}
.warning h3 {
color: #fff;
background-color: #ff7100;
}

La variable est déclarée localement dans la règle CSS parente qu’est .warning. En
revanche, si nous référençons la variable $highlight-color en-dehors de ce contexte,
Sass renvoie une erreur.
Référencer une variable locale dans un contexte extérieur

.warning {
$highlight-color: #ff7100;
color: $highlight-color;
}
.warning-title {
color: #fff;
background-color: $highlight-color; 
}

[Shell] Résultat de la compilation

$ sass -t expanded ch02-006.scss


Syntax error: Undefined variable: "$highlight-color".
on line 7 of ch02-006.scss
Use --trace for backtrace.
Sass et Compass
40

Sass nous indique que la ligne 7 est responsable de l’erreur (). Effectivement, nous
référençons la variable $highlight-color dans la règle .warning-title alors qu’elle a
été définie dans la règle CSS du sélecteur .warning. Pour Sass, la variable existe uni-
quement dans le contexte créé par la règle .warning. La portée de la variable est locale
à la règle CSS et ses enfants.

Variable globale
Afin de pallier cette limitation qui se révèle contre-productive en empêchant toute
réutilisation efficace des variables, il est possible de déclarer des variables dites glo-
bales. Leur mise en œuvre est des plus simples puisqu’il suffit de les écrire à l’exté-
rieur de toute règle CSS.
Déclarer une variable globale Sass

// Déclaration d'une variable globale.


$highlight-color: #ff7100;

.warning {
color: $highlight-color;
}
.warning-title {
color: #fff;
background-color: $highlight-color;
}

CSS compilée

.warning {
color: #ff7100;
}
.warning-title {
color: #fff;
background-color: #ff7100;
}

Désormais, toute référence à la variable globale sera remplacée par sa valeur.

Écraser une variable globale


Prenons la peine d’une mise en garde contre un effet de bord de la portée globale des
variables de Sass – qui m’a causé quelques sueurs froides lors de l’apprentissage de l’outil.
Quel que soit le type de contexte, qu’il soit global ou local, toute redéclaration d’une
variable globale écrase sa précédente valeur.
Une syntaxe de Sass
41
CHAPITRE 2

Considérons les deux listings suivants.


Écraser une variable globale depuis le contexte global

// Déclaration d'une variable globale.


$highlight-color: #ff7100;
.warning {
color: $highlight-color;
}
// Redéclaration de la variable.
$highlight-color: red;
.warning-title {
color: #fff;
background-color: $highlight-color;
}
.test {
color: $highlight-color;
}

Écraser une variable globale depuis un contexte local

// Déclaration d'une variable globale.


$highlight-color: #ff7100;
.warning {
color: $highlight-color;
}
.warning-title {
color: #fff;
// Redéclaration de la variable.
$highlight-color: red; 
background-color: $highlight-color;
}
.test {
color: $highlight-color;
}

Ces deux listings généreront le même code compilé CSS où les redéclarations  et
 auront un impact au niveau des repères  et .

CSS compilée

.warning {
color: #ff7100;
}
.warning-title {
color: #fff;
background-color: red;
}
Sass et Compass
42

.test {
color: red;
}

Redéclarer une variable globale depuis un contexte local écrase la valeur de la variable
globale. Sass ne crée pas une copie de la variable globale dans la règle.

SYNTAXE Variables globales : différence d’avec PHP


Peut-être trouvez-vous ce comportement logique (et il l’est), mais après des années de développement
PHP, les habitudes ont la vie dure. Dans ce langage, l’accès à une variable globale dans une fonction (le
bel appeau à troll que voilà…) se fait explicitement à l’aide de l’instruction global. L’accès implicite aux
variables globales dans Sass peut donc être déroutant.

Variable globale ou locale ?


Le choix entre les deux portées d’une variable est simple. Déclarez votre variable glo-
balement si sa valeur doit être utilisée plusieurs fois dans le projet.
De même, si vous réutilisez les mêmes fichiers entre plusieurs projets, si vous devez
éditer une variable pour satisfaire les contraintes du nouveau projet, déclarez-la de
manière globale : il s’agit tout bonnement d’une variable de configuration.
Toutes les autres variables peuvent être déclarées localement à une règle CSS.

Interpoler une variable


Directement hérité du langage Ruby avec lequel est écrit Sass, la syntaxe de l’inter-
polation d’une variable revient à insérer la valeur d’une variable avant la compilation
finale d’une instruction.
Un exemple sera plus explicite.
Sans interpolation

$test: foobar;
p.$test {
color: blue;
}

Dans le présent listing, nous cherchons à créer dynamiquement le sélecteur p.foobar


via la variable $test. Malheureusement, en l’état, Sass n’apprécie guère la pirouette.
Une syntaxe de Sass
43
CHAPITRE 2

Tentative d’utilisation d’une variable comme nom de classe

Syntax error: Invalid CSS after "...ass: foobar; p.": expected class name, was
"$test { colo..."
on line 1 of standard input
Use --trace for backtrace.

RAPPEL Manipulation de Sass depuis le shell


Vous trouverez dans l’annexe B un aide-mémoire des commandes de terminal les plus fréquemment ren-
contrées dans le cadre d’un développement avec Sass.

Le message est sans appel : Sass invalide le nom de classe CSS $test. Le mécanisme
d’interpolation nous permet d’insérer la valeur de la variable avant la compilation
finale et donc avant la validation CSS.
Interpolation de la variable $test

$test: foobar;
p.#{$test} {
color: blue;
}

L’interpolation est réalisée en entourant notre variable du motif #{…}.


Ce mécanisme sera salutaire lorsqu’il sera question de générer, via un programme, un
ensemble de règles CSS, comme nous l'étudierons au chapitre 3.

Diviser et être plus efficace


Dans bien des disciplines et autres langages de programmation, il est coutume de limiter
la taille de nos productions pour en faciliter la maintenance. CSS fait figure d’exception.
On ne compte plus le nombre de projets constitués d’une unique feuille de styles totali-
sant le nombre hallucinant de 3 000 lignes et il n’est pas rare d’en croiser qui flirtent avec
la dizaine de milliers de lignes. Comment est-il possible dans de telles conditions de
maintenir efficacement son projet ? Comment l’équipe peut-elle s’y retrouver ?
Pour répondre à cette problématique, bien des intégrateurs prennent soin de struc-
turer leur feuille de styles en sections à l’aide de commentaires et, pour s’y repérer, y
adjoignent une table des matières.
Sass et Compass
44

C’était le cas, par exemple, du célèbre framework Foundation avant que son équipe
de développement ne migre le projet sous Sass.
Extrait du fichier globals.css de Foundation 2.2

/*--------------------------------------------------
Table of Contents
--------------------------------------------------
:: Reset & Standards
:: Links
:: Lists
:: Tables
:: Misc
*/

/*--------------------------------------------------
:: Global Reset & Standards
-------------------------------------------------- */

/*--------------------------------------------------
:: Links
-------------------------------------------------- */

/*--------------------------------------------------
:: Lists
-------------------------------------------------- */

Le découpage d’une feuille de styles en plus petites entités est pourtant possible. CSS
dispose de l’instruction @import url('…') pour charger des feuilles de styles addition-
nelles depuis une feuille de styles de base. Mais cette technique est rarement
exploitée pour des raisons de performances. En effet, le principal défaut de cette
méthodologie vient du fait que le chargement est à la charge du client web. Ainsi,
tout chargement d’une feuille de styles additionnelle entraîne une requête HTTP qui
nuit au temps de chargement de la page et donc à sa performance.
Il est évidemment possible de regrouper tous les fichiers CSS avant la mise en pro-
duction du site, mais la tâche serait nettement plus simple si un outil pouvait le faire
automatiquement, tout le temps.

RESSOURCES Le framework responsive Foundation


Basé sur Sass, Foundation est un framework front-end pour développer rapidement des sites au design
adaptif (responsive).
B http://foundation.zurb.com/
Une syntaxe de Sass
45
CHAPITRE 2

Les feuilles de styles partielles


Sass s’appuie justement sur l’instruction @import pour inclure, au moment de la com-
pilation, des fichiers en charge d’une fraction de la logique métier : les feuilles de
styles partielles (ou partial).
Pour créer une feuille de styles partielle, rien de plus simple : préfixez simplement
son nom de fichier par un tiret bas (_). Cette convention indique à Sass que le fichier
ne devra pas générer son homonyme CSS. Ainsi, créer le fichier app.scss générera un
fichier app.css, alors que le fichier _typography.scss n’en générera aucun.

Figure 2–1 Les deux fichiers SCSS sont compilés Figure 2–2 La feuille de styles partielle ne produit
en deux fichiers CSS malgré l’inclusion. pas son homologue CSS.

L’import d’un partial s’effectue en omettant la fonction url() et éventuellement le


tiret bas _ préfixant le fichier, comme suit.
Inclusion d’une feuille de styles partielle _typography.scss

@import "typography.scss";

Si vous utilisez la fonction url(), Sass conservera l’instruction @import dans la feuille
de styles générée. En effet, le préprocesseur se trouvera face à une syntaxe valide de
CSS et ne sera pas en mesure de savoir si vous souhaitez ou non la conserver. Par
sécurité, il laissera l’instruction intacte.
Notez que l’extension du fichier est optionnelle, Sass saura trouver le bon fichier.
Sass et Compass
46

app.scss

body {
background-color: #fff;
}
@import "typography";

Partial_typography.scss

h1, h2, h3, h4, h5 {


small {
color: #777;
}
}

CSS compilée : app.css

body {
background-color: #fff;
}
h1 small, h2 small, h3 small, h4 small, h5 small {
color: #777;
}

Mise en pratique des feuilles de styles partielles


Les feuilles de styles partielles peuvent être organisées dans des sous-répertoires, il
vous faudra alors préciser leur chemin d’accès relatif au fichier qui invoque l’instruc-
tion @import.
Petit exemple pratique. Dans un terminal, déplacez-vous dans un répertoire dédié à
vos tests (livre-sass/ situé dans votre dossier utilisateur par exemple). Créez l’arbo-
rescence qui suit.

Figure 2–3
Arborescence de l’exercice
ch02-007
Une syntaxe de Sass
47
CHAPITRE 2

[Shell] Création de l’arborescence

$ mkdir -p ch02-007/sub1/sub2
$ cd ch02-007
$ touch ch02-007.scss sub1/_reset.scss sub2/_{foo,bar,direct}.scss

À l’aide de votre éditeur de code favori, renseignez les contenus des fichiers nouvelle-
ment créés d’après les listings qui suivent (vous pouvez omettre les commentaires
silencieux // de Sass).
ch02-007.scss

/*!
* Fichier source ch02-007.scss
*/
// Nous importons le partial _reset.scss contenu dans le sous-répertoire
// "sub1/". Le chemin indiqué est relatif à celui du fichier qui invoque
// l'instruction @import.
@import "sub1/reset";

// Il est évidemment possible de charger directement un partial


// situé à n'importe quelle profondeur du projet.
@import "sub1/sub2/direct";

Partial_reset.scss

/*!
* Chargement du partial sub1/_reset.scss
*/
// Les fichiers _foo.scss et _bar.scss se situent dans un répertoire
// enfant au présent fichier (_reset.scss). Nous indiquons donc le
// sous-répertoire uniquement et non le chemin complet depuis le fichier
// source du projet (ch02-007.scss) à savoir "sub1/sub2/".
@import "sub2/foo", "sub2/bar";

Partial_bar.scss

/*!
* Chargement du partial sub1/sub2/_bar.scss
*/

Partial_direct.scss

/*!
* Chargement du partial sub1/sub2/_direct.scss
*/
Sass et Compass
48

Partial_foo.scss

/*!
* Chargement du partial sub1/sub2/_foo.scss
*/

Cela étant fait, vérifiez dans votre terminal que vous vous situez dans le répertoire
ch02-007 à l’aide de la commande pwd. Déplacez-vous dedans le cas échéant.

[Shell] Se positionner dans le projet

$ pwd
/Users/mehdi/livre-sass
$ cd ch02-007
$ pwd
/Users/mehdi/livre-sass/ch02-007

Il ne vous reste plus qu’à compiler le fichier ch02-007.scss en la feuille de styles


éponyme.
[Shell] Compilation de l’exercice

$ sass ch02-007.scss ch02-007.css

Le fichier généré regroupe comme attendu le contenu de nos feuilles de styles par-
tielles, correctement ordonnées.
CSS compilée

/*!
* Fichier source ch02-007.scss
*/
/*!
* Chargement du partial sub1/_reset.scss
*/
/*!
* Chargement du partial sub1/sub2/_foo.scss
*/
/*!
* Chargement du partial sub1/sub2/_bar.scss
*/
/*!
* Chargement du partial sub1/sub2/_direct.scss
*/
Une syntaxe de Sass
49
CHAPITRE 2

Notez en  qu’il est donc permis de regrouper plusieurs importations en une seule
instruction @import, en séparant simplement les différents fichiers par une virgule.

Importations imbriquées
Contrairement à CSS, Sass permet l’usage de l’instruction @import à l’intérieur d’une
règle CSS. Le contenu du partial sera alors copié dans la règle CSS source.
Fichier source

.message {
padding: 8px 35px 8px 14px;
@import "info";
}

Partial _info.scss

.info {
background-color: #d9edf7;
border: 1px solid #bce8f1;
}

CSS générée

.message {
padding: 8px 35px 8px 14px;
.info {
background-color: #d9edf7;
border: 1px solid #bce8f1;
}
}

IMPORTANT Héritage de CSS


Comme avec CSS, il est interdit de déclarer des propriétés en dehors d’une règle de
style. Il en va de même pour les feuilles de styles partielles qui ne pourront pas uni-
quement contenir une liste de propriétés. Un autre mécanisme offert par Sass, les
mixins, abordé plus loin dans le chapitre répondra à cette problématique.

Notez que les règles d’imbrication des sélecteurs ont toujours cours lors d’une impor-
tation imbriquée. Un sélecteur parent renseigné dans un partial prendra pour valeur
le sélecteur compilé de la règle CSS dans laquelle il est importé. Éditons le partial
_info.scss en conséquence pour vérifier ce point.
Sass et Compass
50

Fichier source

.message {
padding: 8px 35px 8px 14px;
@import "info";
}

Partial _info.scss

&.info {
background-color: #d9edf7;
border: 1px solid #bce8f1;
}

CSS générée

.message {
padding: 8px 35px 8px 14px;
}
.message.info {
background-color: #d9edf7;
border: 1px solid #bce8f1;
}

VERSION Apparition des inclusions dans une règle CSS


L’inclusion de feuilles de styles partielles depuis une règle CSS n’est permise que depuis la version 3.1 de
Sass. La restriction était de vigueur car, dans ses versions antérieures, Sass levait une erreur lorsque vous
tentiez de définir un mixin (concept abordé plus loin dans ce chapitre) ailleurs qu’à la racine d’un docu-
ment (le contexte global).

Vraiment pratique. Toutefois, une question demeure : qu’advient-il de la portée des


variables définies globalement dans un partial importé dans un contexte local ?
Partial _info.scss

$info-color1: #d9edf7;
$info-color2: #dce8f1;
$info-font-family: Helvetica, Arial, sans-serif;

.info {
// Les variables globales du partial sont accessibles dans le
// contexte local créé par la règle du sélecteur .info.
background-color: $info-color1;
border: 1px solid $info-color2;
}
Une syntaxe de Sass
51
CHAPITRE 2

ch02-008.scss Fichier source

// Contexte local initial dans lequel est importé la feuille de styles


// partielle "_info.scss".
.message {
padding: 8px 35px 8px 14px;
@import "info";
// La variable globale "$info-font-family" déclarée dans le
// partial "_info.scss" est accessible dans la règle CSS
// où s'effectue l'importation du fichier.
font-family: $info-font-family;

// Création d'une règle imbriquée. Les variables globales


// du partial "_info.scss" sont toujours accessibles.
h3 {
color: $info-color2;
}
}

// Création d'un nouveau contexte local à l'aide d'une nouvelle règle de


// propriété CSS.
// Il est désormais impossible d'accéder à la variable
// "$info-font-family" depuis ce nouveau contexte. Sass génère une
// erreur "Undefined variable" lors de la compilation
.new_context {
font-family: $info-font-family;
}

Ainsi, toute variable définie globalement dans une feuille de styles partielle verra sa
portée être réduite au contexte local de la règle qui importe le fichier.

Limites de l’instruction @import


Sass étant compatible avec CSS, il est des cas où la compilation se doit de générer
l’instruction @import conforme au standard du langage de styles. Ils sont au nombre
de trois et empêcheront Sass de rechercher les fichiers pour les incorporer dans la
feuille de styles compilée.
• Le nom du fichier à inclure possède l’extension de fichier .css.
• La fonction CSS url() est utilisée en conjugaison de l’instruction @import.
• Le fichier est une URL. L’appel à un service externe comme Google Font API est
donc possible.
Grâce aux feuilles de styles partielles vous n’aurez plus d’excuse pour ne pas scinder
votre CSS en de plus petites entités qui faciliteront le suivi et la maintenance de votre
projet. L’exercice demande cependant un peu d’organisation, sujet abordé dans le
chapitre 4 du livre.
Sass et Compass
52

ALLER PLUS LOIN CSS maintenables


Vous pouvez d’ores et déjà améliorer la maintenance de vos projets CSS en découvrant les conseils don-
nés par Kaelig Deloumeau-Prigent dans son livre CSS maintenables, paru aux éditions Eyrolles.
R Kaelig Deloumeau-Prigent, CSS maintenables, Eyrolles, 2012

Définir des variables par défaut


Dans la section dédiée à la découverte des variables Sass, j’avais souligné le risque
d’écraser la valeur d’une variable globale lorsque celle-ci est redéfinie plus loin dans la
feuille de styles. L’introduction du principe de découpage d’un projet en de multiples
fichiers augmente drastiquement cette menace puisque des variables aux noms iden-
tiques sont susceptibles d’être déclarées autant de fois qu’il y a de fichiers.
Dans le prochain exemple le but est d’obtenir une classe alert qui affiche un texte
rouge.
Fichier source

// La variable est définie dans le fichier source avant l'inclusion de


// la feuille partielle.
$alert-color: red;
@import "theme";

.alert {
color: $alert-color;
border: $alert-border;
}

Partial _theme.scss

// La variable $alert-color est également définie dans le partial, à ceci


// près que la valeur assignée diffère.
$alert-color: yellow;
$alert-border: 1px solid $alert-color;

CSS générée

.alert {
color: yellow;
border: 1px solid yellow;
}

Comme vous pouvez le constater, l’inclusion du partial _theme.scss a écrasé la valeur


de la variable $alert-color.
Une syntaxe de Sass
53
CHAPITRE 2

Une solution est d’inverser l’ordre de la première définition de la variable et de


l’inclusion du partial.
Inverser l’ordre des instructions

// La feuille de styles partielle est importée avant la déclaration


// de la variable.
@import "theme";
$alert-color: red;

.alert {
color: $alert-color;
border: $alert-border;
}

CSS générée

.alert {
color: red;
border: 1px solid red;
}

Effectivement, la variable $alert-color vaudra bien red dans la règle .alert. La solu-
tion est toutefois naïve et ne pourra être valide qu’à court terme. Qu’adviendra-t-il
lorsque ce fichier source sera lui-même inclus par un autre fichier ? Allez-vous indé-
finiment inverser les ordres d’apparition de vos variables dans le code ? Non, bien
évidemment.
Sass offre un système de déclaration de variable par défaut. Le mécanisme est
enfantin. Lors de la déclaration d’une variable, suffixez la valeur par !default. Lors
du traitement, Sass agira selon les règles suivantes.
• La variable n’a pas encore été définie, elle est alors créée et aura la valeur qui lui
est assignée.
• La variable existe déjà, elle ne sera pas écrasée par la nouvelle valeur.
Notre exemple devient dès lors le suivant.
Fichier source

$alert-color: red;
@import "theme";

.alert {
color: $alert-color;
border: $alert-border;
}
Sass et Compass
54

Partial _theme.scss

$alert-color: yellow !default;


$alert-border: 1px solid $alert-color !default;

CSS générée

.alert {
color: red;
border: 1px solid red;
}

Nous retrouvons bien le mécanisme énoncé plus haut.


 Dans le fichier source, la couleur red est assignée à la variable $alert-color.
 Sass réalise l’inclusion du partial_theme.scss.
 La variable $alert-color possède l’option !default. Sass vérifie son existence qui
se révèle positive. Le préprocesseur ignore la nouvelle valeur.
 La variable $alert-border possède l’option !default. Sass vérifie son existence, ce
qui n’est pas le cas. La variable $alert-border est créée.
 La valeur de la variable $alert-color vaut bien red.
 La valeur de la variable $alert-border vaut bien 1px solid red.
Pour la pérennité de vos projets, je vous conseille vivement d’adopter cet ordre de
déclaration de variables par défaut, c’est-à-dire de commencer par déclarer les varia-
bles que vous devez surcharger puis assigner les variables par défaut.
D’ailleurs, cette habitude préviendra toute erreur de calcul d’une variable qui en fait
intervenir d’autres. Dans l’exemple qui suit, la redéclaration de la variable $sidebar-
width n’aura pas d’impact sur le contenu de la variable $main-width qui est calculée en
amont.
Une redéclaration de variable inefficace

// Configuration initiale.
$content-width: 960px !default;
$sidebar-width: 250px !default;
$main-width: $content-width - $sidebar-width !default; // Soit 710px.

// Plus loin, la variable $sidebar-width est redéfinie.


// $main-width vaudra toujours 710px au lieu de 660px.
$sidebar-width: 300px;
Une syntaxe de Sass
55
CHAPITRE 2

Déclarer sa variable avant l’étape de configuration

// La variable à surcharger pour les besoins du projet.


$sidebar-width: 300px;

// Configuration initiale.
$content-width: 960px !default;
$sidebar-width: 250px !default;
// Cette fois, la valeur de la variable $main-width vaut bien 660px.
$main-width: $content-width - $sidebar-width !default;

BONNE PRATIQUE Toujours déclarer ses variables par défaut


Soyez prévoyant. À tout moment vous pouvez recevoir la demande de créer une
feuille de styles qui héritera et devra simultanément surclasser celles d’un projet exis-
tant. Dans une telle situation, la solution la plus souple consiste à déclarer toutes les
variables du projet initial avec des valeurs par défaut et, dans le nouveau projet,
déclarer à nouveau les variables qui entraîneront les surcharges avant l’inclusion de
la feuille de styles du projet initial.
De fait, et par convention, il est courant de regrouper les définitions des variables
d’un projet dans un partial que j’ai nommé _base.scss qui sera inclus au début de la
feuille de styles SCSS à transformer en CSS. Les variables ainsi déclarées devront être
suffixées par l’instruction !default pour garantir la bonne évolution du projet.

Réutiliser son code : introduction aux mixins


L’enrichissement de CSS avec le support des variables nous permet de réutiliser des
valeurs mais en aucun cas des ensembles de propriétés et encore moins des règles
CSS complètes. Pourtant, avec des sites de plus en plus complexes, il est parfois
nécessaire de répéter les mêmes propriétés et autres extraits de code dans diverses
portions du projet. Là où CSS oblige à recourir à la sempiternelle solution du copier-
coller, Sass offre la possibilité de créer des modules réutilisables appelés mixins.

Définir un mixin
Un mixin se définit grâce à la directive @mixin. Sa syntaxe est similaire à celle des
autres directives @ de CSS, comme @media, @font-face, @keyframes de CSS3 qui sont
déclaratives : elles créent des ensembles de propriétés, voire des règles de styles dans
le cas de la directive @media. Le listing qui suit déclare un mixin reprenant une tech-
nique d’intégration connue de tous, l’application d’un clearfix.
Sass et Compass
56

Déclaration du mixin clearfix

@mixin clearfix {
overflow: hidden;
*zoom: 1; // hack IE 6 et 7
}

Appeler un mixin
Un mixin est une représentation abstraite destinée à être réutilisée : déclarer un
mixin seul ne générera aucun code CSS. Il vous faudra appeler le mixin avec la direc-
tive @include qui insérera à sa place le contenu du mixin.
Appel du mixin clearfix

.slider {
background-color: #ccc;
@include clearfix;
}

CSS compilée

.slider {
background-color: #ccc;
overflow: hidden;
*zoom: 1;
}

Désormais, au lieu de répéter les deux lignes, qui constituent la technique du clearfix
en de multiples points de votre feuille de styles, définissez simplement le mixin une
fois pour toutes et incluez-le autant de fois qu’il sera nécessaire. Vous économiserez
ainsi un temps non négligeable.
En outre, vous gagnerez sur un autre tableau : celui de la maintenance et de l’évolu-
tion de votre code. Imaginez que vous souhaitiez remplacer cette ancienne technique
du clearfix par une plus récente, comme celle du « Micro clearfix » proposée par
Nicolas Gallagher. Grâce à l’usage d’un mixin, cette tâche se résume à faire évoluer le
contenu du mixin clearfix et non, comme vous l’auriez fait auparavant, à lancer une
opération de rechercher-remplacer sur l’intégralité de la feuille de styles ; ou pire,
manuellement car votre éditeur favori ne supporte pas de motifs de recherche et de
remplacement multiligne.
Une syntaxe de Sass
57
CHAPITRE 2

RESSOURCES Micro clearfix hack


Nicolas Gallagher nous propose une version évoluée du célèbre hack de clearfix qui permet d’étendre le
bas d’un élément afin qu’il englobe tous ses éléments flottants enfants. Le problème rencontré avec
l’ancienne méthode, vu ici en exemple, est qu’il est dès lors impossible de faire déborder un enfant de
l’élément sur lequel s’applique le clearfix. Limite levée par la technique du Micro clearfix.
B http://nicolasgallagher.com/micro-clearfix-hack/

Règles CSS dans les mixins


Nous avons vu qu’un mixin pouvait regrouper un ensemble de propriétés CSS, chose
que même les feuilles de styles partielles n’autorisent pas. Cependant, il serait tout
aussi pratique de pouvoir partager efficacement certaines règles CSS. Le système de
mixins de Sass est conçu en conséquence.
Une règle CSS dans un mixin

@mixin no-bullets {
list-style: none;
li {
list-style-image: none;
list-style-type: none;
margin-left: 0;
}
}
ul, ol {
padding: 0;
@include no-bullets;
}

Lors de la compilation, Sass va remplacer l’appel au mixin no-bullets par son con-
tenu. Les sélecteurs imbriqués ul li et ol li sont alors créés.
SCSS intermédiaire : un sélecteur imbriqué est inséré

ul, ol {
padding: 0;
list-style: none;
li {
list-style-image: none;
list-style-type: none;
margin-left: 0;
}
}
Sass et Compass
58

Finalement, Sass termine la compilation des styles en calculant les divers sélecteurs
imbriqués pour générer la feuille de styles finale.
CSS compilée

ul, ol {
padding: 0;
list-style: none;
}
ul li, ol li {
list-style-image: none;
list-style-type: none;
margin-left: 0;
}

Notez que tout sélecteur parent & présent à la racine d’un mixin aurait pour valeur le
sélecteur imbriqué calculé par Sass au moment de l’appel du mixin.
ch02-009.scss Utilisation du sélecteur parent au sein d’un mixin

@mixin inline-list {
list-style-type: none;
&, & li {
margin: 0;
padding: 0;
display: inline;
#top & {
color: red;
}
}
}
ul.inline {
@include inline-list;
}

CSS compilée

ul.inline {
list-style-type: none;
}
ul.inline, ul.inline li {
margin: 0;
padding: 0;
display: inline;
}
#top ul.inline, #top ul.inline li {
color: red;
}
Une syntaxe de Sass
59
CHAPITRE 2

En , le sélecteur parent & a pour valeur le sélecteur imbriqué calculé au moment de


l’appel du mixin, à savoir ul.inline. Le sélecteur calculé est donc ul.inline,
ul.inline li (). Afin d’enrichir l’explication, un troisième niveau d’imbrication a
été ajouté au mixin inline-list visible en . Le sélecteur parent étant imbriqué,
Sass ajoute à la valeur précédemment calculée en  le préfixe #top. Le sélecteur
imbriqué calculé devient ainsi #top ul.inline, #top ul.inline li ().

Passage d’arguments à un mixin


Il est fréquent de s’appuyer sur un même code où seules quelques valeurs (comme des
informations colorimétriques) divergent. Dans ce but, un mixin peut accepter des
arguments qui aident à personnaliser le code CSS généré au moment de l’appel du
mixin via l’instruction @include.
Un mixin paramétrable

@mixin link-colors($normal, $hover, $visited) {


color: $normal;
&:hover {
color: $hover;
}
&:visited {
color: $visited;
}
}

La syntaxe est similaire à celle des fonctions que l’on retrouve en JavaScript ou en
PHP : des arguments séparés par des virgules sont regroupés dans des parenthèses.
Lors de l’appel du mixin avec @include, les arguments sont passés comme vous le
feriez dans une fonction CSS telle que url().
SCSS

a {
@include link-colors(#0088cc, #005580, #1e347b);
}

CSS compilée

a {
color: #0088cc;
}
a:hover {
color: #005580;
}
Sass et Compass
60

a:visited {
color: #1e347b;
}

Cette méthode est très pratique, mais un inconvénient subsiste lorsqu’un mixin pos-
sède plusieurs arguments. En effet, il est parfois difficile de se souvenir du rôle et de
l’ordre de chacun d’entre eux. De plus, la compréhension du fichier source SCSS est
moins intuitive. Afin d’ôter tout doute, la solution consiste à préciser explicitement le
nom des arguments au moment de l’appel du mixin, ce qui permet également de les
classer dans l’ordre de votre choix.
Gagner en lisibilité en précisant le nom des arguments

a {
@include link-colors(
$normal: #0088cc,
$hover: #005580,
$visited: #1e347b
);
}

SYNTAXE Ligne simple ou multiligne ?


Les arguments sont isolés ligne par ligne dans le listing précédent. Ce choix de présentation n’est pas
obligatoire, bien que plus lisible. Vous pouvez tout à fait renseigner les arguments en une seule ligne lors
de l’appel à la directive @include.

L’oubli d’un argument provoque une erreur lors de la compilation. Sass indiquera
précisément le nom de l’argument négligé.
[Shell] Une erreur explicite

$ sass --scss -s <<"EOF"


> @mixin link-colors($normal, $hover, $visited) {
> color: $normal;
> &:hover {
> color: $hover;
> }
> &:visited {
> color: $visited;
> }
> }
> a {
> @include link-colors(#0088cc, #005580);
> }
Une syntaxe de Sass
61
CHAPITRE 2

> EOF
Syntax error: Mixin link-colors is missing argument $visited.
on line 11 of standard input, in `link-colors'
from line 11 of standard input
Use --trace for backtrace.

Arguments par défaut


En faisant l’analogie avec les fonctions de PHP, les mixins peuvent déclarer des
valeurs par défaut pour certains ou pour tous leurs arguments. Pour cela, il suffit
d’assigner une valeur à un argument lors de l’écriture du mixin.
Deux arguments par défaut

@mixin link-colors($normal, $hover: red, $visited: yellow) { 


color: $normal;
&:hover {
color: $hover;
}
&:visited {
color: $visited;
}
}

a {
@include link-colors(#0088cc); 
}

Dans le listing précédent (), le mixin link-colors assigne une valeur par défaut aux
arguments $hover et $visited. Leur omission est donc possible lors de l’appel du
mixin (). Les valeurs assignées par défaut seront utilisées lors de la compilation.
CSS compilée

a {
color: #0088cc;
}
a:hover {
color: red;
}
a:visited {
color: yellow;
}
Sass et Compass
62

Supposons que vous souhaitiez préciser les valeurs des arguments $normal et $visited,
mais conserver la valeur assignée par défaut à l’argument $hover. Un premier réflexe
serait de recopier la valeur du deuxième argument :

a {
@include link-colors(#0088cc, red, #1e347b);
}

Fonctionnel, mais peu pratique puisqu’il faut connaître la valeur par défaut de l’argu-
ment $hover. Comme nous l’avons vu, Sass autorise une saisie explicite des argu-
ments lors de l’appel à un mixin. En détournant cette règle syntaxique du préproces-
seur, l’omission du deuxième argument se fait en précisant le nom du troisième :

a {
@include link-colors(#0088cc, $visited: #1e347b);
}

Liste d’arguments
CSS3 a introduit une nouvelle syntaxe avec les propriétés à valeurs multiples. Par
exemple, il est désormais possible d’assigner plusieurs fonds à un élément à l’aide de
la propriété background en les séparant par des virgules.
[CSS] Exemple d’utilisation d’images de fond multiples

.weather {
width: 200px;
height: 200px;
background:
url("img/light-cloud.png") no-repeat right 90px,
url("img/sun.png") no-repeat 50% 50%,
url("img/dark-cloud.png") no-repeat left center;
}

Le nombre d’attributs acceptés par la propriété background n’est pas limité ; elle en
assume autant qu’il est nécessaire. Sass, dans sa version 3.2, s’est doté d’un système
équivalent afin de rendre compatible l’écriture de mixins dont les arguments seraient
destinés à ces nouvelles propriétés à valeurs multiples.
Déclarez un argument multiple en le suffixant par trois points « ... » (et non des
points de suspension « … »).
Une syntaxe de Sass
63
CHAPITRE 2

Passer une liste d’arguments à un mixin

@mixin background($backgrounds...) {
background: $backgrounds;
}

.weather {
width: 200px;
height: 200px;
@include background(
url("img/light-cloud.png") no-repeat right 90px,
url("img/sun.png") no-repeat 50% 50%,
url("img/dark-cloud.png") no-repeat left center
);
}

Sass générera la même sortie que le listing CSS vu précédemment.

Figure 2–4
CSS3 permet d’afficher
plusieurs images pour
un même élément.

Un mixin peut être défini avec des arguments simples et une liste d’arguments, à
condition de toujours déclarer la liste d’arguments en dernière position.
Sass et Compass
64

ch02-010.scss Combiner argument et liste d’arguments

@mixin background($fallback-bg, $backgrounds...) {


background: $fallback-bg; 
background: $backgrounds;
}
.weather {
width: 200px;
height: 200px;
@include background(
url("img/weather.png") no-repeat 0 0, 
url("img/light-cloud.png") no-repeat right 90px, 
url("img/sun.png") no-repeat 50% 50%, 
url("img/dark-cloud.png") no-repeat left center 
);
}

Dans cet exemple, le premier argument passé au mixin background sert à déclarer un
fond simple destiné aux anciens navigateurs qui ne supportent pas la syntaxe d’attri-
buts multiples de CSS3 (). Tous les autres arguments renseignés à l’appel du mixin
( à ) sont regroupés au sein de la liste d’arguments $backgrounds.
CSS compilée

.weather {
width: 200px;
height: 200px;
background: url("img/weather.png") no-repeat 0 0; 
background: url("img/light-cloud.png") no-repeat right 90px, 
url("img/sun.png") no-repeat 50% 50%, 
url("img/dark-cloud.png") no-repeat left center; 
}

Passage d’un bloc de contenu à un mixin


Depuis Sass 3.2.0, il est possible de passer des règles CSS à un mixin. Le contenu
transmis au mixin est inséré à la place de la directive @content.
Intégration facile de styles dédiés à IE6

@mixin ie6 {
* html & {
@content;
}
}
Une syntaxe de Sass
65
CHAPITRE 2

.logo {
background: transparent url("img/logo.png ") 0 0;
@include ie6 {
background-image: url("img/logo.jpg ");
}
}

CSS compilée

.logo {
background: transparent url("img/logo.png ") 0 0;
}
* html .logo {
background-image: url("img/logo.jpg ");
}

Si le mixin contient plusieurs occurrences de la directive @content, alors chacune


d’entre elles sera remplacée par les styles passés au mixin.
En revanche, si vous tentez de transmettre des styles CSS à un mixin dépourvu de la
directive @content, Sass générera une erreur de syntaxe : Syntax error: Mixin "ie6"
does not accept a content block.

Comme vous le verrez plus loin, cette directive est des plus utiles pour simplifier
l’écriture des Media Queries.
Cependant, il faudra porter une attention particulière à la portée des variables
lorsque vous utiliserez la directive de passage de blocs de contenu à un mixin. En
effet, les styles transmis sont évalués depuis l’endroit où le mixin est appelé, et non,
comme vous pourriez le penser, à l’intérieur du mixin. Ainsi, les variables déclarées
localement au mixin ne peuvent pas interagir avec le contenu qui lui est passé.
Dans l’exemple qui suit, une variable globale$size est définie avec la valeur 20px ().
Puis est déclaré un mixin title qui accepte un paramètre optionnel de même nom
que la variable globale ; paramètre qui crée une variable locale au mixin ().
Lorsque le mixin est invoqué en , la lecture de la variable $size en  est effectuée
par Sass. La portée de la variable est la même que si elle avait été directement appelée
depuis la règle CSS parente, et non depuis l’intérieur du mixin en . Sa valeur vaut
alors les 20px de la variable globale et non les 15px de la variable locale au mixin.
Par ailleurs, l’utilisation de la variable $size dans le style qui remplace la directive
@content n’a pas écrasé la valeur de la variable locale au mixin. Le calcul de la marge
basse () reste 15px * 1.2 (18px) et n’est pas transformé en 20px * 1.2 (24px).
Sass et Compass
66

Une portée des variables inchangée

$size: 20px; // 
@mixin title($size: 15px) { // 
@content; // 
margin-bottom: $size * 1.2; // 
}
h1 {
@include title { // 
font-size: $size; // 
}
}

CSS compilée

h1 {
font-size: 20px;
margin-bottom: 18px;
}

Héritage avec @extend


La dernière innovation introduite par Sass pour produire un code respectant autant
que possible le principe de non-redondance DRY (Don’t Repeat Yourself, « Ne vous
répétez pas ») est connue sous le nom d’« héritage ». L’héritage est la capacité d’indi-
quer à Sass qu’une règle doit hériter de tous les styles définis par une autre règle CSS.
L’héritage est défini à l’aide de l’instruction @extend suivie d’un sélecteur CSS
(comme input, input[type="text"], .nav, .nav.secondary, #header).

Utiliser l’héritage
Considérons l’exemple d’un composant permettant d’afficher un message d’alerte
dans trois déclinaisons : la forme basique gérée par la classe .alert, une forme
dérivée aux tons rouges .alert-error et une version aux tonalités vertes .alert-
success. Une première approche sans aucune optimisation serait la suivante.

Des répétitions en pagaille

$alert-border_radius: 4px;

// Message d’alerte
.alert {
color: #c09853;
Une syntaxe de Sass
67
CHAPITRE 2

background-color: #fcf8e3;
border: 1px solid #fbeed5;
padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: $alert-border_radius;
-moz-border-radius: $alert-border_radius;
border-radius: $alert-border_radius;
}

// Message d’erreur
.alert-error {
color: #b94a48;
background-color: #f2dede;
border: 1px solid #eed3d7;
padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: $alert-border_radius;
-moz-border-radius: $alert-border_radius;
border-radius: $alert-border_radius;
}

// Message de succès
.alert-success {
color: #468847;
background-color: #dff0d8;
border: 1px solid #d6e9c6;
padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: $alert-border_radius;
-moz-border-radius: $alert-border_radius;
border-radius: $alert-border_radius;
}

Le problème est évident : une même portion de code a dû être saisie à trois reprises.
Afin d’éviter ces répétitions, une approche pragmatique est de recourir à un mixin
paramétrable.
Réduire les répétitions de saisies avec un mixin

@mixin alert($border_color, $border_radius: 4px) {


border: 1px solid $border_color;
padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: $border_radius;
-moz-border-radius: $border_radius;
border-radius: $border_radius;
}
// Message d’alerte
Sass et Compass
68

.alert {
color: #c09853;
background-color: #fcf8e3;
@include alert(#fbeed5);
}
// Message d’erreur
.alert-error {
color: #b94a48;
background-color: #f2dede;
@include alert(#eed3d7);
}
// Message de succès
.alert-success {
color: #468847;
background-color: #dff0d8;
@include alert(#d6e9c6);
}

Le résultat est satisfaisant, le nombre de lignes de code saisies a drastiquement


diminué. Malheureusement, ce constat ne se vérifie que pour la source SCSS. En
effet, la feuille de styles générée conserve toutes les répétitions.
CSS compilée

.alert {
color: #c09853;
background-color: #fcf8e3;
border: 1px solid #fbeed5;
padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}

.alert-error {
color: #b94a48;
background-color: #f2dede;
border: 1px solid #eed3d7;
padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}

.alert-success {
color: #468847;
background-color: #dff0d8;
Une syntaxe de Sass
69
CHAPITRE 2

border: 1px solid #d6e9c6;


padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}

C’est là qu’intervient l’héritage de Sass. Déclenchées grâce à la directive @extend, les


déclinaisons peuvent hériter des styles de la classe de base et ainsi partager une partie
du code SCSS, mais surtout des propriétés CSS réduisant ainsi le poids de la feuille
de styles finale.
ch02-011.scss DRY avec l’héritage

$alert-border_radius: 4px;

// Message d’alerte
.alert { 
color: #c09853;
background-color: #fcf8e3;
border: 1px solid #fbeed5;
padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: $alert-border_radius;
-moz-border-radius: $alert-border_radius;
border-radius: $alert-border_radius;
}

// Message d’erreur
.alert-error {
@extend .alert; 
color: #b94a48;
background-color: #f2dede;
border-color: #eed3d7;
}

// Message de succès
.alert-success {
@extend .alert; 
color: #468847;
background-color: #dff0d8;
border-color: #d6e9c6;
}
Sass et Compass
70

CSS compilée

.alert, .alert-error, .alert-success { 


color: #c09853;
background-color: #fcf8e3;
border: 1px solid #fbeed5;
padding: .5em 2.5em;
margin-bottom: 1.4em;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}

.alert-error { 
color: #b94a48;
background-color: #f2dede;
border-color: #eed3d7;
}

.alert-success { 
color: #468847;
background-color: #dff0d8;
border-color: #d6e9c6;
}

Les deux héritages accomplis en  indiquent à Sass que les sélecteurs .alert-error
et .alert-success doivent hériter des styles de la classe .alert (). Dès lors, le pré-
processeur réunit les trois sélecteurs en un même groupe de sélecteurs (). À ce
niveau de l’analyse, les trois classes sont donc interchangeables : intervertir l’une ou
l’autre des classes sur un élément dans le code source HTML n’aura aucun impact
puisqu’elles définissent la même règle CSS.
En revanche, nous tirons parti en  du principe de cascade de CSS. Les styles de
couleurs déclarés dans les deux classes surchargent ceux de la classe héritée.
Finalement, la feuille de styles obtenue se voit allégée de 230 octets, ce qui traduit
bien une économie d’efforts, pour vous, pour Sass et pour le navigateur.

Du bon usage de l’héritage


L’héritage devrait être utilisé dans le seul but de créer des relations sémantiques entre
les éléments.
Ainsi, lors de la phase d’intégration d’un projet, si vous rencontrez une classe plus
spécifique (.alert-success) qu’une existante (.alert), la mise en place d’un héritage
est justifiée.
Une syntaxe de Sass
71
CHAPITRE 2

Constituant a priori la solution miracle pour alléger une CSS et réduire ainsi le poids
des pages web qui l'appellent, les directives @extend entraînent cependant des effets
de bord aux conséquences fâcheuses.

Implications pour les règles imbriquées


Comme l’héritage d’un sélecteur revient à partager le contenu d’une règle avec
d’autres sélecteurs, ces derniers devront implémenter tout style appliqué aux règles
imbriquées dans le sélecteur étendu.
ch02-012.scss Ajout d’un groupe de règles imbriquées

// Le composant de base.
.widget {
padding: .5em 2.5em;
overflow: hidden;
h2, h3 {
margin-bottom: 1.5em;
}
img {
float: left;
}
}

// Un composant plus spécifique.


.widget-specific {
@extend .widget;
border: 1px solid #c1c1c1;
}

// Un autre composant plus spécifique.


.widget-new {
@extend .widget;
background-color: #c1c1c1;
}

L’ajout de la règle imbriquée dans la classe .widget oblige Sass à calculer le sélecteur
CSS intermédiaire .widget h2, .widget h3, et .widget img. Chacun de ces sélecteurs
est ensuite étendu par les deux classes.
CSS compilée

.widget, .widget-specific, .widget-new {


padding: .5em 2.5em;
overflow: hidden;
}
.widget h2, .widget-specific h2, .widget-new h2, .widget h3, .widget-specific
h3, .widget-new h3 {
Sass et Compass
72

margin-bottom: 1.5em;
}
.widget img, .widget-specific img, .widget-new img {
float: left;
}

.widget-specific {
border: 1px solid #c1c1c1;
}

.widget-new {
background-color: #c1c1c1;
}

À vrai dire, ces sélecteurs générés en surplus deviennent inutiles dès que vous ajoutez
la classe widget aux éléments pourvus d’une des classes widget-specific ou widget-new
dans votre HTML.

Création de sélecteurs nuisibles


Demander à Sass d’hériter une classe va le contraindre à appliquer l’héritage à toutes les
occurrences de cette même classe. Ainsi, si on n’y prend pas garde, Sass peut générer
des sélecteurs improbables – que nous ne croiserons jamais sur le site – et pire encore,
des sélecteurs nuisibles une fois que la cascade de CSS entre en action. Évidemment, ce
surplus aura directement un impact sur le poids de votre feuille de styles.
ch02-013.scss

// Classe de base à hériter.


.important {
color: red;
}

// Un bloc destiné à afficher un message d’erreur.


.error {
@extend .important; // héritage
background-color: #fcc;
// Un titre de niveau 3 contenu dans un élément muni de la classe
// "error" doit s’afficher en gras.
h3 {
font-weight: bold;
}
}

// Plus loin dans la feuille, il est déclaré qu’un élément "important"


// enfant d'un bloc "success" affiche le texte en vert.
.success .important { 
Une syntaxe de Sass
73
CHAPITRE 2

color: green;
}

// Ailleurs dans le site, les titres de niveau 3 d'un élément pourvu de


// la classe "important" (notre classe de base) ne doit pas être
// mis en gras.
.content .important h3 { 
font-weight: normal;
}

CSS compilée

.important, .error {
color: red;
}

.error {
background-color: #fcc;
}
.error h3 {
font-weight: bold;
}

/*
Première anicroche, le sélecteur ".success. error" n'est pas désiré
puisqu’il n'apparaîtra jamais dans une page (non-sens sémantique).
*/
.success .important, .success .error {
color: green;
}

/*
Pire. Si dans une page, un élément résout le sélecteur indésiré
".content .error h3", alors il supprimera toute mise en exergue du fait
de la cascade CSS.
*/
.content .important h3, .content .error h3 {
font-weight: normal;
}

Par conséquent, envisagez d’étendre une classe ou un identifiant si et seulement si


son sélecteur n’est pas surspécifié dans d’autres règles CSS, comme aux repères 
et , ou s’il n’est présent qu’une à deux fois dans votre code.
Sass et Compass
74

Maîtriser l’héritage avec les placeholders


Les performances d’un site, en particulier son temps de chargement, sont devenues
au fil des années une contrainte d'intégration majeure. Dans le but de réduire le
poids des feuilles de styles et par conséquent leur temps de chargement, il était
devenu courant de se constituer un jeu de classes utilitaires à étendre mais inutilisées
telles quelles dans les projets.
Cette mauvaise pratique qui atténue les relations sémantiques entre les éléments d’un
site a fait couler beaucoup d’encre. En effet, cette méthode de travail avait pour con-
séquence la création de sélecteurs difficilement contrôlables sur de gros projets.
De ce constat découle l’une des demandes d’évolution les plus fréquentes émise par
les utilisateurs de Sass : pouvoir faire de l’héritage maîtrisé, sans qu’aucune classe ni
sélecteur additionnel ne soient générés. C’est ainsi qu’a été introduite dans Sass 3.2 la
notion de placeholders.
Les placeholders (ou « éléments de substitution », mais nous conserverons le terme
anglais par souci de clarté) ont pour syntaxe %nom_de_classe. Ils se substituent à une
classe CSS et sont exclusivement destinés à être hérités.
ch02-014.scss Un placeholder en action

// Placeholder pour appliquer une ombre portée.


%drop-shadow { 
// Firefox 3.5
-moz-box-shadow: 8px 8px 5px #888;
// Chrome 1.0+, Safari 3.0+
-webkit-box-shadow: 8px 8px 5px #888;
// Firefox 4.0+, Chrome 10+, Safari 5.1+, IE 9+, Opera 10.5+
box-shadow: 8px 8px 5px #888;
}

// Placeholder pour arrondir les coins d'un élément.


%rounded { 
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}

.box {
@extend %drop-shadow; 
padding: 1em 1.2em;
}
#main .notice {
background-color: #ffc;
@extend %drop-shadow; 
}
Une syntaxe de Sass
75
CHAPITRE 2

 On déclare un placeholder (%drop-shadow) comme s’il s’agissait d’une classe CSS.


 Il est étendu par deux règles (dont les sélecteurs sont .box et #main .notice). Lors
de la compilation, Sass remplacera le placeholder par le regroupement des sélecteurs
qui l’étendent, soit.box, #main .notice.
Si un placeholder n’est pas étendu, alors Sass supprimera du code produit ses réfé-
rences et si nécessaire les règles CSS qu’il définit, comme c’est le cas pour le place-
holder %rounded qui n’est à aucun moment étendu ().
CSS compilée

.box, #main .notice {


-moz-box-shadow: 8px 8px 5px #888;
-webkit-box-shadow: 8px 8px 5px #888;
box-shadow: 8px 8px 5px #888;
}

.box {
padding: 1em 1.2em;
}

#main .notice {
background-color: #ffc;
}

Bien évidemment, l’imbrication des règles est supportée.


ch02-015.scss Une règle imbriquée est déclarée dans un placeholder

%layout-row {
padding: 3px 15px 3px 15px;
> :first-child {
margin-top: 0;
}
}

.row {
@extend %layout-row;
}
.row-separator {
@extend %layout-row;
border: 1px solid #000;
}
Sass et Compass
76

CSS générée

.row, .row-separator {
padding: 3px 15px 3px 15px;
}

.row > :first-child, .row-separator > :first-child {


margin-top: 0;
}

.row-separator {
border: 1px dotted #000;
}

Usage avancé des placeholders


Développons l’exemple précédent, qui doit nous permettre d’afficher des successions
de blocs dotés de bordures horizontales, tel un menu de navigation mobile.
ch02-016.scss Usage avancé des placeholders

.row, %layout-row { 
padding: 3px 15px 3px 15px;
> :first-child {
margin-top: 0;
}
}

%row-with_separator {
@extend %layout-row; 
// Affichera par défaut des bordures horizontales en pointillés.
border: 0 dotted #000;
border-width: 1px 0;
// Si dans la page HTML deux éléments qui étendent ce placeholder sont
// consécutifs, le second ne doit pas afficher de bordure supérieure.
+ %row-with_separator { 
border-top-width: 0;
}
}

// Un élément pourvu de bordures pleines horizontales.


.row-separator_plain {
@extend %row-with_separator; 
border-style: solid;
}
Une syntaxe de Sass
77
CHAPITRE 2

// Un élément pourvu de bordures horizontales en pointillés.


.row-separator {
@extend %row-with_separator;
}

 Pour commencer, le sélecteur .row a été regroupé avec le placeholder %layout-row.


Un placeholder n’est pas obligatoirement isolé dans un sélecteur.
 Puisque les classes .row-separator_plain et .row-separator héritent du placeholder
%row-with_separator, ce dernier sera remplacé par Sass par le groupe de sélecteurs cal-
culé .row-separator_plain, .row-separator.

SCSS intermédiaire

.row-separator_plain, .row-separator {
@extend %layout-row 
border: 0 dotted #000;
border-width: 1px 0;
+ %row-with_separator {
border-top-width: 0;
}
}

Cette nouvelle règle CSS étend le placeholder %layout-row en . Son groupe de


sélecteurs remplace alors la définition du placeholder (). La présence de la règle
imbriquée lance le calcul des sélecteurs pour chaque sélecteur du niveau parent, à
savoir .row, .row-separator_plain et .row-separator.
SCSS intermédiaire

.row, .row-separator_plain, .row-separator {


padding: 3px 15px 3px 15px;
}
.row > :first-child, .row-separator_plain > :first-child,
.row-separator > :first-child {
margin-top: 0;
}
.row-separator_plain, .row-separator {
border: 0 dotted #000;
border-width: 1px 0;
+ %row-with_separator { 
border-top-width: 0;
}
}
Sass et Compass
78

Reste le cas en  dont le traitement a été reporté à des fins pédagogiques ; son rem-
placement par Sass est en réalité effectif dès la deuxième étape de l’analyse. Rap-
pelez-vous, le placeholder %row-width_separator est étendu par les classes .row-
separator_plain et .row-separator. Sass remplaçant toutes les occurrences d’un place-
holder s’il est étendu, ce sélecteur ne déroge pas à la règle, bien qu’il soit imbriqué.
Ici, le placeholder est combiné avec le combinateur d’adjacence directe +. Sass dis-
tribue le combinateur à tout sélecteur contenu dans le placeholder, pour obtenir le
groupe de sélecteurs + .row-separator_plain, + .row-separator. La règle imbriquée
devient alors la suivante.
SCSS intermédiaire

.row-separator_plain, .row-separator {
border: 0 dotted #000;
border-width: 1px 0;
+ .row-separator_plain, + .row-separator {
border-top-width: 0;
}
}

En effet, nous souhaitons que tout élément .row-separator ou .row-separator_plain


suivi par l’un des deux sélecteurs masque sa bordure supérieure pour éviter l’affichage
d’une double bordure – constituée par la bordure inférieure du premier élément et la
bordure supérieure du second. Ainsi, il s’agit de calculer toutes les combinaisons pos-
sibles, à savoir le groupe de sélecteurs qui suit :

.row-separator_plain + .row-separator_plain,
.row-separator + .row-separator_plain,
.row-separator_plain + .row-separator,
.row-separator + .row-separator {

}

Finalement, la feuille de styles produite est plus complexe, moins lisible et d’une
maintenance bien plus difficile que sa version SCSS.
CSS compilée

.row, .row-separator_plain, .row-separator { 


padding: 3px 15px 3px 15px;
}
.row > :first-child, .row-separator_plain > :first-child,
.row-separator > :first-child {
margin-top: 0;
}
Une syntaxe de Sass
79
CHAPITRE 2

.row-separator_plain, .row-separator {
border: 0 dotted #000;
border-width: 1px 0;
}
.row-separator_plain + .row-separator_plain,
.row-separator + .row-separator_plain,
.row-separator_plain + .row-separator,
.row-separator + .row-separator {
border-top-width: 0;
}

.row-separator_plain {
border-style: solid;
}

Support des Media Queries


Les Media Queries (ou « requêtes de média ») fonctionnent avec Sass comme avec
CSS, à une différence près : elles peuvent être imbriquées dans les règles CSS !

RESSOURCES Les Media Queries CSS3


Si vous découvrez les Media Queries, je vous recommande le tour d’horizon de la spécification CSS3 pro-
posé par Rodolphe Rimelé :
B http://www.alsacreations.com/article/lire/930-css3-media-queries.html
R Rodolphe Rimelé, HTML5 - Une référence pour le développeur web, Eyrolles, 2013

Imbriquer les Media Queries


Lorsque Sass rencontre une Media Query à l’intérieur d’une règle CSS, le préproces-
seur la remonte à la racine de la feuille de styles et y insère tous les sélecteurs rencon-
trés. L’écriture des Media Queries n’aura jamais été aussi simple.
Des Media Queries imbriquées dans une règle CSS

.hero {
width: 960px;
max-width: 100%;
min-height: 220px;
@media only screen and (min-width: 1400px) {
width: 1400px;
max-width: 1400px;
Sass et Compass
80

}
@media only screen and (max-width: 450px) {
max-height: 300px;
img {
max-height: 268px
}
}
}

CSS compilée

.hero {
width: 960px;
max-width: 100%;
min-height: 220px;
}
@media only screen and (min-width: 1400px) {
.hero {
width: 1400px;
max-width: 1400px;
}
}
@media only screen and (max-width: 450px) {
.hero {
max-height: 300px;
}
.hero img {
max-height: 268px;
}
}

Sass permet aussi d’imbriquer les instructions @media les unes dans les autres. Les
Media Queries sont alors combinées à l’aide de l’opérateur and. L’exemple précédent
peut donc aussi s’écrire de la manière suivante, nous évitant la répétition de la condi-
tion only screen.
Des Media Queries imbriquées entre elles

.hero {
width: 960px;
max-width: 100%;
min-height: 220px;
@media only screen {
@media (min-width: 1400px) {
width: 1400px;
max-width: 1400px;
}
Une syntaxe de Sass
81
CHAPITRE 2

@media (max-width: 450px) {


max-height: 300px;
img {
max-height: 268px
}
}
}
}

Des variables pour être lisible


Saisir à plusieurs reprises les expressions des différentes Media Queries peut être la
source d’erreurs. Le passage par des variables est préférable.
Sass accepte des variables dans l’instruction @media à tous les niveaux : propriété (min-
width), valeur (450px) et type de média (only screen). Dans ce dernier cas, il vous
faudra cependant interpoler la variable sans quoi la règle CSS invalide @media
$variable est générée.

Des variables pour simplifier la lecture des Media Queries

$media: only screen;


$phone: 450px;
$phone-prop: max-width;
$large-screen: 1400px;
$large-screen-prop: min-width;
.hero {
width: 960px;
max-width: 100%;
min-height: 220px;
@media #{$media} {
@media ($large-screen-prop: $large-screen) {
width: $large-screen;
max-width: $large-screen;
}
@media ($phone-prop: $phone) {
max-height: 300px;
img {
max-height: 268px
}
}
}
}
Sass et Compass
82

Media Queries avancées


L’écriture des points de rupture de votre site est simplifiée grâce aux variables, mais
leur saisie reste des plus rébarbatives. Encore une fois, vous pouvez compter sur Sass
qui a plus d’un tour dans sa manche !
Couplé à l’instruction @content, il devient aisé de créer un mixin qui générera vos
Media Queries tout en douceur. Conformément aux connaissances acquises jusqu’ici,
voici un exemple d’utilisation.
Des mixins aux noms explicites

// Définition des points de rupture


$phone: 450px;
$large-screen: 1400px;

// Requête de média « au moins »


@mixin at-least($device-width) {
@media only screen and (min-width: $device-width) {
@content;
}
}

// Requête de média « jusqu'à »


@mixin until($device-width) {
@media only screen and (max-width: $device-width - 1) {
@content;
}
}

.hero {
width: 960px;
max-width: 100%;
min-height: 220px;
@include at-least($large-screen) {
width: $large-screen;
max-width: $large-screen;
}
@include until($phone) {
max-height: 300px;
img {
max-height: 268px
}
}
}
Une syntaxe de Sass
83
CHAPITRE 2

Limitations
Malgré la puissance de Sass, il faut relever quelques limites d’usage du préprocesseur
avec les Media Queries.
La première limitation concerne l’héritage. À l’intérieur d’une Media Query, Sass
restreint l’héritage aux sélecteurs contenus dans la requête de média. L’exemple qui
suit fonctionne parfaitement.
Héritage d’une classe déclarée dans la même requête de média

@media only screen and (max-width: 500px) {


.hidden {
display: none;
}
.advertisement {
@extend .hidden;
}
}

CSS compilée

@media only screen and (max-width: 500px) {


.hidden, .advertisement {
display: none;
}
}

En revanche, l’exemple suivant produit une erreur, car nous tentons d’étendre une
classe déclarée à l’extérieur de la Media Query.
Tentative d’héritage d’une classe située en dehors de la Media Query

.hidden {
display: none;
}
@media only screen and (max-width: 500px) {
.advertisement {
@extend .hidden;
}
}

Erreur générée

Syntax error: You may not @extend an outer selector from within @media.
You may only @extend selectors within the same directive.
From "@extend .hidden" on line 7.
Sass et Compass
84

La seconde limitation vient de l’incapacité de Sass à regrouper les Media Queries


identiques en une seule déclaration, parce qu’il ne peut pas réordonner les règles CSS
à la légère. Considérez l’exemple suivant :

@media only screen and (min-width: 600px) {


.notice { background: deepskyblue; }
}
.error { background: red; }
@media only screen and (min-width: 600px) {
.error { font-weight: bold; }
}

Appliqué à un élément <div class="notice error"> sur une surface d’affichage infé-
rieure à 600 px de large, son arrière-plan est de couleur rouge.
En revanche, si Sass regroupait les deux Media Queries précédentes en une seule, la
cascade CSS jouerait son rôle et l’élément serait affiché avec une couleur d’arrière-
plan bleu ciel !

.error { background: red; }


@media only screen and (min-width: 600px) {
.notice { background: deepskyblue; }
.error { font-weight: bold; }
}

Il suffirait de rassembler la deuxième Media Query avec la première pour résoudre le


problème, mais est-ce que cette solution sera toujours satisfaisante ? Pouvez-vous
l’affirmer sur un projet long de plusieurs milliers de lignes ? Non, tout simplement. Il
en est de même pour Sass qui, au lieu de risquer de casser la cascade CSS mise en
place, joue la carte de la sécurité en évitant de regrouper les Media Queries.

Les pièges à éviter


Attardons-nous quelques instants sur certains pièges induits par la facilité d’écriture
de la syntaxe Sass. S’il s’avère que vous êtes la victime de l’un d’entre eux, rassurez-
vous : quel que soit son niveau d’expertise en CSS, tout débutant Sass est passé par
là. Vous n’êtes pas le premier et vous ne serez certainement pas le dernier.
Une syntaxe de Sass
85
CHAPITRE 2

Syndrome de l’imbrication aiguë


Le support de l’imbrication des règles CSS est une merveille de lisibilité pour son
code. Néanmoins, il incite à reproduire la hiérarchie de l’arbre DOM du document
HTML dans sa feuille de styles et il n’est pas rare de croiser le genre de code qui suit.
HTML

<div class="news-list">
<div class="news">
<div class="news-inside">
<div class="news-desc">
<ul>
<li><a href="#"><span>Ceci ou cela</span></a></li>
</ul>
</div>
</div>
</div>
</div>

SCSS

.news-list {

.news {

.news-inside {

.news-desc {

ul {

li {

a {

span {

}
}
}
}
}
}
}
}
Sass et Compass
86

Le néophyte sera ravi par la correspondance HTML / SCSS qui l’aide à se repérer
dans son code. Mais le résultat est lourd de conséquences. Des sélecteurs bien trop
spécifiques sont générés par le préprocesseur.
Des sélecteurs CSS trop spécifiques

.news-list { … }
.news-list .news { … }
.news-list .news .news-inside { … }
.news-list .news .news-inside .news-desc { … }
.news-list .news .news-inside .news-desc ul { … }
.news-list .news .news-inside .news-desc ul li { … }
.news-list .news .news-inside .news-desc ul li a { … }
.news-list .news .news-inside .news-desc ul li a span { … }

A-t-on réellement besoin de répéter les sélecteurs.news-list .news puis .news-list


.news .news-inside à chaque niveau d’imbrication alors même qu’un jeu de classes
CSS a été mis en place pour permettre d’isoler chacun des composants ? De même,
est-il réellement utile de descendre à cinq niveaux de profondeur pour styler les listes
non ordonnées et jusqu’à un septième niveau pour les liens ?

ANECDOTE Les experts tombent dans le panneau


Même les meilleurs ont succombé aux charmes envoûtants de la surimbrication. Dans son article « CSS:
Taking control of the cascade » publié sur le blog de la célèbre agence 37signals, Jason Zimdars décrit, à
tort, les bienfaits d’une écriture de ses styles SCSS calqués sur l’arbre du document HTML. Les réactions
ne se sont pas fait attendre.
B http://37signals.com/svn/posts/3003-css-taking-control-of-the-cascade

N’oublions pas que la finalité est de produire une feuille de styles CSS, téléchargée
par le navigateur du visiteur !
Il sera plus optimal d’écrire le code SCSS suivant.
Des sélecteurs moins contraignants

.news-list {

.news {

}
}
.news-inside {

}
Une syntaxe de Sass
87
CHAPITRE 2

.news-desc {

ul {

}
li {

}
a {

span {

}
}
}

Ce code SCSS permet d’obtenir des styles moins verbeux et dont d’éventuelles sur-
charges CSS pourront s’opérer en douceur.
Des sélecteurs CSS poids plume

.news-list { … }
.news-list .news { … }
.news-inside { … }
.news-desc { … }
.news-desc ul { … }
.news-desc li { … }
.news-desc a { … }
.news-desc a span { … }

SE DOCUMENTER Principe de surcharge de CSS


Surcharger une règle CSS revient à la redéfinir plus loin dans la feuille de styles ou à écrire un nouveau
sélecteur plus spécifique.
Par exemple, pour surcharger la règle définie par le sélecteur .news-list .news .news-inside
.news-desc il faudrait soit préfixer le tout par un énième sélecteur (.demo .news-list .news
.news-inside .news-desc) ou remplacer un de ses composants par un identifiant (#featured
.news .news-inside .news-desc). Cela est rendu possible grâce au principe de cascade de CSS et
surtout par son système de priorité des sélecteurs.
Un article édité par le groupe OpenWeb revient en détail sur le principe de la cascade CSS et sur le calcul
des priorités des sélecteurs :
B http://openweb.eu.org/articles/cascade_css
Pour aller plus loin, voici un calculateur en ligne des poids de vos sélecteurs CSS :
B http://specificity.keegan.st/
Sass et Compass
88

La règle de l’inception
Clin d’œil au film Inception de Christopher Nolan, « la règle de l’inception », évo-
quée par Mario « Kuroir » Ricalde dans un article publié sur le blog The Sass Way,
préconise de ne pas descendre au-delà de quatre niveaux d’imbrication.

SE DOCUMENTER La règle de l’inception


Retrouvez en ligne l’article « Nested Selectors: The Inception Rule » sur le blog The Sass Way :
B http://thesassway.com/beginner/the-inception-rule

Héritages complexes
L’héritage est un puissant outil dans une optique DRY, mais il y a des erreurs à ne
pas commettre.
N’utilisez jamais @extend sur une règle qui n’est pas définie par une classe unique ou
qui se trouve être réemployée dans un sélecteur plus complexe, sous peine de générer
des styles imprévisibles et souvent inutiles pour votre projet. Cela vous obligerait à
jouer des coudes avec la cascade CSS pour surcharger les styles produits.
HTML

<div class="post">
<header class="heading">
<h1>Sass et Compass</h1>
</header>
<div class="exclu">
<div class="title">
<h2>Un nouveau livre à paraître aux éditions Eyrolles&nbsp;!</h2>
</div>
</div>
</div>

SCSS

// La classe ".heading" est l’unique sélecteur qui définit la présente


// règle CSS.
.heading {
font-size: 2em;
}

// Plus loin, elle a été réutilisée dans une règle imbriquée


// qui ne concerne qu’une page précise du site, la page d’accueil.
.home {
header, hgroup {
Une syntaxe de Sass
89
CHAPITRE 2

&.heading {
h1, h2, h3 {
padding-bottom: 5px;
border-bottom: 1px solid #ccc;
}
}
}
}

.exclu {
.title {
// La classe ".heading" est étendue.
@extend .heading;
}
}

CSS compilée

.heading, .exclu .title {


font-size: 2em;
}

.home header.heading h1, .home .exclu header.title h1, .exclu .home header.title
h1, .home header.heading h2, .home .exclu header.title h2, .exclu .home
header.title h2, .home header.heading h3, .home .exclu header.title h3, .exclu
.home header.title h3, .home hgroup.heading h1, .home .exclu hgroup.title h1,
.exclu .home hgroup.title h1, .home hgroup.heading h2, .home .exclu hgroup.title
h2, .exclu .home hgroup.title h2, .home hgroup.heading h3, .home .exclu
hgroup.title h3, .exclu .home hgroup.title h3 {
padding-bottom: 5px;
border-bottom: 1px solid #ccc;
}

De nombreux sélecteurs ont été générés alors qu’ils sont totalement inutiles dans
l’exemple présenté. Pire, certains sélecteurs pourraient entrer en conflit avec d’autres
règles de votre projet.
Le plus sûr est de n’étendre que des classes simples qui n’apparaissent jamais plus
d’une fois dans la source SCSS ou, même, de n’utiliser que des placeholders aux
noms explicites.

Consolider à tort un héritage par placeholder


Le mécanisme de placeholder de Sass offre une maîtrise du code produit plus accrue.
Cependant, ajouter un placeholder dans son code ne doit pas se faire à la légère et
doit être dûment réfléchi.
Sass et Compass
90

Considérons le listing ch02-017a.scss :


Listing ch02-017a.scss

SCSS CSS compilée


color: red; important, .error {
h3 { color: red;
font-weight: bold; }
} .important h3, .error h3 {
} font-weight: bold;
.important { }
@extend %important;
} .error {
.error { background-color: #fcc;
@extend %important; }
background-color: #fcc;
} .content .important h3,
.content %important h3 { .content .error h3 {
font-weight: normal; font-weight: normal;
} }

À première vue, puisqu’elle se contente d’étendre un placeholder, la classe .important


pourrait tout aussi bien être regroupée avec le sélecteur %important afin de n’écrire
qu’une seule règle.
La feuille de styles produite est cependant différente. Un sélecteur CSS a disparu,
impliquant potentiellement une régression d’affichage sur le site.
Listing ch02-017b.scss

SCSS CSS compilée


.important, %important { .important, .error {
color: red; color: red;
h3 { }
font-weight: bold; .important h3, .error h3 {
} font-weight: bold;
} }
.error {
@extend %important; .error {
} background-color: #fcc;
.content %important h3 { }
font-weight: normal;
} .content .error h3 {
font-weight: normal;
}
Une syntaxe de Sass
91
CHAPITRE 2

La similitude des noms employés pour déclarer la classe et le placeholder nous a


induits en erreur, ce qui est fréquent lors des premières utilisations de ce système.
Une inspection approfondie de votre code doit être effectuée avant de regrouper un
simple héritage avec son placeholder.

Ordre d’apparition des placeholders


On l’a vu, tout placeholder hérité est remplacé par l’association des sélecteurs impliqués.
Concrètement, les règles qui invoquent l’héritage d’un placeholder sont déplacées à
la position du placeholder dans la feuille de styles.
Dans l’exemple qui suit, alors que la règle qui étend le placeholder %pink se situe après
la première définition de la couleur de lien, son apparition dans la CSS compilée se fait
en premier. Les liens seront affichés en bleu et non en rose comme souhaité.
SCSS

%pink {
color: pink;
}

a {
color: blue;
}

// Plus loin dans le code source, la couleur des liens est redéfinie.
a {
@extend %pink;
}

CSS compilée

/* La règle qui a étendu le placeholder se retrouve au début du fichier,


à l’endroit même où était positionné le placeholder. */
a {
color: pink;
}

a {
color: blue;
}
Sass et Compass
92

En résumé
Le nombre de possibilités offertes par Sass est probablement ce qui surprend le plus.
Grâce à lui, CSS s’ouvre à des concepts avancés d’organisation et d’optimisation de
code. L’introduction des variables et des mixins font évoluer ce langage statique de
création de styles au stade d’un langage dynamique.
Vous constaterez au chapitre suivant que Sass pousse les portes des domaines du
développement et de la programmation en enrichissant CSS de nouveaux types de
données, de fonctions ou encore de directives de contrôle.
3
Développer avec Sass

Développez avec Sass ! L’enrichissement de CSS par le préprocesseur avec de


nouveaux types de données vous ouvre de nouveaux horizons.

SOMMAIRE
B Découvrir les types de données de Sass
B Manipuler les données
B Conserver une approche DRY
Sass et Compass
94

Ce chapitre présente les connaissances de base nécessaires à la programmation. Il


sera effectivement question d’opérations sur des données, de manipulations à l’aide
de structures de contrôle et de programmation fonctionnelle. L’écriture de vos
feuilles de styles sera abordée sous un angle nouveau : dites adieu aux répétitions,
bienvenue à la factorisation !
Cependant, n’oubliez jamais que tout développement aura pour finalité de générer des
styles CSS, qui sont pour leur part bien statiques. N’attendez pas de Sass qu’il calcule et
adapte automatiquement une grille en fonction du périphérique de vos visiteurs.

Sass et les données


Le langage CSS, bien que statique, ne cesse de manipuler des données. De la simple
couleur aux listes de valeurs comme 1px solid #000 en passant par des chaînes de
caractères telles que "Helvetica Neue", nous travaillons finalement avec de grandes
quantités de données. Sass offre la même capacité de traitement de données, mais, le
préprocesseur va plus loin en introduisant de nouveaux types de données qui procu-
reront à l’intégrateur de nouveaux outils pour rendre la génération des feuilles de
styles plus dynamique.

Les principaux types de données


Comme dans de nombreux langages de programmation, toute propriété CSS ou
variable Sass est définie par un type qui dicte son comportement. Ainsi, comme nous le
verrons plus loin dans le chapitre, additionner deux chiffres (3 + 3) ou deux chaînes de
caractères ("3" + "3") ne produira pas le même résultat. Avant de nous lancer dans les
opérations arithmétiques, découvrons les cinq types de données supportées par Sass.

Les chaînes de caractères


Par défaut dans Sass, toute valeur d’une propriété CSS ou toute valeur d’une variable
est considérée comme étant des chaînes de caractères (ou string).
Ainsi, et contrairement à bien des langages de programmation, les guillemets sont
facultatifs. Les deux formes $direction: left et $direction: "left" sont équiva-
lentes. La principale différence entre la forme encapsulée dans des guillemets et la
forme qui en est dépourvue tient dans la liste des caractères autorisés. La version
pourvue de guillemets accepte tout caractère autre que le guillemet " qui fermerait
prématurément la chaîne, tandis qu’une chaîne sans guillemets ne peut commencer
ni par un chiffre, ni par des caractères spéciaux comme #, ., @, <, >, =, ~, * ou & et, sur-
tout, ne peut pas contenir d’espaces.
Développer avec Sass
95
CHAPITRE 3

SYNTAXE Apostrophes simples ou doubles ?


Les deux types de guillemets sont autorisés dans Sass. Placez vos chaînes de caractères dans l’un ou
l’autre selon votre préférence. Néanmoins, vous opterez pour la version alternative si une chaîne contient
un guillemet. Vous écrirez "l'arbre" ou 'Arial, "Helvetica Neue"'.

Si aucun type de données connu de Sass n’est identifié, alors le type appliqué à la valeur
sera string et sera rendu tel quel dans la feuille de styles CSS. Ce mécanisme permet à
Sass de générer des propriétés et des règles qui invalident la syntaxe CSS. Par exemple,
l’écriture d’un filtre propriétaire d’Internet Explorer est invalide en CSS.
Une propriété CSS invalide

filter: progid:DXImageTransform.Microsoft.alpha(opacity=50);

Dans le cas présent, Sass ne détecte aucun type de données particulier et va donc le
traiter comme s’il s’agissait d’une chaîne de caractères. S’il ne réagissait pas de la
sorte, vous devriez écrire le filtre propriétaire décoré par des guillemets qui, malheu-
reusement, seraient générés dans la sortie CSS. Bien évidemment, le filtre ne serait
pas appliqué par Internet Explorer car invalide syntaxiquement.
Des règles syntaxiques peuvent spécialiser une chaîne de caractères dans un type plus
spécifique, comme une valeur numérique.

Les valeurs numériques


Dans Sass comme dans CSS, les valeurs numériques (ou number) se distinguent en
deux groupes : les chiffres et les unités de mesure dont les plus courantes sont le
pixel, le pourcentage ou encore l’unité de mesure relative em.
Toute valeur débutant par un chiffre sera considérée par Sass comme une valeur
numérique.

Les couleurs
Une couleur (ou color) est un type de données spécifique de CSS qui désigne une
couleur dans l’espace colorimétrique sRGB. Une couleur peut être représentée de
plusieurs manières dans CSS.
• La plus courante est la représentation hexadécimale du modèle de couleur RGB
(RVB en français) : #e6e6fa.
• Un nom réservé, décrit dans la spécification SVG 1.0 (voir encadré « Couleurs du
Web ») : lavender (lavande).
• Une représentation RGB à l’aide de la fonction CSS rgb() : rgb(230, 230, 250).
Sass et Compass
96

• Une représentation HSL (Hue Saturation Lightness), ou TSL (Teinte Saturation


Lumière) en français, avec la fonction CSS hsl() : hsl(240deg, 66.67%, 94%).
• Et enfin, les fonctions rgba() et hsla() qui fonctionnent respectivement comme
rgb() et hsl() avec comme quatrième argument un taux de transparence (de 0
pour une transparence complète à 1 pour une couleur totalement opaque).

SE DOCUMENTER Couleurs du Web


Retrouvez en ligne la liste complète des noms des couleurs réservées par la spécification SVG 1.0 implé-
mentée dans le langage CSS :
• La table étendue des mots-clés de couleur, dans le document de la spécification du W3C :
B http://www.w3.org/TR/css3-color/#svg-color
• La version française du tableau sur la page Wikipédia consacrée aux couleurs du Web :
B http://fr.wikipedia.org/wiki/Couleurs_du_Web#Noms_de_couleurs_SVG_1.0

Sass supporte chacune de ces représentations et, lorsqu’il en rencontre une, la stocke
sous les formats RGB et HSL. Cette double mémorisation lui sera utile pour mani-
puler les couleurs, ce que nous verrons bientôt.

HISTORIQUE Introduction des couleurs du Web dans CSS


Lors de l’introduction des mots-clés réservés pour désigner des couleurs dans CSS1, seuls 16 noms furent
réservés. Ils correspondaient aux couleurs VGA que les cartes graphiques de l’époque étaient en mesure
d’afficher. La couleur orange fut intégrée dans la spécification CSS2. Aujourd’hui, CSS3 ne compte pas
moins de 147 noms de couleurs réservés suite à l’intégration de la spécification SVG 1.0.

Les booléens
Issu de l’algèbre de Boole, le type de données booléen représente deux états : vrai ou
faux. Ces deux valeurs, propres à Sass et inconnues de CSS, se notent respectivement
true et false.

Le type de données booléen (ou bool) est utilisé dans Sass pour conditionner la géné-
ration de styles, à l’occasion de tests dits conditionnels que nous aborderons en détail
dans la section « Les tests conditionnels ».

Les listes
Héritage de la syntaxe CSS, les listes (ou list) représentent une séquence de valeurs
dont tirent parti les propriétés composites comme background ou border. Par exemple,
1px solid red est une liste de trois valeurs séparées par des espaces qui pourra ali-
menter une propriété border. Les valeurs d’une liste peuvent également être séparées
Développer avec Sass
97
CHAPITRE 3

par des virgules ; notation que l’on retrouvera dans CSS pour décrire une pile de
polices de caractères (ou font stack).
Tandis que les listes sont limitées pour ne contenir que des valeurs dans CSS, les
listes de Sass acceptent tout type de données connu, incluant les listes elles-mêmes.
La notation la plus naturelle de listes imbriquées est d’écrire une liste principale de
valeurs séparées par des virgules contenant des sous-listes dont le séparateur de
valeurs sera l’espace.
Une liste principale, composée de trois listes séparées par des virgules

$messages: ok green, warning #514721, error darkred;

Toutefois, il est admis de recourir à un unique séparateur dans l’écriture de listes


imbriquées, à condition de délimiter chacune d’entre elles par des parenthèses.
Combinaison de listes de même séparateur à l’aide de parenthèses

$virgules: (ok, green), (warning, #514721), (error, darkred);


$espaces: (ok green) (warning #514721) (error darkred);

Lors de la conversion en CSS, si une liste est attribuée à une propriété CSS, alors
Sass supprimera les éventuelles parenthèses pour garantir la validité du code produit.
Nous verrons plus loin dans le chapitre que les listes relèvent d’un tout autre intérêt
dans Sass. Conjuguées avec les notions de boucles et d’itérateurs, elles seront d’une
grande utilité pour appliquer le principe DRY.

Connaître le type d’une donnée


L’instruction type-of() permet d’interroger le type de données d’une valeur. Le
résultat retourné est une chaîne de caractères, ce qui nous permettra de réaliser des
tests sur le résultat et de réagir en conséquence.
Déterminer le type des données depuis la session interactive de Sass

$ sass -i
>> type-of(left) // une chaîne de caractères sans guillemets
"string"
>> type-of("left") // une chaîne de caractères avec guillemets
"string"
>> type-of(24) // un chiffre
"number"
>> type-of(24px) // un chiffre agrémenté d’unité de longueur
"number"
Sass et Compass
98

>> type-of(#e6e6fa) // une couleur en représentation hexadécimale


"color"
>> type-of(rgb(230, 230, 250)) // une couleur rgb()
"color"
>> type-of(yellow) // une couleur Web
"color"
>> type-of("yellow") // décorée par des guillemets, le type change
"string"
>> type-of(true) // un booléen
"bool"
>> type-of(1px solid red) // une liste avec l’espace pour séparateur
"list"

Au sein de vos fichiers Sass, il arrivera rarement que vous ayez à tester directement le
type d’une valeur sans passer au préalable par une variable. Et heureusement. Une
erreur est levée lorsque vous tenterez de tester directement le type d’une liste de
valeurs séparée par des virgules.
Le problème des listes avec la virgule pour séparateur

>> type-of(Arial, "Helvetica Neue", Helvetica, sans-serif)


SyntaxError: wrong number of arguments (4 for 1) for `type-of'

Sass considère chaque valeur de la liste comme étant un argument passé à la fonction
type-of(). Or, cette dernière n’accepte qu’un seul argument. Pas un de plus.

Si vous tenez à effectuer le test sans recourir à une variable intermédiaire, indiquez
explicitement à Sass que vous transmettez une donnée de type list à l’aide de paren-
thèses.
Il est parfois nécessaire d’expliciter l’usage d’une liste

>> type-of((Arial, "Helvetica Neue", Helvetica, sans-serif))


"list"

Le cas particulier de la valeur nulle


Apparue dans Sass 3.2.0, la valeur null, est pourtant injustement méconnue au
moment de la rédaction de ces lignes. Il s’agit en réalité d’un nouveau type de don-
nées qui s’apparente au booléen false ou à une chaîne de caractères vide mais dont
les implications dans la production du code CSS sont plus importantes.
Développer avec Sass
99
CHAPITRE 3

En effet, renseigner une propriété CSS avec une variable dont la valeur assignée vaut
null obligera Sass à la supprimer de la sortie compilée.

ch03-001.scss

// Cas 1 : la valeur null est directement assignée à la propriété.


.demo_1 {
color: null; 
width: 80%;
}

// Cas 2 : la valeur null est assignée à la propriété via une variable.


.demo_2 {
$demo-color: null;
color: $demo-color; 
width: 80%;
}

CSS compilée

.demo_1 {
color: null; 
width: 80%;
}

.demo_2 { 
width: 80%;
}

 Dans le premier cas de figure, la valeur null est directement assignée à une pro-
priété CSS. Sass traite cette valeur comme s’il était en présence de la chaîne de carac-
tères "null" et, dès lors, n’applique aucune transformation ni traitement ; la propriété
est générée telle quelle ().
 Le second test passe par une variable intermédiaire. Variable dont la valeur vaut
null.Dans ce cas de figure, Sass traite la valeur, non comme une chaîne de caractères,
mais bien comme étant du type null. La notion de nullité n’existant pas dans CSS, la
propriété est supprimée par Sass ().
Si d’aventure une règle de style venait à ne contenir qu’une seule propriété dont la
valeur calculée est null, alors Sass ne générera pas la règle dans la sortie CSS. Dans
l’exemple qui suit, Sass omet la règle définie par le sélecteur .demo.
Sass et Compass
100

ch03-002.scss CSS compilée


.temoin { .temoin {
border: 1px solid #000; border: 1px solid #000;
} }
.demo {
$demo-color: null;
color: $demo_color;
}

Des mathématiques dans vos CSS


Attendue tel le messie par tout intégrateur, la fonction calc() de CSS3, qui permet
de réaliser des calculs mathématiques directement dans les feuilles de styles, est
encore loin de pouvoir être pleinement exploitée en production. Bien que son implé-
mentation progresse à grands pas, en ce début 2013, des navigateurs comme IE8 ou
Safari d’iOS5 ne supportent pas du tout cette fonctionnalité. Certes, des palliatifs à
base de JavaScript (les fameux polyfills) existent, mais ils fonctionnent au détriment
des performances et de la réactivité de votre site.

SE DOCUMENTER Découvrir calc()


Retrouvez en ligne la fonction de calcul telle qu’elle est décrite dans la spécification W3C :
B http://dev.w3.org/csswg/css-values/#calc-notation
Suivez la progression de l’implémentation de la fonction calc() :
B http://caniuse.com/calc

Sass supporte de nombreux mécanismes de calcul, et, même s’ils ne sont pas aussi
riches que ceux permis par la fonction native calc(), ils ouvrent de nouveaux hori-
zons au développeur front-end.
Il devient ainsi possible de créer un système de grille paramétrable en toute simplicité.
Un système de grille évolutif

$grid-columns: 24;
$main-columns: 16;
$sidebar-columns: $grid-columns - $main-columns;
$grid-width: 30px;
$grid-margin: 10px;
$grid-outer-width: $grid-width + $grid-margin;
$container-size: $grid-outer-width * $grid-columns - $grid-margin;
Développer avec Sass
101
CHAPITRE 3

.container {
width: $container-size;
margin: 0 auto;
}
#main {
margin-right: $grid-margin;
width: $grid-width * $main-columns +
$grid-margin * ($main-columns - 1);
}
#sidebar {
margin-right: 0;
width: $grid-width * $sidebar-columns +
$grid-margin * ($sidebar-columns - 1);
}

Comparaison de valeurs
Avant de prendre connaissance des opérations supportées par Sass, sachez que le pré-
processeur autorise les comparaisons d’égalité stricte entre deux valeurs à l’aide des
opérateurs == et !=. Le résultat est un booléen.

T Comparaison d’égalité stricte

En plus de comparer les valeurs, une comparaison d’égalité stricte réalise une comparaison des types des
deux opérandes de l’opération. Ainsi, les opérateurs == et != de Sass équivalent les opérateurs === et
!== de JavaScript et PHP.

Tableau 3–1 Exemples de comparaisons de valeurs

Comparaison Résultat Observation


10 == 10 true Deux chiffres identiques
520px == 520px true Deux longueurs identiques
10 == "10" false Un chiffre est différent de son homonyme écrit dans une
chaîne de caractères.
arial == "arial" true Les guillemets n’ont pas d’impact sur la comparaison de
chaînes de caractères.
arial != "arial narrow" true Deux chaînes différentes
arial == Arial false La comparaison de chaînes de caractères est sensible à la
casse.
#c0c0c0 == #c0c0c0 true Les couleurs en notation hexadécimale sont identiques.
#c0c0c0 == silver true La comparaison peut s’effectuer entre différentes nota-
tions des couleurs.
Sass et Compass
102

Tableau 3–1 Exemples de comparaisons de valeurs (suite)

Comparaison Résultat Observation


#c0c0c0 == rgb(192, 192, true La comparaison peut s’effectuer entre différentes nota-
192) tions des couleurs.
(arial, verdana) == true Deux listes identiques
(arial, verdana)
(arial, verdana) == false L’ordre d’apparition des valeurs est important.
(verdana, arial)
(arial, verdana) == false Le séparateur des valeurs des listes compte lors de la com-
(verdana arial) paraison.

Les valeurs numériques peuvent en plus être comparées à l’aide des opérateurs rela-
tionnels <, >, <=, >=.
Tableau 3–2 Les opérateurs relationnels

Opérateur Signification
$a < $b $a strictement inférieur à $b
$a <= $b $a inférieur ou égal à $b
$a > $b $a strictement supérieur à $b
$a >= $b $a supérieur ou égal à $b
$a == $b $a égal à $b

Une fois n’est pas coutume, les listes sont à traiter avec attention. En l’absence de
variables pour réaliser les tests, l’ajout de parenthèses est obligatoire. Dans l’exemple
qui suit, au lieu de comparer les valeurs contenues par les deux listes, Sass va tester les
deux opérandes situées directement autour de l’opérateur (black et 1px) et retourner
le résultat qui intégrera la liste. Finalement, une liste est retournée et en aucun cas un
booléen, résultat d’une comparaison :

$ sass -i
>> 1px solid black == 1px solid black
(1px solid false solid black)

La désignation explicite des listes résout la situation. Nous pouvons d’ailleurs


observer que Sass compare chaque élément d’une liste en respectant les règles syn-
taxiques de chaque type de données :

$ sass -i
>> (1px solid black) == (1px solid black)
true
>> (1px "solid"black) == (1px solid#000)
true
Développer avec Sass
103
CHAPITRE 3

Une solution plus pérenne est de recourir à des variables :

$ sass -i
>>$a: 1px "solid" black
(1px "solid" #000000)
>>$b: 1px solid #000
(1px "solid" #000000)
>>$a == $b
true

Opérations numériques
Sass supporte les opérations arithmétiques de base (+, -, *, /, %). Bien évidemment,
les règles de priorités algébriques sont respectées.

$ sass -i
>> 24 + 16
40
>> 4 - 4 * 4 + 4 * 4
4
>> 4 - (4 * 4) + (4 * 4) // équivaut à la ligne précédente
4
>> (4 - 4) * (4 + 4) * 4
0

Il faut porter une attention particulière à l’opérateur de division. Sass étant un sur-
ensemble à CSS, il lui faut être compatible avec ce dernier. Or, la syntaxe de CSS dis-
pose d’une forme où intervient le symbole / de la division pour séparer deux valeurs
numériques, à savoir l’écriture raccourcie des propriétés font et line-height :

strong {
font: bold 16px/1.5 Arial, "Helvetica Neue", Helvetica, sans-serif;
}

En présence d’une telle syntaxe, Sass doit conserver le code en l’état et ne pas réaliser
de division. Heureusement, trois cas de figure nous permettent de recourir à l’opéra-
teur de division.
 Si au moins une des opérandes est une variable.
 Si l’opération est entourée de parenthèses.
 Si l’opération s’effectue au sein d’une autre opération arithmétique.
Sass et Compass
104

SCSS

p {
$width: 800px;
font: 10px/8px; // Syntaxe de CSS, la division n’est pas réalisée.
width: $width/2; 
height: (400px/2); 
margin-left: 5px + 8px/2px; 
}

CSS compilée

p {
font: 10px/8px;
width: 400px; 
height: 200px; 
margin-left: 9px; 
}

Un dernier problème se pose lorsque l’on cherche à afficher le contenu des variables
autour du symbole de la division. Sass effectue le calcul.

SCSS CSS compilée


p { p {
$fs: 12px; font: 0.66667;
$lh: 18px; }
font: $fs/$lh;
}

La solution est d’interpoler les variables.

SCSS CSS compilée


p { p {
$fs: 12px; font: 12px/18px;
$lh: 18px; }
font: #{$fs}/#{$lh};
}

Opérations avec des unités


En sus d’un support des opérations arithmétiques basiques sur les chiffres, Sass
intervient sur les unités. Il réalise par ailleurs les conversions dans le cadre de l’addi-
tion et de la soustraction :
Développer avec Sass
105
CHAPITRE 3

$ sass -i
>> (12px + 18px) / 2
15px
>> 1em + 3em
4em
>> 1in + 8pt
1.11111in

À l’issue d’une conversion d’unité, l’unité conservée est celle du premier opérateur :

$ sass -i
>> 16pt + 10px
23.5pt
>> 10px + 16pt
31.33333px

Toujours dans le cadre d’une addition ou d’une soustraction, le calcul ne sera permis
qu’entre des unités compatibles. Seules deux valeurs ayant des unités finies (in, cm,
pc, mm, pt, px) pourront être additionnées, mais l’addition d’unités relatives comme
em et rem, ou d’une unité finie et d’une unité relative, est interdite :

$ sass -i
>> 1cm + 1in // addition d’unités finies
3.54cm
>> 1em + 2rem // addition d’unités relatives
SyntaxError: Incompatible units: 'rem' and 'em'.
>> 10px + 3em // addition d’unités finie et relative
SyntaxError: Incompatible units: 'em' and 'px'.

Tableau 3–3 Table des correspondances des unités

in cm pc mm pt px

in 1 2.54 6 25.4 72 96
cm 1 2.36220473 10 28.3464567 37.795275591
pc 1 4.23333333 12 16
mm 1 2.83464567 3.7795275591
pt 1 1.3333333333
px 1

Une multiplication ou une division d’unités retourne bien le calcul des valeurs numé-
riques, mais conservera les unités (repères  et ). Débarrassez-vous de l’unité en
surplus en divisant le résultat de l’opération par un (repères  et ) :
Sass et Compass
106

$ sass -i
>> 5em* 16px
80em*px 
>> 5em / 16px
0.3125em/px 
>> 5em * 16px / 1em
80px 
>> 5em * 16px / 1px
80em 

Opérations sur les chaînes de caractères


L’unique opération autorisée sur les chaînes de caractères est l’addition +. L’effet obtenu
est comparable à une concaténation et il en résulte une nouvelle chaîne de caractères.
Si jamais une chaîne de caractères intervient dans un calcul impliquant d’autres types
de données, alors le résultat sera une chaîne de caractères ou une erreur si l’opération
appliquée à la chaîne de caractères résultante n’est pas celui de l’addition.
Tableau 3–4 Exemples d’opérations sur les chaînes de caractères

Opération Résultat
Century + Gothic CenturyGothic
"Century" + Gothic "CenturyGothic"
Century + "Gothic" CenturyGothic
"Century" + "Gothic" "CenturyGothic"
"Century" + " " + Gothic "Century Gothic"
Ariane + 5 Ariane5
false + tto "falsetto"
2 * 10 + "13" "2013"
(2 * 10 + "13") * 2 SyntaxError: Undefined operation:
""2013" times 2"

ATTENTION Opérateurs de soustraction et de division


Pour des raisons historiques, les opérateurs de soustraction - et de division/ réalisent eux aussi des conca-
ténations si les opérandes et l’opérateur sont séparés par des espaces. L’opérateur est toutefois conservé :
$ sass -i
>> sans - serif
"sans-serif"
>> sans / serif
"sans/serif"
Développer avec Sass
107
CHAPITRE 3

Opérations sur les couleurs


Aussi étonnant que cela puisse paraître, Sass est capable d’additionner (+), de sous-
traire (-), de multiplier (*), de diviser (/) deux couleurs et même de trouver le modulo
(%) de deux couleurs. Pour cela, il réalise l’opération sur chacune des composantes
rouge, verte et bleue des couleurs.

B.A.-BA Relation entre la représentation RGB et hexadécimale d’une couleur


Chacun des canaux RGB possède 256 niveaux d’intensité, codés de 0 pour une absence totale de couleur
à 255 pour une pleine couleur. Dans CSS, les couleurs sont généralement notées dans leur représentation
hexadécimale où chaque composante rouge, verte et bleue est codée en base 16 (0-9a-f). Ainsi, 00 en
hexadécimal reste 0 en notation RGB et FF correspond à une intensité de canal RVB de 255.

Additionnons les couleurs #010101 et #030303. Lorsque Sass lira ces couleurs, il
mémorisera leurs versions converties dans la représentation RGB, soit respective-
ment rgb(1, 1, 1)et rgb(3, 3, 3) puis les additionnera de proche en proche pour
obtenir la couleur rgb(4, 4, 4). Le résultat retourné sera la couleur #040404 :

$ sass -i
>> #010101 + #030303
#040404
>> rgb(1, 1, 1) + rgb(3, 3, 3)
#040404

Pour obtenir la couleur #FF0101 (rgb(255, 1, 1)) depuis la couleur #010101 (rgb(1, 1,
1)), Sass doit additionner 254 (ou FE en notation hexadécimale) à la composante
rouge :

$ sass -i
>> #010101 + rgb(254, 0, 0)
#ff0101
>> #010101 + #fe0000
#ff0101

Le résultat d’une opération sur un canal de couleur est borné aux valeurs 0 et 255.
Ainsi, additionner #0000FA (rgb(0, 0, 250)) et #00000A (rgb(0, 0, 16)) dont la somme
de la composante bleue est égale à 266 aura pour résultat la couleur #0000FF (rgb(0,
0, 255)). En aucun cas le surplus (valant 11 ici) ne sera appliqué en faveur de la com-
posante voisine.
Attention, les couleurs munies d’un canal alpha ne peuvent intervenir dans des cal-
culs si et seulement si les taux de transparence sont identiques. Autrement, une
erreur est générée par Sass :
Sass et Compass
108

$ sass -i
>>rgba(230, 230, 250, 0.5) + rgba(10, 10, 5, 0.5)
rgba(240, 240, 255, 0.5)
>>rgba(230, 230, 250, 0.5) + rgba(10, 10, 5, 0.2)
SyntaxError: Alpha channels must be equal:
rgba(230, 230, 250, 0.5) + rgba(10, 10, 5, 0.2)
>>rgba(230, 230, 250, 0.5) + rgb(10, 10, 5)
SyntaxError: Alpha channels must be equal:
rgba(230, 230, 250, 0.5) + #0a0a05

Toutefois, ces opérations sont loin d’être intuitives. On leur préférera les fonctions de
manipulation des couleurs abordées dans la section « Fonctions sur les couleurs » qui
offrent une maîtrise plus fine mais surtout plus compréhensible des opérations sur les
couleurs.

Opérations booléennes
Sass supporte les classiques opérateurs logiques and (et), or (ou) et not (non). Si vous
développez, veuillez noter que le préprocesseur ne gère pas les opérateurs && et || ni
la négation ! que l’on retrouve dans bien des langages.
Petit rappel sur les opérations booléennes.
Dans les tableaux qui suivent, les deux premières colonnes $a et $b décrivent la
valeur des variables éponymes, tandis que la dernière colonne retranscrit le résultat de
l’opération booléenne appliquée aux deux variables.
Tableau 3–5 Table de vérité ET (and)

$a $b $a and $b
false false false
false true false
true false false
true true true

Tableau 3–6 Table de vérité OU (or)

$a $b $a or $b
false false false
false true true
true false true
true true true
Développer avec Sass
109
CHAPITRE 3

Tableau 3–7 Table de vérité NON (not)

$a not $a
false true
true false

Les directives de contrôle


Tout l’intérêt des langages de programmation est de permettre au développeur
d’éviter de se répéter. Avec Sass, il dispose déjà des variables et des mixins ; ce qui est
somme toute assez limitatif. C’est pourquoi le préprocesseur introduit des méca-
nismes classiques issus du monde du développement, à savoir les tests conditionnels
et des systèmes de boucles permettant de dupliquer rapidement des styles. L’écriture
de styles CSS n’en sera que plus rapide.

Les tests conditionnels


Comme nous l’avons vu, Sass supporte les opérations booléennes mais, il faut bien
avouer qu’elles ne sont guère utiles en l’état. En effet, une opération booléenne est
généralement employée pour conditionner une action : « si les variables $a ou $b sont
vraies, alors ajouter une marge inférieure, sinon ne rien faire ».
Dans Sass, et comme dans de nombreux autres langages, les tests conditionnels sont
pris en charge par les mots-clés @if, @else et @else if. La notation complète est la
suivante.
Syntaxe des tests conditionnels

@if condition1 {
// Code si la première condition est vraie.
}
@else if condition2 {
// Code si la première condition est fausse et que
// la deuxième condition est vraie.
}
@else {
// Code pris en compte si aucune condition n’est vraie.
}

Bien évidemment, le deuxième test est facultatif tout comme la dernière partie de la
structure de contrôle.
Sass et Compass
110

L’exemple qui suit va conditionner l’ajout de largeurs en fonction de la valeur de la


variable $legacy-support-for-ie8.
Des styles CSS conditionnés par une variable

$legacy-support-for-ie8: false !default;


.couverture {
max-width: 260px;
@if $legacy-support-for-ie8 {
width: 260px;
img {
width: 100%;
}
}
}

La valeur de la variable valant false le code contenu par le test n’est pas inclus dans la
feuille de styles CSS finale. En revanche, si vous déclarez $legacy-support-for-ie8:
true; en amont de l’exemple précédent, alors les styles jusqu’alors ignorés seront
écrits dans la feuille de styles CSS. Cette technique peut se révéler utile dans une
approche d’intégration dite « Mobile First ».

SYNTAXE Compatibilité CSS


Comme vous pouvez en juger, toutes les directives de contrôle de Sass sont préfixées par un arobase.
Cela s’inscrit dans la volonté de rester compatible avec CSS.

Les boucles @for et @while


La structure de contrôle @for permet de répéter un même ensemble d’instructions
tout en maintenant un compteur de boucle. Deux syntaxes sont disponibles.

Forme exclusive Forme inclusive


@for $i from 1 to 5 { @for $i from 1 through 5 {
// instructions // instructions
} }

Dans les deux cas, la variable $i représente le compteur de boucle et sa valeur est ini-
tialisée avec celle de la borne de départ lors de la première itération (1 dans
l’exemple). Chaque fois que les instructions contenues dans le bloc de la boucle
seront compilées, la valeur de la variable $i sera incrémentée de un.
La différence entre les deux syntaxes est liée au comportement adopté lors de l’itéra-
tion finale.
Développer avec Sass
111
CHAPITRE 3

• Dans sa forme exclusive @for $i from 1 to 5, la boucle n’effectuera pas la dernière


itération. Dans notre exemple, elle s’arrêtera lorsque $i vaudra 4.
• Dans sa forme inclusive @for $i from 1 through 5, la boucle exécutera la dernière
itération. Dans notre exemple, elle s’arrêtera lorsque $i sera égal à 5.
Associée à l’interpolation de variable, une boucle @for se révèle être un puissant com-
pagnon pour s’économiser de rébarbatives saisies.

SCSS CSS compilée


@for $i from 1 through 3 { .item-1 {
.item-#{$i} { margin-left: 0em;
margin-left: 1em * ($i - 1); }
} .item-2 {
} margin-left: 1em;
}
.item-3 {
margin-left: 2em;
}

Bien évidemment, l’instruction de contrôle @for accepte aussi pour bornes des varia-
bles. En outre, bien qu’il soit coutume de nommer $i un compteur numérique, le
nom de cette variable est à votre discrétion.
Les boucles @for souffrent cependant de limitations. Elles ne supportent pas, par
exemple, la décrémentation du compteur. Toutefois, un peu d’astuce permet de con-
tourner le problème.
Compter à rebours avec une boucle @for

SCSS CSS compilée


$end: 5; .item-5 { width: 10em; }
@for $i from 0 to $end { .item-4 { width: 8em; }
$i: $end - $i; .item-3 { width: 6em; }
.item-#{$i} { .item-2 { width: 4em; }
width: 2em * $i; .item-1 { width: 2em; }
}
}

À chaque itération, nous assignons à la variable $i le résultat du calcul $end - $i, qui
vaudra successivement la valeur 5, puis 4, 3, 2, et finalement 1. Il est important de
noter ici que le compteur de boucle ignore sa valeur réécrite pour continuer l’itération
normalement.
Sass et Compass
112

RAPPEL Boucle inclusive ou exclusive


Dans l’exemple du compte à rebours, à l’aide d’une instruction @for, le décompte s’arrête à 1 et non à 0, la
valeur de la borne de départ. La boucle est ici de forme exclusive (mot-clé to) et donc la dernière itération
s’arrête à 4 et non à 5. Lors de la réécriture de la variable $i, nous avons bien 5 - 4 qui vaut 1.

Cependant, au lieu de contourner la logique de fonctionnement de l’instruction @for, il


aurait été préférable de recourir à l’instruction de contrôle @while. En effet, cette ins-
truction prend en argument une opération booléenne et boucle sur son bloc d’instruc-
tion tant que l’opération est évaluée à true. La lecture du code s’en retrouve simplifiée.
Compter à rebours avec une boucle @while

SCSS CSS compilée


$i: 5; .item-5 { width: 10em; }
@while $i > 0 { .item-4 { width: 8em; }
.item-#{$i} { .item-3 { width: 6em; }
width: 2em * $i; .item-2 { width: 4em; }
} .item-1 { width: 2em; }
$i: $i - 1;
}

Manipuler un compteur est certes pratique mais il n’est guère d’une grande aide lorsqu’il
faut parcourir une liste. Heureusement, l’instruction @each est prévue à cet effet.

Les itérations de listes avec @each


Similaire aux instructions de contrôle @for et @while, l’instruction @each va répéter un
bloc de styles plusieurs fois. Cependant, au lieu de maintenir un compteur numé-
rique, @each va itérer sur liste <list> et assigner tour à tour la valeur de ses éléments à
la variable $variable. La syntaxe est la suivante.
Syntaxe de l’instruction @each

@each $variable in <list> {


// instructions
}

Il va s’en dire que le nom de la $variable est à votre discrétion. La liste à parcourir
peut être une variable Sass de type list ou une liste « en dur » dont les éléments sont
séparés par des espaces ou des virgules. Dans un souci de lisibilité, nous préférerons
employer la virgule comme séparateur.
Développer avec Sass
113
CHAPITRE 3

Dans l’exemple qui suit, @each est employé avec la saisie directe d’une liste pour
générer un ensemble de règles CSS pour plusieurs images.
Exemple d’itération avec @each

@each $name in mail, phone, person {


.icon-#{$name} {
background-image: url('img/icons/#{$name}.png');
}
}

CSS générée

.icon-mail { background-image: url('img/icons/mail.png'); }


.icon-phone { background-image: url('img/icons/phone.png'); }
.icon-person { background-image: url('img/icons/person.png'); }

Manipulations avancées avec les fonctions


Nous arrivons au terme du tour d’horizon des possibilités offertes par Sass pour vos
futurs développements. Mais Sass ne pourrait pas prétendre aider au développement
s’il ne proposait pas de fonctions.
Une fonction est similaire à un mixin en permettant de réutiliser du code, à la différence
près qu’elle ne génère pas de règles de styles. En effet, alors qu’un mixin sera employé
pour générer un bloc de styles, une fonction servira à retourner une valeur qui pourra
ensuite être assignée à une propriété CSS ou encore dans une instruction de contrôle.
La syntaxe d’appel à une fonction est similaire à celle des fonctions CSS comme url().
Fonctions de Sass en action

.message {
background-color: $color;
// Manipulation par une fonction de la couleur $color.
color: invert($color);
// Les fonctions peuvent s'enchaîner.
border-color: darken(invert($color), 50%);
// Une fonction qui intervient dans une instruction de contrôle.
@if type-of($var) == 'string' {
// instructions
}
}
Sass et Compass
114

Comme nous allons maintenant le voir, Sass n’est pas avare en fonctions prédéfinies
pour vous permettre de manipuler tout type de données.

Fonctions sur les chaînes de caractères


Bien que rarement utilisées, Sass propose une poignée de fonctions de manipulation
des chaînes de caractères. Chacune d’entre elles retourne une donnée de type string.

SYNTAXE Arguments optionnels


Dans les différentes signatures de fonctions décrites dans les prochains tableaux, un argument encadré
par des crochets signifie que ce dernier est optionnel :
str-slice($string, $start, [$end]);
La fonction str-slice peut accepter deux ou trois arguments.

Tableau 3–8 Fonctions dédiées aux chaînes de caractères

Signature Description
unquote($string) Supprime d’éventuelles apostrophes simples ou doubles de la chaîne
$string.
quote($string) Ajoute des apostrophes doubles à la chaîne $string si elle en est
dépourvue.
str-length($string) Retourne le nombre de caractères de la chaîne $string.
str-insert($string, $insert, Insère la chaîne $insert dans la chaîne $string après le caractère
$index) de position $index. Le premier caractère a pour index 1. Un index
négatif parcourt la chaîne à l’envers (-1 représente le dernier carac-
tère).
str-index($string, Retourne la position de la chaîne $substring contenue par la
$substring) chaîne $string. Sinon zéro.
str-slice($string, $start, Extrait une sous-chaîne de $string depuis la position $start
[$end]) jusqu’à la fin de la chaîne ou la position $end si précisée.
to-upper-case($string) Convertit la chaîne $string en majuscules.
to-lower-case($string) Convertit la chaîne $string en minuscules.

VERSION Nouveautés de Sass 3.3.0


De nombreuses fonctions de manipulation de chaînes ont été introduites avec Sass 3.3.0. En effet,
jusqu’alors nous ne disposions que des fonctions unquote et quote ce qui limitait fortement nos
algorithmes !
Développer avec Sass
115
CHAPITRE 3

Fonctions numériques
Incontournables, les fonctions numériques concernent les chiffres et les unités de
mesure. Elles retournent une donnée de type number.
Tableau 3–9 Fonctions dédiées au type de données numériques.

Signature Description
abs($value) Retourne la valeur absolue de la valeur.
ceil($value) Retourne la valeur arrondie au nombre supérieur.
floor($value) Retourne la valeur arrondie au nombre inférieur.
round($value) Retourne la valeur arrondie.
min($x1, $x2, […]) Retourne la plus petite valeur des valeurs passées.
max($x1, $x2, […]) Retourne la plus grande valeur des valeurs passées.
percentage($value) Convertit un nombre dépourvu d’unité en un pourcentage.

ALLER PLUS LOIN Nombre de décimales après la virgule


Par défaut, Sass réalise un arrondi des résultats de division à cinq décimales après la virgule. Vous pou-
vez contrôler cette valeur depuis la ligne de commande en précisant l’argument --precision N, où N
est un chiffre.
Découvrez pourquoi il peut être intéressant de changer le nombre de décimales d’un arrondi :
B https://github.com/nex3/sass/issues/319

Fonctions sur les couleurs


Comme nous l’avions vu, Sass stocke chaque couleur rencontrée sous deux formes :
le format traditionnel RGB et la forme HSL. Cette particularité permet au prépro-
cesseur de manipuler rapidement les couleurs, quel que soit son format initial.
Les fonctions de manipulation des couleurs peuvent ainsi être regroupées en plu-
sieurs catégories.

SYNTAXE Des unités optionnelles


Certaines fonctions de manipulation des couleurs requièrent parfois un argument reflétant une quantité
exprimée en degré (deg) ou en pourcentage (%). Pour ces dernières, la précision de l’unité est alors facul-
tative, puisque Sass connaît le type de données attendu.
Sass et Compass
116

Fonctions RGB
Les fonctions RGB (RVB en français) concernent la notation en triplet des couleurs,
comme rgb(122, 122, 122). Elles sont utiles pour manipuler les canaux rouge, vert et
bleu d’une couleur.
Tableau 3–10 Fonctions dédiées à la manipulation des couleurs RGB

Signature Description
rgb($red, $green, $blue) Convertit une couleur de notation de triplet en notation hexadéci-
male.
red($color) Retourne la composante rouge d’une couleur en notation décimale.
green($color) Retourne la composante verte d’une couleur en notation décimale.
blue($color) Retourne la composante bleue d’une couleur en notation décimale.
mix($color-1, $color-2, Mélange deux couleurs en une nouvelle. L’argument optionnel
[$weight]) $weight (50% par défaut) spécifie la quantité de la première couleur
à conserver.

Fonctions HSL
Les fonctions HSL (TSL en français) seront préférées pour manipuler les compo-
santes de teinte, de saturation ou la luminosité d’une couleur.
Tableau 3–11 Fonctions dédiées à la manipulation des couleurs HSL

Signature Description
hsl($hue, $saturation, Retourne la représentation hexadécimale d’une couleur depuis
$lightness) ses composantes de teinte (en degrés), saturation (en pourcenta-
ges) et de luminosité (en pourcentages).
hsla($hue, $saturation, Similaire à la fonction hsl() mais retourne une couleur au for-
$lightness, $alpha) mat rgba().
hue($color) Retourne la composante de teinte en degrés de la couleur.
saturation($color) Retourne la composante de saturation en pourcentages de la
couleur.
lightness($color) Retourne la composante de luminosité en pourcentages de la
couleur.
adjust-hue($color, $degrees) Ajuste la teinte d’une couleur. La valeur de $degrees doit être
comprise entre -360deg et 360deg.
lighten($color, $amount) Augmente la luminosité d’une couleur. La valeur de $amount
doit être comprise entre 0% et 100%.
darken($color, $amount) Opposée de lighten(), la fonction diminue la luminosité.
saturate($color, $amount) Augmente la saturation d’une couleur. La valeur de $amount doit
être comprise entre 0% et 100%.
Développer avec Sass
117
CHAPITRE 3

Tableau 3–11 Fonctions dédiées à la manipulation des couleurs HSL (suite)

Signature Description
desaturate($color, $amount) Opposée de saturate(), la fonction diminue la saturation.
grayscale($color) Alias de la fonction desaturate($color, 100%)
complement($color) Retourne la couleur complémentaire.
invert($color) Retourne la couleur inverse.

Fonctions d’opacité
Comme CSS, Sass supporte les couleurs munies d’un canal de transparence, dit canal
alpha. Le préprocesseur dispose de quelques fonctions pour faciliter la manipulation
du niveau d’opacité des couleurs.
Tableau 3–12 Fonctions dédiées à la manipulation de l’opacité des couleurs

Signature Description
alpha($color) Retourne le niveau d’opacité d’une couleur. La valeur retournée est
comprise entre 0 (transparent) à 1 (opaque).
opacity($color) Alias de la fonction alpha($color)
rgba($color, $alpha) Ajoute un canal alpha à une couleur où $alpha est un nombre com-
pris entre 0 et 1.
opacify($color, $amount) Rend une couleur plus opaque. La valeur de $amount doit être com-
prise entre 0 et 1.
fade-in($color, $amount) Alias de la fonction opacify($color)
transparentize($color, Rend une couleur plus transparente. La valeur de $amount doit être
$amount) comprise entre 0 et 1.
fade-out($color, $amount) Alias de la fonction transparentize($color)

Autres fonctions
Les dernières fonctions de manipulation des couleurs sont quelque peu à part. En effet,
les fonctions adjust-color(), scale-color() et change-color() vous octroient le contrôle
d’une couleur sur ses représentations RGB ou HSL. La fonction ie-hex-str() quant à
elle n’est utile que dans l’écriture de filtres propriétaires pour Internet Explorer.
Tableau 3–13 Des fonctions de manipulation multiple des couleurs

Signature Description
adjust-color($color, [$red], Manipule simultanément plusieurs composantes RGB ou HSL
[$green], [$blue], [$hue], d’une couleur.
[$saturation], [$lightness],
[$alpha])
Sass et Compass
118

Tableau 3–13 Des fonctions de manipulation multiple des couleurs (suite)

Signature Description
scale-color($color, [$red], Équilibre une ou plusieurs propriétés d’une couleur. Chacun des
[$green], [$blue], arguments doit être exprimé en pourcentages.
[$saturation], [$lightness],
[$alpha])
change-color($color, [$red], Change une ou plusieurs propriétés d’une couleur. Chacun des
[$green], [$blue], [$hue], arguments doit respecter l’unité d’origine (chiffre compris entre
[$saturation], [$lightness], 0 et 255, degré, pourcentage, chiffre compris entre 0 et 1).
[$alpha])
ie-hex-str($color) Retourne une couleur hexadécimale pourvue d’un canal alpha
compatible avec les filtres d’Internet Explorer.

Fonctions sur les listes


En plus de proposer des directives de contrôle pour parcourir les listes, Sass permet
de manipuler ces dernières à l’aide d’un jeu de fonctions qui ne manqueront pas
d’enrichir vos algorithmes.
Tableau 3–14 Fonctions dédiées à la manipulation des listes

Signature Description
length($list) Retourne la longueur de la liste.
nth($list, $n) Retourne l’élément d’index $n de la liste $list.
join($list-1, $list-2, Fusionne plusieurs listes en une seule. Si l’argument $separator
[$separator]) n’est pas renseigné, alors celui de la première liste sera utilisé
dans la liste résultante.
append($list, $value, Ajoute une valeur à une liste.
[$separator])
separator($list) Retourne le caractère séparateur de la liste. Sinon le booléen false.
zip($list-1, $list-2, […]) Combine plusieurs listes en une nouvelle liste.
index($list, $value) Retourne la position d’une valeur dans une liste. Sinon le booléen
false.

La fonction zip() peut être difficile à appréhender, c’est pourquoi un exemple vaudra
tous les discours. Dans le listing qui suit, nous combinons deux listes (a b c) et (1 2
3) en une nouvelle liste composée de trois sous-listes :

$ sass -i
>> zip((a b c), (1 2 3))
(("a" 1), ("b" 2), ("c" 3))
Développer avec Sass
119
CHAPITRE 3

Comme le montre l’exemple, pour chacune des valeurs de la première liste, la fonc-
tion zip() a ajouté les valeurs de même index de la seconde liste. Puisque la fonction
accepte un nombre variable d'arguments, il est bon de noter que le nombre de sous-
listes générées sera égal au nombre d’éléments contenus dans la plus petite des listes
fournies en argument à la fonction zip().
Dans la vraie vie, cette fonction permet de contourner l’incapacité de Sass à générer
dynamiquement le nom d’une variable (). Par exemple, il est tentant de vouloir
déclarer un ensemble de variables qui correspondent aux couleurs de différents
niveaux de messages d’erreur afin d'itérer dessus.
ch03-003a.scss

// Type | Bg | Text | Border | Link


// ----------|-------|-------|--------|-----
$msg-status: #d5edf8 #205791 #92cae4 #205791 !default;
$msg-ok: #e6efc2 #264409 #c6d880 #264409 !default;

@each $type in status, ok {


// Alors que nous voulions ici générer les noms de variables
// "$msg-status" et "$msg-ok", une erreur est levée par Sass. Le
// préprocesseur ne comprend pas l’écriture `$msg-$type`. Le recours
// à l’interpolation de variable est également rejeté.
$mgs-list: join($type, $msg-$type); // 
@each $msg in $msg-list {
// Code
}
}

Malheureusement, Sass lève une erreur lors de la compilation. Le contournement est


réalisé en regroupant les valeurs par propriétés afin de créer un tableau fictif, où
chaque colonne décrit les caractéristiques d’un type de niveau d’erreur. La fonction
zip() permet alors de créer une liste par colonne et ainsi d'itérer dessus.

ch03-003b.scss

// La définition des différents types de messages et leurs couleurs sont


// réunis en un seul endroit. La lecture se fait par colonne.
$msg-types: status, ok, warning, error !default;
$msg-bg-colors: #d5edf8, #e6efc2, #fff6bf, #fbe3e4 !default;
$msg-colors: #205791, #264409, #514721, #8a1f11 !default;
$msg-bd-colors: #92cae4, #c6d880, #ffd324, #fbc2c4 !default;
$msg-link-colors: #205791, #264409, #514721, #8a1f11 !default;

// Création d’une liste de sous-listes composées par :


// un nom de classe, une couleur de fond, une couleur de texte, une
// couleur de bordure et une couleur de lien.
Sass et Compass
120

$msg-list: zip(
$msg-types, $msg-bg-colors, $msg-colors,
$msg-bd-colors, $msg-link-colors
);

// DRY!
// Génération automatisée des 4 règles CSS.
@each $msg in $msg-list {
// Nous retrouvons dans la liste `$msg` les différentes informations
// lues ligne par ligne : de 1 pour le type d'erreur à 5 pour la
// couleur des liens.
.message-#{nth($msg, 1)} {
background: nth($msg, 2);
color: nth($msg, 3);
border-color: nth($msg, 4);
a {
color: nth($msg, 5);
}
}
}

J’aurais en effet pu écrire ces styles manuellement, sans recourir à l'instruction @each,
et donc me passer de l’usage de zip(). Le fait est que j’applique ici les principes DRY
et KISS :
• pour l’aspect DRY : les styles CSS ne sont écrits qu’une seule fois ;
• pour l’aspect KISS : la configuration est centralisée.
Ainsi, cette méthode a pour avantage de ne pas être prédictive : je peux ajouter un
type d’erreur (soit une colonne) sans me soucier de sa prise en compte par Sass ; il
sera automatiquement pris en charge.

Fonctions d’introspection
Le développement d’outils nécessite parfois d’inspecter une variable. C’est pourquoi
Sass dispose de quatre fonctions dites d’introspection.
Tableau 3–15 Fonctions d’introspection

Signature Description
type-of($value) Retourne le type de donnée de la valeur.
unit($number) Retourne l’unité de la valeur numérique.
unitless($number) Teste si la valeur numérique dispose d’une unité. Retourne un boo-
léen.
comparable($number-1, Détermine si les deux valeurs numériques peuvent interagir ensem-
$number-2) ble.
Développer avec Sass
121
CHAPITRE 3

Fonctions utilitaires
Enfin, Sass fournit deux classes utilitaires qui ne sont liées à aucun type de données.
Tableau 3–16 Fonctions utilitaires

Signature Description
unique-id() Retourne un identifiant CSS valide qui sera unique.
if($condition, $if-true, Retourne la variable $if-true si la condition $condition est
$if-false) vraie. Sinon la variable $if-false est retournée.

Fonctions personnalisées
En plus de toutes les fonctions prédéfinies de Sass, le préprocesseur vous permet de
créer vos propres jeux de fonctions. La syntaxe et le fonctionnement est similaire à
celui des mixins : il suffit de remplacer la directive @mixin par @function. La seule dif-
férence majeure est qu’une fonction doit toujours retourner un résultat, à l’aide de la
directive @return.
Le listing qui suit déclare une fonction personnalisée x-em() qui permet de convertir
une valeur en pixels en unité relative (em).
ch03-004.scss

// Taille de base du texte.


$base-font-size: 16px !default;

// Convertir l’unité en px $to en unité relative em par rapport


// à la taille en pixel du $context courant.
@function x-em($to, $context: $base-font-size) {
// Éviter une erreur de syntaxe en l’absence d’unité sur l’un des
// deux arguments.
@if unitless($to) { $to: $to + 0px; }
@if unitless($context) { $context: $context + 0px; }

// Le résultat de la division de composants d’une même unité


// retourne une valeur dépourvue d’unité. Il suffit alors d’ajouter
// 0em pour réaliser la conversion.
@return $to / $context + 0em;
}

h1 {
font-size: x-em(72); // L’argument est dépourvu d’unité.
margin-bottom: x-em(48px); // L’unité est précisée.
small {
// L’élément imbriqué doit avoir une taille de police de 48px.
Sass et Compass
122

// Du fait de la cascade CSS, nous devons définir pour taille de


// base les 72px de son parent.
font-size: x-em(48px, 72);
}
}

CSS compilée

h1 {
font-size: 4.5em;
margin-bottom: 3em;
}
h1 small {
font-size: 0.66667em;
}

BONNE PRATIQUE Préfixer les noms des fonctions et des mixins


Dans le listing ch03-004.scss, la fonction personnalisée est préfixée par la chaîne x-. Cette conven-
tion d’écriture offre un moyen rapide de différencier nos outils de ceux mis à disposition par Sass et
d’éventuelles extensions. Le nom du préfixe est libre et c’est pourquoi, si vous êtes amené à écrire un fra-
mework, je vous conseille de préfixer toutes les variables, fonctions, mixins, et même les classes CSS par
le nom du framework pour éviter toute interférence avec les projets de vos utilisateurs.

En résumé
Des concepts avancés tels que les types de données, les directives de contrôle et une
riche collection de fonctions élèvent Sass au statut de langage de programmation.
L’application du concept DRY (Don’t Repeat Yourself, qui veut bannir la redondance)
dans vos travaux d’intégration n’en sera que plus simple.
Le prochain chapitre sera consacré à la création d’un premier projet et abordera la
méthodologie SMACSS appliquée à Sass, pour garantir la pérennité de vos futurs
projets.
4
Premier projet Sass et contraintes
de production

Réduisez les temps de maintenance de votre projet grâce à une arborescence


robuste et un code modulaire. Économisez du temps en exploitant la
configuration centralisée par Compass.

SOMMAIRE
B Initialiser des projets Sass et Compass
B Créer une arborescence projet robuste
B Découvrir le fichier de configuration de Compass
Sass et Compass
124

Est-il normal de perdre cinq minutes pour trouver comment surcharger un


sélecteur ? Pourquoi devoir analyser des milliers de lignes avant de localiser le code
responsable d’une régression ?
Un temps précieux est souvent perdu en maintenance à cause de l’architecture fragile
du projet. Dans ce chapitre, vous apprendrez à créer un projet Sass dont l’arbores-
cence et l’organisation sont pérennes.
Vous découvrirez également comment Compass se révèle être un allié de premier
ordre pour accélérer la création d’un projet, mais aussi pour réduire drastiquement les
saisies répétitives requises par Sass.

Initialiser l’arborescence du projet


Jusqu’à présent, nous avons réalisé des compilations Sass sur des fichiers individuels
ou nous nous sommes contentés de sessions interactives pour illustrer les nouvelles
notions apprises.
La réalité du terrain est tout autre avec des contraintes comme la génération de plu-
sieurs feuilles de styles, la gestion d’images ou encore un découpage des sources Sass
pour gagner en lisibilité.

Arborescence type
Nous verrons une méthode rapide de création d’une arborescence type d’un projet Sass.
Vous pourrez évidemment l’adapter à votre convenance suivant vos contraintes projet.
La ligne de commande (ou shell) est fortement mise à contribution ici. Bien qu’il soit
possible de réaliser les différentes étapes depuis le navigateur de fichiers, le shell
accélère la procédure.
Je vous propose un exercice pratique qui vous aidera à appréhender le shell pour créer
l’arborescence d’un projet nommé ch04-001.
 Ouvrez un terminal puis, si cela n’est pas déjà fait, déplacez-vous dans votre réper-
toire utilisateur.
 Créez ensuite un répertoire destiné à regrouper votre travail.
 Rendez-vous dans ce dernier.

Création du répertoire de travail

$ cd ~
$ mkdir livre-sass
$ cd livre-sass/
Premier projet Sass et contraintes de production
125
CHAPITRE 4

Créez maintenant le dossier du projet et placez-vous dedans.


Création du dossier du projet

$ mkdir ch04-001
$ cd ch04-001/

L’arborescence de projet qui vous est proposée est visible à la figure 4-1.

Figure 4–1
Arborescence type d’un projet

L’arborescence regroupe dans un répertoire sass/ les fichiers sources qui seront lus
par le préprocesseur. Un sous-répertoire sass/partials/ accueillera les fichiers par-
tiels. Ainsi, tout fichier non préfixé par un tiret bas vous sautera aux yeux, vous évi-
tant de générer une feuille de styles par erreur.
Dans le but d’éviter de rédiger toutes les règles CSS dans le fichier style.scss, nous
découpons dans un sous-répertoire sass/partials/ui/ les différents éléments graphi-
ques de la maquette (« ui » pour User Interface). Par éléments, j’entends des boutons,
des blocs, des navigations, etc.
Dans un répertoire assets/ situé à la racine du projet, des sous-dossiers accueilleront les
ressources statiques que sont les CSS compilées par Sass (assets/css/), les images
(assets/img/), les web fonts (assets/fonts/) et les fichiers JavaScript (assets/js/).
Regrouper les ressources statiques dans un dossier assets/ permet de pointer aisé-
ment un domaine dédié à la distribution des ressources statiques aux navigateurs, en
ciblant le dossier depuis la configuration du serveur web.
Il est en effet conseillé de délivrer aux navigateurs les fichiers statiques que sont les
images, les feuilles de styles et autres JavaScript depuis un domaine dit cookieless ;
autrement dit dépourvu de cookies. Cette mesure a pour but de réduire le nombre
d’informations transmises entre le navigateur et le serveur, améliorant ainsi les per-
formances du site.
Sass et Compass
126

ERGONOMIE Compass n’est pas loin !


Les listings qui vont suivre sont relativement verbeux. Rassurez-vous, la version simplifiée avec Compass
est abordée dans quelques pages.

Création de l’arborescence du projet

$ mkdir -p sass/partials/ui assets/css assets/fonts assets/img assets/js

La commande mkdir accompagnée du paramètre -p permet de créer une arborescence


complète, même en cas d’absence d’un niveau. Par exemple, exécuter la commande
sans l’argument -p provoquera une erreur car le répertoire assets/ n’existe pas encore.
Le projet proposera :
• une feuille de styles style.css pour l’affichage sur écran ;
• une feuille print.css dédiée à l’impression ;
• un fichier partials/_base.scss en charge de stocker la configuration des sources
Sass du projet ;
• un partial partials/_reset.scss qui regroupera l’ensemble des règles de mise à
zéro des styles navigateur ;
• deux fichiers d’éléments d’interface, partials/ui/_button.scss et partials/ui/
_nav.scss, créés à titre d’exemple.

Transposons ces informations en instructions à exécuter depuis la ligne de com-


mande.
Création des fichiers SCSS du projet

$ cd sass/
$ touch style.scss print.scss
$ cd partials/
$ touch _base.scss _reset.scss
$ touch ui/_button.scss ui/_nav.scss
$ cd ../..

Si le shell ne vous est pas familier, voici une explication détaillée des différentes
étapes.
 On se déplace dans le dossier sass/ afin d’économiser sa saisie dans les prochaines
commandes.
 La commande touch crée un nouveau fichier vide, et donc ici les deux fichiers des-
tinés à être compilés en feuilles de styles.
Premier projet Sass et contraintes de production
127
CHAPITRE 4

 Comme nous allons créer les fichiers partiels, nous nous déplaçons dans le sous-
répertoire partials/ pour éviter les répétitions de saisies.
 Nous créons les différents fichiers partiels.
 Puisque nous sommes descendus de deux niveaux dans l’arborescence du projet,
nous remontons à sa racine.
L’arborescence type d’un projet est prête.
Si, comme moi, vous trouvez les manipulations nécessaires encore trop nombreuses
et si la ligne de commande ne vous effraie pas, voyons comment accélérer drastique-
ment la création d’un projet Sass.

Initialisation rapide
Sachez que toutes les manipulations vues précédemment auraient pu être regroupées
en quatre commandes.
Usage avancé de la ligne de commande

$ cd ~/livre-sass/
$ mkdir -p ch04-001/{sass/partials/ui,assets/{css,fonts,img,js}}
$ cd ch04-001/
$ touch sass/{style,print,partials/{_{base,reset},ui/_{button,nav}}}.scss

En shell, les accolades permettent d’itérer sur un ensemble de valeurs séparées par
des virgules. Prenons par exemple la commande de création des répertoires. Elle se lit
en deux temps puisqu’elle possède deux groupes d’accolades.
Premier temps

mkdir -p ch04-001/sass/partials/ui
mkdir -p ch04-001/assets/{css,fonts,img,js}

Deuxième temps

mkdir -p ch04-001/assets/css
mkdir -p ch04-001/assets/fonts
mkdir -p ch04-001/assets/img
mkdir -p ch04-001/assets/js

RESSOURCES Brace Expansion


Le mécanisme qui permet de générer des chaînes arbitraires à l’aide d’accolades est appelé mécanisme
de Brace Expansion. Apprenez-en plus dans le manuel de référence de Bash (en anglais) :
B http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion
Sass et Compass
128

Le nombre d’inclusions de groupes de valeurs n’a pas de limite. Ainsi, un unique


appel à la commande touch permet ici de créer six fichiers à des niveaux d’arbores-
cence différents grâce à quatre groupes de valeurs.
Commande initiale contenant trois groupes

$ touch sass/{style,print,partials/{_{base,reset},ui/_{button,nav}}}.scss

Traitement du premier groupe

$ touch sass/style.scss
$ touch sass/print.scss
$ touch partials/{_{base,reset},ui/_{button,nav}}}.scss

Traitement du deuxième et troisième groupe

$ touch partials/_base.scss
$ touch partials/_reset.scss
$ touch partials/ui/_{button,nav}.scss

Traitement du quatrième groupe

$ touch partials/ui/_button.scss
$ touch partials/ui/_nav.scss

Maîtrisée a minima, la ligne de commande est un formidable outil qui vous fera
gagner énormément de temps.

Le cas des mixins tierce partie


Dans toute discipline, il est contre-productif de réinventer la roue, c’est-à-dire qu’il
est préférable de réutiliser du code déjà éprouvé plutôt que de le réécrire. Il est donc
courant de recourir à des bouts de code développés par d’autres. Avec Sass, cela se
traduit par l’utilisation dans vos projets de fonctions ou de mixins généralement
trouvés sur Github. Dès lors, il est important de pouvoir les identifier en tant que
codes tierce partie, ne serait-ce que pour les maintenir à jour.
Regroupez ces différents codes dans un répertoire dédié, j’ai nommé vendors/, situé
au même niveau que le répertoire partials/.
Il est question ici de regroupement, c’est-à-dire que chaque code tierce partie est
isolé dans un fichier – au nom explicite – qui lui est dédié. Leur maintenance en sera
simplifiée.
Premier projet Sass et contraintes de production
129
CHAPITRE 4

ATTENTION Des codes aux qualités inégales


En récupérant le code d’autres personnes, vous vous exposez à de potentiels conflits de noms. En effet, il
est courant de retrouver dans plusieurs mixins des variables de mêmes noms mais dont les finalités sont
totalement différentes.
Pire, certains omettent de déclarer leurs variables à l’aide de l’instruction !default, ce qui se traduit
par la surcharge de vos propres variables si vous les aviez déjà définies.
Heureusement, ces mauvaises pratiques sont en train de disparaître. La communauté a pris conscience
des impacts d’un tel manque de rigueur. C’est ainsi que l’on trouve désormais des codes où toute varia-
ble et tout mixin sont dûment préfixés par le nom de leur projet, réduisant ainsi le risque de surcharges
malencontreuses.

Renforcer la structure du projet


À ce stade du chapitre, et si vous avez lu les précédents, j’imagine que vous êtes sur le
point de déclarer toutes vos variables dans le fichier partials/_base.scss. Vous y
chargerez le fichier partials/_reset.scss ainsi que les différents composants con-
tenus dans le répertoire partials/ui/ et, pourquoi pas, les codes tierce partie déposés
dans le répertoire partials/vendors/.
Pour finir, vous importerez ce fichier de définitions depuis le fichier source style.scss,
où sont réunies toutes les règles qui ne relèvent pas d’un composant d’interface comme
la titraille, les liens, les listes, le layout, le code spécifique aux pages, etc.
Je faisais de même à mes débuts avec Sass. Et pour cause, toute la configuration et les
différents chargements sont centralisés au même endroit. Pour créer une feuille de
styles pour l’impression ou dédiée à Internet Explorer, je n’avais qu’à charger ce
fichier _base.scss pour appliquer la mise à zéro des éléments HTML et ne plus à
penser aux variables et autres mixins.
Jusqu’au jour où mon projet s’est effondré… Les causes d’un tel dérapage sont multiples.
• Charger des fichiers à la fin de mon document _base.scss pour m’assurer du bon
ordre de déclaration des variables n’était pas naturel. Dans tous les autres langages, la
pratique veut que les chargements soient effectués avant d’écrire la moindre ligne de
code. Inévitablement, j’ai commencé à réaliser les importations avant la déclaration
de mes variables, ce qui entraîna les problèmes de surcharge évoqués au chapitre 2.
• Le fichier était difficilement réutilisable. J’utilise fréquemment les mêmes fichiers
de projet en projet pour gagner du temps. Or, ce mastodonte devenait difficile à
gérer et il m’arrivait souvent d’oublier d’enlever le chargement d’un code tiers.
• Le fichier style.scss contenait trop de code actif. Certes, je commençais à isoler
certains éléments d’interfaces dans le répertoire partials/ui/, mais tout le reste,
comme la définition du layout, les règles spécifiques à un type de contenu ou à une
page, se retrouvait dans le fichier principal du projet. Sa maintenance en pâtissait.
Sass et Compass
130

• Et par un malheureux jeu de chargements croisés entre projets, il arrivait que la


feuille de styles générée contienne deux fois le code de certains fichiers partiels,
comme partials/_reset.scss.
La méthode que j’ai adoptée pour ne pas répéter mes erreurs fut de découper mon
projet en entités plus petites.
Pour commencer, la configuration de mes projets est désormais scindée en deux
fichiers (voir en  dans l’exemple page 132).
• Le partial_base.scss qui a la charge d’importer les codes tiers et mes propres
fonctions ou mixins. Pour s’assurer la réutilisabilité du partial, les fichiers chargés
se contentent de déclarer des mixins et des fonctions, mais en aucun cas de pro-
duire la moindre règle CSS lors de leur chargement.
• Le partial_theme.scss qui accueille la définition des variables utiles au projet.
Le point important ici est que ces deux fichiers sont indépendants. En effet, ils sont
tous deux importés depuis le fichier style.scss. Ce choix structurel a été motivé par
la perspective de pourvoir charger depuis une autre feuille de styles (comme
print.scss) un fichier de définition de variables ou une initialisation des codes tierce
partie plus spécifique.
Puisqu’aucune règle CSS ne doit être générée par ces deux fichiers de configuration,
un fichier comme partials/_reset.scss est à la charge de la feuille de styles qui en a
expressément besoin, comme style.scss (voir  dans le prochain listing). Je
m’assure ainsi une plus grande maîtrise du code généré.
Exemple de fichier _base.scss

// Charger les mixins de Compass.


// Note : importer tout Compass ne produit pas une seule ligne de CSS.
@import "compass";

// Charger les codes tierce partie.


@import "vendors/hidpi";
@import "vendors/rem";

// Charger les mixins et fonctions créés pour le projet.


@import "partials/mixins/logo";
@import "partials/mixins/typography";

Exemple de fichier _theme.scss

// Thème principal
// ===============

// ## Support cross-brower par Compass


Premier projet Sass et contraintes de production
131
CHAPITRE 4

$legacy-support-for-ie6: false !default;


$legacy-support-for-ie7: false !default;
$legacy-support-for-ie8: true !default;
$experimental-support-for-svg: true !default;

// ## Typographie

$base-face: Arial, Helvetica, sans-serif !default;


$base-font_size: 10px !default;
$base-line_height: 1.5 !default;
$body-font_size: 13px !default;
$h1-font_size: 18px !default;
$h2-font_size: 16px !default;
$h3-font_size: 14px !default;

// ## Couleurs

$color-base: #3f3828 !default;


$color-base_dark: #292929 !default;
$color-base_light: #4f4736 !default;
$color-base_lighter: #857f70 !default;

// ## Mixin Hidpi (vendors)

$hidpi-postfix: '@2x' !default;


$hidpi-min-pixel-ratio: 1.5 !default;

J’ouvre une parenthèse pour parler du cas des placeholders. Facilement assimilés à
des pseudo-mixins, il est tentant de tous les regrouper dans un fichier. Je vous le
déconseille fortement. En effet, réunir vos placeholders dans un seul fichier vous
expose à une perte de contrôle de la cascade CSS. Imaginez deux styles A et B, avec
B qui doit surcharger A. Le style B, écrit après A, étend un placeholder situé dans un
fichier _placeholder.scss qui les centralise tous.
Si _placeholders.scss est chargé avant la déclaration du style A dans la feuille de
styles, alors le style B apparaîtra dans la CSS compilée avant A. Par conséquent, c’est
le style A qui surcharge B et non l’inverse ! De quoi vous donner du fil à retordre
pour trouver l’origine du problème puisque vous pensez avoir écrit le contraire.
Afin de prévenir le surpoids de mon fichier styles.scss, je scinde dans un nouveau
répertoire partials/general/ les règles générales au site (). Par exemple, le fichier
partials/general/_basic.scss déclare les styles des balises <html>, <body>, de la
titraille, des emphases, bref les rudiments d’une intégration.
Le fichier partials/general/_helpers.scss regroupe des jeux de classes d’aide au for-
matage du contenu (comme .txt-upper, .txt-bold, .txt-center, etc.) qui ne doivent
en aucun cas être étendus via @extend. Cette restriction m’évite bien des surprises,
Sass et Compass
132

surtout que ces classes sont destinées à être utilisées par les contributeurs du site. Si le
besoin d’étendre une classe de formatage de contenu se fait ressentir, je crée un place-
holder en conséquence :

.txt-left, %helper-txt-left {
text-align: left;
}

Puis j’importe le partial en charge de déclarer l’agencement (ou layout) du site.


Vient ensuite le chargement des divers éléments de l’interface graphique (), suivi
par le chargement d’éventuels types de contenus (). Cet ordre facilite les surcharges
de l’interface depuis les types de contenus.
Dans tous les cas, les styles propres à certaines pages du site sont chargés en toute fin
du document Sass (). On assure ainsi l’ordre de déclaration des styles allant du rôle
le plus général au plus spécifique. Les règles de surcharges CSS seront ainsi plus faci-
lement applicables.
Exemple de fichier style.scss

// Configuration de la feuille de styles 


// -------------------------------------
@import "partials/theme";
@import "partials/base";

// RAZ des éléments 


// ----------------
@import "partials/reset";

// Éléments de base 
// ----------------
@import "partials/general/basic";
@import "partials/general/form";
@import "partials/general/helpers";
@import "partials/general/layout";

// Modules graphiques 
// ------------------
@import "partials/ui/button";
@import "partials/ui/nav";

// Types de contenus 
// -----------------
@import "partials/content-types/node-page";
@import "partials/content-types/node-article";
@import "partials/content-types/views";
@import "partials/content-types/webform";
Premier projet Sass et contraintes de production
133
CHAPITRE 4

@import "partials/content-types/country";

// Surcharges par page 


// -------------------
// On cible en dernier des pages précises du site.
@import "partials/pages/contact";
@import "partials/pages/gouvernance";

Au final, le fichier de la future feuille de styles ne contient pas une seule règle CSS.
Cette particularité incitera votre équipe à respecter l’organisation du projet en place.
De plus, cette segmentation vous assure de ne plus rencontrer de fichiers longs de
plusieurs centaines de lignes, pour le plus grand bonheur de vos nerfs.

IMPORTANT Fournir un fichier README


Comme dans tout projet, sa pérennité dépend de la qualité des échanges entre les différents interve-
nants. La structure que vous avez mise en place vous semble claire et logique, mais ce ne sera peut-être
pas le cas pour vos collègues. C’est pourquoi l’ajout d’un fichier de documentation est important pour
expliquer l’organisation choisie.

Je ne listerai pas ici le contenu de tous les fichiers puisque il dépend du projet. Néan-
moins, vous possédez désormais une vision de ce que peut être un squelette de projet
Sass robuste.
Suite à ces conseils, l’arborescence du projet est visible à la figure 4-2.

Figure 4–2
Une arborescence
pour un projet robuste
Sass et Compass
134

Penser « modulaire » : l’exemple de SMACSS


J’ouvre ici une parenthèse sur une approche d’intégration qui émerge depuis mainte-
nant quelques années.
Le Web d’aujourd’hui demande toujours plus de compétences et voit le nombre de
contraintes augmenter (cibles mobiles, performances, nombre de langages à
apprendre, etc.). De fait, la maintenance et la capacité d’évolution d’un projet sont
désormais cruciales. C’est pourquoi il est préférable de créer un squelette de projet
fractionné pour consolider ses bases.
Malheureusement, cela reste insuffisant pour assurer le succès de votre projet sur le
long terme. En effet, cette approche se borne à dicter des règles d’organisation des
fichiers et en aucun cas des styles CSS. Un projet de petite taille s’en contentera cer-
tainement, mais un projet de taille plus importante sera difficilement maintenable.
Heureusement, des personnes talentueuses partagent les conclusions tirées de leur
longue expérience professionnelle. C’est le cas de Jonathan Snook qui propose la
méthode d’intégration SMACSS. Méthodologie que j’ai adoptée dans plusieurs de
mes projets, et je ne regrette pas mon choix !

Principe de fonctionnement
SMACSS (prononcé « smacks ») est l’acronyme de Scalable and Modular Architecture
for CSS (« architecture évolutive et modulaire des CSS »). Recueil de bonnes prati-
ques tirées de l’expérience de Jonathan Snook, SMACSS vous aide à transformer un
design en une structure souple et modulaire.

RESSOURCES Livre SMACSS


Je vous invite à lire la méthodologie SMACSS développée dans un ouvrage d’une centaine de pages.
Vous pourrez également l’emporter avec vous et le consulter hors-ligne en vous procurant ses versions
numériques ePub, PDF et Mobi :
B http://smacss.com
Si vous êtes plus à l’aise avec la langue de Molière, une traduction française est également disponible :
B http://smacss.com/pages/fr

Pour y parvenir, SMACSS classe les sélecteurs CSS en cinq catégories de règles.
• La base. Concerne les sélecteurs d’éléments qui, dépourvus de classes CSS,
devront porter le même style, quelle que soit leur place sur la page.
Exemples : html, body, form, a.
• L’agencement. Encore appelé layout, il divise la page en sections. Une section
contient un ou plusieurs modules.
Exemples : .l-fixed, .l-grid.
Premier projet Sass et contraintes de production
135
CHAPITRE 4

• Le module. Réutilisables, ce sont les parties modulaires de votre design. Ils cor-
respondent aux éléments que je vous proposais de regrouper dans le sous-réper-
toire partials/ui/.
Exemples : .nav, .button, .listview.
• L’état. Décrit la façon dont un élément doit être affiché. Doit-il être caché ou
déroulé ? Est-il actif ou inactif ? Cette catégorie décrit également le comporte-
ment des modules ou des agencements suivant la taille de l’écran.
Exemples : .is-collaspsed, .is-active, .is-hidden.
• Le thème. Rarement utilisée, la catégorie de thème est similaire à celle d’état,
mais pour spécifier un thème alternatif.
Exemples : .theme-border, .theme-background.
L’objectif principal du classement par catégories est d’identifier et de codifier les
choses qui se répètent dans votre design. On parvient ainsi à diminuer la quantité de
code et la longueur des sélecteurs CSS, donc d’en faciliter la maintenance.
L’étude de la méthode SMACSS sort du cadre du présent ouvrage, c’est pourquoi je
ne m’attarderai pas davantage sur les détails de sa mise en œuvre. Vous trouverez
dans l’encart qui lui est dédié toutes les ressources nécessaires à sa découverte.

SMACSS appliqué à Sass


Un préprocesseur n’est pas un prérequis pour appliquer la méthodologie SMACSS.
Cependant, Sass peut se révéler d’un précieux soutien, alors pourquoi s’en priver ?
SMACSS préconise de différencier la forme et l’apparence d’un élément en plusieurs
classes, voire en de multiples fichiers CSS pour permettre de séparer le chargement
des styles. Le but étant de réduire le poids des données à transférer. Cependant, peu
de projets nécessitent une telle fragmentation.
Toutefois, il est intéressant de respecter ce conseil tout en ne produisant qu’un
nombre limité de classes CSS. Pour cela, les placeholders de Sass sont à l’honneur.
Prenons pour exemple un module d’affichage de boutons, visible dans le listing ch04-
002.scss.

ch04-002.scss

// Module de bouton
// ================

@mixin btn-style($bg: #2ba6cb, $radius: true) {


background-color: $bg;
border-color: darken($bg, 10%);
Sass et Compass
136

&:hover, &:focus {
background-color: darken($bg, 10%);
// La couleur du texte est décidée en fonction de la luminosité
// de la couleur de fond.
$bg_lightness: lightness($bg);
color: if($bg_lightness> 70%, #333, #fff);
}

// Des coins arrondis sont requis.


@if $radius {
-webkit-border-radius: 5px;
border-radius: 5px;
}
}

// Règles d’agencement communes aux différents types de boutons.


%module-btn {
line-height: 1;
margin: 0 0 20px;
position: relative;
text-align: center;
}

// Spécifie les dimensions d'un bouton de taille moyenne.


%module-btn-medium {
@extend %module-btn;
padding: 12px 24px 13px;
font-size: 1em;
}

// Spécifie les dimensions d'un bouton large.


%module-btn-large {
@extend %module-btn;
padding: 16px 32px 17px;
font-size: 1.25em;
}

// Définit l'apparence commune à tous les boutons.


// Nous séparons les propriétés de formatage des règles d’agencement
// pour offrir plus de souplesse dans la personnalisation de l’affichage
// des modules.
%theme-btn-base {
border-style: solid;
border-width: 1px;
cursor: pointer;
font-family: inherit;
font-weight: bold;
text-decoration: none;
&.disabled {
opacity: .6;
Premier projet Sass et contraintes de production
137
CHAPITRE 4

}
}

// Précise l'apparence par défaut d'un bouton.


%theme-btn-default {
@extend %theme-btn-base;
@include btn-style;
}

// Précise l'apparence d'un bouton attestant de la bonne réalisation


// d'une tâche.
%theme-btn-success {
@extend %theme-btn-base;
@include btn-style($bg: #5da423);
}

// Sélecteurs concrets pour un bouton basique.


.btn, button {
@extend %module-btn-medium;
@extend %theme-btn-default;
// État de réussite.
&.success {
@extend %theme-btn-success;
}
}

// Afficher un bouton plus large.


.btn-large {
@extend %module-btn-large;
@extend %theme-btn-default;
// État de réussite.
&.success {
@extend %theme-btn-success;
}
}

Le module est scindé en quatre parties.


1 Comme du code est amené à être répété, un mixin est créé et déclaré en début de
fichier.
2 Divers modules en charge des dimensions et des formats des boutons sont décla-
rés sous la forme de placeholders. Chacun est préfixé par la chaîne module- pour
être sans équivoque.
3 Les multiples déclinaisons visuelles des boutons sont introduites sous la forme de
placeholders préfixés par la chaîne theme-. Si besoin, ces règles étendent un thème
de base afin de réduire les répétitions de code.
4 Les classes concrètes sont écrites en dernier et étendent à la façon d’un jeu de
construction les différents placeholders mis à disposition.
Sass et Compass
138

Bien évidemment, ce découplage des rôles nécessite un savant dosage de réflexion


pour réduire le nombre de surcharges CSS tout en restant simple d’approche.
N’hésitez pas à documenter votre code pour aider vos collègues à comprendre votre
logique de travail.
Voyons le code produit par Sass.
CSS compilée

.btn, button, .btn-large {


line-height: 1;
margin: 0 0 20px;
position: relative;
text-align: center;
}

.btn, button {
padding: 12px 24px 13px;
font-size: 1em;
}

.btn-large {
padding: 16px 32px 17px;
font-size: 1.25em;
}

.btn, button, .btn-large {


border-style: solid;
border-width: 1px;
cursor: pointer;
font-family: inherit;
font-weight: bold;
text-decoration: none;
}
.disabled.btn, button.disabled, .disabled.btn-large {
opacity: .6;
}

.btn, button, .btn-large {


background-color: #2ba6cb;
border-color: #2284a1;
-webkit-border-radius: 5px;
border-radius: 5px;
}
.btn:hover, button:hover, .btn-large:hover, .btn:focus, button:focus,
.btn-large:focus {
background-color: #2284a1;
color: white;
}
Premier projet Sass et contraintes de production
139
CHAPITRE 4

.btn.success, button.success, .btn-large.success {


background-color: #5da423;
border-color: #457a1a;
-webkit-border-radius: 5px;
border-radius: 5px;
}
.btn.success:hover, button.success:hover, .btn-large.success:hover,
.btn.success:focus, button.success:focus, .btn-large.success:focus {
background-color: #457a1a;
color: white;
}

Premier constat avec le présent exemple, le fichier source Sass est plus long que son
équivalent compilé en CSS. Mais une seconde lecture met en évidence la modularité du
composant et le couplage faible des sélecteurs, garantissant sa facilité de maintenance.
L’évolution d’un tel code est également simplifiée. Ajouter un type de bouton d’alerte
nécessitera peu d’effort de votre part ; et, surtout, le code restera lisible et compréhensible.
J’assume ici le fait que les sélecteurs .btn, button, .btn-large soient répétés et non
regroupés en une unique règle CSS. C’est un moindre mal pour la pérennité de mon
module et par conséquent du projet. Il ne faut pas oublier que la suroptimisation est
souvent contre-productive. À vous de placer le curseur au plus juste entre optimisa-
tion et maintenabilité.
Le dernier avantage de Sass pour appliquer la méthodologie SMACSS sont ses
variables. Il est en effet possible de regrouper la configuration d’un module au sein
même de son fichier pour le rendre pleinement portatif. Ainsi, si vous êtes amené à
réutiliser le module dans un autre projet, il vous suffira de définir les variables à sur-
charger dans le partial _theme.scss pour adapter le module aux contraintes du projet.
Voici le module de bouton modifié pour être facilement exportable dans d’autres projets.
Les règles CSS générées sont identiques à celles produites par le fichier ch04-002.scss.
ch04-003.scss, un module réutilisable

// Module de bouton
// ================
$btn-darken-amount: 10% !default;
$btn-disabled-opacity: .6 !default;
$btn-margin: 0 0 20px !default;
$btn-radius: 5px !default;

$btn-border_style: solid !default;


$btn-border_width: 1px !default;
Sass et Compass
140

$btn-font_align: center !default;


$btn-font_color: #fff !default;
$btn-font_color_alt: #333 !default;
$btn-font_family: inherit !default;
$btn-font_weight: bold !default;

$btn-medium-padding: 12px !default;


$btn-medium-font_size: 1em !default;
$btn-large-padding: $btn-medium-padding +
$btn-medium-padding * 1/3 !default;
$btn-large-font_size: 1.25em !default;

$btn-default-bg_color: #2ba6cb !default;


$btn-success-bg_color: #5da423 !default;

@mixin btn-style($bg: $btn-default-bg_color, $radius: true) {


background-color: $bg;
border-color: darken($bg, $btn-darken-amount);

&:hover, &:focus {
background-color: darken($bg, $btn-darken-amount);
// La couleur du texte est décidée en fonction de la luminosité
// de la couleur de fond.
$bg_lightness: lightness($bg);
color: if($bg_lightness> 70%, $btn-font_color_alt, $btn-font_color);
}

// Des coins arrondis sont requis.


@if $radius {
-webkit-border-radius: $btn-radius;
border-radius: $btn-radius;
}
}

// Règles d’agencement communes aux différents types de boutons.


%module-btn {
line-height: 1;
margin: $btn-margin;
position: relative;
text-align: $btn-font_align;
}

// Spécifie les dimensions d'un bouton de taille classique.


%module-btn-medium {
@extend %module-btn;
padding-top: $btn-medium-padding;
padding-bottom: $btn-medium-padding + 1;
padding-right: $btn-medium-padding * 2;
padding-left: $btn-medium-padding * 2;
font-size: $btn-medium-font_size;
Premier projet Sass et contraintes de production
141
CHAPITRE 4

// Spécifie les dimensions d'un bouton large.


%module-btn-large {
@extend %module-btn;
padding-top: $btn-large-padding;
padding-bottom: $btn-large-padding + 1;
padding-right: $btn-large-padding * 2;
padding-left: $btn-large-padding * 2;
font-size: $btn-large-font_size;
}

// Définit l'apparence commune à tous les boutons.


%theme-btn-base {
border-style: $btn-border_style;
border-width: $btn-border_width;
cursor: pointer;
font-family: $btn-font_family;
font-weight: $btn-font_weight;
text-decoration: none;
&.disabled {
opacity: $btn-disabled-opacity;
}
}

// Précise l'apparence par défaut d'un bouton.


%theme-btn-default {
@extend %theme-btn-base;
@include btn-style;
}

// Précise l'apparence d'un bouton attestant de la bonne réalisation


// d'une tâche.
%theme-btn-success {
@extend %theme-btn-base;
@include btn-style($bg: $btn-success-bg_color);
}

// Sélecteurs concrets pour un bouton basique.


.btn, button {
@extend %module-btn-medium;
@extend %theme-btn-default;
// État de réussite.
&.success {
@extend %theme-btn-success;
}
}

// Afficher un bouton plus large.


Sass et Compass
142

.btn-large {
@extend %module-btn-large;
@extend %theme-btn-default;
// État de réussite.
&.success {
@extend %theme-btn-success;
}
}

Le code du fichier ch04-003.scss est verbeux, je vous l’accorde. Je conçois également


que tous les projets ne nécessitent pas un tel niveau de granularité. Mais tendre vers
une organisation modulaire telle que nous venons de le voir joue un rôle décisif dans
la réussite d’un projet sur le long terme ou dans la réutilisabilité de votre code.
Dans ces deux exemples, j’ai volontairement poussé la granularité au maximum pour
vous donner un aperçu complet du principe de fonctionnement. Libre à vous de
l’adapter à vos projets, quitte à en simplifier le code.
Après cette (longue) parenthèse, passons maintenant à la prochaine étape de votre
projet : sa compilation en feuilles de styles.

Compiler un projet Sass


L’arborescence du projet est mise en place. Il s’agit de travailler dessus et de valider
son travail en compilant le projet.
Pour cela, et si ce n’est pas déjà fait, ouvrez un terminal et déplacez-vous à la racine
du projet :

$ cd ~/livre-sass/ch04-001/

Compilation manuelle
Invoquez la commande sass et passez-lui en arguments le répertoire contenant les
sources Sass et le répertoire de destination. Attention, les deux arguments doivent
être joints par un deux-points :

$ sass sass:assets/css
Errno::EISDIR: Is a directory - sass
Use --trace for backtrace.
Premier projet Sass et contraintes de production
143
CHAPITRE 4

Cela ne fonctionne pas. En l’état, la commande sass attend un fichier source et un


fichier cible pour arguments. Or nous lui transmettons des répertoires. Nous pourrions
invoquer la commande en précisant le fichier source et le fichier de destination, mais la
manipulation deviendrait lourde s’il fallait la répéter pour chaque fichier source du
projet : pour le fichier style.scss, puis le fichier print.scss dans notre exemple.
Pour remédier à cette situation, précisez l’option --update qui permet à Sass
d’accepter des répertoires :

$ sass --update sass:assets/css


overwrite assets/css/print.css
overwrite assets/css/style.css

La compilation des deux fichiers Sass est bien réalisée.

IMPORTANT Chemin racine du projet lors de la compilation


Que ce soit avec Sass ou avec Compass, l’endroit depuis lequel la commande de com-
pilation est lancée a son importance. En effet, tous les chemins d’accès aux fichiers
Sass et aux ressources statiques se calculent depuis l’endroit où est exécutée la com-
mande. Ainsi, lancez la compilation depuis la racine de votre projet Sass ou Compass,
c’est-à-dire depuis le répertoire qui vous sert de point de référence pour déclarer les
chemins d’accès aux ressources statiques et aux fichiers Sass.

Lancer la compilation à chaque modification des fichiers est contraignant. C’est


pourquoi Sass est équipé d’un système de compilation automatique.

EN COULISSES Répertoire de cache de Sass


À l’issue d’une compilation, un répertoire invisible .sass-cache/ est créé au niveau de l’arborescence
où est lancée la commande sass. Il permet au préprocesseur de conserver des versions analysées des
fichiers SCSS pour accélérer le temps de compilation.
L’emplacement de ce cache peut se modifier à l’aide de l’option --cache-location path où path est
le chemin d’accès à la nouvelle localisation de stockage du cache.
Si pour une quelconque raison vous ne désirez pas bénéficier du cache, passez l’option --no-cache (ou
-C) à la commande sass.

Compilation automatique
Sass offre la possibilité de surveiller votre projet pour détecter tout changement dans
les fichiers SCSS et, le cas échéant, lancer automatiquement la compilation.
Sass et Compass
144

Pour en bénéficier, remplacez l’option --update par l’option --watch :

$ sass --watch sass:assets/css


>>> Sass is watching for changes. Press Ctrl-C to stop.
>>> Change detected to: /Users/mehdi/livre-sass/ch04-001/sass/style.scss
overwrite assets/css/style.css

Très pratique, vous lancez la commande le matin en arrivant au travail et l’arrêtez


avec la combinaison de touches Ctrl + C (y compris sur Mac OS X), le soir, en ren-
trant chez vous !
Il est possible que le lancement d’une surveillance de projet génère une notification
comme dans l’exemple suivant :

$ sass --watch sass:assets/css


>>> Sass is watching for changes. Press Ctrl-C to stop.
[Listen warning]:
Missing dependency 'rb-fsevent' (version '~> 0.9')!
Please run the following to satisfy the dependency:
gem install --version '~> 0.9' rb-fsevent

For a better performance, it's recommended that you satisfy the missing
dependency.
Listen will be polling changes. Learn more at https://github.com/guard/
listen#polling-fallback.

Le gestionnaire de paquets RubyGems vous informe qu’une dépendance à une


bibliothèque externe lui fait défaut. Le préprocesseur peut fonctionner sans, mais il
précise que les performances de la surveillance seraient accrues si vous installez la
dépendance. Pour y remédier, il faut exécuter la commande qui est directement indi-
quée dans la notification.

RUBY gem install --pre


Vous rencontrerez parfois la commande gem install --pre. L’argument --pre permet de préciser au
système RubyGems qu’il doit installer une version bêta (voire alpha) de la gem.

Utiliser des bibliothèques Sass


Sass est extensible à l’aide de bibliothèques, communément appelées plug-ins, qui
enrichissent les capacités du préprocesseur. Par exemple, si vous souhaitez importer
les fichiers Sass contenus dans un répertoire, vous devez le faire explicitement pour
chaque fichier.
Premier projet Sass et contraintes de production
145
CHAPITRE 4

Chargement séquentiel des fichiers d’un répertoire

@import "partials/ui/logo";
@import "partials/ui/aside";
@import "partials/ui/nav";
@import "partials/ui/list";
@import "partials/ui/button";
@import "partials/ui/table";

Si l’ordre de chargement des fichiers et des règles CSS qu’ils contiennent vous est
indifférent, une autre solution est de recourir à la bibliothèque Sass Globbing Plugin
créée par Chris Eppstein, l’auteur de Compass et développeur de Sass. Cette biblio-
thèque permet de charger tous les fichiers d’un répertoire, ordonnés par leurs noms.

RESSOURCES Sass Globbing Plugin


Retrouvez le projet sur la plate-forme Github :
B https://github.com/chriseppstein/sass-globbing

Pour en bénéficier, il faut dans un premier temps l’installer sur votre poste de travail.
Comme Sass, les bibliothèques sont publiées sous la forme d’une gem, ce qui sim-
plifie leur installation.
Installation de la gem Sass Globbing Plugin

$ gem install sass-globbing

Le plug-in étant installé, vous pouvez éditer votre fichier Sass pour remplacer les
importations séquentielles en une seule, à l’aide du caractère astérisque (*).
Chargement du premier niveau d’un répertoire en une passe

@import "ui/*";

Par ailleurs, cette bibliothèque permet aussi d’importer récursivement les fichiers
d’un répertoire.
Chargement récursif des fichiers d’un répertoire et ses sous-répertoires

@import "ui/**/*";

La bibliothèque est installée, et vos sources sont modifiées en conséquence. Il ne


vous reste plus qu’à préciser à la commande sass qu’il faut charger le plug-in lors de
Sass et Compass
146

la compilation. Pour cela, ajoutez l’option --require nom-bibliothèque (ou -r nom-


bibliothèque) :

$ sass -r sass-globbing --watch sass:assets/css

Si votre projet fait appel à plusieurs bibliothèques, répétez l’option autant de fois que
nécessaire. Ainsi, pour charger deux bibliothèques, la commande devient :

$ sass -r sass-globbing-r breakpoint --watch sass:assets/css

L’outil en ligne de commande de Sass est puissant, mais il contraint à connaître cha-
cune de ses options ou de préciser continuellement le format de sortie si celui par
défaut ne nous convient guère. Il n’est par ailleurs d’aucune aide dans la création d’un
projet. N’existerait-il pas un outil pour faciliter ces tâches rébarbatives ? Compass
bien sûr !

Initialisation de projet facile avec Compass


Compass ne se limite pas à produire des styles CSS. En effet, le framework s’accom-
pagne d’une commande shell éponyme compass qui fournit des d’outils d’aide à la
création de projet.
Par ailleurs, Compass peut aussi centraliser la configuration d’un projet Sass dans un
fichier texte, ce qui se révèle très pratique et met fin à la saisie de commandes à ral-
longe pour compiler un projet !

ATTENTION L’installation de Compass est nécessaire


À partir de maintenant, la présence de Compass sur votre système est requis. Reportez-vous au
chapitre 1 pour trouver les indications qui vous aideront à l’installer.

Créer un nouveau projet Compass


Grâce à Compass, il n’est plus nécessaire de réaliser l’arborescence manuellement, il
s’en charge lui-même !
Pour créer un nouveau projet Compass, il faut, dans un premier temps, vous placer
dans le répertoire qui accueillera le projet. Dans l’exemple qui suit, le projet ch04-004
sera situé à la racine du dossier ~/livre-sass/.
Une fois fait, lancez la commande compass create dont la syntaxe est la suivante.
Premier projet Sass et contraintes de production
147
CHAPITRE 4

Syntaxe de la commande de création de projet Compass

compass create nom_du_projet [options]

ASTUCE Aide en ligne des outils de Compass


La liste des commandes supportées par l’outil compass est disponible en invoquant la commande
compass help. Pour chacune d’entre elles, vous obtiendrez la liste des options disponibles ainsi que
leurs descriptions à l’aide du mot-clé help :
$ compass help create

Afin de reprendre l’arborescence du projet ch04-001, il faut préciser les répertoires des
sources Sass et des différentes ressources statiques, ce qui se traduit par la commande
qui suit (voir figure 4-3) :

$ cd ~/livre-sass/
$ compass create ch04-004 --css-dir assets/css \
--fonts-dir assets/fonts --images-dir assets/img \
--javascripts-dir assets/js

Figure 4–3
Compass affiche une aide
après avoir créé un projet.

Le squelette de l’arborescence a automatiquement été généré, ainsi que les fichiers


sources screen.scss, print.scss et ie.scss qui sont inutiles dans le cadre de notre
projet puisque nous souhaitons disposer des fichiers style.scss et print.scss.
Sass et Compass
148

Empêchez Compass de générer ces fichiers Sass en ajoutant l’option --bare à la com-
mande de création de projet.

SYNTAXE Implications de l’option --bare


L’option --bare empêche Compass de générer les fichiers sources Sass ainsi que leurs versions compi-
lées en CSS. Si elle est précisée, Compass ne créera pas les répertoires cibles des ressources statiques
(comme ici les sous-répertoires du dossier assets/). Compass les générera au moment de la compila-
tion du projet, à moins que vous les ayez créés entre-temps.

Un fichier de configuration config.rb est également créé à la racine du projet. Il


reprend les différentes valeurs précisées à la commande compass create, pour vous
éviter de les renseigner à chaque compilation. Son étude sera abordée un peu plus loin.

SYNTAXE Valeurs par défaut des options


Les différentes options de configuration des chemins d’accès ont des valeurs par défaut qui seront utili-
sées par Compass si vous ne les précisez pas à la commande shell. Reportez-vous au tableau 4-2 pour les
découvrir. Ainsi, si vous souhaitez stocker vos fichiers Sass dans un répertoire sass/, la saisie de l’option
--sass-dir est inutile.

Transformer un projet existant en projet Compass


Il arrive parfois que le projet CSS existe déjà, et que vous souhaitiez le migrer sur
Sass, et plus particulièrement sur Compass.
Dans ce cas de figure, la commande à appeler est compass init, accompagnée de
l’option --prepare qui a une action équivalente à l’option --bare (mais qui n’est pas
disponible pour cette commande).
Convertir le projet ch04-001 en projet Compass

$ cd ~/livre-sass/ch04-001
$ compass init --prepare --css-dir assets/css \
--fonts-dir assets/fonts --images-dir assets/img \
--javascripts-dir assets/js

Puisque l’arborescence du projet existe déjà, Compass se contente de créer un fichier


de configuration config.rb qui lui servira tout au long de la vie du projet.
Premier projet Sass et contraintes de production
149
CHAPITRE 4

S’appuyer sur un fichier de configuration


Personnellement, j’ai rarement recours à la version verbeuse des commandes de créa-
tion ou d’initialisation de projet Compass. Je ne renseigne jamais les différentes
options qui précisent les chemins d’accès aux ressources.
En effet, Compass est capable de lire un fichier de configuration pour générer l’arbo-
rescence en conséquence. Dès lors, il me suffit de copier le fichier de configuration
d’un autre projet et, si nécessaire, de l’éditer pour le faire correspondre aux besoins du
nouveau projet.
Initialisation d’un projet à l’aide du fichier de configuration d’un autre projet

$ cd ~/livre-sass/
$ mkdir ch04-005
$ cp ch04-004/config.rb ch04-005/
$ cd ch04-005/
$ compass init --bare
$ mkdir -p assets/{css,fonts,img,js}

Et si je n’ai pas besoin d’éditer la configuration du projet, la manipulation est encore


plus rapide. Compass permet de spécifier à l’aide de l’argument --config fichier (ou
-c fichier) un fichier de configuration existant pour en tenir compte.

Création d’un projet à l’aide du fichier de configuration d’un autre projet

$ cd ~/livre-sass/
$ compass create ch04-006 --bare -c ch04-004/config.rb
directory ch04-006/
directory ch04-006/sass/
create ch04-006/config.rb
$ mkdir -p ch04-00§/assets/{css,fonts,img,js}

Compass copie le fichier de configuration dans le nouveau projet et en lit le contenu


pour finalement créer le répertoire qui accueillera les sources Sass. Si je n’avais pas
précisé l’option --bare, c’est toute l'arborescence qui aurait été générée.

Compass centralise la configuration du projet


L’un des avantages de Compass est de regrouper la configuration du projet dans un
fichier qui sera lu à chaque compilation. Il automatise le passage d’options à la com-
mande compass mais précise aussi certaines options destinées à l’outil en ligne de
commande de Sass.
Sass et Compass
150

Anatomie d’un fichier de configuration


Un fichier de configuration Compass est écrit dans le langage Ruby, assurant ainsi
une interaction maximale avec le framework et le préprocesseur, tous deux déve-
loppés dans ce même langage de programmation. Comme nous le verrons plus tard,
cette particularité permet d’enrichir aisément la configuration du projet, voire
d’ajouter un soupçon d’automatisation.

NOTE Emplacements possibles du fichier de configuration


Par défaut, Compass génère et recherche à la racine du projet un fichier de configuration nommé
config.rb. Si ce fichier n’existe pas, l’outil recherchera le fichier de configuration dans les chemins
config/compass.rb ou .compass/config.rb ou encore config/compass.config.

Le fichier de configuration généré pour le projet ch04-004 est relativement verbeux.


Fichier ch04-004/config.rb

# Require any additional compass plugins here.



http_path = "/" 
css_dir = "assets/css" 
sass_dir = "sass" 
images_dir = "assets/img" 
fonts_dir = "assets/fonts" 
javascripts_dir = "assets/js" 

# You can select your preferred output style here (can be overridden via
# the command line):
# output_style = :expanded or :nested or :compact or :compressed 

# To enable relative paths to assets via compass helper functions.


# Uncomment:
# relative_assets = true 

# To disable debugging comments that display the original location of


# your selectors. Uncomment:
# line_comments = false 

Richement commenté, son édition est facilement compréhensible :


 Comme nous le verrons dans la prochaine section, Compass permet de charger
des bibliothèques externes, généralement en début du fichier de configuration.
 L’option http_path définit le chemin de l’URL racine de votre projet. Par défaut,
elle est définie à /, soit la racine du nom de domaine. Cette option est utilisée par
Compass pour construire les URL d’accès aux ressources statiques, comme les
Premier projet Sass et contraintes de production
151
CHAPITRE 4

images ou encore les fichiers de polices de caractères. Notez qu’elle n’est exploitée
que lorsque l’option relative_assets vaut false ().
 Il s’agit des différentes options passées à la ligne de commande qui définissent
l’emplacement des ressources statiques.
 L’option output_style correspond à l’option --style (ou -t) de Sass. Précisez le
format de sortie CSS désiré. Par défaut, le format de sortie est expanded.
 Définissez l’option relative_assets à true si vous souhaitez que Compass génère
des chemins relatifs aux feuilles de styles et non basés sur la valeur de l’option
http_path. Dans ce cas, vous pouvez supprimer la déclaration de l’option http_path.
 Par défaut le préprocesseur génère pour chaque règle CSS produite un commen-
taire CSS pour indiquer son origine dans les sources Sass. Pour désactiver ce
comportement, l’option doit valoir false.
Pour être actives, les lignes des repères ,  et  doivent être décommentées. Pour
cela, supprimez simplement le caractère # du début de ligne.

Options disponibles
Compass enrichit la configuration d’un projet Sass par un nombre conséquent
d’options. Une telle abondance s’explique par le fait que Compass, contrairement à
Sass, prend en charge la gestion des ressources statiques, mais aussi car il génère des
images de sprites (voir chapitre 6).
Avec Compass, les chemins d’accès aux ressources statiques sont automatiquement
calculés pour correspondre à la configuration de votre projet. En attendant d’en
apprendre plus dans le prochain chapitre, notez que vous n’aurez plus à renseigner
leurs chemins dans les règles CSS, mais vous utiliserez à la place des fonctions qui se
chargeront de produire les chemins d’accès adéquats.

RESSOURCES Documentation du fichier de configuration


Retrouvez la documentation en ligne qui décrit chaque option disponible pour configurer votre projet :
B http://compass-style.org/help/tutorials/configuration-reference/

Les tableaux 4-1 et 4-2 présentent les différentes options disponibles.


Tableau 4–1 Options de configuration du projet Compass.

Option Description
project_type Le type de projet. Vaut par défaut :stand_alone mais devra prendre la valeur
:rails si vous travaillez dans un projet Ruby On Rails.
Sass et Compass
152

Tableau 4–1 Options de configuration du projet Compass. (suite)

Option Description
preferred_syntax La syntaxe d’écriture des fichiers Sass. Vaut par défaut :scss mais accepte la
valeur :sass si vous souhaitez utiliser la syntaxe historique.
environment Le type d’environnement du projet : développement (valeur :development) ou
production (valeur :production).
Sa valeur par défaut est :development.
Cette option en impacte d’autres. Ainsi, passée à :production, l’option
line_comments est définie à false et l’option :output_style prend pour
valeur :compressed, quel que soit l’ordre de déclaration des options.
output_style Le format de sortie des fichiers Sass. Correspond à l’option --style (ou -t) de la
commande sass (voir chapitre 2).
Les valeurs possibles sont :nested, :expanded (défaut), :compact, ou
:compressed.
line_comments Booléen qui permet d’activer ou de désactiver les commentaires ajoutés par Sass
avant chaque règle CSS générée pour indiquer le fichier et la ligne d’origine dans le
projet Sass.
Sa valeur par défaut est true (commentaires activés).
disable_warnings Booléen qui permet d’activer ou de désactiver les messages d’alerte de déprécia-
tion émis par Sass ou Compass.
Sa valeur par défaut est false (messages activés).
additional_import_ Tableau de chemins système où Compass pourra rechercher des fichiers à importer
paths dans le projet. La syntaxe étant héritée de Ruby, voici un d’exemple d’usage :
Ajouter les répertoires sass/ de deux autres projets :
additional_import_paths = ["../projet2/sass",
"../projet3/sass"]
sass_options Toutes les options de Sass ne sont pas retranscrites dans la configuration de Com-
pass. Utilisez cette option qui attend un Hash (une structure de données clé/valeur
issue de Ruby) pour passer des options directement au préprocesseur. Par exemple,
pour activer le mode de débogage de Sass (voir chapitre 7), renseignez l’option
comme suit :
sass_options = {
:debug_info => true
}
Reportez-vous à l’encadré « Options de configuration de Sass » pour accéder à la
liste complète des paramètres disponibles.
sprite_engine Précise le générateur de sprites à utiliser. Actuellement, seule l’option
:chunky_png est disponible.
chunky_png_options Options a passer au générateur de sprites Chunky PNG. Cette option étant très
rarement utilisée, nous ne nous étendrons pas sur le sujet.
Premier projet Sass et contraintes de production
153
CHAPITRE 4

RESSOURCES Options de configuration de Sass


Retrouvez en ligne la liste des options de configuration de Sass acceptées par l’option sass_options :
B http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options

Tableau 4–2 Options de configuration des ressources statiques du projet

Option Description
project_path Le chemin du projet. Notez que cette option est inutile lorsque l’option
project_type est définie à :standalone. Dans ce cas, sa valeur sera celle
du chemin depuis lequel est exécutée la commande compass.
http_path Le chemin d’accès au projet depuis un navigateur.
Sa valeur par défaut est "/".
relative_assets Booléen qui indique si la construction des URL d’accès aux ressources stati-
ques doit utiliser les options préfixées par http_ ou non.
Sa valeur par défaut est false.
sass_dir Nom du dossier où les fichiers sources Sass sont stockés. Il est relatif au che-
min précisé par l’option project_path.
Sa valeur par défaut est "sass".
sass_path Chemin système d’accès aux fichiers sources Sass.
Sa valeur par défaut est <project_path>/<sass_dir>.
css_dir Nom du dossier qui accueillera les feuilles de styles générées. Il est relatif au
chemin précisé par l’option project_path.
Sa valeur par défaut est "stylesheets".
css_path Chemin système qui accueillera les feuilles de styles générées.
Sa valeur par défaut est <project_path>/<css_dir>.
http_stylesheets_path L’URL d’accès complète au répertoire des feuilles de styles générées. Cette
option est très utile si vous souhaitez héberger vos CSS sur un domaine
cookieless.
Exemple : http://cdn.monsite.tld/css.
Sa valeur par défaut est <http_path> + "/" + <css_dir>.
images_dir Nom du dossier où sont stockées les images du projet. Il est relatif au chemin
précisé par l’option project_path.
Sa valeur par défaut est "images".
images_path Chemin système d’accès aux images.
Sa valeur par défaut est <project_path>/<images_dir>.
http_images_path L’URL d’accès complète au répertoire des images du projet. Cette option est
très utile si vous souhaitez héberger vos images sur un domaine cookieless.
Exemple : http://cdn.monsite.tld/images.
Sa valeur par défaut est <http_path> + "/" + <images_dir>.
Sass et Compass
154

Tableau 4–2 Options de configuration des ressources statiques du projet (suite)

Option Description
generated_images_dir Nom du dossier où sont stockées les images générées par Compass (les
fameux sprites). Il est relatif au chemin précisé par l’option project_path.
Sa valeur par défaut est <images_dir>, soit le même dossier que les images.
generated_images_path Chemin système d’accès aux images générées.
Sa valeur par défaut est <project_path>/<generated_images_dir>.
http_generated_images L’URL d’accès complète au répertoire des images générées du projet. Cette
_path option est très utile si vous souhaitez héberger vos images sur un domaine
cookieless.
Exemple : http://cdn.monsite.tld/images.
Sa valeur par défaut est
<http_path> + "/" + <generated_images_dir>.
sprite_load_path Tableau de chemins système où Compass pourra rechercher des images à
compiler sous la forme de sprites (voir chapitre 6). La syntaxe étant héritée de
Ruby, voici deux d’exemples d’usage :
Ajouter les répertoires img/ de deux autres projets :
sprite_load_path = ["../projet2/img",
"../projet3/assets/img"]
Ajouter un répertoire img/ issu d’un code tierce partie :
sprite_load_path << "vendors/foobar/img"
fonts_dir Nom du dossier où sont stockés les web fonts du projet. Il est relatif au che-
min précisé par l’option project_path.
Sa valeur par défaut est <css_dir>/fonts.
fonts_path Chemin système complet d’accès aux polices de caractères.
Sa valeur par défaut est <project_path>/<fonts_dir>.
http_fonts_path L’URL d’accès complète au répertoire des polices du projet. Cette option est
très utile si vous souhaitez héberger vos images sur un domaine cookieless.
Exemple : http://cdn.monsite.tld/css/fonts.
Sa valeur par défaut est <http_path> + "/" + <fonts_dir>.
http_fonts_dir Le chemin d’accès au répertoire des polices, depuis le dossier des feuilles de
styles.
javascripts_dir Nom du dossier où sont stockés les fichiers JavaScript du projet. Il est relatif
au chemin précisé par l’option project_path.
Sa valeur par défaut est "javascripts".
javascripts_path Chemin système complet d’accès aux fichiers JavaScript.
Sa valeur par défaut est <project_path>/<javascripts_dir>.
http_javascripts_path L’URL d’accès complète au répertoire des fichiers JavaScript du projet. Cette
option est très utile si vous souhaitez héberger vos images sur un domaine
cookieless.
Sa valeur par défaut est <http_path> + "/" + <images_dir>.
Premier projet Sass et contraintes de production
155
CHAPITRE 4

Le nombre d’options est impressionnant. Heureusement, il est rarement utile d’en


renseigner plus de cinq. Mais il est toujours rassurant de savoir que nos besoins spé-
cifiques pourront être satisfaits grâce à l’une d’entre elles.

ASTUCE Connaître la valeur d’une option calculée


Comme certaines options sont calculées par Compass, il peut être difficile de connaître leurs valeurs fina-
les. La commande compass config, accompagnée de l’option -p nom_de_l_option, permet d’affi-
cher ces valeurs. Par exemple, pour afficher le chemin du répertoire de destination des images de sprites
générées (voir chapitre 6), la commande à saisir devient :
$ compass config -p generated_images_path
/Users/mehdi/livre-sass/ch04-004/assets/img

Fichier de configuration type


Le nombre d’options disponibles étant important, il peut être difficile de savoir com-
ment s’y prendre. C’est pourquoi je vous propose un fichier de configuration type qui
satisfera la majorité de vos projets.
Une configuration classique

css_dir = 'assets/css'
images_dir = 'assets/img'
fonts_dir = 'assets/fonts'
javascripts_dir = 'assets/js'
relative_assets = true

# Configuration conditionnée par l’environnement. 


if environment == :production
output_style = :compressed
else
output_style = :expanded
sass_options = { :debug_info => true }
end

Une nouveauté est visible en  : la déclaration des options output_style et sass_options


se fait de manière conditionnelle. Le fichier de configuration étant un fichier Ruby, nous
profitons des capacités du langage pour rendre notre fichier dynamique.
Ainsi, comme la variable environment vaut par défaut :development, une compilation pro-
duira des fichiers CSS à la syntaxe étendue accompagnée d’informations de débogage.
En revanche, si l’option -e production est passée à la commande de compilation (voir
section suivante), alors les feuilles de styles seront minifiées et dépourvues de toute
information de débogage.
Sass et Compass
156

ASTUCE Éviter la configuration conditionnelle


La configuration conditionnelle peut ne pas correspondre à votre besoin ou à votre philosophie de tra-
vail. Ainsi, au lieu de préciser une option lors de la compilation, vous préférerez charger un fichier de
configuration dédié par type d’environnement.
Pour cela, créez autant de fichiers de configuration souhaités puis, au moment de la compilation, spéci-
fiez à Compass celui à utiliser à l’aide de l’argument -c environnement_dedie.rb.

Bien que Compass fournisse un nombre conséquent d’options, il propose également


un ensemble de fonctions pour vous assurer toujours plus de flexibilité et de maîtrise
de votre projet. Cependant, les aborder dans ce chapitre serait prématuré. En effet,
les fonctions de configuration sont essentiellement utiles dans la manipulation des
ressources statiques que nous aborderons plus loin dans ce livre. Si vous souhaitez en
savoir plus dès maintenant, rendez-vous à la fin du chapitre 5.
Votre projet Compass est configuré, voyons sans plus tarder comment le compiler.

Compiler un projet Compass


La compilation d’un projet Compass est plus simple qu’avec son parent Sass. En
effet, comme la configuration est stockée dans un fichier de configuration, il suffit de
lancer la commande de compilation dépourvue de la moindre option.

Compilation manuelle
Dans un premier temps, déplacez-vous dans le répertoire qui contient à sa racine le
fichier de configuration, puis, lancez la compilation à l’aide de la commande compass
compile.

Compilation simplifiée grâce à Compass

$ cd ~/livre-sass/ch04-004/
$ compass compile
create assets/css/print.css
create assets/css/style.css
Premier projet Sass et contraintes de production
157
CHAPITRE 4

SYNTAXE Changer le répertoire de cache de Compass


S’appuyant sur le préprocesseur Sass, la compilation d’un projet Compass produit un répertoire .sass-
cache/ à la racine du projet. Mais contrairement à Sass, aucune option n’est disponible depuis la com-
mande compass pour manipuler son emplacement.
À la place, vous devez renseigner le nouveau chemin à l’aide de la clé :cache_location de l’option
sass_options depuis le fichier de configuration du projet. Par exemple, pour générer les fichiers de
cache dans le répertoire tmp/sass-cache/ de votre projet, l’option devient :
sass_options = {
:cache_location => "#{Compass.configuration.project_path}/tmp/
sass-cache"
}

Compilation automatique
Comme le préprocesseur sur lequel il s’appuie, Compass est capable de surveiller
votre projet pour détecter les changements intervenus dans vos fichiers sources Sass
afin de lancer une compilation automatiquement. La commande correspondante est
compass watch.

Surveillance du projet par Compass

$ compass watch
>>> Compass is watching for changes. Press Ctrl-C to Stop. 
info sass/style.scss was modified
overwrite assets/css/style.css
^C info Good bye! 

Pour quitter le mode de surveillance, il suffit de suivre l’indication donnée par Com-
pass , et d’utiliser la combinaison de clavier Ctrl + C .

À SAVOIR Surveillance de projet et lecture du fichier de configuration


Lors d’une session de surveillance de projet à l’aide de la commande compass watch, toute modifica-
tion du fichier de configuration sera ignorée. Vous devrez quitter la surveillance (à l’aide du raccourci cla-
vier Ctrl + C — y compris sur Mac OS X) puis la relancer pour que Compass tienne compte de la nouvelle
configuration.
Sass et Compass
158

Utiliser des bibliothèques Sass dans un projet Compass


À l’instar de Sass, Compass permet de charger des bibliothèques externes. Après ins-
tallation de la bibliothèque souhaitée, éditez le fichier de configuration pour la
charger à l’aide de l’instruction require de Ruby.
Charger une librairie Sass depuis le fichier de configuration Compass

require 'sass-globbing'

css_dir = "assets/css"
sass_dir = "sass"
images_dir = "assets/img"

RESSOURCES Trouver de nouvelles bibliothèques Sass et Compass


Trouvez des bibliothèques pour étendre les fonctionnalités du préprocesseur sur le site RubyGems.org.
Lancez simplement une recherche sur les mots « sass » ou « compass » pour découvrir un riche écosys-
tème de plug-ins.
B http://rubygems.org

En résumé
Suite à la lecture de ce chapitre, vous possédez maintenant de solides bases pour
créer, organiser et compiler un projet Sass. J’espère vous avoir convaincu de l’impor-
tance de modulariser votre projet afin d’en faciliter la maintenance.
Par ailleurs, nous avons pu manipuler pour la première fois le célèbre framework
CSS3 de Sass. Dans les prochains chapitres, vous découvrirez les autres avantages,
grâce auxquels, j’en suis persuadé, vous l’adopterez dans vos prochaines intégrations.
5
Compass, votre futur meilleur ami

Gagner toujours plus de temps en exploitant la collection de mixins et de


fonctions d’aide de Compass.

SOMMAIRE
B Manipuler les images
B Exploiter la documentation
B Contrôler le support cross-browser
Sass et Compass
160

Figure 5–1

Certains outils deviennent indispensables une fois qu’on les a utilisés. C’est le cas de
Compass qui nous épargne la gestion des images et, surtout, simplifie significative-
ment le support cross-browser de nos intégrations.
La lecture de ce chapitre changera votre rapport aux images. Imaginez que vous puis-
siez récupérer automatiquement les dimensions d’une image ou être alerté de son
absence dans le projet !
Apprenez à exploiter des composants CSS3 qui font de Compass un framework
CSS3 digne de ce nom.
Enfin, le chapitre présentera les mécanismes de Compass qui vous permettront de
produire un code compatible avec tous les navigateurs cibles de votre projet sans
effort de votre part.

Accès simplifié aux ressources statiques


L’accès aux ressources statiques a toujours été un point sensible des projets d’intégra-
tion. Et pour cause, il est souvent source d’erreur, en particulier dans l’écriture du
chemin d’une image. L’erreur est humaine après tout.
Compass, votre futur meilleur ami
161
CHAPITRE 5

Si cette tâche ingrate était à la charge de la machine, il est certain que ce type
d’erreur disparaîtrait.

Ne perdez plus vos images


Dans la configuration du projet, Compass permet de renseigner une option
images_dir. Grâce à elle, il est capable de calculer automatiquement le chemin d’accès
aux images, même si vous décidez d’en changer plus tard !
Pour bénéficier de ce comportement, il faut simplement remplacer les appels à la
fonction CSS url() par des appels à la fonction Compass image-url().
La syntaxe de la fonction image-url() est similaire à son homologue CSS, à la diffé-
rence près qu’elle attend le chemin d’une image, depuis le répertoire déclaré par
l’option images_dir.
Ainsi, en admettant que images_dir vaille 'img', l’accès à l’image img/logo.png s’écrit
comme dans l’exemple qui suit (rappel : l’option s’écrit --images-dir en ligne de com-
mande).
Initialisation de l’exemple

$ cd ~/livre-sass/
$ compass create ch05-001 --bare --css-dir css --images-dir img
directory ch05-001/
directory ch05-001/sass/
create ch05-001/config.rb
$ cd ch05-001/

ch05-001/style.scss

.logo {
background: transparent image-url('logo.png') no-repeat 0 0;
}

RAPPEL Guillemets optionnels


Sass n’oblige pas à entourer par des guillemets l’écriture d’une chaîne de caractères. Ainsi vous pouvez
directement saisir image-url(logo.png). Pour ma part, je préfère les renseigner pour conserver la
coloration syntaxique des données de type string dans mon éditeur de code.

Aucun fichier ou répertoire n’est généré, car la commande de création du projet est
pourvue de l’option --bare. Vous devez donc créer le répertoire img/ à la racine du
dossier ch05-001/. Puis vous y déposez une image nommée logo.png. Cela fait, vous
pouvez compiler le projet.
Sass et Compass
162

Compilation de l’exemple

$ compass compile
directory css/
create css/style.css

Fichier css/style.css compilé

/* line 1, ../sass/style.scss */
.logo {
background: transparent url('/img/logo.png?1374695188') no-repeat 0 0;
}

Deux remarques peuvent être formulées sur le code généré.


La première, évidente, est la présence de l’argument ?1374695188 ajouté au chemin de
l’image. Cet argument est un « casseur de cache » ou cache buster, c’est-à-dire que sa
présence force le navigateur à recharger l’image si elle venait à changer. En effet, il
est courant de mettre à jour une image sans en changer le nom. Pourtant, un naviga-
teur ayant déjà chargé l’ancienne version en conserve une version en cache. Le nom
de l’image restant intact, le navigateur affiche sa copie locale au lieu de récupérer la
nouvelle image depuis le serveur. Ajouter un casseur de cache permet de changer le
chemin d’accès à l’image si elle est modifiée, et donc de forcer son téléchargement.

EN ANNEXE Personnaliser le casseur de cache


La présence d’un casseur de cache sous la forme d’un argument peut être une gêne pour les proxies. Dans
l’annexe A, section « Maintenir un casseur de cache », apprenez à optimiser son ajout par Compass.

L’ajout du casseur de cache peut se désactiver en ajoutant, dans le fichier de configu-


ration config.rb, l’option asset_cache_buster :none. J’attire votre attention sur la syn-
taxe de l’option. Le deux-points est bien collé à la valeur :none et non à l’option
asset_cache_buster. Il s’agit d’une syntaxe propre au langage Ruby.

REMARQUE Aide à la lecture


Pour des raisons de lisibilité, les prochains listings CSS seront dépourvus de casseur de cache. De la
même manière, les commentaires de débogage seront eux aussi supprimés.

En seconde remarque, il est à noter que l’accès à l’image se fait depuis la racine du
domaine (voir le / en début de chemin). Le fichier de configuration du projet ne pré-
cisant pas l’option relative_assets = true, Compass utilise la valeur de l’option
http_images_path pour construire le chemin d’accès à l’image (voir tableau 4-2).
Compass, votre futur meilleur ami
163
CHAPITRE 5

Ajoutez l’option relative_assets = true au fichier de configuration puis lancez une


nouvelle compilation. Le chemin d’accès à l’image a évolué.
Le chemin d’accès est relatif à la feuille de styles

.logo {
background: transparent url('../img/logo.png') no-repeat 0 0;
}

Désormais, le chemin d’accès à l’image calculé par Compass via la fonction image-
url() est relatif à la position de la feuille de styles générée dans l’arborescence du
projet.
Là où Compass est génial, c’est qu’il pointe vos erreurs. Ainsi, lorsqu’une image
n’existe pas, il vous préviendra. Par exemple, si dans le fichier style.scss vous
changez le nom de l’image logo.png par une image new-logo.png absente du réper-
toire img/, le message affiché est très clair.
Une erreur est affichée lorsqu’une image est manquante

$ compass compile
WARNING: 'new-logo.png' was not found (or cannot be read) in
/Users/mehdi/livre-sass/ch05-001/img
overwrite css/style.css

La feuille de styles est tout de même générée, mais au moins vous corrigerez immé-
diatement un oubli que vous n’auriez peut-être vu qu’une fois le projet mis en pro-
duction.

Récupérer les dimensions d'une image


Qui n’a jamais espéré un jour pouvoir lire les dimensions d’une image depuis CSS
pour calculer automatiquement la disposition des éléments ? Avec Compass, ce doux
rêve devient réalité !
Le framework dispose pour cela de deux fonctions :
• image-height($image) qui retourne la hauteur en pixels de l’image $image trouvée
dans le répertoire précisé par l’option de configuration images_dir ;
• image-width($image) qui retourne quant à elle la largeur en pixels de l’image
$image.

L’argument $image n’est pas nécessairement une variable et peut directement être une
chaîne de caractères : image-height('logo.png').
Sass et Compass
164

ch05-002/sass/style.scss : remplacer un texte par une image de fond

$logo: 'logo.png';
.logo {
display: block;
text-indent: -20000em;
overflow: hidden;
text-align: left;
background: transparent image-url($logo) no-repeat 0 0;
height: image-height($logo);
width: image-width($logo);
}

CSS compilée

.logo {
display: block;
text-indent: -20000em;
overflow: hidden;
text-align: left;
background: transparent url('../img/logo.png') no-repeat 0 0;
height: 150px;
width: 200px;
}

En usant intelligemment de ces deux fonctions, vous n’aurez plus à vous soucier du
changement des dimensions de vos images.

Embarquer des images dans la feuille de styles


Pour des raisons de performances, et si votre projet cible IE8+, il est parfois pertinent
d’embarquer une petite icône directement dans la feuille de styles plutôt que de la
charger via une requête HTTP. Ce choix impose de recourir au schéma Data-URI
(voir encadré), donc d’encoder le contenu de l’image en base64.

RESSOURCES Le schéma Data-URI


Je vous invite à lire l’excellent article de présentation des Data-URI (Uniform Resource Identifier) publié
sur le site de la communauté Alsacréations :
B http://www.alsacreations.com/article/lire/1439-data-uri-schema.html
Compass, votre futur meilleur ami
165
CHAPITRE 5

ATTENTION Utilisez les Data-URI avec parcimonie


De récentes recherches ont démontré que charger une image via Data-URI est six fois plus lent que de
charger une image de manière traditionnelle. Apprenez-en plus grâce à l’article « On Mobile, Data URIs
are 6x Slower than Source Linking » écrit par Peter McLachlan pour Mobify :
B http://www.mobify.com/blog/data-uris-are-slow-on-mobile/

Habituellement, cette technique requiert des outils externes pour transformer son
image en Data-URI. Avec Compass, son application est des plus aisée, grâce à la
fonction inline-image() dont la syntaxe est :

inline-image($image, [$mime-type])

La fonction attend en premier argument une image trouvée dans le répertoire précisé
par l’option de configuration images_dir. Le second argument, facultatif, est à pré-
ciser si Compass n’arrive pas à déterminer le type de l’image (PNG, GIF, etc.).
Son usage est simple : remplacez l’appel à la fonction image-url() par inline-image().
ch05-002/sass/inline-image.scss

.bullets {
li {
list-style-image: inline-image('bullet.png');
}
}

CSS compilée

ul.bullets li {
list-style-image: url(
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAR
ElEQVQ4y2NgGAW0Ad7+/lJA3ADEV6EYxJYixYCGwrKy/50TJoAxiA0SI8WAqyCN0+fNA2MQG
yRGVwMo9gJlgTgKSAMAq0ZHPQ6QxoIAAAAASUVORK5CYII=');
}

Compass, une boîte à outils DRY


La richesse du catalogue de mixins et autres fonctions en tous genres de Compass est
l’un de ses points forts. Vous trouverez assurément un mixin pour répondre à votre
besoin, vous évitant ainsi de réinventer la roue.
Sass et Compass
166

Prenons l’exemple ch05-002/style.scss. Dans ce fichier, le texte de l’élément est


masqué en dehors de la zone de visualisation. Ce cas de figure se rencontre souvent
dans les projets. Puisque cette tâche est courante, Compass la propose sous la forme
du mixin hide-text.
ch05-003/sass/hide-text.scss

@import "compass/typography/text/replacement"; // 

$logo: 'logo.png';
.logo {
display: block;
@include hide-text; // 
background: transparent image-url($logo) no-repeat 0 0;
height: image-height($logo);
width: image-width($logo);
}

CSS compilée

.logo {
display: block;
text-indent: -119988px;
overflow: hidden;
text-align: left;
background: transparent url('../img/logo.png') no-repeat 0 0;
height: 150px;
width: 200px;
}

Le mixin utilisé en  répond parfaitement à nos attentes. Cependant, il a fallu


charger dans un premier temps le fichier qui le déclare (). Mais comment connaître
son emplacement ? Compass met à disposition en ligne une documentation des plus
complètes pour vous aider à trouver les mixins qui renforceront l’aspect DRY de
votre projet.

Une documentation riche


Une des difficultés de prise en main de Compass est certainement l’apprentissage des
mixins qu’il met à votre disposition. En effet, l’outil ne vous fournit aucune aide en
ligne de commande pour rechercher et découvrir son véritable potentiel.
C’est pourquoi il est crucial de connaître l’adresse de la documentation en ligne.

B http://compass-style.org/reference/compass/
Compass, votre futur meilleur ami
167
CHAPITRE 5

Elle regroupe l’ensemble des fonctionnalités de Compass divisées en sept modules.


1 CSS3. Ensemble des mixins utilisés pour produire des propriétés CSS3.
2 Helpers. Regroupe les diverses fonctions de manipulation des couleurs, d’aide à la
création de sélecteurs, de calculs mathématiques et bien d’autres encore. Ces
fonctions viennent renforcer la bibliothèque de fonctions fournie par Sass (voir
chapitre 3).
3 Layout. Ce module donne accès à des mixins d’aide à la création d’agencements,
tel qu’un pied de page fixe, ou à l’affichage en image de fond d’une grille.
4 Reset. Il s’agit de l’unique module qui génère des styles CSS lors de son importa-
tion. Les styles générés réinitialisent les styles des éléments HTML sur la base du
travail d’Eric Meyer (voir encadré).
5 Reset (legacy). Les mixins de cette catégorie sont dépréciés, c’est-à-dire qu’ils ne
seront bientôt plus supportés par Compass, au profit de ceux de la précédente
catégorie. Compass laisse sa documentation accessible pour permettre aux utilisa-
teurs de migrer vers la nouvelle version. Compass tient compte des contraintes
que rencontrent ses utilisateurs qui ne peuvent pas migrer du jour au lendemain
sur une version plus récente du framework sous prétexte de son évolution.
6 Typography. Le module typographique fournit un ensemble basique de mixins de
personnalisation des textes. Nous y retrouvons des mixins d’aide à la coloration
des liens, de personnalisation des listes, de création de rythmes verticaux et de
manipulation des textes.
7 Utilities. Divers mixins utilitaires transversaux sont regroupés dans cette catégorie.
Ils vont de la génération d’un clearfix à la manipulation avancée des images de
sprites.
Chacune des catégories mène à différents sous-ensembles de mixins pour un accès
rapide à l’information qui vous sera utile. La lecture de la page listant les mixins est
découpée en quatre parties (voir figure 5-1).
En , un descriptif suivi par la ligne d’import à ajouter à votre source Sass pour
bénéficier du ou des mixins présentés dans la page. Le descriptif est suivi par un
éventuel lien d’accès à un exemple d’utilisation. De la même manière, si le module a
une dépendance à un autre module, la page d’aide vous l’indiquera (). Certains
modules disposent de variables pour configurer globalement le comportement des
mixins (). Enfin, une section liste les différents mixins du module (). Chaque
mixin est représenté par sa signature, un descriptif et un lien de bascule vers sa source
SCSS. En effet, tous les mixins de Compass sont écrits en SCSS. Cette particularité
nous permet de les surcharger si nous en avons besoin. Par exemple, nous pourrions
écrire un nouveau mixin hide-text pour nous conformer aux besoins du projet.
Sass et Compass
168

Figure 5–2
L’interface de l’aide en ligne

RESSOURCES Documentation en ligne


Le nombre de fonctionnalités offertes par Compass est si grand que je vous invite à consulter la docu-
mentation en ligne plutôt que de les lister sur une cinquantaine de pages. De plus, la consultation en
ligne vous assurera la primeur de l’information.
B http://compass-style.org/reference/compass/

En plus de ce découpage logique et plutôt intuitif, un moteur de recherche permet de


trouver rapidement un mixin. Seule contrainte, le projet étant à 100 % anglophone,
vous devrez effectuer vos recherches en anglais. Ainsi, pour chercher l’éventuelle exis-
tence d’un mixin pour masquer du texte, vous devez chercher le terme « hide text ».
D’ailleurs, en recherchant le terme « hide text », un lien d’accès à la page Compass
Text Replacement apparaît où nous retrouvons bien le descriptif du mixin hide-text
utilisé dans le listing ch05-003/sass/hide-text.scss. On découvre par la même occa-
sion que la page liste différents mixins pour remplacer du texte par une image, ce qui
correspond finalement à notre volonté d’afficher le logo !
Compass, votre futur meilleur ami
169
CHAPITRE 5

Le code Sass d’affichage d’une image de logo en remplacement d’un texte devient alors :
ch05-003/sass/replace-text-with-dimensions.scss

@import "compass/typography/text/replacement";

.logo {
display: block;
@include replace-text-with-dimensions('logo.png', 0, 0);
}

Le gain de temps est flagrant !


La feuille de styles générée est identique à celle produite à partir du fichier ch05-003/
sass/hide-text.scss.

Déterminer quels fichiers importer


Parcourir la documentation en ligne de Compass est incontournable pour toute per-
sonne souhaitant appliquer le concept DRY dans son projet Compass. Nous l’avons
vu, il est possible de trouver, au détour d’une recherche, un mixin qui réponde com-
plètement à notre besoin.
Cependant, il peut être difficile de savoir quel fichier ou quelles dépendances charger
dans son projet pour bénéficier de ces nouvelles fonctionnalités. La méthode la plus
directe est d’importer le framework dans son intégralité.
Import du framework depuis le partial _base.scss

@import "compass";

Cette importation globale charge les trois modules Utilities, Typography et CSS3 dans
votre projet. Chaque module est divisé en plus petites entités en fonction de leurs
rôles. Ainsi, charger un module Compass revient à dire que nous chargeons plusieurs
briques du framework.
Par exemple, charger le module Typography importe le partial qui suit.
Contenu du module Typography

@import "typography/links";
@import "typography/lists";
@import "typography/text";
@import "typography/vertical_rhythm";
Sass et Compass
170

Chacun de ces fichiers vont à leur tour en importer d’autres et, au final, charger
l’intégralité du framework, ce qui implique le chargement d’un nombre conséquent
de fichiers. Si votre projet ne fait appel à aucun mixin typographique, il serait peut-
être judicieux de ne pas les charger.
Encore une fois, le site de la documentation va nous aider à trouver comment faire. Sur
la page principale de la documentation, nous retrouvons la consigne @import "compass".
Un lien Source on Github (voir les sources sur Github, en français) est également pré-
sent sur la page. En le suivant, vous arrivez sur le fichier source SCSS du projet Com-
pass pour constater que le fichier importé ne contient en fait que trois lignes.
Contenu du fichier _compass.scss

@import "compass/utilities";
@import "compass/typography";
@import "compass/css3";

Il est maintenant aisé de comprendre que dans votre projet, il vous suffit de charger
les fichiers compass/_utilities.scss et compass/_css3.scss pour éviter d’importer les
mixins dédiés à la typographie.

Par souci de lisibilité, les prochains exemples du chapitre ne mentionneront pas les imports de modules
Compass.

Compass, un framework CSS3

La guerre des préfixes, un lointain souvenir


Lorsque l’on évoque Compass, la première particularité qui vient à l’esprit est sa
capacité à générer les préfixes constructeurs (vendor prefixes en anglais) des propriétés
CSS3.
En effet, les divers mixins de Compass génèrent, lorsque c’est nécessaire, les pro-
priétés munies de préfixes constructeurs (-moz-, -webkit-, -ms-, -o-, -khtml-) destinés
aux différents acteurs du marché. Bien évidemment, la propriété officielle est elle
aussi générée pour être compatible avec les futurs navigateurs.
Pour être facilement accessibles, les mixins CSS3 attendent des arguments écrits
dans la syntaxe CSS3. Ainsi, l’intégrateur qui en usera n’aura plus à se soucier de
l’interminable écriture des préfixes. Les exemples qui rythment la suite du chapitre
sauront vous en convaincre.
Compass, votre futur meilleur ami
171
CHAPITRE 5

Les grands classiques de CSS3


La recommandation CSS3 est vaste. À tel point qu’il est inconcevable de décrire tous
les mixins que Compass lui dédie. À la place, je vous en présente quelques-uns qui
sont incontournables et qu’il est désormais habituel de croiser dans nos projets.
Dans les exemples qui suivent, nous considérons que le module CSS3 de Compass est
déjà chargé à l’aide de l’instruction @import "compass/css3".

Coins arrondis
L’ajout de coins arrondis à un élément est certainement l’effet CSS3 le plus répandu
sur la Toile. Bien que la majorité des navigateurs modernes le supportent nativement,
nous devons assurer pendant un temps la rétrocompatibilité pour les utilisateurs qui
se servent encore d’anciens navigateurs.
Le mixin border-radius([$radius], [$vertical-radius]) possède deux arguments
facultatifs. Le premier, qui définit la longueur du rayon de l’arrondi, a pour valeur par
défaut celle de la variable globale $default-border-radius (soit 5px). Le second argu-
ment sert à préciser la longueur verticale de l’arrondi. Par défaut, sa valeur sera iden-
tique à celle du premier paramètre.

SCSS CSS compilée


div { div {
@include border-radius; -webkit-border-radius: 5px;
} -moz-border-radius: 5px;
border-radius: 5px;
}

Pour être compatible avec la spécification CSS3 du W3C, les paramètres du mixin
border-radius acceptent une liste de valeurs séparées par des espaces. Si tel est le cas,
la liste de valeurs est assignée au premier argument du mixin. Compass détectant une
liste et non une dimension, il utilisera telle quelle la valeur qui lui est passé. Il est
ainsi possible d’appliquer un arrondi différent pour chacun des quatre coins d’un élé-
ment. L’exemple qui suit applique un coin arrondi de 50px sur les coins supérieur et
inférieur droits de l’élément <div>.

SCSS CSS compilée


div.corner-right { div.corner-right {
@include border-radius(0 50px 50px -webkit-border-radius: 0;
0); -moz-border-radius: 0 50px 50px 0;
} border-radius: 0 50px 50px 0;
}
Sass et Compass
172

L’exemple précédent fonctionne mal. En effet, la propriété générée pour WebKit est
mauvaise : seule la longueur du coin supérieur gauche est renseignée. Ce comporte-
ment est dû au fait que d’anciennes versions de WebKit (avant la version 532.5)
n’acceptent pas cette syntaxe raccourcie.
Afin d’être compatible, nous devons faire évoluer le code pour définir explicitement
les coins droits à l’aide de la forme longue des définitions : border-top-right-radius
et border-bottom-right-radius. Deux mixins éponymes sont disponibles dans Com-
pass. Mieux encore, un mixin border-right-radius([radius]) existe, nous simplifiant
l’écriture du style.

SCSS CSS compilée


div.corner-right { div.corner-right {
@include border-right-radius(50px); -moz-border-radius-topright: 50px;
} -webkit-border-top-right-radius:
50px;
border-top-right-radius: 50px;
-moz-border-radius-bottomright: 50px;
-webkit-border-bottom-right-radius:
50px;
border-bottom-right-radius: 50px;
}

Ombres portée
Compass dispose de deux mixins d’aide à l’écriture des ombres portées (propriété
CSS3 box-shadow) :
• box-shadow([$shadow-1], [$shadow-2], ...) ;
• single-box-shadow([$color], [$hoff], [$voff], [$blur], [$spread], [$inset]).
Le premier, box-shadow(), fournit un moyen de générer de une à dix ombres portées
dans des syntaxes compatibles avec WebKit, Gecko et le standard CSS3. Chaque
ombre renseignée doit respecter la syntaxe du standard CSS3 (en  du prochain lis-
ting), Compass se chargeant de générer les versions préfixées.

RESSOURCES CSS3 shadows


Si vous découvrez les ombres portées de CSS3 et que vous aimeriez en apprendre davantage, voici un
article proposé par Geoffrey Crofte publié sur le site de la communauté Alsacréations qui saura répondre
à vos attentes :
B http://www.alsacreations.com/tuto/lire/1338-css3-box-shadow-ombre.html
Compass, votre futur meilleur ami
173
CHAPITRE 5

Le second mixin est un raccourci au premier lorsque vous n’avez qu’une ombre à
appliquer sur l’élément. Il devient surtout intéressant si les ombres portées de votre
projet sont identiques. En effet, chacun de ses arguments s’appuie sur une variable
globale pour définir le comportement par défaut du mixin (). Il devient ainsi trivial
de changer la couleur d’une ombre en particulier ().
ch05-003/box-shadow.scss

// La couleur par défaut des ombres portées.


$default-box-shadow-color: rgba(black, .5) !default;

// Le décalage horizontal par défaut.


$default-box-shadow-h-offset: 1px !default;

// Le décalage vertical par défaut.


$default-box-shadow-v-offset: 2px !default;

// La distance du flou.
$default-box-shadow-blur: 5px !default;

// La taille de l'ombre, permet de redimensionner l'ombre.


$default-box-shadow-spread : 1px !default;

// La position interne de l'ombre.


$default-box-shadow-inset : false !default;

// Chargement du module d'ombres portées de Compass.


@import "compass/css3/box-shadow";

.simple-shadow {
@include single-box-shadow;// 
&.alert {
@include single-box-shadow(red);// 
}
}

.both-shadow {
// Ajout d’une ombre portée et une ombre interne pour simuler 
// une lueur interne.
@include box-shadow(1px 2px 20px rgba(white, .6) inset,
1px 2px 5px 1px rgba(black, .5));
}
Sass et Compass
174

CSS compilée

.simple-shadow {
-webkit-box-shadow: 1px 2px 5px 1px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 1px 2px 5px 1px rgba(0, 0, 0, 0.5);
box-shadow: 1px 2px 5px 1px rgba(0, 0, 0, 0.5);
}
.simple-shadow.alert {
-webkit-box-shadow: red 2px 5px 1px rgba(0, 0, 0, 0.5);
-moz-box-shadow: red 2px 5px 1px rgba(0, 0, 0, 0.5);
box-shadow: red 2px 5px 1px rgba(0, 0, 0, 0.5);
}

.both-shadow {
-webkit-box-shadow: 1px 2px 20px rgba(255, 255, 255, 0.6) inset,
1px 2px 5px 1px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 1px 2px 20px rgba(255, 255, 255, 0.6) inset,
1px 2px 5px 1px rgba(0, 0, 0, 0.5);
box-shadow: 1px 2px 20px rgba(255, 255, 255, 0.6) inset,
1px 2px 5px 1px rgba(0, 0, 0, 0.5);
}

CSS3 décrit aussi une propriété text-shadow pour ajouter une ombre portée sur les
textes. Compass l’intègre sous la forme de deux mixins text-shadow et single-text-
shadow sur le même modèle que les ombres portées de boîtes.

ASTUCE Supprimer l’effet d’ombre portée


Supprimez l’ombre portée d’un élément en passant l’argument none aux mixins de Compass :
single-box-shadow(none), box-shadow(none), single-text-shadow(none)
ou text-shadow(none).

@font-face facile
De nos jours, il est courant de devoir intégrer un design qui fait appel à une police de
caractères spécifique, c’est-à-dire qui n’est pas installée par défaut sur les ordinateurs
des visiteurs du site. Le web designer peut laisser libre cours à sa créativité pour offrir
une expérience utilisateur en accord avec les objectifs du site.
À l’origine, la déclaration de polices de caractères via la règle @font-face fut intro-
duite du temps de CSS2 et était supportée par Internet Explorer 6, comme par
Netscape 4. Mais à l’époque, ni les développeurs de navigateurs, ni les créateurs de
polices de caractères n’arrivèrent à s’accorder sur un format commun. Ajoutez à cela
le fait que le haut débit ne s’était pas encore démocratisé et vous comprendrez pour-
quoi @font-face fut retiré de la norme CSS2.1.
Compass, votre futur meilleur ami
175
CHAPITRE 5

Le débit des connexions grandissant, CSS3 s’est doté d’un module dédié à l’insertion
des fontes personnalisées. Malheureusement, tous les acteurs du marché ne suppor-
tent pas les mêmes formats de fontes et nous obligent à charger un éventail de for-
mats pour satisfaire le maximum de cibles : EOT, WOFF, TTF, OTF et SVG.

RESSOURCES Pour aller plus loin avec @font-face


Découvrez l’historique de la syntaxe de la règle @font-face dans l’article « Bonnes pratiques pour les
déclarations @font-face » écrit par Jérémie Patonnier :
B http://typographisme.net/post/Bonnes-pratiques-pour-les-d%C3%A9clarations-%40font-face
Apprenez à améliorer le rendu de vos de @font-face grâce à l’article « Optimiser le rendu de @font-
face : tout un programme ! » de Marie Guillaumet :
B http://fr.clever-age.com/veille/blog/optimiser-le-rendu-de-font-face.html

L’intégration de polices de caractères n’est pas compliquée en soi, mais elle est relati-
vement verbeuse, ce qui accroît le risque d’erreurs de saisie.
Appliquer en CSS3 une @font-face aux titres

@font-face{
font-family: 'MuseoSlab500Regular'; 
src: url('fonts/Museo_Slab_500.eot'); 
src: url('fonts/Museo_Slab_500.eot?#iefix') format('eot'), 
url('fonts/Museo_Slab_500.woff') format('woff'), 
url('fonts/Museo_Slab_500.ttf') format('truetype'), 
url('fonts/Museo_Slab_500.svg#MuseoSlab500Regular') 
format('svg');
font-weight: normal; 
font-style: normal; 
}

h1, h2, h3, h4, h5, h6 {


font-family: 'MuseoSlab500Regular', Arial, sans-serif;
}

 Nous déclarons le nom de la police de caractères.


 Une première source est renseignée. Ici, la version EOT (Embedded OpenType)
qui sera interprétée par IE9.
 IE6 à IE8 ont besoin d’un hack pour supporter la lecture de l’attribut src (on ne
rit pas) en présence de multiples déclarations de l’attribut, comme c’est le cas ici.
 Le format WOFF (Web Open Font Format) de la police sera pris en charge par les
navigateurs modernes.
Sass et Compass
176

 Safari et les navigateurs mobiles, quant à eux, requièrent une police au format
TTF (TrueType).
 Une version SVG (Scalable Vector Graphics) est requise pour iOS 4 et inférieur.
 Chaque police est prévue pour fonctionner dans une graisse et un style donné.
La police de caractères est appliquée en se référant au nom donné en .
Heureusement, Compass allège la syntaxe à l’aide du mixin font-face pour obtenir le
même résultat avec une saisie minimale.
Utiliser @font-face avec Compass

@include font-face('MuseoSlab500Regular',
font-files('Museo_Slab_500.woff', woff,
'Museo_Slab_500.ttf' , truetype,
'Museo_Slab_500.svg#MuseoSlab500Regular', svg),
'Museo_Slab_500.eot', normal, normal);

#{headers()} {
font-family: 'MuseoSlab500Regular', Arial, sans-serif;
}

Le code est plus court, gagne en lisibilité et en robustesse. La fonction d’aide font-
files() joue ici un rôle important. Elle a pour rôle de générer les fonctions CSS
url() et format(), mais aussi de produire des chemins d’accès aux fichiers de la police
de caractères en tenant compte de la configuration de votre projet Compass.

SYNTAXE Générateur de sélecteurs de titres


Dans le précédent listing, la fonction d’aide headers() de Compass a été utilisée. Dépourvue d’argu-
ments, elle retourne les six niveaux de titre sous la forme d’une chaîne (string) ("h1, h2, h3, h4,
h5, h6"). Afin d’être interprétée comme un sélecteur CSS, il vous faut l’interpoler.
Deux arguments peuvent être précisés : le premier pour spécifier le niveau de titre de départ, le second
pour celui d’arrivée. Ainsi, headers(2, 4) retournera la chaîne "h2, h3, h4". À noter que cette
fonction peut également être appelée headings().

Un module d'image très complet


Des mixins, fournis par Compass, facilitent grandement l’écriture cross-browser de
propriétés qui acceptent des images ou des valeurs d’image, comme les dégradés. Le
framework ajoutera si nécessaire les propriétés dotées de préfixes constructeurs.
La syntaxe est intuitive puisqu’elle se conforme à celle définie par le W3C. Le
dégradé radial suivant ne sera compris que par les navigateurs modernes.
Compass, votre futur meilleur ami
177
CHAPITRE 5

Un dégradé radial d’après la syntaxe officielle

.radial-gradient {
background: radial-gradient(ellipse at center top, green, blue);
}

STANDARD Qu’est-ce qu’un navigateur moderne ?


J’entends par navigateur moderne, un navigateur qui propose un bon support de CSS3 et un support par-
tiel de HTML5. Pour l’exemple des dégradés radiaux, cela concerne des navigateurs comme Chrome 26+,
Firefox 16+, Safari 7+, Opera 12.1+ ou Internet Explorer 10+.

En revanche, en remplaçant la propriété background par l’appel au mixin éponyme,


votre code sera compatible avec un large panel de navigateurs.
Le même dégradé radial porté sur Compass

.radial-gradient {
@include background(
radial-gradient(ellipse at center top, green, blue)
);
}

CSS compilée

.radial-gradient {
background: -webkit-gradient(radial, ellipse at center top, 0,
ellipse at center top, 100,
color-stop(0%, #008000), color-stop(100%, #0000ff));
background: -webkit-radial-gradient(ellipse at center top, #008000,
#0000ff);
background: -moz-radial-gradient(ellipse at center top, #008000,
#0000ff);
background: -o-radial-gradient(ellipse at center top, #008000,
#0000ff);
background: radial-gradient(ellipse at center top, #008000, #0000ff);
}

La transition vers Compass est vraiment très simple et permet de bénéficier d’un
support multinavigateur.
Les mixins du module image prennent en charge les fonds multiples.
Sass et Compass
178

Simulation d’un halo blanc au-dessus d’une image

.multiple-backgrounds {
$img: 'kitten.jpg';
display: block;
width: image-width($img);
height: image-height($img);
@include background(
radial-gradient(ellipse, rgba(#fff ,0), #fff),
image-url($img)
);
}

CSS compilée

.multiple-backgrounds {
display: block;
width: 408px;
height: 287px;
background: -webkit-gradient(radial, ellipse, 0, ellipse, 100,
color-stop(0%, rgba(255, 255, 255, 0)),
color-stop(100%, #ffffff)),
url('/images/kitten.jpg?1375097713');
background:
-webkit-radial-gradient(ellipse, rgba(255, 255, 255, 0), #ffffff),
url('../img/kitten.jpg');
background:
-moz-radial-gradient(ellipse, rgba(255, 255, 255, 0), #ffffff),
url('../img/kitten.jpg');
background:
-o-radial-gradient(ellipse, rgba(255, 255, 255, 0), #ffffff),
url('../img/kitten.jpg');
background:
radial-gradient(ellipse, rgba(255, 255, 255, 0), #ffffff),
url('../img/kitten.jpg');
}

Il est à noter que Compass fournit un mixin pour générer des dégradés linéaires com-
patibles avec Internet Explorer 6, 7 et 8. Le mixin attend une couleur de début de
dégradé, une couleur de fin et une direction optionnelle (vertical ou horizontal).
Syntaxe du mixin de création de dégradés linéaire pour IE 6 à 8

filter-gradient($start-color, $end-color, [orientation])


Compass, votre futur meilleur ami
179
CHAPITRE 5

Ce mixin génère un filtre propriétaire à Internet Explorer et devrait donc être dans
l’idéal écrit dans une feuille de styles dédiée. Autrement, appelez le mixin avant toute
définition de fond de l’élément.
Utilisation du filtre propriétaire

.linear-gradient {
@include filter-gradient(#a9e4f7, #0fb4e7); // IE6-8
@include background(linear-gradient(#a9e4f7, #0fb4e7));
}

CSS compilée

.linear-gradient {
*zoom: 1;
filter: progid:DXImageTransform.Microsoft.gradient(
gradientType=0, startColorstr='#FFA9E4F7', endColorstr='#FF0FB4E7');
background: -webkit-linear-gradient(#a9e4f7, #0fb4e7);
background: -moz-linear-gradient(#a9e4f7, #0fb4e7);
background: -o-linear-gradient(#a9e4f7, #0fb4e7);
background: linear-gradient(#a9e4f7, #0fb4e7);
}

Un support cross-browser
Ainsi, la force de Compass est sa capacité à produire un code qui sera compatible
avec un large éventail de navigateurs.

Un outil à l'écoute du marché


L’équipe derrière le développement de Compass est sensibilisée aux standards définis
par le W3C et intègre rapidement leurs dernières évolutions. Néanmoins, tout cela
se fait avec discernement et pondération pour ne pas abandonner pour autant le sup-
port d’une syntaxe compatible avec des navigateurs qui ne sont pas à la page.
Il est en effet important d’accepter le fait que tous les utilisateurs ne migrent pas sys-
tématiquement sur une nouvelle version d’un navigateur. Et heureusement, tout le
monde n’est pas geek dans l’âme.
Une ancienne syntaxe sera retirée du code produit si, et seulement si, les parts de
marché des navigateurs la supportant sont devenues insignifiantes.
Sass et Compass
180

Le meilleur exemple est certainement celui de la création de dégradés. La spécification


a énormément évoluée au cours des dernières années et des navigateurs ont implémenté
une syntaxe qui est désormais obsolète (notamment sur iOS inférieur à 5 et Android
inférieur à la version 4). Cela obligeait l’intégrateur à maintenir et surtout à retenir une
syntaxe désuète en plus d’être radicalement différente du nouveau standard.
Ancienne syntaxe de linear-gradient sous WebKit

background: -webkit-gradient(linear, 50% 0%, 50% 100%,


color-stop(0%, #a9e4f7), color-stop(100%, #0fb4e7)
);

Syntaxe actuelle de linear-gradient sous WebKit

background: -webkit-linear-gradient(#a9e4f7, #0fb4e7);

Compass nous retire ici une belle épine du pied en générant les deux syntaxes, nous
assurant un support maximal de la fonctionnalité.

Un support cross-browser paramétrable


Tous les projets web ont des contraintes différentes, le support de l’ancienne syntaxe
des dégradés par WebKit importe donc peu. Au contraire, on aimerait ne pas les
générer pour économiser quelques précieux octets dans la masse d’informations à
envoyer aux clients web.
L’équipe de Compass l’entend et a mis en place tout un jeu de variables booléennes
pour vous permettre d’activer ou de désactiver l’inclusion de code constructeur (voir
tableau 5-1). Déclarez-les une fois pour toutes dans le fichier de définition des varia-
bles de votre projet pour assurer une production de code cohérente.
Tableau 5–1 Variables de configuration du support cross-browser par Compass

Variable Valeur par défaut Description


$legacy-support-for-ie true Support de IE6 à IE8.
$legacy-support-for-ie6 $legacy-support- Support de IE6.
for-ie
$legacy-support-for-ie7 $legacy-support- Support de IE7.
for-ie
$legacy-support-for-ie8 $legacy-support- Support de IE8.
for-ie
$legacy-support-for-mozilla true Support de versions de Firefox antérieures à
3.6.
Compass, votre futur meilleur ami
181
CHAPITRE 5

Tableau 5–1 Variables de configuration du support cross-browser par Compass (suite)

Variable Valeur par défaut Description


$experimental-support-for- true Support du préfixe constructeur -moz-.
mozilla
$experimental-support-for- true Support du préfixe constructeur -webkit-.
webkit
$support-for-original- true Support de l’ancienne syntaxe des dégradés
webkit-gradients par WebKit.
$experimental-support-for- true Support du préfixe constructeur -o-.
opera
$experimental-support-for- true Support du préfixe constructeur -ms-.
microsoft
$experimental-support-for- false Support du préfixe constructeur -khtml-.
khtml
$experimental-support-for- false Support du format SVG dans les propriétés
svg CSS3.
$experimental-support-for- false Support des propriétés CSS3 par CSS PIE.
pie

Ainsi, déclarez la variable $support-for-original-webkit-gradients: false pour


empêcher Compass de générer l’ancienne syntaxe des dégradés linéaires.
Par exemple, Internet Explorer 9 prend en charge les dégradés en s’appuyant sur une
image au format SVG. Encore faut-il la générer, ce qui n’est pas si évident lorsque votre
projet en contient plusieurs. À nouveau, Compass vous facilite le travail : il peut créer la
version SVG de votre dégradé et l’intégrer à l’aide du schéma Data-URI.
Pour en bénéficier, déclarez simplement la variable $experimental-support-for-svg:
true.Dès lors, Compass embarquera la version SVG des dégradés.
Au final, générer un dégradé linéaire compatible avec une majorité de navigateurs,
dont Internet Explorer dans ses versions 6 à 9 (et plus, IE 10 étant un navigateur
moderne) se résume à écrire trois petites lignes de code !
Trois lignes pour générer un dégradé linéaire

$experimental-support-for-svg: true; // IE9


.linear-gradient {
@include filter-gradient(#a9e4f7, #0fb4e7); // IE6-8
@include background(linear-gradient(#a9e4f7, #0fb4e7));
}
Sass et Compass
182

CSS compilée

.linear-gradient {
*zoom: 1;
filter: progid:DXImageTransform.Microsoft.gradient(
gradientType=0, startColorstr='#FFA9E4F7', endColorstr='#FF0FB4E7');
background:
url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0id
XRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yM
DAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzP
SJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+P
HN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2E5ZTRmNyIvPjxzdG9wIG9mZnNldD0iM
TAwJSIgc3RvcC1jb2xvcj0iIzBmYjRlNyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZ
WN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ
3JhZCkiIC8+PC9zdmc+IA==');
background: -webkit-linear-gradient(#a9e4f7, #0fb4e7);
background: -moz-linear-gradient(#a9e4f7, #0fb4e7);
background: -o-linear-gradient(#a9e4f7, #0fb4e7);
background: linear-gradient(#a9e4f7, #0fb4e7);
}

Compass, ou comment oublier Internet Explorer


L’utilisation systématique des mixins de Compass vous apportera plus qu’un support
de CSS3 sur les différents navigateurs le supportant à l’aide de préfixes constructeurs.
Vos séances de débogage sous Internet Explorer seront – du moins je l’espère –
réduites à une peau de chagrin.
Pour vous donner un ordre d’idée, dans un projet Drupal 7 que j’ai mené à Clever
Age composé de 21 types de contenus, la feuille de styles CSS du thème compte
environ 700 règles. Pourtant, le débogage IE7+ s’est fait avec seulement 30 règles
CSS. Ce fut un réel gain de temps pour moi et mon client !

Génération automatique de hacks


Le secret d’une telle économie d’énergie en débogage IE est directement dû au fait
que Compass intègre des hacks connus dans le code généré.
Un hack est une technique pour contourner un problème d’interprétation des stan-
dards CSS par le navigateur. L’usage des hacks est souvent décrié car ils reposent sur
certaines déficiences des navigateurs pour nous permettre d’arriver à nos fins. Défi-
ciences qui pourraient être corrigées dans un avenir proche.
Enfin, ça c’est en théorie. En pratique, nous devons faire face à des navigateurs devenus
obsolètes et dont la maintenance est abandonnée par leur constructeur. Les navigateurs
récents, Internet Explorer y compris, respectent de mieux en mieux les standards, limi-
Compass, votre futur meilleur ami
183
CHAPITRE 5

tant ainsi le risque qu’un ancien hack interfère avec leur interprétation des feuilles de
styles. C’est pourquoi il est aujourd’hui relativement sûr de s’appuyer sur les hacks qui
ciblent IE 6 à 8, sans porter préjudice à la stabilité future de votre projet.

RESSOURCES Collection de hacks de compatibilité aux navigateurs


Browserhacks, une initiative de Hugo Giraudel et Tim Pietrusky, regroupe l’ensemble des hacks connus
pour cibler les différents navigateurs du marché. À utiliser avec discernement.
B http://browserhacks.com/

Par exemple, si vous comptez appliquer un affichage inline-block sur un élément de


type block, les versions d’Internet Explorer inférieures à 8 ne comprendront pas cette
valeur pour la propriété display. Une astuce connue des intégrateurs pour contourner
le problème est d’appliquer dans une feuille de styles chargée conditionnellement les
propriétés suivantes.
Simuler display: inline-block sous IE7

element {
zoom: 1;
display: inline;
}

La feuille de styles doit être chargée séparément pour n’être appliquée que par IE7 et
inférieur. Autrement, une étourderie forcerait les autres navigateurs à interpréter la
nouvelle valeur de la propriété display. Mais Compass (ou Sass à vrai dire) n’est pas
en mesure de produire plusieurs feuilles de styles à partir d’une même source Sass,
alors le framework, au travers du mixin inline-block, va recourir à un hack pour
cibler ces versions défectueuses d’Internet Explorer.

SCSS CSS compilée


@import "compass/css3" element {
element { // Firefox < 3
@include inline-block; display: -moz-inline-stack;
} display: inline-block;
vertical-align: middle;
// IE < 8 jusqu’à la fin
*vertical-align: auto;
zoom: 1;
*display: inline;
}
Sass et Compass
184

Ainsi, il suffit de faire appel au mixin du même nom que la propriété CSS qui pose
problème dans certaines conditions pour assurer sa prise en charge par IE. Rien de
tel pour vous embellir une journée !

Désactiver le support d’Internet Explorer


Comme nous l’a appris le tableau 5-1, des variables permettent de désactiver la pro-
duction de code spécifique à Internet Explorer.
Pour désactiver la génération de hacks par Compass, il suffit de déclarer à false la
variable $legacy-support-for-ie.

En résumé
Compass simplifie grandement la gestion des ressources statiques. Grâce à lui, il est
aisé de déplacer le répertoire des images d’un site : il suffit d’éditer une option dans le
fichier de configuration du projet et de lancer une compilation du projet. Il se charge
de générer tous les nouveaux accès !
À travers une riche collection de mixins aux noms intuitifs, Compass mérite son titre
de framework CSS3. Son support cross-browser vous permet de vous concentrer sur
la recherche de solutions pour intégrer une maquette audacieuse, sans perdre de
temps à rechercher la syntaxe des différentes propriétés CSS propriétaires.
Le prochain chapitre est dédié à la découverte d’une autre facette de Compass qui
saura être bénéfique aux performances de votre site : son générateur d’images de
sprites.
6
Création de sprites CSS
avec Compass

Créer des sprites a toujours été la bête noire des intégrateurs car la tâche est
fastidieuse. Mais c’était avant Compass qui facilite grandement la vie !

SOMMAIRE
B Comprendre les enjeux derrière les sprites CSS
B Exploiter efficacement le générateur de sprites CSS de Compass
B Créer manuellement vos sprites CSS
B Réduire les temps de traitement des sprites
Sass et Compass
186

Ce chapitre est dédié à un sujet devenu incontournable dans l’optique d’améliorer les
performances d’un site. Néanmoins, ses difficultés de mise en œuvre et de mainte-
nance découragent plus d’un intégrateur. Vous l’aurez reconnu, ce chapitre traitera de
la gestion des sprites CSS avec Compass.

Qu'est-ce qu'un sprite CSS ?


Derrière ce terme anglais se cache une technique fondamentale du jeu vidéo en deux
dimensions. Rappelez-vous ce héros se déplaçant sur un décor. Au lieu de charger
une image différente à chacun de ses mouvements, le chargement d’une seule image
formée de toutes ses postures se révèle bien plus performant (voir figure 6-1). Il suffit
de restreindre l’affichage de la posture du héros à la zone concernée (voir figure 6-2).

Figure 6–1
Les différentes postures
du personnage sont réunies
en une image.

Figure 6–2
Seule la portion utile de l’image
est affichée.

RESSOURCES Sprites CSS : meurs, découpe d’images, meurs !


La technique des sprites CSS n’est pas si récente. Je vous invite à lire la traduction française d’un article
rédigé par Dave Shea en 2004 :
B http://www.pompage.net/traduction/sprites

Il en est de même avec les sprites CSS, tout simplement : on affecte une image de
fond à un élément dont on restreint son viewport, c’est-à-dire sa surface d’affichage.
Création de sprites CSS avec Compass
187
CHAPITRE 6

Un cas d’usage des sprites CSS

.heroes {
/* Une image d’arrière plan est appliquée à l'élément */
background: url('img/sprite-heroes.png') 0 0;
/* Puis on restreint sa surface d’affichage */
display: block;
height: 48px;
width: 48px
}
/* Chaque mouvement du personnage correspond à une position différente
dans l'image de la sprite map. */
.heroes.waiting {
background-position: -48px -24px;
}
.heroes.walk {
background-position: -48px -48px;
}

GLOSSAIRE Sprite map, sprite


L’image qui regroupe les différentes images requises par la technique de sprite CSS est appelée une
sprite map ou encore une sprite sheet. Littéralement, un « plan du sprite » (et nous éviterons de traduire
le mot sprite par « lutin » pour ne pas interloquer nos voisins de bar).
Un sprite désigne quant à lui une image intégrée dans la sprite map.

Compass facilite grandement notre travail puisqu’il se charge de réunir les images
dans un seul PNG et, surtout, de produire les styles CSS qui y sont associés. Grâce à
Compass, ce qui vous prenait auparavant une heure de travail ne vous occupera plus
que quelques secondes, le temps d’écrire trois lignes de code. Pour les situations les
plus complexes, comme la création de sprites haute définition, Compass vous sera
d’une grande aide en vous fournissant bon nombre d’outils pour produire des sprites
CSS sur mesure.

Les sprites, une nécessité


Étendez l’exemple de notre jeune héros de jeux vidéo aux éléments d’interface de
votre site. Grâce à cette technique, l’interface devient plus réactive car le navigateur
n’aura pas à faire patienter l’utilisateur le temps de télécharger une autre image suite à
l’action de survol ou de clic sur un élément. Mais est-ce le seul argument à mettre au
crédit des sprites CSS ?
Sass et Compass
188

Accélérer le chargement de la page web


Regrouper plusieurs images en une seule accélère le chargement de votre site. Pour
commencer, il faut savoir que le poids de la sprite map est généralement inférieur à
celui du cumul de toutes les images qui la compose.
La vraie force des sprites réside dans la réduction du nombre d’échanges effectués
entre le navigateur et le serveur. Cela permet d’obtenir un temps de chargement plus
court pour le client, mais aussi un allègement de la charge de travail du serveur.
En effet, à chaque demande de ressource statique le navigateur doit attendre la
réponse du serveur puis télécharger les données. Même sur des sites aux infrastruc-
tures performantes, cette latence incompressible est de l’ordre de 50 millisecondes
auxquelles il faut ajouter le temps de chargement des données. Multipliez cela par un
nombre conséquent d’images et vous comprendrez pourquoi (voir figure 6-3) des
géants comme Amazon ou Google ont vite fait d’intégrer les sprites CSS dans leur
flux de travail (voir figure 6-4).

Figure 6–3 Diagramme de chargement des images sur une page. Avant et après regroupement des images
dans une sprite map : un gain de temps de chargement non négligeable !
Création de sprites CSS avec Compass
189
CHAPITRE 6

Figure 6–4
Une sprite map de la plate-
forme sociale Google+

Créer une sprite map n'est pas une sinécure


Il devient vite intéressant de réunir toutes les images de décoration d’un site en une
sprite map. Mais attention, plus il y aura d’images, plus sa maintenance sera difficile.
Une image change de dimensions ? Vous êtes bon pour réordonner une partie de la
sprite map, puis pour répercuter les nouvelles coordonnées dans la feuille de styles
CSS. La sentence est la même si vous supprimez une image de la sprite map.
Un véritable cauchemar pour le web designer ou l’intégrateur.
Cette contrainte est la cause principale de la faible adoption des sprites CSS. Pendant
de nombreuses années, seuls les sites ayant un trafic très important appliquaient cette
technique à toutes leurs images décoratives pour alléger la charge de leurs serveurs.
La situation a cependant évolué grâce à l’émergence d’outils en ligne ou à installer sur
son poste de travail pour vous aider à générer une sprite map et les règles CSS associées.
Néanmoins, la vie ne serait-elle pas plus simple si tout le processus de gestion des
sprites CSS pouvaient se faire de lui-même et au même endroit ?

Compass, ce super-héros
Puisque Compass est intégré à votre flux de conception des feuilles de styles, pour-
quoi ne pas lui demander de gérer les sprites CSS ? Il connaît déjà l’emplacement des
images du projet grâce au fichier de configuration (voir chapitre 5) et il est en charge
de produire les feuilles de styles. Bref, il serait le compagnon idéal pour s’atteler à
cette tâche ingrate.
Voyons comment il vole au secours de l’intégrateur.

La magie de Compass pour la génération de sprites


Compass embarque justement un générateur de sprites CSS qui, dans sa forme la
plus simple, se contente de trois lignes de code pour créer une sprite map et les règles
CSS associées, et ce, que vous ayez 5 ou 100 images à gérer. De quoi booster votre
productivité !
Sass et Compass
190

ATTENTION Des images au format PNG


Actuellement, une sprite map ne peut être générée qu’à partir d’images au format
PNG, ce qui n’est pas un véritable problème puisque ce format est celui qui se prête
le mieux aux images décoratives.

Créer une sprite map CSS avec Compass


Avec Compass, la création d’une sprite map se fait en deux étapes : importez, dans
un premier temps, le module de sprites de Compass, puis toutes les images PNG
d’un répertoire. Ce dernier doit être accessible depuis le chemin défini par l’option
images_dir du fichier de configuration du projet.

Générer une sprite map avec Compass

@import "compass/utilities/sprites";
@import "html5/*.png";

Le recours à l’instruction @import sur des images active le générateur de sprites dit
« automatique » de Compass. Automatique parce que l’outil crée un ensemble de
variables, de mixins et de fonctions.
Pour commencer, Compass utilise le nom du répertoire comme base pour identifier
la sprite map, soit html5 dans notre exemple. Afin de nous conformer à la documen-
tation en ligne de Compass, nous appellerons cet identifiant <map>.

Figure 6–5
L’image sprite map générée

L’outil crée ensuite la sprite map au même niveau que le répertoire (voir figure 6-5).
Le nom de la sprite map a pour forme <map>-s23d7ec50de.png où le suffixe
-s23d7ec50de joue le rôle d’un accélérateur de cache (voir chapitre 5).
Création de sprites CSS avec Compass
191
CHAPITRE 6

CSS compilée

.html5-sprite {
background-image: url('../img/html5-s23d7ec50de.png');
background-repeat: no-repeat;
}

Une règle CSS est générée pour vous permettre d’accéder à la sprite map. La classe
.html5-sprite est appelée classe de base. Son nom est construit de la sorte : .<map>-
sprite.

Comme vous pouvez le constater à la figure 6-5, la sprite map est organisée verticale-
ment par défaut. Nous verrons plus loin qu’il est possible d’agir sur la position des
images et sur l’agencement de la sprite map, mais penchons-nous dans un premier
temps sur la création des règles CSS.

Générer les sprites CSS


Un mixin all-<map>-sprites est automatiquement créé par Compass pour vous per-
mettre d’insérer en une fois les règles CSS qui régissent tous les sprites de la sprite map :

@include all-html5-sprites;

Compass utilise la classe de base qu’il avait générée lors de la création de la sprite
map pour étendre chacune des règles dédiées au positionnement des images. Le code
Sass intermédiaire peut s’écrire ainsi :

.html5-sprite {
background-image: url('../img/html5-s23d7ec50de.png');
background-repeat: no-repeat;
}

.html5-connectivity {
@extend .html5-sprite;
background-position: 0 0;
}

.html5-device_access {
@extend .html5-sprite;
background-position: 0 -32px;
}
Sass et Compass
192

.html5-effects_3d {
@extend .html5-sprite;
background-position: 0 -64px;
}

Au final, nous générons les règles CSS de positionnement des neuf images contenues
dans le répertoire html5/ avec seulement trois lignes de Compass.
ch06-01/sass/01.scss

@import "compass/utilities/sprites";
// …
@import "html5/*.png";
@include all-html5-sprites;

Le code CSS généré est simple d’utilisation, notamment grâce à l’identification aisée
des images par une classe CSS qui reprend leur nom : .<map>-<sprite> où <sprite>
correspond au nom de l’image intégrée à la sprite map, dépourvue de son extension.
CSS compilée

// …
.html5-sprite, .html5-connectivity, .html5-device_access,
.html5-effects_3d, .html5-logo, .html5-multimedia,
.html5-offline_storage, .html5-performance, .html5-semantics,
.html5-styling {
background-image: url('../img/html5-s23d7ec50de.png');
background-repeat: no-repeat;
}

.html5-connectivity { background-position: 0 0; }
.html5-device_access { background-position: 0 -32px; }
.html5-effects_3d { background-position: 0 -64px; }
.html5-logo { background-position: 0 -96px; }
.html5-multimedia { background-position: 0 -160px; }
.html5-offline_storage { background-position: 0 -192px; }
.html5-performance { background-position: 0 -224px; }
.html5-semantics { background-position: 0 -256px; }
.html5-styling { background-position: 0 -288px; }
Création de sprites CSS avec Compass
193
CHAPITRE 6

ATTENTION Des noms d’images valides CSS


À partir du moment où Compass s’appuie sur le nom des images pour générer les
noms de classes CSS associées, vous êtes dans l’obligation de veiller à donner à vos
images des intitulés qui valident les noms de classes CSS. Ainsi, vous ne pourrez par
faire débuter le nom d’une image par un chiffre et il ne pourra pas contenir de carac-
tères blancs comme l’espace.

Paramétrer une sprite map


L’aide apportée par Compass est déjà conséquente mais cela va encore plus loin.
Son générateur de sprites se démarque des outils que vous pourriez trouver en ligne
en vous permettant d’agir sur la création de la sprite map de manière élégante, pour
vous offrir plus de flexibilité.
Votre intervention peut se faire à deux niveaux : globalement, sur l’apparence finale
de la sprite map, et de manière individuelle, sur chacun des sprites qui la compose.
Pour cela, au moment d’importer les images, Compass vérifie l’existence d’un certain
nombre de variables de configuration.

IMPORTANT Du bon ordre de déclaration des variables de configuration


Toute variable de configuration d’une sprite map doit être déclarée avant l’importation des images. Com-
pass ne modifiera pas la sprite map a posteriori.

Les variables de configuration globale sont notées sous la forme $<map>-<option> où


<option> vaut l’une des valeurs suivantes : spacing, repeat, position, sprite-
dimensions, sprite-base-class, clean-up ou layout.

Le nombre de possibilités de configuration d’un sprite est plus limité. Le nom de la


variable est construit selon le modèle $<map>-<sprite>-<option>. Cette fois-ci, seules
les options spacing, repeat et position sont disponibles.
Passons sans plus tarder à l’étude de ces différentes options.

Augmenter l'espace autour des sprites


Il est parfois utile d’ajouter des pixels transparents autour d’un sprite, par exemple
lorsque la hauteur de l’élément sur lequel est appliqué l’image d’arrière-plan est plus
grande que celle du sprite. Sans quoi, le sprite situé en dessous devient visible (voir
figure 6-6).
Sass et Compass
194

Figure 6–6
Le sprite inférieur est visible.

Compass permet d’ajouter cet espace additionnel via la variable $<map>-spacing pour
l’appliquer sur toutes les images ou à l’aide de la variable $<map>-<sprite>-spacing
pour une image précise.
ch06-01/sass/02_spacing.scss : ajout d’espace entre les images de la sprite map

$html5-spacing: 5px;
$html5-effects_3d-spacing: 20px;
@import "html5/*.png";
@include all-html5-sprites;

La figure 6-7 met en évidence la sprite map où toutes les images sont espacées entre
elles de 5px, hormis l’image effect_3d qui est espacée de 20px.

Figure 6–7
Comparaison de l’effet de
l’espacement sur la sprite-map

Préciser les dimensions


Dans le cadre d’un affichage d’icônes comme c’est le cas avec l’exemple précédent,
préciser les dimensions des différents sprites peut être une étape incontournable.
Pour cela, rien de plus simple : définissez la variable de configuration globale $<map>-
sprite-dimensions comme true avant l’importation des images.
Création de sprites CSS avec Compass
195
CHAPITRE 6

ch06-01/sass/03_dimensions.scss

$html5-sprite-dimensions: true;
@import "html5/*.png";
@include all-html5-sprites;

CSS compilée


.html5-connectivity {
background-position: 0 0;
height: 32px;
width: 32px;
}
.html5-effects_3d {
background-position: 0 -64px;
height: 32px;
width: 32px;
}
.html5-logo {
background-position: 0 -96px;
height: 64px;
width: 64px;
}

Chaque classe qui cible un sprite déclare désormais les dimensions de l’image. Nous
verrons plus loin dans ce chapitre comment éviter les répétitions si elles vous gênent.
Notez que cette option n’a aucune incidence sur la sprite map créée par Compass.

Configurer la position
Compass permet de modifier la position d’un ou de tous les sprites sur l’axe des abs-
cisses. Cette option de configuration est utile pour ajouter des espacements horizontaux
aux sprites. Acceptant une valeur en pixels ou en pourcentages, les variables dédiées à
cette option sont les suivantes : $<map>-position et $<map>-<sprite>-position.
Dans l’exemple qui suit, toutes les images sont centrées dans la sprite map. L’image
du logo est quant à elle alignée sur le côté droit de l’image générée.
ch06-01/sass/04_position.scss

$html5-large-position: 50%;
$html5-large-logo-position: 100%;
@import "html5-large/*.png";
@include all-html5-large-sprites;
Sass et Compass
196

Comme le montre les règles CSS générées, la position en abscisses des sprites est
déclarée en pixels.
CSS compilée

.html5-large-compass { background-position: 0 0; }
.html5-large-connectivity { background-position: -195px -84px; }
.html5-large-device_access { background-position: -195px -116px; }
.html5-large-logo { background-position: -359px -180px; }
.html5-large-effects_3d { background-position: -195px -148px; }

Figure 6–8
Compass permet
de personnaliser la position
des sprites dans la sprite map.

BONNE PRATIQUE Des <map> avec des tirets


Il est tout à fait possible de nommer le nom de dossier d’images avec des tirets. Cependant, l’enchaîne-
ment des tirets peut rendre la lecture des variables et des mixins difficile. Pour vous aider, vous pouvez
saisir des tirets bas à la place des tirets dans les noms des variables : $html5_large-position au lieu
de $html5-large-position. Rappelez-vous, Sass ne fait pas la distinction entre les deux formes,
comme nous l’avions vu au chapitre 2.

Des positions exprimées en pourcentages


Si vous êtes amené à positionner vos sprites CSS de manière fluide, vous savez à quel
point calculer les positions d’un sprite à l’aide de pourcentages peut être complexe.
Compass propose la variable $<map>-use-percentages pour générer automatiquement
le positionnement des sprites en pourcentages ! La variable accepte un booléen, ainsi
précisez-lui la valeur true pour en bénéficier.
Création de sprites CSS avec Compass
197
CHAPITRE 6

ch06-01/sass/05_use-percentages.scss

$html5-use-percentages: true;
@import "html5/*.png";
@include all-html5-sprites;

CSS compilée

// …
.html5-connectivity { background-position: 0 0; }
.html5-device_access { background-position: 0 10%; }
.html5-effects_3d { background-position: 0 20%; }
.html5-logo { background-position: 0 33.33333%; }
.html5-multimedia { background-position: 0 50%; }
// …

Répéter un sprite horizontalement


L’option de configuration qui suit est magique ! C’est un peu la fonctionnalité dont
tout intégrateur web rêve de disposer, sans avoir à lancer un éditeur d’image comme
Photoshop ou Gimp.
Lorsque vous déclarez la variable de configuration globale $<map>-repeat ou la
variable $<map>-<sprite>-repeat avec la valeur repeat-x, Compass va automatique-
ment dupliquer les images concernées afin qu’elles occupent toute la largeur de la
sprite map.
Cependant, il existe une subtilité dont il faut avoir connaissance. En effet, recourir à
$<map>-<sprite>-repeat: repeat-x ne va en aucun cas générer la propriété CSS
background-repeat: repeat-x. Il faut bien différencier la configuration qui sera utile
au générateur de sprites pour construire la sprite map et son affichage par CSS.
Ainsi, vous devez doubler la configuration du sprite par la déclaration de la propriété
background-repeat: repeat-x dans la règle CSS concernée.

Un exemple sera plus explicite.


Considérons le dossier rx/ qui contient une image badge.png et un motif pattern.png
destiné à être affiché à l’aide d’une répétition horizontale (voir figure 6-9).

Figure 6–9
À gauche badge.png.
À droite, pattern.png
Sass et Compass
198

Importez comme d’habitude vos sprites, sans configurer la sprite map, et précisez
explicitement en CSS une répétition de l’image d’arrière-plan pour la classe .rx-
pattern.

ch06-01/sass/06_repeat-1.scss

@import "rx/*.png";
@include all-rx-sprites;

.rx-pattern {
background-repeat: repeat-x;
}

Comme vous pouvez en juger sur la figure 6-10, l’effet obtenu n’est pas vraiment
celui escompté. Le motif est bien répété tout le long de l’élément mais entrecoupé
d’espaces vides. La cause en est simple : la sprite map générée par Compass est plus
large que le motif à cause de la présence de l’image badge.png (voir figure 6-11).

Figure 6–10
Une mauvaise répétition du
motif

Figure 6–11
L’espace vide à droite du motif
empêche sa répétition avec
CSS.

Maintenant, supprimez la propriété background-repeat: repeat-x et déclarez la


variable $<map>-<sprite>-repeat: repeat-x avant d’importer les images.
ch06-01/sass/06_repeat-2.scss

$rx-pattern-repeat: repeat-x;
@import "rx/*.png";
@include all-rx-sprites;

.rx-pattern {
}
Création de sprites CSS avec Compass
199
CHAPITRE 6

À défaut d’être répétée horizontalement par CSS, Compass a dupliqué autant de fois
que nécessaire l’image pattern.png dans la sprite map pour qu’elle occupe toute sa
largeur (voir figure 6-12) !

Figure 6–12
Le motif est maintenant répété
dans la sprite map, mais la
sprite map n’est pas répétée
sur la largeur de l’élément.

Finalement, vous devez doubler la duplication horizontale du sprite dans la sprite


map par une répétition horizontale avec CSS pour arriver au résultat escompté (voir
figure 6-13).
ch06-01/sass/06_repeat-3.scss

$rx-pattern-repeat: repeat-x;
@import "rx/*.png";
@include all-rx-sprites;

.rx-pattern {
background-repeat: repeat-x;
}

Figure 6–13
Le motif est correctement
répété sur toute la largeur
de l’élément.

Lorsque vous êtes amené à répéter une image dans une sprite map, Compass veillera à
ne pas couper votre image et agrandira en conséquence la sprite map (voir figure 6-14).

Figure 6–14
L'intégrité du motif est assurée.
Sass et Compass
200

VERSION Quid de la prise en charge des répétitions verticales ?


Au moment de la rédaction du présent ouvrage, la version stable de Compass (0.12.2) ne supporte pas
les répétitions verticales. En revanche, la fonctionnalité sera intégrée dès la prochaine version majeure de
l’outil, à savoir Compass 0.13.
L’usage de la répétition verticale sera néanmoins restreint à l’agencement horizontal de la sprite map.
Les différents types d’agencements sont abordés un peu plus loin dans le chapitre.

Configurer le nom de la classe de base


La variable $<map>-sprite-base-class permet de changer la classe CSS de base qui est
générée lors de l’importation des images. Dans l’exemple qui suit, la classe de base
.badge est produite à la place de la classe .html5-sprite.

SCSS CSS compilée


$html5-sprite-base-class: '.badge'; .badge {
@import "html5/*.png"; background-image:
url('../img/html5-
s9d5de60943.png');
background-repeat: no-repeat;
}

Attention, seule la classe de base est modifiée. Les variables de configuration et le mixin
de création des règles CSS conservent le nom du répertoire comme valeur de <map>.

ASTUCE Supprimer la classe de base


Il peut être irritant de retrouver dans son projet une classe CSS qui reste inutilisée. Pour supprimer la
classe de base, rien de plus simple : précisez un placeholder à la variable $<map>-sprite-base-
class. Veillez cependant à donner un placeholder au nom unique pour éviter d’être en conflit avec les
autres placeholders du projet. Par exemple :
$html5-sprite-base-class: '%badge-html5';
Aucune classe superflue ne sera générée, puisque la raison d’être d’un placeholder est d’être remplacé
par tout sélecteur qui l’étend. Si vous appliquez l’astuce à l’exemple ch06-01/sass/01.scss, vous
verrez disparaître la classe .html5-sprite du premier groupe de sélecteurs généré.

Choisir l'agencement optimal


Compass crée par défaut des sprite maps verticales avec des sprites empilés les uns
sous les autres. Pratique, mais pas dans toutes les situations. C’est pourquoi Compass
offre trois autres agencements de sprites dans une sprite map.
Création de sprites CSS avec Compass
201
CHAPITRE 6

Pour en bénéficier, il vous suffit de déclarer la variable globale $<map>-layout:


<agencement> où <agencement> correspond à l’une des valeurs suivantes.
• vertical. L’agencement que vous connaissez déjà (voir figure 6-15).
• horizontal. Répartit horizontalement les images (voir figure 6-16).
• diagonal. Les images sont distribuées dans une diagonale de la sprite map (voir
figure 6-17). Attention, ce format produit des images plus grandes et parfois plus
lourdes, ce qui augmente la consommation de mémoire par les navigateurs.
• smart. Agencement dit intelligent car chaque image est accolée à sa voisine de
telle sorte à obtenir la plus petite sprite map possible (voir figure 6-18). Cet agen-
cement nécessite moins de mémoire pour être traité par les navigateurs.

Figure 6–15 Figure 6–16 Figure 6–17 Figure 6–18


Agencement vertical Agencement horizontal Agencement en diagonale Agencement intelligent

L’agencement vertical conviendra dans une majorité des cas. J’ai cependant une nette
préférence pour l’agencement intelligent qui produit des images fréquemment plus
légères. La seule contrainte étant de limiter la zone d’affichage aux dimensions de
chaque sprite pour ne pas dévoiler les images voisines.

ATTENTION Une absence totale de configuration


Les agencements diagonal et smart ne tiennent pas compte des variables de configu-
ration que vous pouvez déclarer ! Actuellement, seuls les agencements vertical et
horizontal sont paramétrables.

L’agencement intelligent est plus contraignant, mais un peu d’astuce permet d’en
profiter. Par exemple, une technique vulgarisée par les sets d’icônes comme Font
Awesome consiste à appliquer le sprite sur un élément vide.
HTML

<i class="icon-twitter" aria-hidden="true">&nbsp;</i>


Sass et Compass
202

L’élément n’est pas réellement vide : une espace insécable est nécessaire pour que le
navigateur applique correctement les dimensions du sprite. Bien sûr, la propriété
display appliquée doit être de type bloc, comme block ou inline-block.

Ordonner les images dans la sprite map


À partir de Compass 0.13, il vous est permis de trier les sprites de la sprite map à l’aide de
la variable $<map>-sort-by qui accepte trois valeurs différentes (voir figure 6-19).
• name. Les images sont triées par leurs noms. C’est le tri par défaut.
• size. Les images sont triées par leurs poids.
• width. Les images sont triées en fonction de leur largeur en pixels.
Ces tris sont ascendants par défaut. Vous pouvez inverser l’ordre de tri des images en pré-
fixant le critère par un point d’exclamation : !name, !size et !width. Le critère devra dans
ce cas être entouré de guillemets pour ne pas lever une erreur : $icons-sort-by: '!name'.

Figure 6–19
Différents types de tri. De gauche à droite : name, size, width et !name.

Intégrer la sprite map via Data-URI


Depuis Compass 0.13, vous avez la possibilité d’embarquer la sprite map générée
directement dans votre feuille de styles. Ceci peut être pertinent lorsque l’image est
légère pour économiser une requête HTTP avec le serveur.
Pour cela, déclarez la variable $<map>-inline avec le booléen true.

ATTENTION Utilisez les Data-URI avec parcimonie


De récentes recherches ont démontré que charger une image via Data-URI est six fois
plus lent que de charger une image de manière traditionnelle. Apprenez-en plus
grâce à l’article « On Mobile, Data URIs are 6x Slower than Source Linking » écrit par
Peter McLachlan pour Mobify :
B http://www.mobify.com/blog/data-uris-are-slow-on-mobile/
Création de sprites CSS avec Compass
203
CHAPITRE 6

Gestion automatique des pseudo-classes CSS


L’usage de sprites CSS est un réel avantage pour améliorer la réactivité de l’interface,
notamment en éliminant les temps d’attente lors du chargement d’une nouvelle
image lorsqu’un élément est survolé.
Toujours dans une optique de réduire votre charge de travail, Compass permet de
générer les règles CSS des différentes pseudo-classes CSS que sont :hover, :active,
:target et :focus.

VERSION Prise en charge de la pseudo-classe :focus


La pseudo-classe :focus est prise en charge à partir de Compass 0.13.

Son usage est des plus simples : il vous suffit d’ajouter au nom de l’image le nom de la
pseudo-classe en remplaçant le deux-points par un tiret bas (:hover devient _hover).
Ainsi, pour bénéficier du support de l’ensemble des pseudo-classes pour l’image
styling.png, il faut créer les images styling_hover.png, styling_active.png,
styling_target.png et styling_focus.png.

Un effet de survol sans le moindre effort

.html5-styling {
background-position: 0 -96px;
}
.html5-styling:hover, .html5-styling.styling-hover {
background-position: -32px 0;
}

Notez qu’en plus d’ajouter la pseudo-classe à la classe correspondant au sprite, Com-


pass ajoute une classe .<sprite>-<pseudo-classe> qui précise la classe du sprite pour
aider vos manipulations de l’interface à l’aide de JavaScript.
La gestion automatique des pseudo-classes CSS peut être désactivée en déclarant la
variable $disable-magic-sprite-selectors: true avant d’importer les images. Atten-
tion, cette variable configure globalement le support des pseudo-classes et agira sur
toutes vos sprite maps. Si vous souhaitez désactiver ce support pour une seule sprite
map, redéfinissez simplement la variable à false après l’importation des images.
SCSS

// On désactive le supporte des pseudo-classes pour


// la sprite map sharebox.
$disable-magic-sprite-selectors: true;
Sass et Compass
204

@import "sharebox/*.png";

// Le support des pseudo-classes est réactivé pour les


// autres sprite maps.
$disable-magic-sprite-selectors: false;
@import "icons/*.png";

@include all-icons-sprites;
@include all-sharebox-sprites;

Maîtriser les sélecteurs


Il existe des situations courantes qui conviennent parfaitement à l’usage de sprites
CSS, comme l’affichage d’un set d’icônes.
Malheureusement, si nous utilisons la classe de base créée par Compass dans la feuille de
styles, ce dernier va étendre nos règles et produire de nombreux sélecteurs. De plus, ces
icônes ont généralement des dimensions identiques et pourtant Compass duplique leur
déclaration dans chacune des classes créées au lieu de les regrouper dans la classe de base.
Prenons pour exemple une liste de liens ciblant des réseaux sociaux, à afficher sous la
forme d’icônes.
HTML
<ul class="list-inline">
<li><a href="#" class="social-twitter">Twitter</a></li>
<li><a href="#" class="social-linkedin">LinkedIn</a></li>
<li><a href="#" class="social-googleplus">Google+</a></li>
</ul>

La tâche est classique, à savoir :


• afficher la liste non ordonnée en ligne ;
• opter pour un agencement intelligent puisque les images seront contraintes à leurs
dimensions ;
• donner à chaque lien un affichage de type bloc ;
• masquer de manière accessible le texte des liens ;
• donner un peu de peps, en réduisant l’opacité des icônes par défaut pour la réini-
tialiser au survol et lorsque le lien détient le focus.
Le premier réflexe sera d’effectuer les actions qui suivent :
• appliquer le mixin horizontal-list pour afficher la liste non ordonnée en ligne ;
Création de sprites CSS avec Compass
205
CHAPITRE 6

• indiquer que nous souhaitons une sprite map intelligente grâce à la variable
$<map>-layout ;
• demander à Compass d’inclure les dimensions des images à l’aide de la variable
$<map>-sprite-dimensions ;
• surcharger la classe de base .social-sprite commune à tous les sprites.

ch06-002/sass/social-links.scss
@import "compass";

// Afficher une liste horizontale.


// Note : la sortie de cette règle sera ignorée pour faciliter
// la lecture.
.list-inline { @include horizontal-list; }

// Création des sprites CSS pour les images du dossier social/.


$social-layout: smart; // Agencement intelligent.
$social-sprite-dimensions: true;// Ajouter les dimensions des sprites.
@import "social/*.png"; // Créer la sprite map.
@include all-social-sprites; // Créer les classes des sprites.

.social-sprite { // Sur la classe de base, on :


@include hide-text; // - masque le texte
@include opacity(.5); // - réduit l'opacité (IE6+)
display: block; // - applique un affichage en bloc
&:hover, &:focus { // Puis, au survol et au focus,
@include opacity(1); // l'opacité est réinitialisée.
}
}

Figure 6–20
Une liste d’icônes sociales
Sass et Compass
206

Le résultat est satisfaisant (voir figure 6-20). Cependant, une analyse de la feuille de styles
compilée met en évidence que Compass a non seulement dupliqué les dimensions
(repères  dans la CSS compilée), mais que chacune des classes correspondantes aux
sprites surchargent les règles dans lesquelles la classe de base est utilisée (repères ).
CSS compilée

.social-sprite, .social-googleplus, .social-linkedin, .social-twitter {


background-image: url('../img/social-s4363aa6d7e.png');
background-repeat: no-repeat;
}
.social-googleplus {
background-position: 0 0;
height: 48px; width: 48px;// 
}
.social-linkedin {
background-position: 0 -48px;
height: 48px; width: 48px;// 
}
.social-twitter {
background-position: 0 -96px;
height: 48px; width: 48px;// 
}

// 
.social-sprite, .social-googleplus, .social-linkedin, .social-twitter {
text-indent: -119988px;
overflow: hidden;
text-align: left;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
opacity: 0.5;
display: block;
}
// 
.social-sprite:hover, .social-googleplus:hover,
.social-linkedin:hover, .social-twitter:hover {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
opacity: 1;
}

Ce résultat est tout à fait légitime. En effet, Compass ne peut pas présumer de
l’usage que vous ferez des classes CSS puisqu’il n’a pas connaissance du DOM de
votre page. Comment peut-il deviner si vous allez ou non ajouter la classe de base à
tous vos items de la liste ?
Il n’empêche, le problème reste entier. Le nombre de sélecteurs ajouté est négligeable
dans cet exemple, mais reportez ce cas de figure à un grand set d’icônes comme
Création de sprites CSS avec Compass
207
CHAPITRE 6

Glyphicons, et vous obtenez la création de quelques 800 sélecteurs en sus (voir


figure 6-21). Ce qui représente pas moins de 19 Ko de CSS à charger !

Figure 6–21
Des sélecteurs produits
au kilomètre pour rien

Voyons comment il est possible, avec un soupçon d’astuce, de réduire le nombre de


sélecteurs à deux, quel que soit le nombre de sprites contenus dans la sprite map.
ch06-002/sass/social-links-2.scss

// …
$social-layout: smart; // Agencement intelligent.
$social-sprite-dimensions: false; // Ne pas ajouter les dimensions.
@import "social/*.png"; // Créer la sprite map.
@include all-social-sprites; // Créer les classes des sprites.

[class*="social-"] {
@include hide-text;
@include opacity(.5);
display: block;
// Ajouter les dimensions d’une des images.
@include social-sprite-dimensions('twitter');
&:hover {
@include opacity(1);
}
}
Sass et Compass
208

La feuille de styles est considérablement allégée.


La CSS allégée

.social-sprite, .social-googleplus, .social-linkedin, .social-twitter {


background-image: url('../img/social-s4363aa6d7e.png');
background-repeat: no-repeat;
}
.social-googleplus { background-position: 0 0; }
.social-linkedin { background-position: 0 -48px; }
.social-twitter { background-position: 0 -96px; }

[class*="social-"] {
text-indent: -119988px;
overflow: hidden;
text-align: left;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
opacity: 0.5;
display: block;
height: 48px;
width: 48px;
}
[class*="social-"]:hover {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
opacity: 1;
}

Toute l’astuce réside dans l’utilisation du sélecteur d’attribut [class*="social-"] qui


va cibler tout élément dont l’attribut class contient la sous-chaîne social-, soit le
préfixe ajouté automatiquement par Compass.

ATTENTION Conséquence d’usage du sélecteur d’attribut *=


Le sélecteur d’attribut *= est rendu possible ici car nous connaissons toutes les classes
utilisées dans la page. Nous savons qu’un tel sélecteur ciblera uniquement nos icônes.
En effet, un élément pourvu de la classe foo social-bar est également ciblé par le
sélecteur d’attribut [class*="social-"] !
Si vous vous retrouvez dans cette situation, la solution est de remplacer le sélecteur
d’attribut par les deux sélecteurs [class*=" social-"], [class^="social-"]. Tandis que
le second va cibler les éléments dont la première classe déclarée débute par social-, le
premier sélecteur ciblera les autres classes de l’élément qui débutent par le même pré-
fixe. Veillez à bien saisir l’espace avant le préfixe dans le premier sélecteur.

Par ailleurs, nous profitons du sélecteur d’attribut pour y déléguer la gestion des
dimensions des sprites à l’aide du mixin social-sprite-dimensions mis à disposition
par Compass.
Création de sprites CSS avec Compass
209
CHAPITRE 6

En effet, jusqu’à maintenant, seul le mixin all-<map>-sprites a été évoqué. En réa-


lité, Compass crée dynamiquement une multitude de mixins et de fonctions pour
vous aider à personnaliser vos sprites CSS.

Des sprites aux petits oignons


La création automatisée de sprites CSS par Compass est utile, mais elle ne répondra
pas forcément à tous vos besoins. C’est pourquoi le module de sprites de Compass
génère dynamiquement un ensemble de mixins et de fonctions dès la création de la
sprite map à l’aide de l’instruction @import "<map>/*.png" (voir tableau 6-1).
Tableau 6–1 Mixins et fonctions de manipulation d’une sprite map automatique

Signature Type Description


<map>-sprite(<sprite>) mixin Étend la classe de base et fait appel au mixin
$<map>-sprite-background-position.
<map>-sprite-background- mixin Ajoute la propriété CSS background-position
position(<sprite>) pour le <sprite> contenu dans la sprite map.
<map>-sprite-dimensions(<sprite>) mixin Ajoute les propriétés CSS height et width cor-
respondantes au <sprite> contenu dans la
sprite map.
<map>-sprite-height(<sprite>) fonction Retourne la hauteur du <sprite> contenu dans
la sprite map.
<map>-sprite-width(<sprite>) fonction Retourne la largeur du <sprite> contenu dans la
sprite map.

Pratiques, ces instructions ne sont pourtant pas les seules à exister. En effet, Com-
pass permet de créer manuellement des sprites CSS.
En mode avancé, vous ne créez pas la sprite map à l’aide de l’instruction @import,
mais vous la stockez dans une variable avec la fonction sprite-map($glob, ...).
Créer et stocker une sprite map

$map: sprite-map("social/*.png");

Contrairement à l’instruction @import de la version automatique, la fonction sprite-


map() ne génère pas de règles CSS et ne déclenche pas la sauvegarde de la sprite map
sur le disque dur.
Pour enregistrer la sprite map sur le disque, utilisez simplement la variable dans une
propriété background ou background-image pour déclencher sa création.
Sass et Compass
210

Utiliser la sprite map

$map: sprite-map("social/*.png");
.icons {
background: $map no-repeat;
}

Bien évidemment, la création de la sprite map est paramétrable de manière globale


ou individuellement pour chaque image. Mais cette fois, les différentes variables sont
à déclarer comme arguments de la fonction sprite-map().
Par exemple, pour préciser un agencement horizontal, un espacement de 20 pixels
sur toutes les images et répéter horizontalement dans la sprite map l’image
gradient.png, l’appel à la fonction devient :

Personnaliser la sprite map

$map: sprite-map("social/*.png",
$layout: horizontal,
$spacing: 20px,
$social-gradient-repeat: repeat-x);

Notez que seuls les arguments globaux $layout, $repeat et $spacing sont acceptés par
la fonction sprite-map(). Point de $sprite-dimensions comme on aurait pu le sup-
poser. La demande d’insérer les dimensions des sprites se fait explicitement lors de
l’appel à d’autres fonctions de création manuelle de sprites CSS.
À ce niveau de lecture, il est normal de se demander dans quels cas de figure il faut
utiliser la version automatique ou manuelle du générateur de sprites de Compass.
Tout dépendra de vos besoins. Par exemple, la gestion d’un set d’icônes convient par-
faitement à la création automatisée des sprites CSS parce que les règles sont répéti-
tives et que leur mise en place dans la page se résume à ajouter une classe CSS sur des
éléments. En revanche, si vous devez intervenir sur des éléments que vous ne con-
trôlez pas – comme une contribution – alors la construction manuelle des sprites
CSS est toute désignée, car plus flexible.
Un ensemble de mixins (voir tableau 6-2) et de fonctions (voir tableau 6-3) sont
fournis nativement par Compass pour vous permettre d’écrire les différentes règles
CSS qui manipuleront la sprite map.
Pour comprendre ces tableaux, retenez ces conventions :
• $map représente la variable utilisée pour mémoriser le résultat de la fonction
sprite-map().
• $dimensions est un booléen. Lorsqu’il vaut true, il déclenche l’ajout des dimen-
sions de l’image <sprite>.
Création de sprites CSS avec Compass
211
CHAPITRE 6

ALLER PLUS LOIN Syntaxe des noms des arguments individuels


Une incertitude plane actuellement sur la syntaxe des arguments individuels à passer
à sprite-map(). En effet, la syntaxe historique attendait une variable ayant pour nom
$<sprite>-<option> comme $gradient-repeat. Or, depuis Compass 0.12.1 la syntaxe
est devenue $<map>-<sprite>-<option> comme $social-gradient-repeat.
Malheureusement, la documentation en ligne présente toujours l’ancienne syntaxe.
De quoi laisser planer le doute sur la syntaxe retenue. Reportez-vous au bogue 828
pour suivre l’évolution du choix de la syntaxe.
B https://github.com/chriseppstein/compass/issues/828

• $offset-x et $offset-y permettent respectivement de décaler la position CSS hori-


zontalement et verticalement du sprite<sprite>. Le décalage est relatif à la position
du sprite dans la sprite map. Ainsi, si la position d’un sprite est initialement égale à
0 34px, l’appel à la fonction sprite-position($map, <sprite>, 3px, -2px) retournera
la position 3px -36px.
Tableau 6–2 Mixins d’aide à la création manuelle de sprites CSS

Signature Description
sprite($map, <sprite>, [$dimensions], Ajoute la propriété background-position et
[$offset-x], [$offset-y]) éventuellement les dimensions du <sprite>.
sprite-background-position($map, <sprite>) Ajoute la propriété background-position
du <sprite>.
sprite-dimensions($map , <sprite>) Ajoute les dimensions du <sprite> à l’aide
des propriétés height et width.
sprites($map, $sprite-names, [$base-class], Génère pour chaque image de la liste
[$dimensions], $sprite-names une règle CSS qui contient la
[$prefix], [$offset-x], propriété background-position et éventuel-
[$offset-y]) lement les dimensions de l’image.
Si une classe de base est précisée à l’aide de
$base-class, alors chaque règle créée l’éten-
dra.
Chacune des règles a pour sélecteur la classe
.#{$prefix}-<sprite> où $prefix vaut
par défaut <map> (soit le nom du répertoire
d’images chargé).

Tableau 6–3 Fonctions d’aide à la création manuelle de sprites CSS

Signature Description
sprite-map-name($map) Retourne le nom du dossier d’images chargé (le fameux
<map>).
sprite-path($map) Retourne le chemin d’accès système à la sprite map.
Sass et Compass
212

Tableau 6–3 Fonctions d’aide à la création manuelle de sprites CSS (suite)

Signature Description
sprite-url($map) Retourne l’URL de la sprite map.
sprite-height($map, [<sprite>]) Retourne la hauteur de la sprite map. La fonction retour-
nera la hauteur de l’image <sprite> si son nom est pré-
cisé.
sprite-width($map, [<sprite>]) Retourne la largeur de la sprite map. La fonction retour-
nera la largeur de l’image <sprite> si son nom est pré-
cisé.
sprite-names($map) Retourne une liste des noms des images (au format
<sprite>) chargées dans la sprite map.
inline-sprite($map) Retourne la Data-URI de la sprite map. Exemple :
background-image: inline-sprite($icons);
sprite($map, <sprite>, Retourne l’URL d’accès à la sprite map et la position de
[$offset-x], [$offset-y], l’image <sprite>. Exemple :
[$use-percentages]) background: sprite($icons, twitter) no-
repeat;
produira la propriété
background: url('../img/icons-
sbbbd1f7aa3.png') no-repeat 0 -384px;
sprite-position($map, <sprite>, Retourne la position de l’image <sprite> dans la sprite
[$offset-x], [$offset-y], [$use- map.
percentages])
sprite-file($map, <sprite>) Retourne le chemin d’accès système à la l’image
<sprite>.
sprite-has-selector($map, <sprite>, Retourne un booléen indiquant s’il existe une image de
<selector>) nom <sprite>_<selector>.png où <selector> cor-
respond aux pseudo-classes hover, active, target ou
focus.
sprite-does-not-have-parent($map, Retourne un booléen indiquant s’il existe une image de
<sprite>) nom dépourvue de pseudo-classes hover, active,
target ou focus.
Fonction inverse de sprite-has-selector().

Le nombre de directives disponibles est impressionnant ! Notez cependant que les


fonctions sprite-width() et sprite-height() ne sont actuellement disponibles que
dans la version de développement de Compass et seront donc officiellement disponi-
bles lors de la sortie de la version 0.13.
Pour vous aider à appréhender les cas de figure où il est opportun de recourir à ces
directives avancées, je vous propose de découvrir quelques exemples.
Création de sprites CSS avec Compass
213
CHAPITRE 6

NOTE Des codes sources commentés


Par souci de concision et pour faciliter la compréhension des prochains exemples, les différentes explica-
tions seront directement intégrées au code sous la forme de commentaires.

Exemple 1 : personnaliser les sélecteurs des sprites


Dans le cadre d’une évolution, vous devez appliquer un jeu d’icônes mais, malheureuse-
ment, vous ne pouvez pas modifier la structure HTML en place (tiens, une contribution
WYSIWYG). Et si les images des icônes sont affichées dans des contenus contribués,
vous n’êtes pas autorisé à les renommer. Les classes CSS vous sont donc imposées.
La solution est de créer une par une les règles CSS pour préciser les sélecteurs adéquats.
Ce cas d’usage étant simple, il est possible d’utiliser le module de sprites automatiques.
ch06-003/sass/01.scss

@import "compass";

// Les dimensions des icônes doivent être ajoutées à la


// feuille de styles.
$icons_01-sprite-dimensions: true;

// L'usage d'un placeholder est motivé par l'inutilité de la classe de


// base créée automatiquement par Compass. En effet, nous ne
// l'utiliserons pas puisque la structure HTML est déjà en place.
$icons_01-sprite-base-class: '%icons_01';

// On souhaite profiter des mixins automatiques de Compass.


@import "icons-01/*.png";

// Les icônes seront présentées en ligne tout en bénéficiant d’un


// affichage de type bloc pour pouvoir leur donner des dimensions.
%icons_01 {
@include inline-block;
}

// Finalement, nous précisons la position et les dimensions de chaque


// sprite pour les sélecteurs imposés par le HTML.
// Nous utilisons ici le mixin <map>-sprite créé dynamiquement par
// Compass.
.top { @include icons_01-sprite('arrow_up'); }
.next { @include icons_01-sprite('arrow_right'); }
.bottom { @include icons_01-sprite('arrow_down'); }

// L’image "arrow_left" sera pour sa part affichée pour les éléments


// ciblés par deux sélecteurs.
.prev, a.back { @include icons_01-sprite('arrow_left'); }
Sass et Compass
214

CSS compilée

.top, .next, .bottom, .prev, a.back {


background-image: url('../img/icons-01-s85f6753e7d.png');
background-repeat: no-repeat;
}
.top, .next, .bottom, .prev, a.back {
display: -moz-inline-stack; display: inline-block;
vertical-align: middle; *vertical-align: auto;
zoom: 1; *display: inline;
}
.top {
background-position: 0 -96px;
height: 32px; width: 32px;
}
.next {
background-position: 0 -64px;
height: 32px; width: 32px;
}
.bottom {
background-position: 0 0;
height: 32px; width: 32px;
}
.prev, a.back {
background-position: 0 -32px;
height: 32px; width: 32px;
}

Exemple 2 : supprimer la répétition des dimensions


La démonstration précédente est efficace mais les dimensions de nos icônes sont
identiques. Pourquoi les répéter dans chacune des règles CSS ? L’exemple qui suit
montre comment supprimer très simplement cette répétition.
Le principe est enfantin. Il suffit de demander à Compass de ne pas ajouter les
dimensions des sprites à chaque sélecteur soit en évitant de déclarer la variable
$<map>-sprite-dimensions, soit en la définissant à false. Il ne reste plus qu’à déclarer
les dimensions d’un seul sprite dans la règle CSS ayant pour sélecteur la classe de
base de la sprite map, et le tour et joué.
ch06-003/sass/02.scss

@import "compass";

$icons_02-sprite-base-class: '%icons_02';
@import "icons-02/*.png";
Création de sprites CSS avec Compass
215
CHAPITRE 6

%icons_02 {
@include inline-block;

// Nous savons que toutes les images de la sprite map ont les
// mêmes dimensions. Il suffit donc de déclarer les propriétés CSS
// 'height' et 'width' d'une des images depuis le placeholder qui fait
// office de classe de base pour que toutes en bénéficies.
@include icons_02-sprite-dimensions('arrow_up');
}

// Comme nous n'avons pas défini à true la variable


// $icons_02-sprite-dimensions, Compass ajoute uniquement les
// positions de chacun des sprites.
.top { @include icons_02-sprite('arrow_up'); }
.next { @include icons_02-sprite('arrow_right'); }
.bottom { @include icons_02-sprite('arrow_down'); }
.prev, a.back { @include icons_02-sprite('arrow_left'); }

CSS compilée

.top, .next, .bottom, .prev, a.back {


background-image: url('../img/icons-02-sf6a3361a01.png');
background-repeat: no-repeat;
}
.top, .next, .bottom, .prev, a.back {
display: -moz-inline-stack; display: inline-block;
vertical-align: middle; *vertical-align: auto;
zoom: 1; *display: inline;
height: 32px; width: 32px;
}
.top { background-position: 0 -96px; }
.next { background-position: 0 -64px; }
.bottom { background-position: 0 0; }
.prev, a.back { background-position: 0 -32px; }

Je ne vous cache pas que je suis du genre à ne pas supporter que des espaces vagabon-
dent à la fin de mes lignes de code, alors imaginez à quel point la tentation de
regrouper les deux règles CSS formées par le groupe de sélecteurs .top, .next,
.bottom, .prev, a.back est grande.

Certes, servir notre feuille de styles avec une compression Gzip est largement suffi-
sant pour réduire efficacement le coût du transfert de ce doublon, mais ce cas de
figure est idéal pour aborder la génération manuelle des sprites CSS.
Dans l’exemple qui suit, la sprite map est entièrement gérée à la main. Compass ne
génère aucune variable, fonction ou mixin dynamiquement.
Sass et Compass
216

ch06-003/sass/03.scss

@import "compass";

// Nous stockons la sprite map dans une variable.


$icons: sprite-map("icons-03/*.png");

// Ce placeholder servira à regrouper les propriétés communes à tous


// les sprites.
%icons_03 {
@include inline-block;
// Nous appliquons la sprite map en arrière-plan, ce qui déclenche
// la sauvegarde de l'image sur le système de fichier.
background: $icons no-repeat;
@include sprite-dimensions($icons, 'arrow_right');
}

// Pour chaque sprite, nous étendons le placeholder des propriétés


// communes et nous incluons sa position dans la sprite map.
.top {
@extend %icons_03;
@include sprite-background-position($icons, 'arrow_up');
}
.next {
@extend %icons_03;
@include sprite-background-position($icons, 'arrow_right');
}
.bottom {
@extend %icons_03;
@include sprite-background-position($icons, 'arrow_down');
}
.prev, a.back {
@extend %icons_03;
@include sprite-background-position($icons, 'arrow_left');
}

CSS compilée

.top, .next, .bottom, .prev, a.back {


display: -moz-inline-stack; display: inline-block;
vertical-align: middle; *vertical-align: auto;
zoom: 1; *display: inline;
background: url('../img/icons-03-se34d2ead9a.png') no-repeat;
height: 32px; width: 32px;
}
.top { background-position: 0 -96px; }
.next { background-position: 0 -64px; }
.bottom { background-position: 0 0; }
.prev, a.back { background-position: 0 -32px; }
Création de sprites CSS avec Compass
217
CHAPITRE 6

Malgré la longueur du fichier Sass, la CSS compilée est des plus concises. À vous de
déplacer le curseur entre la facilité de lecture de votre code et l’optimisation des styles
CSS produits.

Exemple 3 : des sprites CSS en haute définition


Avec l’apparition sur le marché d’écrans haute définition (ou HD, ou Retina), nous
devons désormais délivrer deux formats d’images. Le premier est le format classique,
que nous utilisons depuis la création du Web. Le second format est destiné aux
hautes résolutions, ce qui se traduit par des images quatre fois plus grandes (deux fois
en largeur et deux fois en hauteur).
Techniquement, cela revient à effectuer un chargement des images HD, conditionné
par une Media Query. Rien de bien compliqué. Sauf que la gestion des sprites com-
patibles HD est plus délicate.
En effet, il faut s’assurer que :
• l’ordre des images rassemblées dans les deux sprite maps soit identique pour assu-
rer la bonne correspondance entre les deux formats d’affichage ;
• seules les instructions CSS relatives à l’image non HD soient générées. À quoi
vous servirait un sélecteur .icon-hd-twitter alors que vous utilisez la classe .icon-
twitter dans votre page HTML ?

Depuis Compass 0.13, la réalisation du premier point est triviale. Il suffit en effet de
recourir à l’option de tri par nom, à condition bien évidemment de conserver les mêmes
noms d’images dans les deux dossiers d’images qui serviront à générer les sprite maps.
Le second point nous oblige à gérer manuellement la sprite map HD pour éviter de
produire des règles CSS qui seront inutilisées.
Dans l’exemple qui suit, nous commençons par exploiter le générateur automatique
de sprites de Compass. En effet, il répond à notre besoin initial, à savoir produire les
sprites CSS de nos icônes classiques.
ch06-004/sass/sprites-hd.scss : gestion des images de base

@import "compass";

$social-sprite-base-class: '%social_base';
$social-layout: smart;

// Le tri est forcé par nom, pour s'assurer du bon ordre des images dans
// la sprite map.
$social-sort-by: name;
Sass et Compass
218

// Dans cet exemple, les images ont des dimensions différentes.


// Nous devons les préciser pour chacune d'entre elles.
$social-sprite-dimensions: true;

// Utilisation des sprites automatisés pour les images classiques.


@import "social/*.png";

// Nous demandons à Compass de générer les règles CSS pour chacune des
// images classiques.
@include all-social-sprites;

// Les propriétés communes à tous les sprites sont regroupées ici.


// Nous réutilisons la variable de configuration de la classe de base
// pour que Compass l'étende automatiquement. Elle est interpolée pour
// que Sass ne génère pas d’erreur (voir chapitre 2).
// Note : la variable $<map>-sprite-base-class est créée par le module
// automatique de sprites même si vous ne la personnalisez pas.
#{$social-sprite-base-class} {
@include hide-text;
display: block;
}

NOTE Un choix pédagogique


On aurait pu utiliser le groupe de sélecteurs [class*=" social-"], [class^="social-"] pour
réduire le nombre de sélecteurs générés, à la place de l’interpolation de la variable #{$social-
sprite-base-class}. Mais montrons plutôt qu’il est possible de réutiliser les variables de configura-
tion des sprite maps dans un contexte différent de celui de la personnalisation de Compass.

Cela étant fait, nous passons à la gestion des versions haute définition de nos sprites.
Voici le principe de fonctionnement.
1 Nous chargeons dans une variable la sprite map des images haute définition
contenues dans un répertoire dédié.
2 Dans une Media Query et grâce au sélecteur de base utilisé par Compass pour
déclarer l’image d’arrière-plan des sprites classiques, nous regroupons les surchar-
ges CSS qui vont permettre au navigateur de charger et d’afficher la version HD
de l’image de la sprite map.
3 Finalement, nous spécifions la largeur de l’image d’arrière-plan pour que sa lar-
geur soit égale à celle de la sprite map classique.
Création de sprites CSS avec Compass
219
CHAPITRE 6

ch06-004/sass/sprites-hd.scss : gestion des images HD

// Nous ne voulons pas que Compass génère les sélecteurs CSS des sprites
// donc nous gérons manuellement la création de la sprite map.
// Afin de s'assurer la bonne correspondance de l'ordre des images entre
// les deux sprite maps, il est important de réutiliser les options
// utilisées pour créer la sprite map classique.
$social_hd-sprites: sprite-map("social_x2/*.png",
$layout: $social-layout,
$sort-by: $social-sort-by);

// Les surcharges HD sont déclarées dans une Media Query qui cible les
// écrans à haute densité.
@media (-webkit-min-device-pixel-ratio: 1.3),
(min-resolution: 124.8dpi),
(min-resolution: 1.3dppx) {
// Les surcharges concernent tous les sprites. Le module de sprites
// étendra automatiquement la classe de base déclarée ci-dessous.
#{$social-sprite-base-class} {
// Nous déclarons l'image de la sprite map HD comme fond des
// éléments.
// Note : Compass sauvegarde sur le disque la sprite map HD.
background-image: $social_hd-sprites;
// Puisque l'image HD est plus grande que l'image classique, nous
// précisons une largeur d'image égale à celle de la sprite map
// classique. Pour ce faire, nous utilisons la variable
// $<map>-sprites que Compass a créé lors de l'importation des
// images classiques : $social-sprites.
background-size: sprite-width($social-sprites) auto;
}
}

Le fichier sprites-hd.scss démontre qu’il est tout à fait possible de conjuguer les
deux méthodes de gestion des sprites.
CSS compilée

.social-github, .social-gplus, .social-instagram, .social-linkedin,


.social-twitter {
background-image: url('../img/social-s034619cf01.png');
background-repeat: no-repeat;
}
.social-github {
background-position: 0 -288px;
height: 64px; width: 64px;
}
Sass et Compass
220

.social-github:hover, .social-github.github-hover {
background-position: 0 -224px;
}
.social-gplus {
background-position: 0 -32px;
height: 32px; width: 32px;
}
.social-gplus:hover, .social-gplus.gplus-hover {
background-position: -32px -32px;
}
// …

.social-github, .social-gplus, .social-instagram, .social-linkedin,


.social-twitter {
text-indent: -119988px; overflow: hidden;
text-align: left;
display: block;
}

@media (-webkit-min-device-pixel-ratio: 1.3),


(min-resolution: 124.8dpi),
(min-resolution: 1.3dppx) {
.social-github, .social-gplus, .social-instagram, .social-linkedin,
.social-twitter {
background-image: url('../img/social_x2-sb61c3fd85f.png');
background-size: 64px auto;
}
}

RESSOURCES Media Query haute définition


Je vous invite à lire l’article « Cross Browser Retina/High Resolution Media Queries » de Brett Jankord qui
analyse différentes Media Queries les plus couramment utilisées pour finalement en proposer une nou-
velle offrant une meilleure compatibilité cross-browser :
B http://www.brettjankord.com/2012/11/28/cross-browser-retinahigh-resolution-media-queries/

Il est possible d’écrire de manière plus concise le précédent exemple, puisque Sass permet
d’imbriquer les Media Queries (voir chapitre 2). Le fichier SCSS devient dès lors :
ch06-004/sass/sprites-hd-2.scss

@import "compass";

$social-sprite-base-class: '%social_base';
$social-layout: smart;
$social-sort-by: name;
$social-sprite-dimensions: true;
Création de sprites CSS avec Compass
221
CHAPITRE 6

@import "social/*.png";
$social_hd-sprites: sprite-map("social_x2/*.png",
$layout: $social-layout,
$sort-by: $social-sort-by);

@include all-social-sprites;
#{$social-sprite-base-class} {
@include hide-text;
display: block;
@media (-webkit-min-device-pixel-ratio: 1.3),
(min-resolution: 124.8dpi),
(min-resolution: 1.3dppx) {
background-image: $social_hd-sprites;
background-size: sprite-width($social-sprites) auto;
}
}

Exemple 4 : déclarer les dimensions des sprites par taille d’image


Dans cette dernière démonstration d’usage des outils de production de sprites CSS
mis à disposition par Compass, nous allons voir un exemple qui permet également de
souligner la puissance de Sass lorsqu’il est question de mettre au point un algorithme
un peu plus évolué.
Considérons le répertoire icons/ qui contient 11 images :
• quatre de 32 px de côté dont deux dédiées à l’effet de survol ;
• deux de 64 px de côté dont une dédiée à l’effet de survol ;
• cinq de 128 px de côté dont une dédiée à l’effet de survol.
L’exercice consiste à regrouper les sprites en fonction de leurs dimensions. Nous
devons donc obtenir trois règles CSS différentes.
De plus, seuls les sélecteurs dépourvus du support de la pseudo-classe de survol
doivent bénéficier du regroupement. En effet, le module automatisé de sprites se
contente d’augmenter la précision du sélecteur et ne crée pas de règle CSS supplé-
mentaire. Nous devons donc limiter notre action aux sélecteurs qui pointent les
sprites dépourvus du suffixe _hover dans leur nom.
ch06-005/sass/demo.scss

@import "compass";
// Nous importons un partial où est déclaré le mixin
// x-sprites-dimensions utilisé en fin de fichier.
@import "x-sprites-dimensions";
Sass et Compass
222

// Les dimensions seront gérées par le mixin x-sprites-dimensions.


$icons-sprite-dimensions: false;
$icons-sprite-base-class: '%icons_base';
$icons-layout: smart;
@import "icons/*.png";
@include all-icons-sprites;

// Rappel : à ce niveau et parce que nous avons eu recours à la création


// automatisée des sprites CSS, nous avons à disposition la variable
// $<map>-sprites instanciée par Compass.

[class*=" #{sprite-map-name($icons-sprites)}-"],
[class^="#{sprite-map-name($icons-sprites)}-"] {
@include hide-text;
display: block;
}

// Nous regroupons les classes des sprites par dimensions d'images.


@include x-sprites-dimensions($icons-sprites);

ch06-005/sass/_x-sprites-dimensions.scss

@mixin x-sprites-dimensions($map,
$sprite-names: sprite-names($map),
$prefix: null) {
// Nous itérons sur le nom des sprites pour générer ou étendre la
// règle CSS qui correspond à ses dimensions.
@each $name in $sprite-names {
@include x-single-sprite-dimensions($map, $name, $prefix);
}
}

// Pile privée.
$x-sprites-dimensions-stack: ();

// Produit la règle déclarative des dimensions d'un sprite.


//
// Les sélecteurs sont regroupés par dimensions identiques à l'aide
// de placeholders créés dynamiquement afin de réduire les répétitions.
//
// Si aucun préfixe n'est précisé nous utiliserons le nom de la sprite
// map. Désactivez l'ajout du préfixe en précisant le booléen false.
@mixin x-single-sprite-dimensions($map, $name, $prefix: null) {
// Construction du nom de la clé de cache qui servira à identifier
// par taille d'image le groupe de règles CSS dans lequel ajouter le
// sprite.
$map-name: sprite-map-name($map);
$sprite-height: sprite-height($map, $name);
$sprite-width: sprite-width($map, $name);
Création de sprites CSS avec Compass
223
CHAPITRE 6

$cache-key: "#{$map-name}_#{$sprite-width}x#{$sprite-height}";
// Si la clé de cache n'existe pas dans la pile privée
@if not index($x-sprites-dimensions-stack, $cache-key) {
// nous l'ajoutons pour nous assurer que nous rentrons dans ce bloc
// de code qu'une seule fois par taille d'image.
$x-sprites-dimensions-stack: append($x-sprites-dimensions-stack,
$cache-key);
// Un placeholder reprenant la clé de cache est créé.
// Les propriétés CSS de largeur et de hauteur du sprite sont alors
// ajoutées à la règle CSS.
// Avec une image de 64px pixels de côté pour une <map> "icons", le
// placeholder devient : %x-sprites-dimensions-icons_64x64.
// Il est important de générer un placeholder au nom unique qui ne
// sera qu'étendu programmatiquement.
%x-sprites-dimensions-#{$cache-key} {
@include sprite-dimensions($map, $name);
}
}

// Nous ne devons pas traiter les sprites qui contiennent une


// pseudo-classe dans leur nom (_hover, _active, _target, _focus)
// puisque Compass ne lui génère pas de classes CSS.
@if sprite-does-not-have-parent($map, $name) {
// Nous devons déclarer la variable $selector en-dehors du test
// conditionnel pour pouvoir la réutiliser plus loin, conformément
// aux règles de portée des variables vues dans le chapitre 2.
$selector: null;
// Gestion du préfixe
@if false == $prefix { $selector: $name; }
@else {
// Nous utilisons du nom de la sprite map si le préfixe n'est pas
// précisé.
$prefix: if($prefix, $prefix, $map-name);
$selector: #{$prefix}-#{$name};
}
// Enfin, nous étendons le placeholder qui correspond aux dimensions
// du sprite.
// Si <map> est égal à "icons", que $name vaut "twitter" et que la
// variable $prefix est nulle, le sélecteur créé sera .icons-twitter.
.#{$selector} {
@extend %x-sprites-dimensions-#{$cache-key};
}
}
}

Vous pouvez souffler un coup ! Observez le résultat dans le prochain listing et cons-
tatez que la tâche est dûment remplie.
Sass et Compass
224

CSS compilée

.icons-dribbble, .icons-github, .icons-gplus, .icons-instagram,


.icons-linkedin, .icons-twitter, .icons-youtube {
background-image: url('../img/icons-sf7f5afa0d9.png');
background-repeat: no-repeat;
}
.icons-dribbble { background-position: 0 0; }
.icons-dribbble:hover, .icons-dribbble.dribbble-hover {
background-position: -32px 0;
}
/* … */
[class*=" icons-"], [class^="icons-"] {
/* … */
}

/* Les dimensions des sprites sont bien regroupées selon les trois
différentes tailles d’images dont nous disposions. */
.icons-dribbble, .icons-github {
height: 32px; width: 32px;
}
.icons-gplus, .icons-instagram, .icons-linkedin, .icons-youtube {
height: 128px; width: 128px;
}
.icons-twitter {
height: 64px; width: 64px;
}

En finir avec des compilations trop longues


Il a été dit en début de chapitre que Compass écrit l’image de la sprite map sur le
disque lorsque vous déclarez la variable qui la stocke dans une propriété background
ou background-image. La réalité est un peu plus subtile.

Origine du problème
Dans les faits, Compass construit l’image de la sprite map suite à l’appel à la fonction
sprite-map() et la conserve en mémoire. L’outil cherchera à l’écrire sur le disque :
• lorsque la variable est appliquée à n’importe quelle propriété CSS ;
• lors de l’appel aux fonctions sprite-url(), inline-sprite() et sprite().
À première vue, cela relève du détail. Pas tant que ça en réalité.
Création de sprites CSS avec Compass
225
CHAPITRE 6

En effet, à l’issue d’une compilation du projet, la console de Compass peut afficher


qu’il cherche à générer à plusieurs reprises la même sprite map (voir figure 6-22).
Ennuyeux, cela signifie que Compass effectue inutilement de nombreuses opérations.

Figure 6–22
Compass cherche à créer
l’image de sprite map à
plusieurs reprises.

Mais la situation devient critique si vous forcez la compilation à l’aide de l’argument


--force. Dans ce cas de figure, Compass ne se contente pas de vérifier si la sprite map
qu’il a en mémoire diffère de la version stockée sur le disque, mais il va simplement
supprimer l’image existante pour la recréer et, enfin, la sauvegarder sur le disque (voir
figure 06-23).

Figure 6–23
Une image de sprite map
recréée sans raison apparente

Par exemple, créer l’image de sprite map du jeu d’icônes WooFunctions (distribué
par Woothemes) qui contient 178 images nécessite 8,2 secondes sur ma machine (un
MacBook Pro de mi-2010). Si j’ai le malheur de faire six appels à des fonctions ou
variables qui déclenchent la sauvegarde de la sprite map sur le disque, le temps de
traitement augmente légèrement jusqu’à 8,5 secondes. Rien de dramatique.
Sass et Compass
226

En revanche, si je force la compilation, mon temps d’attente grimpe à 43,4 secondes !


Vous avez bien lu, la compilation est plus longue de 530 %. Reporté à une journée de
travail, cela représente une perte de temps non négligeable.

Solution
D’après les conditions qui régissent la création de l’image de sprite map sur le disque,
nous pouvons conclure que l’événement survient à chaque fois que nous demandons
l’URL d’accès à l’image. Pour répondre à notre requête, Compass a besoin d’écrire le
fichier sur le disque.
Si vous ne pouvez pas réduire vos nombres d’appels à un seul, la solution semble
évidente : mémoriser dans une variable le retour de la fonction sprite-url() et l’uti-
liser avec les autres fonctions de création manuelle de sprites CSS.
Voici un exemple pour remplacer des appels successifs à la fonction sprite() qui
retourne l’URL de la sprite map et la position d’une sprite.
État initial : Compass tente sauvegarder trois fois la sprite map

.top { background: sprite($map, 'arrow_up') no-repeat; }


.next { background: sprite($map, 'arrow_right') no-repeat; }
.bottom { background: sprite($map, 'arrow_down') no-repeat; }

Après correction, une seule sauvegarde de la sprite map est réalisée

$map-url: sprite-url($map);
.top {
background: $map-url sprite-position($map, 'arrow_up') no-repeat;
}
.next {
background: $map-url sprite-position($map, 'arrow_right') no-repeat;
}
.bottom {
background: $map-url sprite-position($map, 'arrow_down') no-repeat;
}

Évidemment, éviter de recourir à l’argument --force est aussi une solution à moindre
coût, mais qui ne résout pas le vrai problème.
Une astuce pour clore ce chapitre. Chunky PNG, le moteur Ruby de génération
d’images PNG utilisé par Compass pour créer les images sprite map n’est pas vrai-
ment véloce. Accélérez simplement le temps de création des images PNG en instal-
lant la gemme oily_png, écrite en C.
Création de sprites CSS avec Compass
227
CHAPITRE 6

Installer la gemme oily_png

$ gem install oily_png

Compass détectera sa présence sur le système et l’utilisera. Grâce à elle, le temps de


génération de l’image de sprites des 178 images du jeu d’icônes WooFunctions passe
de 8,2 secondes à 2,7 secondes. Un gain de temps impressionnant !

BONNE PRATIQUE Réduire le poids des images avant la création de la sprite map
Pour obtenir une sprite map légère et réduire les temps de traitement par Compass, pensez à optimiser le
poids de vos PNG avant la création de la sprite map. Vous devrez toujours passer la sprite map générée
dans un outil comme ImageOptim sous Mac OS X, Trimage sous Linux ou PNGGauntlet sous Windows
pour lui faire perdre quelques octets.

En résumé
La lecture de ce chapitre vous aura, je l’espère, convaincu dans votre choix d’intégrer
Compass à votre boîte à outils web. Les possibilités qu’il offre sont nombreuses, vous
n’avez que l’embarras du choix pour parvenir à vos fins !
Personnellement, le module de sprites de Compass est un des critères qui a le plus
pesé dans la balance lorsque j’ai eu à faire un choix entre les différents préprocesseurs
du marché. Et ce n’est pas prêt de changer. En effet, l’équipe de développement envi-
sage de prendre en charge d’autres formats que le PNG, comme le JPEG et, qui sait,
peut-être un jour le format vectoriel SVG.
Dans le prochain chapitre nous aborderons la gestion d’un projet Compass, avec
notamment la découverte de méthodes de débogage et l’apprentissage de la bonne
gestion des versions des gems.
7
Gérer un projet Compass :
un peu de méthodologie

Découvrez comment mener plusieurs projets Sass et Compass en parallèle ;


l’échange de fichiers entre collaborateurs se fera alors sans problème.

SOMMAIRE
B Apprendre à utiliser plusieurs versions de Sass et Compass
B Déboguer un projet
B Découvrir Source Maps pour un débogage survitaminé
B Choisir le mode de partage des feuilles de styles avec son équipe
Sass et Compass
230

Ce chapitre couvre tout d’abord un aspect de la gestion de projets Sass et Compass


qui peut être difficile à appréhender : la gestion de versions des outils. Il est en effet
essentiel pour le succès d’un projet de s’assurer que tous les intervenants travaillent
avec des outils identiques.
Dans un deuxième temps, il sera question de débogage de projets Sass et Compass.
Pour nous aider à faire la liaison entre la feuille de styles générée et les fichiers Sass,
le préprocesseur CSS offre plusieurs possibilités.
Enfin, la génération de CSS compressés pouvant poser problème dans le flux de tra-
vail d’une équipe, le chapitre s’achèvera sur des propositions de stratégies de gestions
des feuilles de styles CSS dans un projet placé sous contrôle de versions.

De la bonne gestion des versions de Sass et Compass


Lorsque vous travaillez régulièrement avec Sass ou Compass, il peut être difficile de
résoudre un cas de figure sans l’aide d’un logiciel qui automatise le processus d’instal-
lation, de mise à jour et de résolution des dépendances des gems.

Problèmes rencontrés
Tous les projets n’évoluent pas à la même vitesse. C’est la raison pour laquelle il arrive
fréquemment que plusieurs versions de Sass ou Compass soient utilisées dans une
même journée.
Imaginons par exemple que vous deviez intervenir sur un ancien projet qui utilise
une vieille version de Compass, comme la 0.10.6. Cette dernière est obsolète –
publiée fin octobre 2010 – au point que le passage à la dernière version stable en date
du framework n’est pas envisageable ; car vous ne disposez pas d’assez de temps.
Comment vous sortir de cette situation ?
Si vous aimez tester les nouveautés introduites dans les versions de développement
des outils, vous avez sans doute aussi pu vous retrouver dans la situation suivante.
Vous venez d’installer la version de développement de Sass pour la tester dans un
coin, puis vous travaillez sur un projet et là Compass refuse de fonctionner parce qu’il
est incompatible avec la version de développement de Sass. Qu’importe le projet, il
vous faut désormais utiliser la version de développement de Sass… Se reposer sur
une version sujette aux évolutions n’est pas confortable.
Voyons comment faire face ces situations.
Gérer un projet Compass : un peu de méthodologie
231
CHAPITRE 7

Le gestionnaire de paquets Bundler


Puisqu’il est question de gérer des versions de gems, ce qu’il nous faut est un gestion-
naire de paquets, comme ceux que nous utilisons pour maintenir notre base de logi-
ciels (dpkg, RPM, Homebrew, etc.). Dans l’écosystème RubyGems, le plus connu
s’appelle Bundler.

RESSOURCES Documentation de Bundler


Retrouvez la documentation en ligne de Bundler à l’adresse :
B http://bundler.io/

Déclarer les gems d’un projet


Bundler nous permet de maintenir les versions de gems d’un projet, ainsi que de
résoudre leurs dépendances à l’aide d’un simple fichier nommé Gemfile.
Dès que vous lancez une commande issue d’une gem, Bundler recherche dans le
répertoire courant un fichier Gemfile pour lire les contraintes fixées pour le projet. S’il
n’en trouve pas, l’outil remonte l’arborescence du système jusqu’à ce qu’il rencontre
un fichier Gemfile. Sa présence bénéficie donc à tous les sous-répertoires d’un projet.
Enfin, si aucun fichier Gemfile n’est trouvé, alors Bundler utilisera les versions des
gems disponibles sur le système.
Généralement déposé à la racine du projet, la syntaxe d’un Gemfile est facile à
appréhender.
Exemple de fichier Gemfile

source 'https://rubygems.org'
gem "compass"
gem "oily_png"

La première ligne sert à déclarer la source où chercher les gems. La version HTTPS
du site officiel de RubyGems est conseillée.
Les autres lignes du fichier indiquent que nous souhaitons bénéficier des versions
stables des gems compass et oily_png. Attention, ces versions sont stables au moment
où vous les installerez pour la première fois.

RESSOURCES Documentation des fichiers Gemfile


B http://bundler.io/gemfile.html
Sass et Compass
232

Pour utiliser une version spécifique d’une gem, il suffit de préciser sa version séparée
du nom par une virgule.
Déclaration d’une version spécifique de Compass

source 'https://rubygems.org'
gem "compass", "0.12.2"
gem "oily_png"

Il est également possible de déclarer des intervalles de versions, comme dans


l’exemple suivant qui indique à Bundler que votre projet accepte une version de
Compass supérieure ou égale à la version 0.12.2, mais qu’elle devra être strictement
inférieure à 0.13 :
Déclaration d’un intervalle de versions pour Compass

source 'https://rubygems.org'
gem "compass", ">= 0.12.2", "< 0.13"
gem "oily_png"

Notez que cette notation peut être allégée grâce à l’opérateur pessimiste ~> (égale-
ment connu sous le nom de spermy operator).
Utilisation de l’opérateur pessimiste

source 'https://rubygems.org'
gem "compass", "~> 0.12.2"
gem "oily_png"

L’opérateur pessimiste va satisfaire ici toutes les versions notées sous la forme 0.12.X,
où X sera supérieur ou égal à 2. De la même manière, si vous indiquez une version "~>
0.12", alors toutes les gems dont la version est de la forme 0.X avec X supérieur ou
égal à 12 seront acceptées.

RESSOURCES Trouver la bonne syntaxe


Un trou de mémoire sur la syntaxe de déclaration d’une gem ? Retenez une seule adresse web, celle du
projet RubyGems. Après avoir trouvé la gem qui vous intéresse à l’aide du moteur de recherche, le site
affiche dans un encart intitulé Gemfile la syntaxe à reporter dans votre fichier Gemfile pour bénéficier
de la version stable du projet.
Si une autre version de la gem vous intéresse, un encart Versions vous donne accès à la liste des versions
disponibles. Cliquez sur celle que vous rechercher pour afficher la page correspondante et son encart
Gemfile. Idéal pour déclarer une version de développement dans votre fichier Gemfile.
B http://rubygems.org/
Gérer un projet Compass : un peu de méthodologie
233
CHAPITRE 7

Installation de Bundler
Bundler est une gem comme Sass et Compass. Son installation est donc des plus simples.
Installer Bundler

$ gem install bundler

Une nouvelle commande bundle est à présent disponible sur votre système. Avant
d’étudier en détail l’utilisation de Bundler, sachez que l’outil peut lancer la bonne
version d’une gem dans un projet à l’aide de la commande bundle exec. Ainsi, la
commande pour lancer une compilation Compass devient :

$ bundle exec compass compile

Nombre de développeurs ont trouvé que la saisie répétée de ce préfixe était une pure
perte de temps. C’est pourquoi ils ont créé l’outil rubygems-bundler pour s’en affran-
chir. Distribué sous la forme d’une gem, son installation se fait en deux temps.
Installer rubygems-bundler

$ gem install rubygems-bundler


$ gem regenerate_binstubs

Après avoir installé la gem, il vous faut regénérer les environnements binaires (les
binstubs) déjà installés sur votre système.
Et c’est tout ! Vous n’aurez jamais à lancer la commande bundle exec et c’est pourquoi
vous ne la croiserez pas dans la suite du chapitre.

ALLER PLUS LOIN Désinstaller rubygems-bundler et Bundler


Si vous souhaitez désinstaller rubygems-bundler puis Bundler, il vous faudra lancer les commandes qui
suivent :
$ rubygems-bundler-uninstaller
$ gem uninstall rubygems-bundler
$ gem uninstall bundler

Installer les gems propres au projet


Pour le moment, vous n’avez fait qu’ajouter un fichier Gemfile à la racine du projet,
sans rien installer encore.
Lancez l’installation des gems déclarées et de toutes leurs dépendances à l’aide de la
commande bundle install, après vous être déplacé à la racine de votre projet :
Sass et Compass
234

Installation des gems du projet

$ cd my_project/
$ bundle install
Fetching gem metadata from https://rubygems.org/.............
Fetching gem metadata from https://rubygems.org/..
Enter your password to install the bundled RubyGems to your system: 
Installing chunky_png (1.2.8) 
Using fssm (0.2.10) 
Using sass (3.2.10) 
Installing compass (0.12.2) 
Installing oily_png (1.1.0) with native extensions 
Using bundler (1.2.3)
Your bundle is complete! Use 'bundle show [gemname]' to see where a
bundled gem is installed.

Décryptons les actions réalisées par Bundler.


 Bundler ne possède pas suffisamment de permissions pour écrire les gems sur le
système. Il demande notre mot de passe utilisateur afin qu’il puisse obtenir les privi-
lèges du super-utilisateur root.
 La gem chunky_png est installée par Bundler parce qu’elle est une dépendance de
Compass.
 Les gems fssm et sass sont également des dépendances de Compass mais,
puisqu’elles sont déjà présentes sur ce système, Bundler indique qu’il utilisera les ver-
sions existantes au lieu de les installer.
 Finalement, les deux gems indiquées dans le fichier Gemfile sont installées.
Notez que RubyGems permet d’avoir plusieurs versions d’une même gem sur son
système. Pour afficher la liste des versions installées, utilisez la commande gem list
<gem> :

Cinq versions de Compass sont installées sur le système

$ gem list compass


compass (0.12.2, 0.12.1, 0.11.5, 0.10.6)

Bundler utilisera automatiquement la version requise par votre projet.


Pour y parvenir, après installation des gems du projet, Bundler crée, au même niveau
que le fichier Gemfile, un fichier Gemfile.lock qui est une cartographie des versions des
gems et de leurs dépendances à utiliser. Désormais, à chaque appel à la commande
bundle, l’outil lira ce fichier Gemfile.lock pour respecter les contraintes du projet.

Il est donc important de ne pas supprimer le fichier Gemfile.lock.


Gérer un projet Compass : un peu de méthodologie
235
CHAPITRE 7

MÉTHODE Installer les gems dans votre projet


Peut-être souhaitez-vous ne pas polluer l’environnement global de vos RubyGems et, à la place, vous
préféreriez installer les gems dans un répertoire local à votre projet ? Bundler le permet en précisant le
chemin d’installation des gems à l’aide de l’option --path :
$ bundle install --path vendors/bundle
C’est la méthode utilisée par le fichier d’installation livré avec les codes sources du livre : pour chaque
projet, les gems sont installées dans un dossier caché .vendors/ afin de ne pas interférer avec votre
environnement.
Cette technique est idéale pour tester localement une version de développement de Sass ou de Compass.

Maintenant, si on lance la commande compass version depuis différents emplace-


ments sur le système, la version utilisée diffère conformément aux versions qui ont
été précisés dans les différents fichiers Gemfile.
Absence de Gemfile : utilisation de la version globale de Compass

$ cd ~/
$ cat Gemfile
cat: Gemfile: No such file or directory
$ compass version
Compass 0.12.1 (Alnilam)

Un Gemfile est trouvé déclarant Compass 0.12.2

$ cd ~/my_project/
$ cat Gemfile
source 'https://rubygems.org'
gem "compass", "0.12.2"
gem "oily_png"
$ compass version
Compass 0.12.2 (Alnilam)

Un Gemfile est trouvé déclarant une version de développement de Compass

$ cd ~/my_beta_project/
$ cat Gemfile
source "https://rubygems.org"
gem "compass", "~> 0.13.alpha"
gem "rb-fsevent", "~> 0.9"
gem "oily_png", "~> 1.1.0"
$ compass version
Compass 0.13.alpha.4 (Markab)
Sass et Compass
236

Cycle de vie des gems d’un projet avec Bundler


La gestion de versions des gems d’un projet avec Bundler se résume à deux
commandes : bundle install et bundle update. En un mot, bundle install gère les
modifications apportées au fichier Gemfile et bundle update les mises à jour des gems
déjà prises en charge par Bundler.
Un petit exemple pour clarifier l’explication. Soit le fichier Gemfile suivant :

source 'https://rubygems.org'
gem "compass"
gem "sass-globbing"

Au moment de la rédaction de ces lignes, lancer la commande bundle install va ins-


taller la version 0.12.2 de Compass et la version 1.1.0 de sass-globbing, ainsi que
leurs dépendances.
Supposons que vous souhaitiez maintenant utiliser une version antérieure de la gem
sass-globbing. Il faut éditer le fichier Gemfile pour préciser la version.

source 'https://rubygems.org'
gem "compass"
gem "sass-globbing", "1.0.0"

La commande bundle install va détecter la demande de régression de version et ins-


taller la version antérieure de la gem. Elle va également mettre à jour le fichier
Gemfile.lock pour mémoriser le nouveau choix.

Imaginez maintenant que vous ne souhaitiez plus utiliser la gemsass-globbing. Sup-


primez la ligne correspondante du fichier Gemfile puis lancez la commande bundle
install. Bundler supprime la référence à sass-globbing du fichier Gemfile.lock et
résout les nouvelles dépendances.
Bundler ne supprime pas du système la gem sass-globbing, si elle a été installée glo-
balement. Sa désinstallation relève de votre responsabilité, à l’aide de la commande
qui suit.
Désinstaller du système une gem devenue inutile

$ gem uninstall sass-globbing

En revanche, si les gems avaient été installées dans un répertoire dédié à l’aide de
l’option --path, il faudrait lancer la commande bundle clean depuis le répertoire géré
par Bundler. L’outil va automatiquement supprimer les gems inutilisés. L’exemple qui
suit est le résultat d’une régression de Sass version 3.3.0.alpha.229 à 3.3.0.alpha.103.
Gérer un projet Compass : un peu de méthodologie
237
CHAPITRE 7

Supprimer d’un répertoire géré par Bundler les gems devenues inutiles

$ bundle clean
Removing ffi (1.9.0)
Removing listen (1.1.6)
Removing rb-fsevent (0.9.3)
Removing rb-inotify (0.9.1)
Removing rb-kqueue (0.2.0)
Removing sass (3.3.0.alpha.229)

Tout cela est très bien, mais à quel moment la commande bundle update entre-t-elle
en action ? Comme son nom l’indique, cette commande se charge de mettre à jour
une gem existante. Admettons que Compass 0.13.0 soit publié (yes!) et que vous
aimeriez en bénéficier sur le projet. Lancez la commande bundle update <gem> pour
réaliser la mise à jour.
Mise à jour de la version de Compass

$ bundle update compass

Le fichier Gemfile.lock est également mis à jour en conséquence. Pour rappel, la mise
à jour de Compass vers la version 0.13.0 depuis la version 0.12.2 a été possible parce
qu’aucune version n’était précisée dans le fichier Gemfile.

ATTENTION N’oubliez pas de préciser le nom de la gem


Exécuter la commande bundle update dépourvue du nom d’une gem va entraîner la
mise à jour en masse de toutes les gems gérées par Bundler dans le projet. À moins
d’être sûr de ce que l’on fait, il est préférable de procéder à une mise à jour manuelle
des gems au moment où l’on souhaite monter de version.

Pour résumer…
• Il faut toujours utiliser en premier lieu la commande bundle install.
• Si l’on souhaite qu’une gem monte de version ou si une mise à jour ne se fait pas
comme attendu, il faut utiliser la commande bundle update <gem>.

Partager son projet géré par Bundler


Jusqu’ici, il a été à plusieurs reprises question du fichier Gemfile.lock. Et pour cause,
il joue un rôle essentiel dans le partage entre plusieurs intervenants d’un projet géré
par Bundler.
Sass et Compass
238

En effet, le fichier Gemfile.lock est un instantané des versions de gems utilisées dans
un projet. Lorsqu’un nouvel intervenant récupère le projet, ce fichier doit également
être transmis. Bundler le détectera et l’utilisera à la place du fichier Gemfile pour con-
figurer l’environnement de développement du nouvel intervenant.
Il assure ainsi que toute personne qui travaille sur le projet utilisera les mêmes ver-
sions de gems requises. Fini les régressions surprises entre deux commits.
Vous l’aurez compris, si vous travaillez avec un gestionnaire de versions – comme
Git, Mercurial ou Subversion – vous devez versionner le fichier Gemfile.lock en plus
du fichier Gemfile.
Si l’intérêt de cette manipulation est difficile à appréhender, il faut tenter d’imaginer
un fichier Gemfile qui liste des gems sans jamais préciser de versions ; c’est-à-dire
qu’il demande les dernières versions stables en date des différentes gems. La com-
mande bundle install fait son office, puis, seul le fichier Gemfile est transmis au ges-
tionnaire de version. Tous les intervenants du projet récupèrent le projet dans la
foulée et lancent l’installation des gems. Tout le monde travaille bien avec les mêmes
versions de gems.
Trois mois plus tard, un nouvel intervenant récupère le projet et l’installe. Entre-
temps, une version majeure stable d’une des gems (au hasard Compass) a été publiée.
Rien ne va plus : le nouveau collègue travaille sur une version de Compass qui peut
avoir un impact sur les styles produits.
Et c’est ainsi que commence le ballet des régressions entre les commits du nouvel
intervenant et d’un ancien qui travaille avec version de Compass plus ancienne, mais
qui avait été choisie au moment du développement du projet.
Bref, versionnez – ou à défaut partagez – le fichier Gemfile.lock de votre projet. Il est le
garant d’une gestion saine et cohérente des versions de gems utilisées dans un projet.

MÉTHODE Un Gemfile averti en vaut deux : indiquez les versions !


Personnellement, j’indique explicitement les versions des gems principales utilisées dans le projet. Par
« principale » j’entends les gems clés du projet. Pour un projet Compass, j’indique par exemple les ver-
sions des gems compass et sass alors même que cette dernière est une dépendance de la première.
Tant pis, je préfère répéter une information que de risquer l’apparition d’une gem dont je ne maîtrise pas
les dernières évolutions.
Gérer un projet Compass : un peu de méthodologie
239
CHAPITRE 7

Déboguer un projet Sass


Par défaut, lorsqu’une erreur survient lors de la compilation des feuilles de styles,
Sass (et Compass) l’affichent dans le terminal.

$ sass --scss --watch -t expanded sass:css


>>> Sass is watching for changes. Press Ctrl-C to stop.
>>> Change detected to: sass/styles.scss
error sass/styles.scss (Line 25: wrong number of arguments
(1 for 2) for 'desaturate')

Au cas où vous n’auriez pas vu l’erreur, Sass va carrément injecter l’erreur dans le
corps de la page HTML grâce à la propriété CSS content. Comme l’illustre la
figure 7-1, il est ainsi impossible d’ignorer une erreur !

Figure 7–1
Des erreurs qui ne passent
pas inaperçues.

Cette fonctionnalité de Sass est intéressante pour détecter rapidement les erreurs de
syntaxe. Elle est néanmoins inefficace dans la difficile tâche de déboguer un style
tombé sous le joug de la cascade CSS.

Exploiter les informations de débogage de Sass


Une difficulté rencontrée par les nouveaux utilisateurs de Sass et de Compass est
l’incapacité à déboguer facilement une feuille de styles générée par le préprocesseur.
En effet, dans les outils de développement des navigateurs (Firebug, DevTools, etc.),
nous n’avons accès qu’aux feuilles de styles compilées et non aux fichiers sources Sass
(voir figure 7-2). À moins de parfaitement maîtriser son projet, il peut être difficile
de s’y repérer.
Sass et Compass
240

Heureusement, avec le temps Sass s’est enrichie de méthodes d’aides au débogage.

Figure 7–2
Par défaut, seules
les références aux fichiers
compilés sont accessibles
depuis le navigateur.

La première méthode apparue est l’ajout d’informations de débogage dans les feuilles
de styles. L’ajout de ces informations s’active grâce à l’option --debug-info (ou -g) de
la commande sass, ou avec l’option :debug-info dans le fichier de configuration de
Compass.
Activer les informations de débogage dans Compass

css_dir = "css"
images_dir = "img"
sass_options = {
:debug_info => true
}

Désormais, la compilation du projet va ajouter pour chacune des règles CSS le fichier
et la ligne qui l’a généré (voir figure 7-3). Ces informations, isolées dans une requête
de média spécifique, sont lues normalement par le navigateur mais n’ont pas d’impact
sur la feuille de styles car les sélecteurs utilisés (filename et line) n’existent pas en
HTML (voir figure 7.4).
Gérer un projet Compass : un peu de méthodologie
241
CHAPITRE 7

Figure 7–3
Des informations de débogage
précèdent chaque règle CSS.

Figure 7–4
Les marques de débogage
sont lues comme de simples
règles CSS.

Cependant, les informations de débogage ajoutées sont inexploitables en l’état puisque


le navigateur les traite comme de simples styles CSS. Les plug-ins FireSass pour
Mozilla Firefox (attention, ce dernier nécessite la présence du plug-in FireBug) et Sass
Inspector pour Google Chrome existent pour nous aider à exploiter ces informations.

RESSOURCES Plug-ins de lecture des informations de débogage Sass


FireSass pour Firefox, développé par l’actuel mainteneur de Sass, Nathan Weizenbaum :
B https://addons.mozilla.org/fr/firefox/addon/firesass-for-firebug/
Sass Inspector, un portage de FireSass sur Chrome :
B http://goo.gl/uaG5Ce

Une fois installés, ces plug-ins changent l’affichage de l’inspecteur d’éléments du


navigateur : la référence au fichier CSS et la ligne d’apparition de la règle de styles est
Sass et Compass
242

remplacée par leurs équivalents Sass (voir figure 7-5). Il est ainsi bien plus simple de
localiser son intervention dans le projet Sass pour résoudre un bogue.

Figure 7–5
FireSass affiche la position de la
règle CSS dans les sources Sass.

Le poids ajouté par les informations de débogage est important. Il est donc essentiel
de les désactiver avant de pousser en production les feuilles de styles, ou mieux, de
compiler le projet avec le type de sortie compressé. Pour cela, il faut préciser l’option
-t compressed à la ligne de commande de Sass, ou ajouter l’option output_style =
compressed dans le fichier de configuration de Compass. Avec Compass, vous pouvez
aussi définir l’environnement de production lors de la compilation des styles à l’aide
de l’argument -e production.
Ces informations de débogage sont utiles mais restent un obstacle au flux de travail.
En effet, des allers et retours incessants entre le navigateur et notre éditeur de code
sont obligatoires pour modifier les sources Sass.

Focus sur une solution en devenir : Source Maps


Les Source Maps offrent un moyen, indépendant de tout langage de programma-
tion, de faire le lien entre le code délivré au navigateur et le code original qui a servi à
le générer.
Cela se révèle d’autant plus pratique que le format du code original diffère du code
généré. Ce qui est justement le cas avec Sass : nous travaillons sur des fichiers SCSS
Gérer un projet Compass : un peu de méthodologie
243
CHAPITRE 7

dont la structure et l’organisation du code diffèrent totalement de ceux des feuilles de


styles lues par les navigateurs.
Pour cela, le préprocesseur doit fournir un fichier dit « de mapping », ayant pour
extension .map. Son format et ce qu’il contient nous importent peu ici. L’essentiel
étant que cela fonctionne !

AVERTISSEMENT Prise en charge balbutiante de Source Maps


Avant de continuer la lecture de cette partie, sachez que le support de Sass dans les
Source Maps par les navigateurs est très récent au moment de l’écriture de cet
ouvrage. C’est pourquoi une version de développement de Google Chrome est utili-
sée pour illustrer les exemples. Il y a fort à parier que toutes ces fonctionnalités
seront rapidement intégrées à la version stable de ce navigateur. Souhaitons aussi
son support natif par Mozilla Firefox !
De la même manière, Sass supporte la génération des Source Maps à partir de la
future version stable 3.3.0, actuellement en développement. Pour Compass, la situa-
tion est plus difficile : à l’heure où j’écris ces lignes, il est impossible de produire des
Source Maps avec Compass. Mais la situation devrait rapidement évoluer !
Pour information, voici les versions utilisées dans le chapitre :
• Google Chrome 30 (version stable : 28)
• Sass 3.3.0.alpha.229 et 3.3.0.alpha.103 (version stable : 3.2.10)
Si ces versions de développement vous intéressent, je vous conseille de les installer
dans un projet isolé via Bundler. Pour commencer, renseignez à la racine de votre
projet le Gemfile qui suit :
source "https://rubygems.org"
gem "sass", "~> 3.3.0.alpha.229"
Lancez maintenant l’installation des gems en n’oubliant pas de préciser l’option --path
pour ne pas polluer votre environnement global :
$ bundle install --path .vendors/bundle

Activer le support de Source Maps dans Sass


Activer la création d’un fichier de mapping entre les sources Sass du projet et les
feuilles de styles générées se résume à ajouter l’argument --sourcemap à la ligne de
commande du préprocesseur.
Un fichier de mapping est créé en même temps que la feuille de styles

$ sass --watch --scss --sourcemap sass:css


>>> Sass is watching for changes. Press Ctrl-C to stop.
write css/styles.css
write css/styles.css.map
Sass et Compass
244

Conformément aux recommandations de la spécification de Source Maps, Sass


ajoute dans la feuille de styles générée un commentaire qui sera lu par le navigateur,
pour que ce dernier puisse trouver le fichier de mapping styles.css.map.
Indication de l’accès au fichier de mapping

/* … */
.hero {
margin: 1em; }

/*# sourceMappingURL=styles.css.map */

SYNTAXE Bénéficier de Source Maps sur des feuilles de styles compressées


Si vous souhaitez bénéficier de Source Maps avec une feuille de styles compressée, ajoutez simplement
en fin de fichier le commentaire de localisation du fichier de mapping.

Activer le support de Source Maps dans Compass


Les explications qui suivent sont à considérer avec beaucoup de prudence ! En effet,
Compass ne supporte pas encore Source Maps. En attendant un réel support de
Source Maps par le framework CSS3, il est cependant possible d’en bénéficier sous
trois conditions :
1 Utiliser la versions de développement de Sass version 3.3.0.alpha.103 et la ver-
sions stable de Compass 0.12.2.
2 Il vous faut utiliser la commande sass et non compass pour lancer la compilation
de votre projet.
3 Le fichier de configuration du projet doit obligatoirement se nommer config.rb et
être situé au même niveau que le dossier depuis lequel vous lancez la compilation.
Ces précautions prises, la commande pour lancer la surveillance d’un projet est la
suivante.
Béquille pour utiliser Source Maps depuis Compass

$ sass --scss --sourcemap--compass --watch sass:css

Bien entendu, vous devrez remplacer les répertoires sass/ et css/ conformément aux
spécificités de votre projet.
Il est possible que plusieurs messages d’alerte concernant les ressources statiques
(images, polices, etc.) s’affichent. Rien de grave, Sass est encore incapable de pro-
duire les fichiers Source Maps pour ces fichiers. C’est justement l’un des nombreux
éléments que doivent prendre en compte l’équipe de développement de Compass.
Gérer un projet Compass : un peu de méthodologie
245
CHAPITRE 7

Activer le support de Source Maps dans le navigateur


À l’heure actuelle, seul Google Chrome supporte Source Maps pour les fichiers Sass.
En effet, Firefox, le navigateur de la fondation Mozilla, a intégré son support mais
uniquement pour les sources JavaScript : il devient dès lors possible de se repérer
dans un fichier JavaScript minifié.
Nul besoin d’extension, il est toutefois nécessaire de réaliser quelques opérations
pour activer le support de Source Maps dans Google Chrome (version 30).

RESSOURCES Activer le support de Source Maps dans Firefox


Les équipes de Mozilla fournissent de gros efforts pour enrichir Firefox d’outils natifs pour développeurs
afin de pourvoir se passer d’extensions comme Firebug qui posent de gros soucis de performance. Ils ont
ainsi doté la nouvelle boîte à outils de Firefox du support de Source Maps.
Pour l’activer, ouvrez le débogueur JavaScript via le raccourci clavier Ctrl + Maj + S (Alt + Maj + S sous
Mac OS X), puis, dans le panneau qui s’ouvre, déroulez ses options par un clic sur la roue dentée et, fina-
lement, cochez l’option Show original sources (Afficher les sources originales).
B https://developer.mozilla.org/en-US/docs/Tools/Debugger#Use_a_source_map

VERSION Une procédure d’activation bientôt obsolète ?


Vous l’aurez remarqué, j’insiste lourdement sur les numéros des versions utilisées. Et pour cause : peut-
être que lorsque vous lirez ces lignes, les procédures d’activation de Source Maps auront disparues et se
résumerons à une simple case à cocher dans les préférences des outils de développement de Chrome.
C’est aussi ça un Web qui évolue vite !

En premier lieu, vérifiez que les expérimentations pour les outils de développement
soient bien activées. Pour cela, rendez-vous à l’adresse about:flags puis recherchez la
ligne Activer les expérimentations dans les outils de développement (astuce : recherchez
dans la page le terme « expérimentation »). Si ce n’est pas fait, activez-les (voir
figure 7-6).
Relancez le navigateur puis affichez les DevTools de Google Chrome aussi appelés
outils de développement (Afficher>Options pour les développeurs>Outils de développe-
ment ou Maj + Ctrl + I ou Alt + Cmd + I sous Mac OS X). Dans le panneau qui
s’affiche, cliquez sur la roue dentée située dans le coin inférieur droit (voir figure 7-7).
Le panneau de configuration des outils de développement apparaît. Cochez les cases
Enable CSS source maps (Activer les sources maps CSS) et Auto-reload generated CSS
(Recharger automatiquement les CSS générées).
Vous pouvez fermer le panneau de configuration, le support de Source Maps est
directement disponible dans les pages qui sont déjà ouvertes !
Sass et Compass
246

Figure 7–6
Les outils expérimentaux sont
indispensables pour bénéficier
de Source Maps.

Figure 7–7
Accéder à la configuration
des outils de développement
Gérer un projet Compass : un peu de méthodologie
247
CHAPITRE 7

Figure 7–8
À deux cases à cocher
du support de Source Maps
dans Chrome

Voyons maintenant comment profiter de Source Maps pour Sass dans Google Chrome.

Exploiter les Source Maps du préprocesseur dans le navigateur


Le support de Source Maps dans Google Chrome offre un accès rapide aux styles
écrits dans les fichiers sources Sass.
Par exemple, après avoir inspecté un élément, dans le panneau Styles de droite, un clic
sur la localisation d’une des règles CSS appliquée (comme styles.scss:51) vous
amène dans le panneau Sources où sera ouvert le fichier SCSS positionné sur la règle
correspondante (voir figure 7-9).

Figure 7–9
Appréciez la coloration
syntaxique SCSS !
Sass et Compass
248

Maintenant, si vous souhaitez accéder à la déclaration d’une valeur d’une propriété,


comme la couleur de fond de page, cliquez dessus en maintenant enfoncée la touche
Ctrl ou Cmd sous Mac OS X (voir figure 7-10). Chrome vous positionne automati-
quement sur sa déclaration dans les sources SCSS. Mieux, si la valeur est renseignée
dans les sources SCSS par le biais d’une variable, vous serez placé à l’endroit même
où la variable a été initialisée (voir figure 7-11). Procédez de même en cliquant sur la
propriété pour accéder à sa déclaration dans le fichier source Sass (voir figure 7-12).

Figure 7–10
Ctrl + clic sur la valeur
d’une propriété

Ce que nous venons de voir est l’usage basique de Source Maps dans Chrome. En
effet, le navigateur nous permet d’aller beaucoup plus loin pour améliorer notre flux
de travail. Il offre notamment la possibilité d’éditer et de sauvegarder nos modifica-
tions directement sur le disque local.
Il faut tout d’abord lier le répertoire du projet à la page affichée. Dans la termino-
logie Chrome, cela consiste à ajouter le répertoire à l’espace de travail ou workspace.
Dans le panneau de gauche de l’onglet Sources, cliquez droit sur le répertoire du
projet affiché sous le nom du domaine utilisé pour y accéder (soit source-maps situé
sous localhost dans la figure 7-13), puis sélectionnez Add Folder to Workspace
(Ajouter le dossier à l’espace de travail). Parcourez votre système de fichiers jusqu’à
sélectionner le répertoire correspondant à celui que vous souhaitez lier (pour réaliser
l’exemple, j’ai sélectionné le répertoire /var/www/htdocs/source-maps/).
Gérer un projet Compass : un peu de méthodologie
249
CHAPITRE 7

Figure 7–11
Un accès rapide à la déclaration
de la variable utilisée pour
définir la couleur de fond
de page

Figure 7–12
La propriété était déclarée
dans un mixin.
Sass et Compass
250

Figure 7–13
Lier un dossier système
à l’espace de travail

Figure 7–14
Liaison d’un fichier à un fichier
présent dans le workspace
Gérer un projet Compass : un peu de méthodologie
251
CHAPITRE 7

Une fois le répertoire à ajouter à l’espace de travail choisi, DevTools en demande


l’accès complet. Acceptez. Maintenant, une boîte de dialogue vous propose de
relancer les outils de développement afin de prendre en compte la modification.
Acceptez à nouveau.
Lors de la dernière étape, vous devez lier chaque fichier Sass de votre système que
vous souhaitez éditer à un fichier présent dans l’espace de travail : toujours dans le
panneau de gauche de l’onglet Sources, cliquez droit sur le fichier Sass que vous sou-
haitez éditer depuis Chrome (style.scss dans l’exemple), puis cliquez sur l’entrée de
menu Map to File System Resource (Lier à un fichier du système, voir figure 7-14).
Dans la fenêtre volante qui s’affiche, sélectionnez le fichier correspondant (voir
figure 7-15). Attention, veillez bien à ne pas choisir un fichier situé dans le répertoire
.sass-cache/ du projet.

Figure 7–15
Recherche du fichier à lier dans
l’espace de travail

La liaison du fichier est désormais effective : modifiez le fichier depuis Chrome et


enregistrez directement vos modifications sur le disque à l’aide du raccourci Ctrl + S
(ou Cmd + S). Répétez l’opération pour chaque fichier à éditer depuis les outils de
développement de Chrome, fichiers partiels y compris puisqu’ils remontent dans
l’onglet Sources.
Déclenchez une surveillance Sass du projet et le préprocesseur lancera automatique-
ment sa compilation à chaque enregistrement d’un fichier depuis votre navigateur.
Magique ! Vos méthodes de travail ne seront désormais plus les mêmes.

OUPS Rechargement automatique des feuilles de styles


Je vous avais fait cocher l’option Auto-reload generated CSS qui doit normalement recharger les feuilles
de styles de la page lorsqu’elles sont modifiées. Au moment de la rédaction du chapitre, cette fonction-
nalité ne marche pas encore. Lorsqu’elle sera opérationnelle, vous pourrez abandonner les solutions
payantes telles que LiveReload.
Sass et Compass
252

Travailler en équipe
Avec Bundler, nous avons déjà eu un aperçu des pratiques qui favorisent le travail en
équipe. Le gestionnaire de paquets pour RubyGems assure un environnement de déve-
loppement pour Sass et Compass identique pour chaque intervenant sur le projet.
Voyons comment renforcer vos méthodes de travail en équipe.

Stratégies de gestion des styles CSS générés


Une question qui revient fréquemment lors d’échanges sur les réseaux sociaux ou à
l’occasion de cycles de conférences est l’épineuse problématique de gestion des
feuilles de styles générées par le préprocesseur.
• Faut-il les publier dans le gestionnaire de versions ? Compressées ou non ?
• Faut-il les ignorer et lancer la compilation sur un serveur de développement ?
• Devrait-on utiliser une script de déploiement ?
Toutes ces questions conduisent à des réponses différentes, contextualisées par votre
flux de travail et c’est pourquoi il serait bien prétentieux de ma part de vous donner la
solution. À la place, voici des pistes de réflexions qui vous conduiront, je l’espère, à
opter pour la solution qui convient le mieux à votre projet.
Dans tous les cas de figure envisagés, il est primordial que chaque intervenant déve-
loppe et compile le projet en local ! Il est à mon sens inconcevable que l’on puisse
partager un code qui ne fonctionne pas, ou pire, qui affiche une erreur de syntaxe
Sass sur le site.

Stratégie 1 : versionner les styles CSS compressés


Vous décidez de versionner les feuilles de styles générées par le préprocesseur. Très
bien, mais dans ce cas versionnez les formes compressées. Ce choix vous évitera bien
des déboires.
J’ai déjà eu à gérer une situation où un prestataire externe intervenait directement
dans les feuilles de styles et non dans les sources SCSS. On aimerait éviter. D’autant
plus qu’il ne m’en avait pas informé, et ce qui devait arriver arriva : j’ai écrasé ses
modifications sans comprendre pourquoi le site subissait une régression. Fournir des
versions compressées décourage ce genre d’initiatives.
Un autre avantage à versionner les feuilles de styles générées est que le projet est pré-
sentable immédiatement après sa récupération : inutile de lancer une installation ou
de faire quoi que ce soit si un de vos collaborateurs doit en faire la présentation
depuis son poste de travail.
Gérer un projet Compass : un peu de méthodologie
253
CHAPITRE 7

Ciel, un conflit !
Le principal inconvénient de versionner les CSS est de s’exposer à un conflit entre
votre version locale et la version entrante à chaque mise à jour du dépôt local.
La solution est pourtant simple : si vous récupérez des changements dans les feuilles
de styles c’est qu’inévitablement les sources SCSS ont elles aussi évolué. Dès lors,
vous devrez à nouveau compiler le projet Sass avant de commiter et diffuser vos pro-
pres modifications.
Ainsi, si vous travaillez avec Subversion, qu’importe la version que vous acceptez (la
vôtre ou la rentrante) : les fichiers CSS seront dans tous les cas écrasés suite à la com-
pilation qui précédera le commit.
Avec Git, la logique est exactement la même en cas de conflit : vous tenez compte de
l’une des deux versions du fichier, vous l’ajoutez à l’index de Git puis effectuez le
commit qui termine le merge. Plus facile à dire qu’à faire ? Pas du tout. Prenons
l’exemple d’un conflit qui survient suite à la mise à jour de la branche sur laquelle
vous travaillez.

RESSOURCE Mémento Git à 100 %


R Pierre Habouzit et Raphaël Hertzog, Mémento Git à 100 %, Eyrolles 2012

Le début d’un conflit

$ git pull
Auto-merging css/styles.css
CONFLICT (content): Merge conflict in css/styles.css
Automatic merge failed; fix conflicts and then commit the result.

Vérifions le statut de la copie locale.


Le conflit est confirmé

$ git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 1 and 1 different commit each, respectively.
# (use "git pull" to merge the remote branch into yours)
#
# You have unmerged paths.
# (fix conflicts and run "git commit")
#
# Changes to be committed:
#
Sass et Compass
254

# modified: css/styles.css.map
#
# Unmerged paths:
# (use "git add <file>..." to mark resolution)
#
# both modified: css/styles.css

Le merge effectué par Git échoue effectivement sur une feuille de styles. Les deux
fichiers ont évolué et leur format compressé empêche Git de résoudre le conflit auto-
matiquement.
Conformément à la marche à suivre annoncée, acceptez l’un des deux fichiers en pré-
cisant l’option --theirs (les leurs) à la commande git checkout. Git récupérera ainsi
la version entrante du fichier. Si vous préférez récupérer votre version locale, rem-
placez l’option --theirs par --ours (les nôtres).
Accepter la copie entrante du fichier css/styles.css

$ git checkout --theirs -- css/styles.css

Aucune indication visuelle ne permet de savoir si la commande a eu un quelconque


effet, même en affichant le statut du dépôt local (à l’aide de la commande git
status). En revanche, si vous éditez le fichier concerné, vous constaterez que son
contenu a évolué pour correspondre à celui de la version entrante, ou qu’il est resté
inchangé si vous avez opté pour l’option --ours.
Il suffit ensuite de suivre les indications données par Git pour marquer le conflit
comme résolu et achever le merge. À savoir :

$ git add css/styles.css


$ git commit

Il ne vous reste plus qu’à compiler le projet Sass pour intégrer les évolutions entrantes
à vos propres modifications, puis de commiter le tout : fichiers SCSS et CSS.

Stratégie 2 : utiliser un script de déploiement


Une autre solution pour gérer les feuilles de styles générées par Sass et Compass est
de ne pas les versionner. La compilation finale est alors à la charge d’un script de
déploiement.
Gérer un projet Compass : un peu de méthodologie
255
CHAPITRE 7

Chaque intervenant du projet compile le projet en local, pour s’assurer du bon fonc-
tionnement du code Sass, mais il se contentera de commiter les sources utiles au pré-
processeur. Ni les feuilles de styles, ni les sprites générés, ni les fichiers Source Maps
ne seront poussés dans le gestionnaire de versions. Ainsi, aucune résolution de conflit
n’est à prévoir sur ces éléments.
Pour faciliter les déploiements, un tag qui balise une étape stable du développement
sera créé. Ce tag sera utilisé par le script de déploiement pour récupérer le projet puis
générer les feuilles de styles. Éventuellement, le script pourra optimiser toutes les
images de sprites construites par Compass. Enfin, le projet compilé sera poussé sur le
serveur de recette, de développement ou de production suivant le besoin.
Cette solution est de loin la plus robuste, mais nécessite des compétences en interne
pour créer et gérer un tel script.

Documentez !
Après toutes les considérations techniques, la bonne gestion d’un projet Sass et
Compass passe avant tout par sa documentation.
Un fichier README.md (ou README si vous n’êtes pas un fan de la syntaxe Markdown) à
la racine du projet ne mange pas de pain et permet d’expliciter vos choix techniques
comme celui des gems et leurs versions utilisées, ou encore les motivations de l’archi-
tecture retenue.
De même, une procédure d’installation est toujours bonne à prendre. Elle profitera à
tout nouvel intervenant sur le projet et vous économisera bien des questions.
N’hésitez pas non plus à faire débuter chacun de vos fichiers Sass, partials y compris,
par une notice qui décrit le rôle du fichier. Par ailleurs, expliquez-y le rôle de chacun
des variables, mixins et fonctions créés même si leurs noms vous semblent explicites.
En effet, vos collègues interpréteront peut-être différemment ces noms et pourront
passer à côté de certaines subtilités.
Enfin, n’oubliez pas que CSS est déjà un langage difficile à documenter et à appré-
hender pour les personnes qui n’ont pas elles-mêmes rédigé les règles de styles. Dès
lors, imaginez la difficulté que peuvent rencontrer certains intervenants devant de
multiples héritages de placeholders. N’hésitez pas à stocker dans un commentaire,
même succinct, la raison de l’héritage effectué.
Quelques exemples…
Sass et Compass
256

Partial _block--lang_dropdown.scss

// Bloc Language switcher dropdown


// ===============================
//
// Le bloc Language switcher dropdown est fourni par le module
// **Language Dropdown**. Il permet de sélectionner la langue du site.
.block-lang-dropdown {

}

Décrire un module, même brièvement, pour gagner en clarté

// ## Liste de documents à télécharger


//
.list-docs {
@extend %module-list-unstyled;
}
// Un item de la liste de documents
.list-docs--item {
// On aère un peu l'affichage en ligne pour faciliter le clic au doigt.
@include rem('margin', nth($layout-inner_space, 1) 0);
}
// Le lien de la ressource à télécharger
.list-docs--link {
text-decoration: none;
&:before {
content: "";
@include main-sprite('icon-download', true);
// On aligne le picto par rapport au lien.
position: relative; top: 2px;
}
}

Un petit rappel de la situation est toujours bon à prendre

// Il est important de cibler la région du contenu éditorial sous peine


// de surcharger des menus ou Listview des autres régions, comme
// Post Content.
// Exemple : surcharge des h2 munis de la classe '.listview--heading'
// situés dans la région Post Content.
.region-content {
h2, p {
margin-bottom: .5em;
}
}
Gérer un projet Compass : un peu de méthodologie
257
CHAPITRE 7

Expliquer son choix

.form-text, textarea, .form-select {


// Pour les champs textuels et les sélecteurs, nous inhibons le zoom
// réalisé par l'OS sur le champs lors de sa prise de focus.
// Voir http://stackoverflow.com/q/2989263/392725
// Note : ajoutez la classe 'no-fx-unzoom' sur un élément pour ne pas
// appliquer le correctif.
&:focus:not(.no-fx-unzoom) {
@include rem('font-size', 16px);
}
}

Commenter une variable pour aider la compréhension de son format

// Dimensions (largeur hauteur) des items.


$damier__item-size: ($damier-font_size * 2) ($damier-font_size * 2 );

En résumé
De la gestion des versions des gems utilisées sur le projet à la bonne communication
des sources du projet entre les intervenants, en passant par les conseils d’organisation
présentés dans le chapitre 4, vous possédez maintenant toutes les clés pour gérer effi-
cacement un projet Compass.
Ainsi s’achève notre exploration de Sass et de Compass.
A
Configuration avancée
avec Compass

SOMMAIRE
B Maintenir un casseur de cache personnalisé
B Afficher des notifications Growl sous Mac OS X
B Partager des fichiers entre plusieurs projets
Sass et Compass
260

Maintenir un casseur de cache personnalisé


Nous l’avons vu au chapitre 5, la fonction image-url() de Compass suffixe automati-
quement toute URL d’image d’un casseur de cache (cache buster) sous la forme d’un
argument d’URL (query string) :
URL générée pour une image après usage de image-url()

.logo {
background-image: url('/img/logo.png?1374695188');
}

Très utile pour forcer le navigateur à recharger l’image depuis le serveur si elle a été
modifiée, ce paramètre peut poser problème avec un proxy. En effet, certains proxies
excluent de leur cache les ressources pourvues d’un paramètre, signe probable d’une
requête personnalisée.
Pour rappel, un serveur proxy (ou serveur mandataire) est un intermédiaire entre le
réseau local et l’extérieur dont l’une des fonctions peut consister à accélérer la naviga-
tion des clients du réseau local. Pour ce faire, il stocke en cache les ressources stati-
ques téléchargées, qu’il sert ensuite aux machines du réseau local. Les clients locaux
n’ont alors plus besoin de récupérer ces ressources statiques depuis les sites d’origine,
ce qui permet de réduire les temps de chargement des pages.
Calculé à partir de la date de dernière modification de l’image, le casseur de cache de
Compass peut être personnalisé via la fonction de configuration asset_cache_buster.
Comme il s’agit d’une fonction à ajouter dans le fichier configuration du projet, son
code devra être écrit en Ruby.
La fonction asset_cache_buster prend deux arguments : l’URL du fichier et son
chemin réel sur le disque. Elle doit renvoyer une chaîne de caractères ou un hash, ou
la valeur nil (nul).
Si une chaîne de caractères est renvoyée, elle est directement ajoutée à l’URL en tant
que casseur de cache, et automatiquement préfixée du caractère ?. Lorsque la valeur
retournée est un hash, alors deux valeurs sont attendues : :path et :query qui sont res-
pectivement la nouvelle URL de l’image et la nouvelle query string.
Ainsi, la fonction qui suit va intégrer dans le nom des images leurs dates de dernière
et ne renseigne pas de query string :
Configuration avancée avec Compass
261
ANNEXE A

Un casseur de cache personnalisé

asset_cache_buster do |path, real_path|


if File.exists?(real_path)
pathname = Pathname.new(path)
modified_time = File.mtime(real_path).strftime("%s")
new_path = "%s/%s-%s%s" % [
pathname.dirname,
pathname.basename(pathname.extname),
modified_time,
pathname.extname]
{:path => new_path, :query => nil}
end
end

Après une nouvelle compilation du projet, le précédent exemple devient :

.logo {
background-image: url('/img/logo-1374695188.png');
}

La query string a bien disparu et, désormais, chaque modification du fichier logo.png
entraînera la mise à jour de l’URL servie au navigateur.
Puisque la fonction asset_cache_buster se contente de modifier l’URL de l’image, le
fichier logo-1374695188.png n’existe pas sur le disque. Il faut préciser à votre serveur la
méthode qui lui permettra d’accéder au bon fichier. Avec un serveur Apache, la
configuration qui suit est suffisante (à intégrer dans la configuration de votre Virtual
Host ou dans un fichier .htaccess) :
Configuration Apache associée

<IfModule mod_rewrite.c>
RewriteEngine On 
RewriteCond %{REQUEST_FILENAME} !-f 
RewriteRule ^(.+)-\d+\.(png|jpe?g|gif)$ $1.$2 [L] 
</IfModule>

 La première ligne du bloc de la directive IfModule active le moteur de réécriture


d’URL d’Apache.
 La ligne d’après teste la présence sur le disque du fichier demandé. S’il n’existe
pas, alors la ligne qui suit est lue, sinon elle est ignorée. Cela garantit de pouvoir con-
tinuer à servir des images qui existent réellement dans votre projet, même si leur nom
se termine par une suite de chiffres.
Sass et Compass
262

 Enfin, la dernière ligne va tester le nom du fichier demandé pour valider son
format :
1 ^(.+)- : capture tous les caractères depuis le début du nom de fichier jusqu’à ren-
contrer un tiret (qui est exclu de la capture).
2 \d+\. : le nom du fichier doit ensuite posséder au moins un chiffre, suivi par un
point.
3 (png|jpe?g|gif) : l’extension du fichier doit être png ou jpg ou jpeg ou gif. Elle est
capturée.
Finalement la règle retourne au navigateur la bonne image en concaténant les deux
captures séparées par un point ($1.$2) pour reconstituer le nom de l’image présente
sur le disque. Le drapeau [L] (pour Last, la dernière) indique à Apache de ne pas lire
d’éventuelles règles qui suivraient celle-ci, puisque le bon fichier a été trouvé.

NOTE Une fonction non appliquée aux sprites


Les images des sprite maps ne sont pas concernées par le casseur de cache. En effet, Compass en intègre
déjà un nativement sous la forme du suffixe -s<cache buster>.

Afficher des notifications Growl sous Mac OS X


Sous Mac OS X, les utilisateurs peuvent disposer du système de notification Growl.
Voyons comment en profiter dans un projet à l’aide de quelques lignes de code Ruby.

B http://growl.info/

L’exemple qui suit se repose sur la gem ruby_gntp. N’oubliez pas de l’installer sur votre
système ou de renseigner la ligne gem "ruby_gntp" dans le fichier Gemfile de votre projet.
annexeA/growl-notification/config.rb

sass_dir = "."
css_dir = "."

# Utilisation du système de notifications Growl lorsque la gem


# ruby_gntp est disponible. Aucune erreur ne sera émise par Ruby
# sur les systèmes qui en sont dépourvu.
begin
require "ruby_gntp"
Configuration avancée avec Compass
263
ANNEXE A

# Définition des attributs communs aux notifications.


# Important :
# Utilisez si possible le même :app_name entre tous vos projets.
# Chaque nouveau nom ajoute une entrée dans l'onglet Applications
# de Growl.
growl_data = {
:app_name => "Compass",
# Personnalisez le chemin de l'icône de la notification à afficher.
# Ici, l'icône compass_icon.png est située au même niveau que le
# fichier de configuration.
:icon => "#{File.expand_path('./compass_icon.png')}",
}

# Affichage d'une notification Growl lorsqu'une feuille de styles


# est sauvegardée sur le disque.
on_stylesheet_saved do |filename|
GNTP.notify(growl_data.clone.merge({
:title => "Mise à jour d'une CSS",
:text => "#{File.basename(filename)}",
}))
end

# Affichage d'une notification Growl lorsqu'une erreur de compilation


# est survenue.
on_stylesheet_error do |filename, message|
GNTP.notify(growl_data.clone.merge({
:title => "Erreur de compilation",
:text => "#{File.basename(filename)}: #{message}",
:sticky => true, # La notification sera persistante
}))
end

# Affichage d'une notification Growl lorsqu'une sprite map


# est sauvegardée sur le disque.
on_sprite_saved do |filename|
GNTP.notify(growl_data.clone.merge({
:title => "Sprite sauvegardé",
:text => "#{File.basename(filename)}",
}))
end
rescue LoadError
end
Sass et Compass
264

AVIS L’alternative compass-growl


Au détour d’une recherche, peut-être avez-vous découvert l’existence de la gemcompass-growl, destinée
à afficher automatiquement les notifications Growl que nous venons de créer. Cette gem fonctionne mais
présente à mes yeux trois faiblesses :
1. Elle produit l’inutile notification Compass Growl has been initialized à chaque compila-
tion.
2. L’application enregistrée dans Growl possède le nom générique fourni par la gem ruby_gntp, à savoir
Ruby/GNTP. Il devient dès lors impossible de personnaliser l’affichage des notifications de Compass
indépendamment des autres applications qui se déclarent sous le nom Ruby/GNTP.
3. L’icône des notifications n’est pas personnalisable.
À l’inverse, la gem compass-growl a pour avantage d’éviter la duplication de code entre les projets. Il
vous suffit de l’installer ou de la déclarer dans vos fichiers Gemfile puis de la charger dans vos fichiers
de configuration à l’aide du code qui suit :
begin
require "compass-growl"
rescue LoadError
end
B http://rubygems.org/gems/compass-growl

Partager des fichiers entre plusieurs projets


Certaines interfaces graphiques pour Sass et Compass vantent leur capacité à per-
mettre le partage des mêmes fichiers entre plusieurs projets. En réalité, tout le mérite
en revient à Sass et Compass, qui font tout le travail.
Supposons un répertoire contenant deux projets, l’un utilisant Sass et l’autre Com-
pass. Tous deux possèdent un fichier source styles.scss dans lequel est utilisé un
mixin ppm-absolute. Or, ce mixin est déclaré dans le fichier position.scss du réper-
toire pmm/ qui est situé dans un dossier lib/ en dehors des deux projets. L’arbores-
cence est la suivante :
Arborescence de l’exemple

~/livre-sass/annexeA/load-path
lib/
ppm/
position.scss
projet-compass/
config.rb
styles.scss
projet-sass/
styles.scss
Configuration avancée avec Compass
265
ANNEXE A

styles.scss

.sample-absolute {
@include ppm-absolute($left: 10px, $top: 1em);
background: deepskyblue;
height: 10em;
width: 10em;
}

Pour disposer du mixin, nous devons donc charger le fichier position.scss depuis le
fichier styles.scss à l’aide de l’instruction @import.

Mise en œuvre avec Sass


Une première solution, quelque peu naïve, consisterait à écrire l’instruction :

@import "../lib/ppm/ppm-position"

Cela va fonctionnera effectivement, mais à condition d’adapter le chemin dès que


votre projet Sass ne sera pas situé au même niveau que le répertoire lib/. Autant dire
que vous devrez l’adapter pour chacun de vos projets.
Suite à ce constat, le deuxième réflexe est de préciser le chemin d’accès absolu au
fichier :
styles.scss

@import "~/livre-sass/annexeA/load-path/lib/ppm/position"
.sample-absolute { … }

La transformation du fichier se solde cependant par un échec . En effet, comme le


précise Sass en erreur, le préprocesseur ne connaît qu’un seul emplacement pour
rechercher les fichiers à importer, à savoir le répertoire courant  :
Première tentative de transformation du fichier SCSS

$ cd ~/livre-sass/annexeA/load-path/projet-sass/
$ sass styles.scss
Syntax error: File to import not found or unreadable: ppm-position. 
Load path: ~/livre-sass/annexeA/load-path/projet-sass 
on line 1 of styles.scss
Use --trace for backtrace.
Sass et Compass
266

Ainsi, la solution la plus robuste consiste à permettre au préprocesseur d’effectuer des


recherches de fichiers à importer dans le répertoire lib/. Pour cela, ajoutez l’option
--load-path <path> à la commande sass pour rendre accessible le chemin <path>.

Avant de lancer la compilation du fichier, n’oubliez pas d’importer le fichier ppm/ppm-


position.scsssans préciser le répertoire lib/ :
styles.scss

@import "ppm/position";
.sample-absolute {
@include ppm-absolute($left: 10px, $top: 1em);
background: deepskyblue;
height: 10em;
width: 10em;
}

La compilation se déroule correctement :


Sass trouve le mixin ppm-absolute

$ sass --load-path ~/livre-sass/annexeA/load-path/lib styles.scss


.sample-absolute {
position: absolute;
top: 1em;
left: 10px;
background: deepskyblue;
height: 10em;
width: 10em; }

Notez que vous pouvez spécifier plusieurs répertoires comme chemins possibles de
chargement de Sass, en répétant autant de fois que nécessaire l’option --load-path.

MÉTHODE De l’importance de regrouper vos fichiers partagés


Pour faciliter le partage de fichiers SCSS entre les projets, il est conseillé de les
regrouper dans un répertoire — comme ppm/ dans l’exemple — qui sera enfant du
dossier ajouté aux chemins de chargement (comme lib/).
Le chargement des fichiers SCSS sera préfixé par le nom du dossier de regroupement,
vous assurant que le bon fichier est chargé – plutôt qu’un éventuel fichier portant le
même nom situé dans votre projet.
Configuration avancée avec Compass
267
ANNEXE A

Mise en œuvre avec Compass


Les observations précédentes sont également valables pour un projet Compass. Seule dif-
fère la méthode pour déclarer un répertoire supplémentaire aux chemins de chargement.
Au lieu de passer une option à la commande compass, il faut ajouter le chemin dans le
fichier de configuration du projet à l’aide de la fonction de configuration
add_import_path. Afin de permettre à Compass d’accéder plus rapidement aux
fichiers, on utilise la méthode Ruby File.expand_path() pour enregistrer le chemin
réel du dossier (/Users/mehdi/livre-sass/annexeA/load-path/lib dans mon cas) :
config.rb

sass_dir = "."
css_dir = "."
add_import_path File.expand_path("~/livre-sass/annexeA/load-path/lib")

Compass retrouve bien le fichier ppm-position.scss

$ cd ~/livre-sass/annexeA/load-path/projet-compass/
$ compass compile
create ./styles.css
$ cat styles.css
/* line 3, styles.scss */
.sample-absolute {
position: absolute;
top: 1em;
left: 10px;
background: deepskyblue;
height: 10em;
width: 10em;
}

Puisque add_import_path est une fonction et non une variable de configuration, vous
pouvez répéter son usage dans le fichier de configuration pour ajouter plusieurs
répertoires comme chemins de chargement, sans craindre d’écraser les anciens che-
mins ajoutés.
B
Guide de survie de l’interface
en ligne de commande

SOMMAIRE
B Apprendre les rudiments de l’interface en ligne de commande
B Manipuler le système de fichiers
Sass et Compass
270

NOTE Le cas de Windows


L’interface en ligne de commande de Windows est limitée par rapport à celles que l’on trouve sur des sys-
tèmes comme Linux et Mac OS X. Il est généralement plus simple d’utiliser l’explorateur de fichiers du
système d’exploitation pour manipuler les fichiers.
C’est pourquoi la présente annexe ne traitera pas de Windows.

L’invite de commandes
Lorsqu’une interface de ligne de commande est prête pour recevoir des instructions,
une invite de commandes est affichée. Couramment désignée par l’anglicisme
prompt, elle consiste en un ensemble de caractères en début de ligne, indiquant sou-
vent le nom de la machine, le nom de l’utilisateur, le chemin système courant.
L’invite de commandes se termine généralement par un caractère comme $, > ou #
qui invite l’utilisateur à saisir une commande (voir chapitre 1).
L’invite de commandes par défaut sous Mac OS X

sphax:~ mehdi$

Sous Mac OS X, l’invite de commandes débute par le nom de la machine (ici, sphax).
Séparé par un double point, suit le dernier répertoire du chemin courant ~ qui
signifie que je suis dans mon répertoire utilisateur (le caractère ~ étant un raccourci
pour /Users/<nom>). Nous verrons plus loin comment nous déplacer dans le système
de fichiers, mais sachez que la commande pwd (pour Print Working Directory,
« afficher le répertoire de travail ») permet d’afficher le répertoire courant :

$ pwd
/Users/mehdi

La dernière partie de la ligne de commandes est le nom de l’utilisateur de la session


Mac OS X – en l’occurrence, mehdi.

Lister les fichiers


Vous pouvez afficher la liste des fichiers du répertoire courant à l’aide de la com-
mande ls (pour list) :
Guide de survie de l’interface en ligne de commande
271
ANNEXE B

Afficher la liste des fichiers du répertoire courant

sphax:~ mehdi$ ls
Applications Downloads Public Pictures
Code Dropbox README Sites
Desktop Hello World.txt Movies
Documents Library Music

Faciliter la lecture de la liste de fichiers


La distinction entre les dossiers et les fichiers n’est pas facile à faire dans l’exemple
précédent. Ajoutez l’option -p à la commande pour voir s’afficher le caractère / à la
fin des dossiers :
Des fichiers visibles au premier coup d’œil

sphax:~ mehdi$ ls -p
Applications/ Downloads/ Public/ Pictures/
Code Dropbox/ README Sites/
Desktop/ Hello World.txt Movies/
Documents/ Library/ Music/

La sortie est déjà plus lisible et fait ressortir le fichier Code qui pouvait être considéré
comme un répertoire de par son absence d’extension. Notez que vous pouvez rem-
placer l’option -p par l’option -F pour différencier plus de types de fichiers, comme
les liens symboliques (sortes de raccourcis vers un autre fichier ou répertoire).
Pour gagner encore en lisibilité, vous pouvez afficher une sortie en couleurs à l’aide de
l’option -G sous Mac OS X (et tout système BSD) ou l’option --color sous Linux.
Enfin, le format d’affichage condensé peut être difficile à lire, ou pas assez informatif
(il ne donne pas le poids des fichiers, par exemple). La commande ls dispose de
l’option -l (avec un L minuscule) pour produire une sortie enrichie :
Sortie longue de la commande ls

sphax:~ mehdi$ ls -l
total 10
drwxr-xr-x 6 mehdi staff 204 17 aoû 02:12 Applications
-rw-r--r-- 13 mehdi staff 2599 31 jul 23:23 Code
drwx------+ 6 mehdi staff 204 20 aoû 14:29 Desktop
drwx------+ 12 mehdi staff 408 19 aoû 10:52 Documents
drwx------+ 516 mehdi staff 17544 21 aoû 01:01 Downloads
drwx------@ 17 mehdi staff 578 19 aoû 11:50 Dropbox
-rw-r--r-- 1 mehdi staff 0 21 aoû 02:17 Hello World.txt
drwx------@ 57 mehdi staff 1938 6 aoû 11:28 Library
Sass et Compass
272

drwx------+ 3 mehdi staff 102 12 déc 2012 Movies


drwx------+ 4 mehdi staff 136 27 déc 2012 Music
drwx------+ 8 mehdi staff 272 23 jan 2013 Pictures
drwxr-xr-x+ 5 mehdi staff 170 14 déc 2012 Public
-rw-r--r-- 1 mehdi staff 0 21 aoû 02:24 README
drwxr-xr-x 2 mehdi staff 68 14 déc 2012 Sites

Il est possible de combiner plusieurs options comme ls -l -p --color, voire de regrouper


toutes les options d’une seule lettre : ls -lp --color (ls -lpG sous Mac OS X).
L’option -h (pour human) permet d’afficher le poids des fichiers dans un format plus
facilement compréhensible par un humain (nous parlons rarement en octets) :
Des poids de fichiers compréhensibles

sphax:~ mehdi$ls -lFh


total 10
drwxr-xr-x 6 mehdi staff 204B 17 aoû 02:12 Applications/
-rw-r--r-- 13 mehdi staff 2,5K 31 jul 23:23 Code
drwx------+ 6 mehdi staff 204B 20 aoû 14:29 Desktop/
drwx------+ 12 mehdi staff 408B 19 aoû 10:52 Documents/
drwx------+ 516 mehdi staff 17K 21 aoû 01:01 Downloads/
drwx------@ 17 mehdi staff 578B 19 aoû 11:50 Dropbox/
-rw-r--r-- 1 mehdi staff 0B 21 aoû 02:17 Hello World.txt
drwx------@ 57 mehdi staff 1,9K 6 aoû 11:28 Library/
drwx------+ 3 mehdi staff 102B 12 déc 2012 Movies/
drwx------+ 4 mehdi staff 136B 27 déc 2012 Music/
drwx------+ 8 mehdi staff 272B 23 jan 2013 Pictures/
drwxr-xr-x+ 5 mehdi staff 170B 14 déc 2012 Public/
-rw-r--r-- 1 mehdi staff 0B 21 aoû 02:24 README
drwxr-xr-x 2 mehdi staff 68B 14 déc 2012 Sites/

Vous pouvez vous reporter à l’aide intégrée à votre système d’exploitation pour en apprendre d’avantage
sur cet affichage, par exemple à l’aide de la commande man ls (man comme manuel).

Afficher les fichiers cachés


Dans les différents chapitres du livre, il est question de dossiers cachés comme .sass-
cache/, .bundle/ ou encore .vendors/. Sur les systèmes de type Unix (*nix comme
Linux, BSD, Mac OS X, etc.), un fichier est masqué lorsqu’il débute par un point
(comme le fichier .htaccess dont vous avez certainement déjà croisé la route).
Guide de survie de l’interface en ligne de commande
273
ANNEXE B

Pour les afficher, ajoutez l’option -a à la commande ls :


Sans affichage des fichiers cachés

sphax:demo mehdi$ ls -F
Gemfile css/ sass/
Gemfile.lock index.html

Avec l’affichage des fichiers cachés

sphax:demo mehdi$ ls -aF


./ .sass-cache/ Gemfile.lock sass/
../ .vendors/ css/
.bundle/ Gemfile index.html

Se déplacer dans le système de fichiers


Vous pouvez changer de répertoire avec la commande cd (pour change directory). La
commande cd attend pour seul argument le nom de la nouvelle destination :

sphax:~ mehdi$ cd Documents


sphax:Documents mehdi$

Notez que l’invite de commande a changé pour afficher le nouveau répertoire de tra-
vail. Utilisez la commande pwd pour vérifier le chemin d’accès complet du répertoire
courant :

sphax:Documents mehdi$ pwd


/Users/mehdi/Documents

Revenir dans son répertoire personnel


Trois méthodes existent pour revenir dans votre répertoire personnel. De la plus
longue à la plus rapide nous avons :
• cd /User/<nom> avec <nom> correspondant à votre nom d’utilisateur (ou /home/<nom>
sous Linux) ;
• cd ~ ;
• ou simplement cd dépourvu d’argument.
Sass et Compass
274

Remonter dans l’arborescence


Dans la section sur les fichiers cachés, l’exemple affichait les deux dossiers cachés ./ et ../
qui représentent respectivement le dossier listé et un accès à son répertoire parent.
Ainsi, utilisez la commande cd .. pour remonter au dossier parent. Vous pouvez
remonter de plusieurs niveaux dans l’arborescence en séparant plusieurs .. par un slash :
Descendre et remonter dans l’arborescence de fichiers

sphax:~ mehdi$ cd ~
sphax:~ mehdi$ cd Documents/
sphax:Documents mehdi$ pwd
/Users/mehdi/Documents

sphax:Documents mehdi$ cd ..
sphax:~ mehdi$ pwd
/Users/mehdi

sphax:~ mehdi$ cd Documents/Articles/Blog/


sphax:Blog mehdi$ pwd
/Users/mehdi/Documents/Articles/Blog

sphax:Blog mehdi$ cd ../..


sphax:Documents mehdi$ pwd
/Users/mehdi/Documents

Alterner entre deux emplacements


Si vous devez vous déplacer plusieurs fois entre deux dossiers, utilisez le raccourci cd -
(avec un tiret) après vous être déplacé la première fois. La commande affiche le nouveau
répertoire après son exécution.
Ainsi, si je me positionne dans mon répertoire utilisateur :

sphax:Documents mehdi$ cd
sphax:~ mehdi$ pwd
/Users/mehdi

puis que je me déplace dans un répertoire différent :

sphax:~ mehdi$ cd Documents/Articles/Blog/


sphax:Blog mehdi$ pwd
/Users/mehdi/Documents/Articles/Blog
Guide de survie de l’interface en ligne de commande
275
ANNEXE B

je peux maintenant retourner au précédent emplacement (mon répertoire utilisateur)


avec la commande cd -.

sphax:Blog mehdi$ cd -
/Users/mehdi

Je peux aussi saisir la commande cd ../../.. parce que je veux remonter de trois niveaux dans
l’arborescence du système de fichiers, mais c’est bien plus long.

Je peux ainsi très facilement alterner entre les deux emplacements :

sphax:~ mehdi$ cd -
/Users/mehdi/Documents/Articles/Blog
sphax:Blog mehdi$ cd -
/Users/mehdi
sphax:~ mehdi$ cd -
/Users/mehdi/Documents/Articles/Blog

Manipuler les fichiers

Créer un fichier
Créez un nouveau fichier à l’aide de la commande touch <nom> :
Créer un fichier Gemfile vide

$ touch Gemfile

Un fichier vide est alors créé. La commande touch accepte un ou plusieurs noms de
fichiers qui peuvent être situés à différents niveaux d’arborescence :
Création de trois fichiers vides

$ touch Gemfile config.rb sass/styles.scss

Créer un répertoire
Créez un répertoire avec la commande mkdir <nom> (pour make directory) :
Sass et Compass
276

Créer le répertoire du projet et un sous-dossier sass/

$ mkdir projet
$ cd projet
$ mkdir sass
$ ls -F
sass/

La commande mkdir accepte un ou plusieurs noms de dossier :


Création de trois répertoires en une seule commande

$ mkdir css img js


$ ls -F
css/ img/ js/ sass/

La commande mkdir produira une erreur si vous lui demandez de créer un sous-
répertoire dans un répertoire qui n’existe pas encore. C’est-à-dire qu’elle ne peut pas
créer d’arborescence :

$ cd ~
$ mkdir projet2/sass
mkdir: projet2: No such file or directory

Ajoutez l’option -p et la commande mkdir créera l’arborescence demandée :

$ mkdir -p projet2/sass
$ ls -F projet2/
sass/

Copier des fichiers


La copie d’un fichier s’effectue à l’aide de la commande cp <source> <destination>
(pour copy) :
Copier un fichier

$ cp screen.scss ie.scss

Vous pouvez cibler des fichiers situés dans des répertoires extérieurs au dossier cou-
rant. Dans l’exemple qui suit, le fichier config.rb d’un autre projet est copié dans le
répertoire courant. Parce que nous souhaitons conserver le même nom de fichier,
nous indiquons le dossier courant (./) comme destination de la copie :
Guide de survie de l’interface en ligne de commande
277
ANNEXE B

Copie d’un fichier extérieur au projet

$ cp ../autre-projet/config.rb ./

Si nous voulons changer le nom du fichier copié, il suffit de le préciser :


Copier un fichier dans un fichier avec un nom différent

$ cp ../autre-projet/config.rb compass.rb

La copie d’un répertoire nécessite l’ajout de l’option -r ou -R à la commande :


Copier du dossier partials/ d’un autre projet dans le répertoire sass/ du dossier courant

$ cp -r ../autre-projet/sass/partials sass/

ATTENTION Copie de dossier sous Mac OS X


Sous Mac OS X et tout autre système BSD, si vous ajoutez un slash (/) au dossier
source, seul le contenu du dossier sera copié et non le dossier lui-même !

Déplacer des fichiers


La commande mv <source> <destination> (pour move) permet de déplacer des
fichiers et des répertoires :
Déplacer un fichier d’un autre projet dans le répertoire courant

$ mv ../autre-projet/styles.scss ./

Déplacer un fichier du répertoire courant dans un autre projet

$ mv styles.scss ../autre-projet/

La commande mv est également utilisée pour renommer les fichiers puisqu’au final
cela revient à déplacer un fichier sous un nom différent :
Renommer un répertoire

$ mv projet1 projet2
Sass et Compass
278

Supprimer des fichiers

ATTENTION Une suppression irréversible


L’interface en ligne de commande ne dispose pas de corbeille. C’est à dire que tout
fichier ou dossier supprimé sera irrémédiablement perdu, sans possibilité de retour
en arrière comme c’est le cas avec la corbeille. Préférez passer par l’explorateur de
fichiers de votre système d’exploitation si vous avez la moindre hésitation quant aux
arguments à passer à la commande rm.

Supprimez un ou plusieurs fichiers à l’aide de la commande rm (pour remove). Une


confirmation de suppression des fichiers vous sera demandée. Répondez-y par y
(pour oui) pour confirmer ou n (pour non) pour décliner l’action :
Supprimer un fichier

$ rm css/screen.css
remove css/screen.css? y

Supprimer plusieurs fichiers

$ rm css/screen.css css/print.css
remove css/screen.css? y
remove css/print.css? y

Il est possible de confirmer par défaut la suppression des fichiers en ajout l’option -f
(pour forcer) à la commande :
Supprimer plusieurs fichiers sans confirmation

$ rm -f css/screen.css css/print.css

La suppression d’un répertoire est par défaut interdite. Précisez l’option -r ou -R


pour autoriser l’effacement récursif d’un dossier :
La suppression d’un dossier échoue

$ rm css
rm: css: is a directory

Supprimer un répertoire sans confirmation

$ rm -rf css
Guide de survie de l’interface en ligne de commande
279
ANNEXE B

ATTENTION sudo rm -rf /


Des plaisantins s’amusent parfois aux dépens des personnes les moins expérimentées
avec le shell. L’exemple le plus connu est la commande sudo rm -rf / donnée en
réponse à une question posée sur un forum. Ne lancez jamais cette commande, qui a
pour effet de lance la suppression de tout le contenu de votre disque dur ! L’instruc-
tion sudo est utilisée pour obtenir les permissions nécessaires à la manipulations des
fichiers de tout le système. Elle est associée à la commande rm forcée (-f) sur la racine
du disque dur (/), et ce de manière récursive (-r).
Je ne peux que vous conseiller d’être attentif avant d’exécuter toute commande de
suppression rm.

Motifs de remplacements
Toutes les commandes abordées dans cette annexe acceptent les deux motifs de rem-
placement suivants :
• l’astérisque * pour représenter n’importe quelle succession de caractères ;
• le point d’interrogation ? pour représenter n’importe quel caractère.
Par exemple, pour afficher la liste de toutes les images PNG du répertoire courant,
vous allez utiliser la commande ls *.png :

$ ls
connectivity.png effects_3d.jpg multimedia.png performance.png
device_access.gif logo.png offline_storage.png semantics.jpg
$ ls *.png
connectivity.png effects_3d.png multimedia.png
logo.png offline_storage.png performance.png

Le motif de remplacement peut-être écrit à n’importe quel endroit. Dans l’exemple


qui suit, le motif * est utilisé pour copier tous les fichiers SCSS qui commencent par
la chaîne de caractères ie :

$ ls sass/
app.scss
$ ls ../autre-projet/sass/
ie.scss ie8.scss
ie7.scss screen.scss
$ cp ../autre-projet/sass/ie*.scss sass/
$ ls sass/
app.scss ie7.scss
ie.scss ie8.scss
Index
@extend 88
# (caractère) voir Interface en ligne de commande commentaire
#{…} (motif) voir Interpolation important 34
$ (caractère) voir Interface en ligne de commande silencieux 33
& (caractère) voir Sélecteur parent fonction zip 118
Internet Explorer 27, 64, 110
A placeholder 76, 89, 91
Arborescence portée de variable 41
organiser 124 sélecteur parent 27
renforcer 129 sprites CSS
B génération automatique 213
Bibliothèque 144, 158 haute définition 217
charger 145, 158 par dimensions 221
installer 145 valeur null 99
Bonnes pratiques variable par défaut 54
préfixer 122 Cascade CSS 72, 84, 87, 88, 239
variable par défaut 55 Casseur de cache 162
Boucles 110, 112 désactiver 162
à rebours 111 personnaliser 260
Bundler 231, 232, 243, 252 Chrome 1, 74, 177, 241, 243, 245, 247
déclarer des gems 233 Clever Age 2, 4, 182
désinstaller 233 Code tierce partie 128
installer 233 CodeKit 16
maintenir 236 Commentaire
nettoyer 237 CSS 33
publier 237 important 34
utiliser 233, 235 silencieux 33
supprimer 33
C Compass
Cache 143, 157 histoire 1
buster voir Casseur de cache installation 6
Canal versions 6, 200, 202, 203, 212
alpha 107, 117, 118 Compass.app 15
couleur (de) 107 Compiler
Cas d’usage automatiquement 143, 157
@content 82 manuellement 142, 156
Sass et Compass
282

un fichier Sass 17, 24 .scss 22


un projet Compass 156 optionnelle 45
un projet Sass 142
Concaténation 106
F
Conflit Feuille de styles partielle 45, 49, 53, 125
merge 253 réutiliser 130
résoudre 253, 254 Fichier de configuration 149, 150
Cookieless 125, 153, 154 options (liste) 151
Cross-browser 159, 160, 176, 179, 180, 220 Firebug 239
CSS Firefox 74, 177, 180, 183, 241, 243, 245
cascade 87 Fonction
hack 182 arguments (optionnels) 114
sélecteurs 31, 78 chaînes (sur les) 114
CSS3 couleurs (sur les) 115
@font-face 174 créer 121
background (multiple) 62, 177 font-files 176
border-radius 171 headers 176
box-shadow 172 hsl 96
linear-gradient 178, 181 hsla 96
radial-gradient 177 image-url 161
sélecteurs 31 introspection 120
text-shadow 174 listes (sur les) 118
numériques 115
D rgb 95, 107
Data-URI 164 rgba 96, 107
sprite CSS 202 type-of 97
Déboguer 239 url 45, 51, 161
Source Maps voir Source Maps utilitaires 121
Définition front-end 2, 25, 34, 44, 100
héritage 66
mixin 55
G
Source Maps 242 Gemfile 231, 232, 233, 243, 273
sprite CSS 186 Gemfile.lock 234, 236, 238
sprite map 187 Git 238
sprite sheet 187 conflit (résoudre) 253, 254
variable 36 Github 128, 145, 170
Division (opérateur de) 103, 106 Google Font API 51
Documentation 166 Growl 262
DRY 66, 69, 88, 97, 120, 165, 169 GUI voir Interface graphique
Guillemets (choix de) 95
E
Équipe 252
H
Extension Haml 22
.css 51 Haute définition 217
.sass 22 Héritage 66, 83, 88
Index
283

maîtriser 74 Internet Explorer 27, 64, 117, 181, 182


placeholder 75 désactiver (support) 184
sémantique 70, 74 filtre 95, 178
utiliser 69 Interpolation 42, 104, 111
HSL 96, 115 Introspection 120
I K
Image 161 KISS 120
Data-URI 164
dimensions 163
L
Imbriquer Layout 75, 76, 77, 129, 132, 134, 210
@import 49 Loud comment voir Commentaire important
groupes de sélecteurs 29 M
Media Queries 79 Maintenance 21, 43, 51, 52, 56, 78, 123, 128, 129,
propriétés 32 134, 135, 139, 182, 186, 189
règles voir Règles imbriquées Media Queries 65, 79, 82, 217, 220
Importer 45, 49, 169 imbriquer 79
Inception 88 limitations 83
Installation variables 81
de Compass 6 Mixin 57, 58
de Ruby 6, 13 arguments 59
de Sass 6 liste 62
de XCode 10 par défaut 61
sous Linux 14 bloc de contenu 64
sous Mac OS X 6 déclarer 55
sous Windows 12 limitations 63, 65
Interface en ligne de commande 8, 124, 127, 270 utiliser 56, 67
cd 273 Mixture 16
cp 276
ls 270 O
mkdir 275 oily_png 226
mv 277 Optimiser
pwd 270 arborescence 43
répertoire personnel 273 code 86
rm 278 code (réutiliser) 55
sous Mac OS X (ouvrir) 7 compilation 226
sous Windows (ouvrir) 12 imbrications 86
touch 275 poids 69, 135, 227
Interface graphique sélecteurs 139, 207
CodeKit 16 P
Compass.app 15 Partial voir Feuille de styles partielle
Mixture 16 Performance 34, 44, 74, 100, 125, 134, 164, 186
Prepros 16 Placeholder 74, 89, 131, 135, 137
Scout 16 déclarer 74
Sass et Compass
284

étendre 75 de Compass 20
ordre 91 de Sass 19
Plug-in voir Bibliothèque quitter 19
Préfixes constructeurs 170 SMACSS 134, 139
Prepros 16 Source Maps 242
Projet Compass activer
configuration voir Fichier de configuration Compass 244
convetir en 148 navigateur 245
créer 146 Sass 243
Prompt voir Interface en ligne de commande définition 242
Proxy 260 lier un fichier 251
Pseudo-classes 25, 31 lier un projet 248
utiliser 247
R workspace 248
Racine de projet 143 Sprite CSS 221
README (fichier) 133, 255 classe de base 191
Règles imbriquées 23, 25, 29, 31, 32, 39, 49, 57, configurer 200
71, 75, 220 supprimer 200
inception 88 configurer 193
surimbrication 85 créer 190
Requête de média voir Media Queries Data-URI 202
Retina voir Haute définition définition 186
RGB 95, 107, 115 dimensions 194
Ruby espacement 193
installation 6, 13 fonctions 209, 210
RubyGems 144, 158, 231 génération
FilePermissionError 8 automatique 190
mettre à jour 7 manuelle 209
S haute définition 217
Sass layout 200
histoire 1, 22 mixins 209, 210
versions 6, 114, 243 optimiser 207
SassScript 19 optimiser (compilation) 226
Sassy CSS 22 ordonner 202
Scout 16 position 195
Sélecteur pseudo-classes 203
imbriqué voir Règles imbriquées répétition 197
parent 26, 31, 49, 58 Subversion 238
cas d’usage 27 conflit (résoudre) 253
limitations 28 Surimbrication 85
syntaxe 26, 27, 28 Surveillance (de projet) 144, 157
pseudo-classes voir Pseudo-classes arrêter 144, 157
Session interactive SVG 95, 181
Syntaxe
Index
285

!default 53 couleur 95, 107


@content 64 division 103, 106
@each 112 liste 96, 102, 112
@extend 66 null (valeur) 98
@for 110 numérique 95, 104
@function 121 tester 97
@if, @else, @else if 109 tests conditionnels 109
@import 45, 49, 51
@include 56, 59
U
@mixin 55, 59, 61, 62 Unicode 37
@return 121 Unités
@while 112 calcul 104
argument multiple (caractère ...) 62 correspondances 105
commentaire V
CSS 33 Variable
important 34 contenu 38
silencieux 33 déclarer 36
indentée (historique) 22 définition 36
Media Queries 79 écraser 40
placeholder 74 interpoler 42
SCSS 22 Media Queries (expression) 81
sélecteur parent 26, 27, 28 par défaut 52, 53
variable 36, 38 portée
T choix de 42
globale 40, 50, 65
Terminal voir Interface en ligne de commande
locale 39, 50, 65
Test contitionnel 109
redéclarer 42
TSL 96
surcharger 139
Types de données 94
syntaxe 36
algèbre 103
unicode 37
booléen 96, 108
chaîne 94, 106 X
comparer 101 XCode 10

Vous aimerez peut-être aussi