Performances des Sélecteurs
Un sujet qui est—avec la qualité des navigateurs modernes—plus intéressante qu'importante, est les performances des sélecteurs. En gros, avec quel rapidité le navigateur peut déterminer la correspondance des sélecteurs de votre CSS avec les nodes qu'il trouve dans le DOM.
De manière générale, plus un sélecteur est long (plus il a de composants), plus il est lent, par exemple :
body.home div.header ul { }
…est bien moins efficace que :
.primary-nav { }
Cela car les navigateurs lisent les sélecteurs de droite à gauche. Un navigateur lira le premier sélecteur comme suit :
- trouver tous les éléments ul dans le DOM;
- vérifier s'ils se trouvent à n'importe quel niveau dans un élément avec la classe .header;
- puis vérifier si cette classe .header se trouve sur un élément div;
- ensuite vérifier si tout cela se situe quelque par à l'intérieur de n'importe quel élément avec la classe .home;
- et enfin, vérifier si cette classe .homese trouve sur un élément body.
Le second, par contraste, est simplement un cas ou le navigateur s'inquiète de :
- chercher tous les éléments avec une classe .primary-nav.
Pour aller plus loin dans la composition du problème, on utilise des sélecteurs descendant (e.g. .foo .bar {}). La conséquence de cela est que le navigateur doit commencer par la partie du sélecteur la plus à droite (i.e. .bar) et continuer à regarder le DOM jusqu'à trouver la partie suivante (i.e. .foo). Cela peut signifier interroger le DOM des dizaines de fois avant qu'un correspondance soit trouvée.
C'est une des raison qui font que le nichage avec les préprocesseurs est parfois une fausse économie; tout comme créer des sélecteurs inutilement plus spécifiques, et créer des dépendances de localisation, il engendre aussi plus de travail pour le navigateur.
En utilisant le sélecteur enfant (e.g. .foo > .bar {}) on peut rendr le processus bien plus efficace, car cela requiert que le navigateur ne regarde qu'un niveau au dessus dans le DOM, et n'ira pas plus loin qu'il trouve ou non une correspondance.
The Key Selector
Étant donné que les navigateurs lisent les sélecteurs de droite à gauche, le sélecteur le plus à droite est souvent critique pour les performances : il est appelé le key selector.
Le sélecteur suivant peut paraître très performant au premier abord. Il utilise un ID, ce qui est bien et rapide, il ne peux y en avoir qu'un seul sur la page, cela sera donc certainement une recherche de correspondance correcte et rapide — il s'agit juste de trouver un ID et de styler tout ce qu'il contient :
#foo * { }
Le problème avec ce sélecteur est que le sélecteur clé (*) a une très, très grande portée. Ce que fait ce sélecteur est sélectionner absolument tous les nodes dans le DOM (même les éléments <title>, <link> et, <head> ; tout) et ensuite vérifie s'il se trouve, à n'importe quel niveau, dans un élément #foo. C'est un sélecteur très, très gourmand, et devrait à priori être évité ou réécrit.
Heureusement, en écrivant ses sélecteurs abev de bonnes Selector Intent, on évite probablement d'écrire par défaut des sélecteurs inefficaces; il est très peu probable d'avoir des sélecteurs gourmands si l'on cible les bonnes choses pour la bonne raison.
Toutefois, les performances des sélecteurs CSS devraient être assez bas dans votre liste de choses à optimiser. Les navigateurs sont rapides, et cela ne va qu'en s'améliorant, et ce n'est que dans des cas très particuliers qu'un sélecteur inefficace posera problème.
Au delà de leur problèmes spécifiques, le nichage, la qualification et les piètres selector intents contribuent à des sélecteurs moins efficaces.