LESS: CSS avancé

Même si CSS évolue plutôt bien, la sortie de CSS 3 a frustré pas mal de développeurs. Beaucoup réclamaient, et réclament toujours, la notion de variables et/ou de constantes, pour éviter la multiplication des mêmes valeurs numériques (couleurs, dimensions, …) dans leurs feuilles de styles. Malheureusement, CSS3 n’apporte pas cette fonctionnalité, et nos amis du W3C ne semblent pas persuadés de son utilité.

Heureusement, Alexis Sellier a pensé à nous, en nous proposant LESS, un outil qui améliore considérablement la syntaxe de CSS. Je vais donc vous parler aujourd’hui de LESS.

Qu’est ce que LESS?

LESS est un langage qui étend les capacités de description de nos styles CSS.

Comme je le disais en introduction, nos feuilles de styles sont souvent truffées des mêmes valeurs numériques (codes de couleur, marges, …). Lorsque nous souhaitons modifier une couleur par exemple, nous sommes obligés de modifier sa valeur numérique dans toute la feuille de styles, avec les erreurs que cela peut générer (même avec des fonctions recherche/remplacement). LESS nous évite cela, en proposant, par exemple, de définir une seule fois la couleur en question.

Code CSS standard

1
2
3
a { color: #3C0; }
... ...
h5 {  color: #3C0; }

Code LESS:

1
2
3
@color: #3C0;
a { color: @color; }
h5 {  color: @color; }

Cette notion de variable, n’est qu’une partie des fonctionnalités proposées par LESS, qui permet, comme nous allons le voir un peu plus bas, d’effectuer des opérations assez complexes.

Par défaut nos navigateurs ne comprennent pas la syntaxe de LESS. Son utilisation nécessite donc des outils. Il y a globalement trois façons de l’utiliser:

  • Directement dans un navigateur,
  • Sur le serveur,
  • En ligne de commande.

Directement dans un navigateur
Après avoir chargé la feuille de styles (fichier .less) avec la méthode classique, il faut également charger le script less.js, qui va « traduire » la syntaxe LESS, en syntaxe CSS standard, compréhensible par le navigateur.

1
2
<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="less.js" type="text/javascript"></script>

Sur le serveur:
Avec la méthode précédente, le fichier LESS est envoyé par le serveur, puis traduit par le navigateur. L’autre technique consiste à traduire le fichier LESS en CSS au niveau du serveur, puis à envoyer le fichier CSS résultant vers le navigateur. Cette méthode se base sur Node.js, qui permet de faire tourner Javascript sur un serveur, comme on peut le faire avec d’autres langages, comme PHP.

Ces deux méthodes permettent des changements dynamiques de la feuille de styles. A chaque requête de l’utilisateur, la feuille peut être modifiée, puis appliquée.

Les compilateurs
Cette troisième méthode consiste à traduire notre fichier LESS en fichier CSS, en utilisant explicitement un outil, qui peut être en ligne de commande, ou un logiciel sous Windows ou Mac. L’outil le plus connu est lessc(comme LESS Compiler).

1
$ lessc styles.less > styles.css

Contrairement aux autres méthodes, celle-ci est statique. La feuille de styles CSS n’est générée qu’une seule fois, au lancement de la commande.

Le Langage

Entrons maintenant dans le vif du sujet, en regardant ce que nous pouvons faire avec LESS.

Les variables

L’exemple que j’ai donné plus haut explique bien cette notion de variable.
La déclaration d’une variable se fait de la façon suivante: @nom de la variable: valeur. On utilise ensuite la variable en faisant précéder son nom par un @ (@nom de la variable).

Exemple:

1
2
3
@border-color: #DDD;
.dialog { border: 1px solid @border-color; }
.menu { border-bottom: 1px solid @border-color; }

Une fois compilé, le code CSS sera

1
2
.dialog { border: 1px solid #DDD; }
.menu { border-bottom: 1px solid #DDD; }
Les mixins

Je ne sais pas trop comment traduire le terme mixins. En langage objet, nous parlerions de classe abstraite, mais ce terme s’applique mal aux mixins, qui ressemblent plus à des « patterns ». Je vais donc rester avec le terme mixin.

Les mixins sont des ensembles de propriétés CSS. Pour résumer, les mixins ressemblent à des variables contenant des propriétés CSS. Cela permet d’utiliser le même jeu de propriétés CSS dans plusieurs classes.

Exemple:

1
2
3
4
5
6
7
8
9
10
11
12
.bordered {
	border-top: 2px solid black;
	border-bottom: 1px solid #ccc;
}
.widget-title {
	color: #333;
	.bordered;
}
nav.main-menu li {
	color: #3C0;
	.bordered;
}

Ce qui donnera, après compilation:

1
2
3
4
5
6
7
8
9
10
.widget-title {
	color: #333;
	border-top: 2px solid black;
	border-bottom: 1px solid #ccc;
}
nav.main-menu li {
	color: #3C0;
	border-top: 2px solid black;
	border-bottom: 1px solid #ccc;
}

Les mixins servent donc à déclarer des patterns, que l’on peut ensuite utiliser à volonté.

Jusqu’à présent, nous n’avons finalement abordé que la notion de « variables ». Mais les mixins nous permettent d’aller plus loin: ils sont paramétrables.

1
2
3
4
5
6
7
8
9
10
11
12
.bordered(@top-border: 2px, @border-color: #ccc) {
	border-top: @top-border solid black;
	border-bottom: 1px solid @border-color;
}
.widget-title {
	color: #333;
	.bordered(1px, black);
}
nav.main-menu li {
	color: #3C0;
	.bordered(2px, #CCC);
}

Donnera le code CSS suivant:

1
2
3
4
5
6
7
8
9
10
.widget-title {
	color: #333;
	border-top: 1px solid black;
	border-bottom: 1px solid black;
}
nav.main-menu li {
	color: #3C0;
	border-top: 2px solid black;
	border-bottom: 1px solid #CCC;
}

Tout cela devient très intéressant, mais il y a mieux, avec les définitions conditionnelles des mixins:

1
2
3
4
5
6
.mixin (@a) when (@a > 10), (@a < -10) { ... } @media: mobile;
.mixin (@a) when (@media = mobile) { ... }
.mixin (@a) when (@media = desktop) { ... }
.mixin (@a, @b: 0) when (isnumber(@b)) { ... }
.mixin (@a, @b: black) when (iscolor(@b)) { ... }
.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }

Ces règles nous montrent tous le potentiel d’un tel langage, avec notamment la capacité de générer des feuilles de styles différentes à partir d’un même fichier LESS.

Les opérations

LESS gère les opérations arithmétiques de base. Nous pouvons donc avoir des règles du type:

1
2
3
4
5
6
7
@base: 5%;
@filler: @base * 2;
@other: @base + @filler;
 
color: #888 / 4;
background-color: @base-color + #111;
height: 100% / 2 + @filler;

En découvrant cela, j’ai immédiatement pensé à l’élaboration « automatisée » de styles typographiques. Exemple

1
2
3
4
5
6
7
8
@fontsize: 13;
@lineheight: 18;
 
body {
	font-family: Georgia, Times, serif;
	font-size: (16 / @fontsize) + 0em;
	line-height: @lineheight / @fontsize;
}

Donne:

1
2
3
4
5
body {
 	font-family: Georgia, Times, serif;
	font-size: 1.2307692307692308em;
	line-height: 1.3846153846153845;
}

Pour ceux qui pensent qu’il y a beaucoup trop de chiffres après la virgule, LESS a ce qu’il vous faut

1
2
3
4
5
6
7
8
@fontsize: 13;
@lineheight: 18;
 
body {
	font-family: Georgia, Times, serif;
	font-size: (round((16 / @fontsize)*10000)/10000) + 0em;
	line-height: round((@lineheight / @fontsize)*10000)/10000;
}

Qui donne:

1
2
3
4
5
 body {
	font-family: Georgia, Times, serif;
	font-size: 1.2308em;
	line-height: 1.3846;
}

Ce qui est assez étonnant, c’est qu’il reconnaît les unités de base des feuilles de types comme px, em, %.

Dans l’exemple précédent, j’avais écrit au départ:

1
2
3
@fontsize: 13px;
@lineheight: 18px;
font-size: 1.2308px; !
Règles imbriqués et pseudo-classes

LESS sait également simplifier la syntaxe CSS. Dans une feuille de styles, nous trouvons souvent des styles du type:

1
2
3
4
5
6
7
8
9
10
#header { color: black; }
#header .navigation {
  font-size: 12px;
}
#header .logo {
  width: 300px;
}
#header .logo:hover {
  text-decoration: none;
}

(L’exemple provient de la documentation de LESS)

LESS autorise la syntaxe suivante:

1
2
3
4
5
6
7
8
9
10
11
#header {
  color: black;
 
  .navigation {
    font-size: 12px;
  }
  .logo {
    width: 300px;
    &amp;:hover { text-decoration: none }
  }
}
La gestion des couleurs

