Académique Documents
Professionnel Documents
Culture Documents
& Compass
avancé
Optimiser ses feuilles de styles CSS
Mehdi Kabab
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 ?
@
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
Mehdi Kabab
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
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
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
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
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
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
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
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.
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.
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.
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
B http://rubygems.org/
Sass et Compass
8
Installation de Sass
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
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
$ 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 !
Figure 1–4
Xcode dans l’App Store
Figure 1–5
Installation des outils
de développement de Xcode
Sass et Compass
12
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
Figure 1–8
Bien configurer l’installateur
Ruby
Figure 1–9
Ruby est correctement installé.
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.
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
.nav {
h2 {
margin-bottom: 8px;
}
li {
margin-bottom: 1px;
}
a {
display: block;
&:hover, &:focus {
color: royalblue;
}
&:active {
color: royalblue;
}
}
}
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 :
.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 -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
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.
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
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.
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.
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.
<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>
.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;
}
}
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;
}
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).
ch02-003.scss
.menu {
a {
text-decoration: none;
&:hover {
text-decoration: underline;
}
&:focus {
text-decoration: underline;
}
}
}
.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;
}
}
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
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;
}
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.
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;
}
.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
/* 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é.
.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.
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
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
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.
$highlight-color: #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 -.
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.
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;
}
$highlight-color: #ff7100;
.warning {
color: $highlight-color;
border: 1px solid $highlight-color;
}
.warning {
color: #ff7100;
border: 1px solid #ff7100;
}
Ce qui nous amène à nous pencher davantage sur la portée des variables Sass.
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;
}
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
.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;
}
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.
$test: foobar;
p.$test {
color: blue;
}
Syntax error: Invalid CSS after "...ass: foobar; p.": expected class name, was
"$test { colo..."
on line 1 of standard input
Use --trace for backtrace.
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;
}
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.
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.
@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
body {
background-color: #fff;
}
h1 small, h2 small, h3 small, h4 small, h5 small {
color: #777;
}
Figure 2–3
Arborescence de l’exercice
ch02-007
Une syntaxe de Sass
47
CHAPITRE 2
$ 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";
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.
$ pwd
/Users/mehdi/livre-sass
$ cd ch02-007
$ pwd
/Users/mehdi/livre-sass/ch02-007
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;
}
}
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;
}
$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
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.
.alert {
color: $alert-color;
border: $alert-border;
}
Partial _theme.scss
CSS générée
.alert {
color: yellow;
border: 1px solid yellow;
}
.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
CSS générée
.alert {
color: red;
border: 1px solid red;
}
// Configuration initiale.
$content-width: 960px !default;
$sidebar-width: 250px !default;
$main-width: $content-width - $sidebar-width !default; // Soit 710px.
// 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;
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
@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
@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
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
);
}
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
> 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.
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
@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
);
}
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
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;
}
@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 ");
}
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
$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;
}
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.
$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
.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);
}
.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
$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-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.
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.
// Le composant de base.
.widget {
padding: .5em 2.5em;
overflow: hidden;
h2, h3 {
margin-bottom: 1.5em;
}
img {
float: left;
}
}
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
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.
color: green;
}
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;
}
.box {
@extend %drop-shadow;
padding: 1em 1.2em;
}
#main .notice {
background-color: #ffc;
@extend %drop-shadow;
}
Une syntaxe de Sass
75
CHAPITRE 2
.box {
padding: 1em 1.2em;
}
#main .notice {
background-color: #ffc;
}
%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-separator {
border: 1px dotted #000;
}
.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;
}
}
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;
}
}
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;
}
}
.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-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;
}
.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
.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
CSS compilée
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
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 !
<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 { … }
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 { … }
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.
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 !</h2>
</div>
</div>
</div>
SCSS
&.heading {
h1, h2, h3 {
padding-bottom: 5px;
border-bottom: 1px solid #ccc;
}
}
}
}
.exclu {
.title {
// La classe ".heading" est étendue.
@extend .heading;
}
}
CSS compilée
.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.
%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
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
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
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 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
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.
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
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.
$ 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
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
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
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
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
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.
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.
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)
$ sass -i
>> (1px solid black) == (1px solid black)
true
>> (1px "solid"black) == (1px solid#000)
true
Développer avec Sass
103
CHAPITRE 3
$ 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.
$ 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'.
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é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"
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
$a $b $a or $b
false false false
false true true
true false true
true true true
Développer avec Sass
109
CHAPITRE 3
$a not $a
false true
true false
@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
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 ».
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
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
À 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
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.
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
CSS générée
.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.
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.
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.
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
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
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.
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
ch03-003b.scss
$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
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
CSS compilée
h1 {
font-size: 4.5em;
margin-bottom: 3em;
}
h1 small {
font-size: 0.66667em;
}
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
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
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.
$ cd ~
$ mkdir livre-sass
$ cd livre-sass/
Premier projet Sass et contraintes de production
125
CHAPITRE 4
$ 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
$ 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
$ touch sass/{style,print,partials/{_{base,reset},ui/_{button,nav}}}.scss
$ touch sass/style.scss
$ touch sass/print.scss
$ touch partials/{_{base,reset},ui/_{button,nav}}}.scss
$ touch partials/_base.scss
$ touch partials/_reset.scss
$ touch partials/ui/_{button,nav}.scss
$ 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.
// Thème principal
// ===============
// ## Typographie
// ## Couleurs
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;
}
// É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";
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.
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
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.
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.
ch04-002.scss
// Module de bouton
// ================
&: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);
}
}
}
.btn, button {
padding: 12px 24px 13px;
font-size: 1em;
}
.btn-large {
padding: 16px 32px 17px;
font-size: 1.25em;
}
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;
&: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);
}
.btn-large {
@extend %module-btn-large;
@extend %theme-btn-default;
// État de réussite.
&.success {
@extend %theme-btn-success;
}
}
$ 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
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
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.
@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.
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
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/**/*";
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 :
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 !
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.
Empêchez Compass de générer ces fichiers Sass en ajoutant l’option --bare à la com-
mande de création de projet.
$ cd ~/livre-sass/ch04-001
$ compass init --prepare --css-dir assets/css \
--fonts-dir assets/fonts --images-dir assets/img \
--javascripts-dir assets/js
$ 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}
$ 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}
# You can select your preferred output style here (can be overridden via
# the command line):
# output_style = :expanded or :nested or :compact or :compressed
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.
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
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
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
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
css_dir = 'assets/css'
images_dir = 'assets/img'
fonts_dir = 'assets/fonts'
javascripts_dir = 'assets/js'
relative_assets = true
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.
$ 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
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.
$ 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 .
require 'sass-globbing'
css_dir = "assets/css"
sass_dir = "sass"
images_dir = "assets/img"
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
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.
Si cette tâche ingrate était à la charge de la machine, il est certain que ce type
d’erreur disparaîtrait.
$ 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;
}
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
/* line 1, ../sass/style.scss */
.logo {
background: transparent url('/img/logo.png?1374695188') no-repeat 0 0;
}
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
.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.
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
$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.
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=');
}
@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;
}
B http://compass-style.org/reference/compass/
Compass, votre futur meilleur ami
167
CHAPITRE 5
Figure 5–2
L’interface de l’aide en ligne
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);
}
@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.
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.
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>.
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.
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.
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 distance du flou.
$default-box-shadow-blur: 5px !default;
.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.
@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.
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;
}
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.
.radial-gradient {
background: radial-gradient(ellipse at center top, green, blue);
}
.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
.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
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.
Compass nous retire ici une belle épine du pied en générant les deux syntaxes, nous
assurant un support maximal de la fonctionnalité.
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);
}
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.
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.
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 !
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.
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.
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
.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;
}
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.
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+
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.
@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.
@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
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
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.
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%; }
// …
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.
$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.
$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
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>.
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.
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
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.
Figure 6–19
Différents types de tri. De gauche à droite : name, size, width et !name.
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.
.html5-styling {
background-position: 0 -96px;
}
.html5-styling:hover, .html5-styling.styling-hover {
background-position: -32px 0;
}
@import "sharebox/*.png";
@include all-icons-sprites;
@include all-sharebox-sprites;
• 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";
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 {
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
Figure 6–21
Des sélecteurs produits
au kilomètre pour rien
// …
$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
[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;
}
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
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");
$map: sprite-map("social/*.png");
.icons {
background: $map no-repeat;
}
$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
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é).
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
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().
@import "compass";
CSS compilée
@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');
}
CSS compilée
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";
CSS compilée
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.
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
// Nous demandons à Compass de générer les règles CSS pour chacune des
// images classiques.
@include all-social-sprites;
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
// 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: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;
}
// …
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;
}
}
@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
[class*=" #{sprite-map-name($icons-sprites)}-"],
[class^="#{sprite-map-name($icons-sprites)}-"] {
@include hide-text;
display: block;
}
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: ();
$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);
}
}
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
/* 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;
}
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
Figure 6–22
Compass cherche à créer
l’image de sprite map à
plusieurs reprises.
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
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
$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
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
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
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
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.
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"
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.
Installation de Bundler
Bundler est une gem comme Sass et Compass. Son installation est donc des plus simples.
Installer 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 :
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
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.
$ 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.
$ cd ~/
$ cat Gemfile
cat: Gemfile: No such file or directory
$ compass version
Compass 0.12.1 (Alnilam)
$ cd ~/my_project/
$ cat Gemfile
source 'https://rubygems.org'
gem "compass", "0.12.2"
gem "oily_png"
$ compass version
Compass 0.12.2 (Alnilam)
$ 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
source 'https://rubygems.org'
gem "compass"
gem "sass-globbing"
source 'https://rubygems.org'
gem "compass"
gem "sass-globbing", "1.0.0"
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
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.
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>.
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.
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.
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.
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.
/* … */
.hero {
margin: 1em; }
/*# sourceMappingURL=styles.css.map */
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
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.
Figure 7–9
Appréciez la coloration
syntaxique SCSS !
Sass et Compass
248
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
Figure 7–15
Recherche du fichier à lier dans
l’espace de travail
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.
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.
$ 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.
$ 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
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.
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
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
.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
.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>
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é.
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 = "."
~/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.
@import "../lib/ppm/ppm-position"
@import "~/livre-sass/annexeA/load-path/lib/ppm/position"
.sample-absolute { … }
$ 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
@import "ppm/position";
.sample-absolute {
@include ppm-absolute($left: 10px, $top: 1em);
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.
sass_dir = "."
css_dir = "."
add_import_path File.expand_path("~/livre-sass/annexeA/load-path/lib")
$ 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
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
sphax:~ mehdi$ ls
Applications Downloads Public Pictures
Code Dropbox README Sites
Desktop Hello World.txt Movies
Documents Library Music
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
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).
sphax:demo mehdi$ ls -F
Gemfile css/ sass/
Gemfile.lock index.html
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:~ mehdi$ cd ~
sphax:~ mehdi$ cd Documents/
sphax:Documents mehdi$ pwd
/Users/mehdi/Documents
sphax:Documents mehdi$ cd ..
sphax:~ mehdi$ pwd
/Users/mehdi
sphax:Documents mehdi$ cd
sphax:~ mehdi$ pwd
/Users/mehdi
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.
sphax:~ mehdi$ cd -
/Users/mehdi/Documents/Articles/Blog
sphax:Blog mehdi$ cd -
/Users/mehdi
sphax:~ mehdi$ cd -
/Users/mehdi/Documents/Articles/Blog
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
Créer un répertoire
Créez un répertoire avec la commande mkdir <nom> (pour make directory) :
Sass et Compass
276
$ mkdir projet
$ cd projet
$ mkdir sass
$ ls -F
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
$ mkdir -p projet2/sass
$ ls -F projet2/
sass/
$ 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
$ cp ../autre-projet/config.rb ./
$ cp ../autre-projet/config.rb compass.rb
$ cp -r ../autre-projet/sass/partials sass/
$ mv ../autre-projet/styles.scss ./
$ 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
$ rm css/screen.css
remove css/screen.css? y
$ 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
$ rm css
rm: css: is a directory
$ rm -rf css
Guide de survie de l’interface en ligne de commande
279
ANNEXE B
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
$ 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
é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