CSS 2.1, puis 3 apportent une gestion plus élaborée des couleurs, avec notamment la gestion de la transparence. LESS dispose également de fonctions poussées dans ce domaine.

Voici quelques exemples pris sur le site de LESS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
lighten(@color, 10%);     // return a color which is 10% *lighter* than @color
darken(@color, 10%);      // return a color which is 10% *darker* than @color
 
saturate(@color, 10%);    // return a color 10% *more* saturated than @color
desaturate(@color, 10%);  // return a color 10% *less* saturated than @color
 
fadein(@color, 10%);      // return a color 10% *less* transparent than @color
fadeout(@color, 10%);     // return a color 10% *more* transparent than @color
fade(@color, 50%);        // return @color with 50% transparency
 
spin(@color, 10);         // return a color with a 10 degree larger in hue than @color
spin(@color, -10);        // return a color with a 10 degree smaller hue than @color
 
mix(@color1, @color2);    // return a mix of @color1 and @color2
 
@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;
 
#header { color: @light-blue; }
Evaluation du code Javascript

LESS sait exécuter des commandes Javascript, et en renvoyer le résultat dans des variables.
Exemple

1
2
 @str: "hello";
@var: ~`"@{str}".toUpperCase() + '!'`;

(exemple disponible sur le site de LESS)

Là encore, cette fonctionnalité laisse entrevoir de vastes possibilités. Javascript sachant récupérer les informations liées au navigateur, il serait possible de construire des feuilles de styles en fonction de ces informations.

Les outils

J’ai déjà cité certains outils dans le premier paragraphe. En voici une liste non exhaustive qui permet déjà de démarrer correctement.

Less.js

Pour qu’un navigateur sache interprêter un fichier .less, il faut télécharger le script less.js, ajouter le code suivant à votre page HTML (ou votre thème):

1
2
<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="less.js" type="text/javascript"></script>

Veillez bien à ce que la feuille de styles soit déclarée avant l’inclusion du script.

Les compilateurs
  • pour Windows, en ligne de commande: Less.js for Windows,
  • pour windows toujours, mais sous forme d’application: Winless complet, mais peut-être un peu trop envahissant,
  • encore pour windows, mais également pour Mac et Linux, SimpLess, beaucoup plus simple (comme son nom l’indique),
  • Pour Mac Mac.

LSS: pour quel usage?

La vocation de LESS n’est pas de remplacer CSS, puisque, dans tous les cas, il y a traduction en CSS avant utilisation par le navigateur.

Nous pouvons identifier trois principales utilisations:

Outil de développement

En fournissant des variables, des opérateurs, des classes abstraites (mixins), nous pouvons construire de véritables bibliothèques de patterns paramétrables. Nous pouvons imaginer, par exemple, une grille paramétrable, des styles de typographie dont nous n’avons plus qu’à indiquer les paramètres fondamentaux (font-size, line-height). Nous pouvons également penser aux styles de CSS 3, comme les dégradés, les coins arrondis, … , qui nécessitent beaucoup de paramètres.

En CSS, la façon de réutiliser le code s’arrête au copier/coller. Avec LESS, nous réutilisons des bibliothèques, que nous pouvons assembler, et « compiler ».

Avec cette approche, le fichier LESS reste un fichier de travail. Une fois de design terminé, le fichier LESS est converti en fichier CSS (avec les outils en ligne de commande, par exemple), avant publication.

Des frameworks comme Boostrap utilise LESS comme outil de personnalisation. Après avoir choisi les modules désirés, le développeur peut également choisir les paramètres de base des différents modules, avant de télécharger le framework ainsi personnalisé.

Feuilles de styles dynamiques

Un fichier LESS peut être interprété, à chaque requête d’un utilisateur, soit du côté navigateur, soit du côté serveur. De plus, contrairement à CSS, ce même fichier peut contenir des opérations et des conditions. Le code CSS généré peut donc varier d’une requête à l’autre.

La technologie LESS peut donc être une alternative / un complément aux media-queries, ou aux solutions Javascript, pour fournir une feuille de styles aux navigateurs en fonction de valeurs ou d’évènements extérieurs.

Pour ce type d’utilisation, je pense qu’il est préférable de « compiler » les fichiers LESS côté serveur. J’ai pu constaté, en effet, que l’utilisation du script less.js au niveau du navigateur n’était pas anodine pour les performances.

CSS sémantique

Le concept vient d’un framework appelé Semantic Grid System. Les auteurs de ce framework partent du principe, que lorsque nous utilisons une grille, le code HTML ressemble souvent à cela:

1
2
3
4
5
6
7
8
<div class="grid_12">
	<section class="grid_8">
 
	</section>
	<section class="grid_4">
 
	</section>
</div>

Aucun des classes CSS associées à cette structure HTML n’a de sens. Elles décrivent la grille, pas le contenu du document.

En utilisant LESS, les concepteurs de Semantic GS ont remédié à ce problème. Reprenons une version épurée de notre code HTML:

1
2
3
4
5
6
7
8
<div class="content">
	<section class="main">
 
	</section>
	<section class="sidebar">
 
	</section>
</div>

Nous lui associons une feuille de styles LESS de ce type:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// LESS
@numcol: 12;
@colwidth: percentage(1 / @numcol) - 2%;
 
.column(@num) {
    float: left;
    width: @num * @colwidth + (@num - 1 ) * 1%;
    margin: 0 1%;
}
 
section.main {
    .column(8);
}
section.sidebar {
    .column(4);
}

Qui donnera après « compilation »:

1
2
3
4
5
6
7
8
9
10
11
section.main {
    float: left;
    width: 64.6666%;
    margin: 0 1%;
}
 
section.sidebar {
    float: left;
    width: 31.3333%;
    margin: 0 1%;
}

Cette approche a de multiples intérêts:

  • Le code HTML est allégé,
  • Il ne contient que des classes « utiles »,
  • Tout se passe au niveau de la feuille de styles. Nous pouvons très rapidement modifier les dimensions de nos colonnes, et même la structure de la grille,
  • Les media-queries restent utilisables pour obtenir un design « responsive ».

Plusieurs frameworks proposent ce concept

Pour terminer, j’ai trouvé deux articles intéressants, décrivant l’élaboration d’une grille en utilisant LESS:

Utilisation raisonnée

A priori, LESS cumule beaucoup d’avantages, et j’avoue être assez séduit par cet outil. Mais comme tout produit LESS a quelques défauts.

Si nous poussons la logique de LESS jusqu’au bout, avec notamment la notion de grille sémantique, décrite précédemment, nous avons un code LESS qui utilise

  • massivement les mixins: pour construire la grille, par exemple, chaque élément/colonne/bloc de cette grille, va contenir un mixin décrivant un conteneur flottant, avec sa largeur, ses marges, …
  • la notion de classe imbriquée, d’héritage, … parce que cela permet d’être beaucoup plus efficace dans la saisie, et cela rend le code plus lisible.

Dans le code CSS généré, nous trouverons alors:

  • des propriétés CSS qui se répètent un grand nombre de fois,
  • des sélecteurs dont la complexité et proportionnelle à l’utilisation des classes imbriquées.

Cela génère donc un code lourd, et assez peu efficace (voir l’article de Steve souders sur l’impact des sélecteurs CSS sur les temps de rendu par les navigateurs).

Donc, soit nous codons en gardant à l’esprit ce que donnera le code CSS, soit nous passons par une phase d’optimisation du code CSS, avec des outils comme Minify ou d’autres. Dans ce second cas, nous perdons un peu la maîtrise de notre code CSS.

Conclusion

Lorsque LESS est apparu, le concept ne m’a pas intéressé, parce qu’il faisait uniquement appel à un « compilateur » Javascript, du côté serveur, ou du côté navigateur. Aujourd’hui le produit, et son environnement ont évolué, avec notamment des compilateurs en ligne de commande.

Après avoir un peu travaillé avec LESS, j’avoue être assez emballé. LESS est un outil extrêmement puissant, qui offre de réels leviers pour

  • améliorer la productivité du développeur HTML/CSS,
  • construire des bibliothèques / des frameworks entièrement paramétrables,
  • construire des feuilles de styles dynamiques, en complément des technologies existantes (media-queries).
Références

Partager cet article