mozilla

Revision 265934 of Écriture de CSS efficace

  • Raccourci de la révision : Écriture_de_CSS_efficace
  • Titre de la révision : Écriture de CSS efficace
  • ID de la révision : 265934
  • Créé :
  • Créateur : rd6137
  • Version actuelle ? Non
  • Commentaire 3 words added, 2 words removed

Contenu de la révision

Ce document vous donne des indications pour optimiser votre code CSS, et plus particulièrement comment écrire des sélecteurs efficaces.

La spécification CSS ne précise pas comment les navigateurs doivent implémenter le système de style, mais le résultat final. De fait, de nombreux moteurs de styles peuvent avoir des comportements très différents en terme de performance. Gecko et WebKit, tous deux libres, utilisent des algorithmes similaires, avec des forces et des faiblesses similaires. Les astuces présentées ici seront donc utiles pour les documents réels du Web.

La première section traite de la manière habituelle dont les styles sont catégorisés. Basé sur cette connaissance, les sections suivantes contiennent des indications qui utilisent ce style de système d'implémentation.

Comment le système de style différencie les règles

Les règles de style sont tout d'abord séparées en quatre catégories

  1. Règles d'identifiant
  2. Règles de classe
  3. Règles de balise
  4. Règles universelles

Il vous est nécessaire de comprendre ces catégories, car elles sont les blocs fondamentaux utilisés pour construire les règles d'attribution des blocks.

La clé de sélection, dans les paragraphes suivants, signifie l'extrémité du sélecteur (celle qui pointe vers l'élément souhaité, et non un de ses ancêtres).

Par exemple, dans la règle

a img, div > p, h1 + [title] {…} 

les clés de sélections img, p, et {{ mediawiki.external('title') }}.

Règles d'identifiant

La première catégorie de règles concerne les règles qui utilisent un champ ID comme clé de sélection.

Exemple
button#backButton {…} /* This is an ID-categorized rule */
#urlBar[type="autocomplete"] {…} /* This is an ID-categorized rule */
treeitem > treerow > treecell#myCell:active {…} /* This is an ID-categorized rule */ 

Règles de classe

Concerne les règles qui utilisent l'attribut class comme clé de sélection.

Exemple
button.toolbarButton {…} /* A class-based rule */
.fancyText {…}	/* A class-based rule */
menuitem > .menu-left[checked="true"] {…} /* A class-based rule */ 

Règles de balise

S'il la clé de sélection n'est ni class, ni ID, le système considère alors les balises. Si une règle utilise une balise comme clé de sélection, alors c'est ce type de règle qui est utilisé.

Exemple
td {…} /* A tag-based rule */
treeitem > treerow {…} /* A tag-based rule */
input[type="checkbox"] {…} /* A tag-based rule */ 

Règles universelles

Toutes les règles qui sont hors des catégories précédentes

Exemple
[hidden="true"] {…} /* A universal rule */  
* {…}		/* A universal rule */
tree > [collapsed="true"] {…} /* A universal rule */

Comment le système de style attribue les règles

Le système de style attribue les règles en commençant par la clé de sélection, puis en allant à gauche (c'est-à-dire vers les ancêtres du sélecteur de règle). Tant que possible, le système de style continue de chercher à gauche une attribution possible, jusqu'à ce qu'il en trouve une ou s'arrête sans rien.

Le concept le plus important ici est le filtrage des règles. L'utilisation de catégories permet de filtrer les règles non applicables, ce qui évite au système de perdre du temps à essayer de les attribuer.

C'est le moyen d'améliorer de façon notable les performances. Le moins d'essais d'application de règles , le plus vite la résolution de style.

Par exemple, dans le cas d'un élément avec un identifiant (ID), seules les règles liées à l'identifiant vont être lues. Si un élément possède de plus un attribut de classe, alors seules les règles de sa classes vont être lues, et enfin seules les règles correspondant à sa balise vont être lues. Les règles universelles seront elles toujours lues.

Guide pour écrire un CSS efficace

Éviter les règles universelles

Faites votre possible pour éviter qu'une règle ne se trouve dans la catégorie universelle!

N'utilisez pas de classe ou de balise en plus d'un identifiant

Si une règle est basée sur un sélecteur d'identifiant, n'utilisez pas une balise ou une classe en plus: les identifiants sont uniques, et l'utilisation des balise va ralentir l'attribution sans bénéfice aucun.

Exception: Il peut être souhaitable de changer dynamiquement la propriété class d'un élément pour varier le style en fonction de la situation, quand d'autres éléments utilisent la même classe.
Éviter
button#backButton {…}
Éviter
.menu-left#newMenuIcon {…}
Préférer
#backButton {…}
Préférer
#newMenuIcon {…}

N'utilisez pas une balise en plus d'une classe

Dans la même logique que précedemment, utiliser une balise en plus d'une classe est contre-productif.

Vous pouvez, si vous le souhaitez, inclure le nom d'une balise dans le nom de classe. Cependant, ceci se fera au détriment de la flexibilité : si des changements sont apportés à la mise en page, tous les noms de classe doivent aussi être changés. Nous vous conseillons d'utiliser plutôt des désignations adaptés au sens de votre page, car une feuille de style devrait rester flexible.

Éviter
treecell.indented {…}
Plutôt
.treecell-indented {…}
Préférer
.hierarchy-deep {…}

Utiliser la catégorie de règles la plus précise possible

La principale cause de ralentissement est l'abondance de règles dans la catégorie des balises. Vous pouvez, en ajoutant un attribut de classe à vos éléments, les diviser en classes, et ainsi éliminer le temps perdu à essayer d'attribuer des règles à une balise.

Éviter
treeitem{{ mediawiki.external('mailfolder=\"true\"') }} > treerow > treecell {…}
Préférer
.treecell-mailfolder {…}

Se méfier du sélecteur descendant

Le sélecteur descendant est le sélecteur le plus gourmand du CSS. Il est incroyablement lourd, en particulier si le sélecteur est dans la catégorie des balises ou la catégorie universelle.

Vous aurez besoin, le plus souvent, du sélecteur fils. S'il vous faut un autre argument pour vous convaincre, sachez que le sélecteur descendant est tout simplement interdit dans les fichiers CSS de l'interface utilisateur de Firefox, et ce sans aucune justification. Vous devriez en faire de même dans vos pages internet.

Éviter
treehead treerow treecell {…}
Mieux, mais toujours non optimal (lisez la suite)
treehead > treerow > treecell {…}

Les règles de balise ne devraient jamais avoir de sélecteur fils

Évitez d'utiliser le sélecteur fils avec des règles de catégories. Ceci ralentira par trop le traitement par la machine à chaque élément listé. Cet effet est d'autant plus fort qu'il est probable que la règle soit appliquée.

Éviter
treehead > treerow > treecell {…}
Préférer
.treecell-header {…}

Posez-vous la question de l'utilisation du sélecteur fils

Utilisez le sélecteur fils avec précaution, et, si possible, ne l'utilisez pas.

Le sélecteur fils est trop souvent utilisé lors du parcours des arbres RDF et des menus, comme par exemple:

Éviter
treeitem{{ mediawiki.external('IsImapServer=\"true\"') }} > treerow > .tree-folderpane-icon {…}

Sachez que les attributs REF peuvent être copiés dans un modèle de document! Profitez-en, par exemple en copiant les propriétés RDF des éléments fils d'un élément XUL, et en les sélectionnant sur leurs attributs.

Préférer
.tree-folderpane-icon{{ mediawiki.external('IsImapServer=\"true\"') }} {…}

Utiliser l'héritage

Sachez quelles sont les propriétés transmises par héritage, et abusez-en!

Par exemple, les gadgets XUL sont configurés pour que les règles list-style-image ou font filtrent jusqu'à un contenu anonyme. Ne perdez donc pas de temps sur des règles qui portent sur le contenu anonyme.

Évite
#bookmarkMenuItem > .menu-left { list-style-image: url(blah) }
Préférer
#bookmarkMenuItem { list-style-image: url(blah) }

Dans l'exemple ci-dessus, la recherche de l'élément anonyme (sans prendre en compte l'héritage de list-style-image) a fait passer la règle dans la catégorie classe, alors qu'elle devrait être dans la catégorie d'identifiants, c'est-à-dire la catégorie la plus restreinte!

Pense-bête: tous les éléments ont la même classe, et en particulier les éléments anonymes!

La « mauvaise règle » ci-dessus va vérifier pour chaque élément que celui-ci est bien un élément du menu des marques-pages. C'est très coûteux, car il existe de nombreux menus. A contrario, la « bonne règle » limite la recherche aux éléments du menu des marques-pages.

Utilisez la propriété -moz-image-region!

Groupez plusieurs images dans une grande image et sélectionnez-en une partie avec {{ Cssxref("-moz-image-region") }}. Ceci fonctionne beaucoup plus vite que si chaque image est dans son propre fichier.

Use scoped stylesheets

If you specify a stylesheet as an XBL resource, the styles only apply to the bound elements and their anonymous content. This reduces the inefficiency of universal rules and child selectors because there are fewer elements to consider.

Source de la révision

<p>Ce document vous donne des indications pour optimiser votre code CSS, et plus particulièrement comment écrire des sélecteurs efficaces.</p>
<p>La spécification CSS ne précise pas comment les navigateurs doivent implémenter le système de style, mais le résultat final. De fait, de nombreux moteurs de styles peuvent avoir des comportements très différents en terme de performance. Gecko et WebKit, tous deux libres, utilisent des algorithmes similaires, avec des forces et des faiblesses similaires. Les astuces présentées ici seront donc utiles pour les documents réels du Web.</p>
<p>La première section traite de la manière habituelle dont les styles sont catégorisés. Basé sur cette connaissance, les sections suivantes contiennent des indications qui utilisent ce style de système d'implémentation.</p>
<h3 name="How_the_style_system_breaks_up_rules">Comment le système de style différencie les règles</h3>
<p>Les règles de style sont tout d'abord séparées en quatre catégories</p>
<ol> <li>Règles d'identifiant</li> <li>Règles de classe</li> <li>Règles de balise</li> <li>Règles universelles</li>
</ol>
<p>Il vous est nécessaire de comprendre ces catégories, car elles sont les blocs fondamentaux utilisés pour construire les règles d'attribution des blocks.</p>
<p>La clé de sélection, dans les paragraphes suivants, signifie l'extrémité du sélecteur (celle qui pointe vers l'élément souhaité, et non un de ses ancêtres).</p>
<p>Par exemple, dans la règle</p>
<div style="width: 100%;"> <pre class="eval deki-transform"><code style="">a img, div &gt; p, h1 + [title] {…} </code>
</pre>
</div>
<p>les clés de sélections <code>img</code>, <code>p</code>, et <code>{{ mediawiki.external('title') }}</code>.</p>
<h4 name="ID_Rules">Règles d'identifiant</h4>
<p>La première catégorie de règles concerne les règles qui utilisent un champ <code>ID</code> comme clé de sélection.</p>
<h5>Exemple</h5>
<pre class="eval deki-transform"><code style="">button#backButton {…} /* This is an ID-categorized rule */
#urlBar[type="autocomplete"] {…} /* This is an ID-categorized rule */
treeitem &gt; treerow &gt; treecell#myCell:active {…} /* This is an ID-categorized rule */ </code>
</pre>
<h4 name="Class_Rules">Règles de classe</h4>
<p>Concerne les règles qui utilisent l'attribut <code>class </code>comme clé de sélection.</p>
<h5>Exemple</h5>
<pre class="eval deki-transform"><code style="">button.toolbarButton {…} /* A class-based rule */
.fancyText {…}	/* A class-based rule */
menuitem &gt; .menu-left[checked="true"] {…} /* A class-based rule */ </code>
</pre>
<h4 name="Tag_Rules">Règles de balise</h4>
<p>S'il la clé de sélection n'est ni <code>class</code>, ni <code>ID</code>, le système considère alors les balises. Si une règle utilise une balise comme clé de sélection, alors c'est ce type de règle qui est utilisé.</p>
<h5>Exemple</h5>
<pre class="eval deki-transform"><code style="">td {…} /* A tag-based rule */
treeitem &gt; treerow {…} /* A tag-based rule */
input[type="checkbox"] {…} /* A tag-based rule */ </code>
</pre>
<h4 name="Universal_Rules">Règles universelles</h4>
<p>Toutes les règles qui sont hors des catégories précédentes</p>
<h5>Exemple</h5>
<pre class="eval deki-transform"><code style="">[hidden="true"] {…} /* A universal rule */  
* {…}		/* A universal rule */
tree &gt; [collapsed="true"] {…} /* A universal rule */</code>
</pre>
<h3 name="How_the_Style_System_Matches_Rules">Comment le système de style attribue les règles</h3>
<p>Le système de style attribue les règles en commençant par la clé de sélection, puis en allant à gauche (c'est-à-dire vers les ancêtres du sélecteur de règle). Tant que possible, le système de style continue de chercher à gauche une attribution possible, jusqu'à ce qu'il en trouve une ou s'arrête sans rien.</p>
<p>Le concept le plus important ici est le filtrage des règles. L'utilisation de catégories permet de filtrer les règles non applicables, ce qui évite au système de perdre du temps à essayer de les attribuer.</p>
<p><strong>C'est le moyen d'améliorer de façon notable les performances.</strong> Le moins d'essais d'application de règles , le plus vite la résolution de style.</p>
<p>Par exemple, dans le cas d'un élément avec un identifiant (<code>ID</code>), seules les règles liées à l'identifiant vont être lues. Si un élément possède de plus un attribut de classe, alors seules les règles de sa classes vont être lues, et enfin seules les règles correspondant à sa balise vont être lues. Les règles universelles seront elles toujours lues.</p><h3 name="Guidelines_for_Efficient_CSS">Guide pour écrire un CSS efficace</h3>
<h4 name="Avoid_Universal_Rules.21">Éviter les règles universelles</h4>
<p>Faites votre possible pour éviter qu'une règle ne se trouve dans la catégorie universelle!</p>
<h4 name="Don.27t_qualify_ID-categorized_rules_with_tag_names_or_classes">N'utilisez pas de classe ou de balise en plus d'un identifiant</h4>
<p><strong>Si une règle est basée sur un sélecteur d'identifiant, n'utilisez pas une balise ou une classe en plus</strong>: les identifiants sont uniques, et l'utilisation des balise va ralentir l'attribution sans bénéfice aucun.</p>
<div class="note"><strong>Exception:</strong> Il peut être souhaitable de changer dynamiquement la propriété <code>class </code>d'un élément pour varier le style en fonction de la situation, quand d'autres éléments utilisent la même classe.</div>
<dl style="margin: 1em 12.5%"> <dt><span style="color: rgb(128, 0, 0); ">Éviter</span></dt> <dd><code>button#backButton {…}</code></dd> <dt><span style="color: rgb(128, 0, 0); ">Éviter</span></dt> <dd><code>.menu-left#newMenuIcon {…}</code></dd> <dt><span style="color: rgb(51, 153, 102); ">Préférer</span></dt> <dd><code>#backButton {…}</code></dd> <dt><span style="color: rgb(51, 153, 102); ">Préférer</span></dt> <dd><code>#newMenuIcon {…}</code></dd>
</dl>
<h4 name="Don.27t_qualify_class-categorized_rules_with_tag_names">N'utilisez pas une balise en plus d'une classe</h4>
<p>Dans la même logique que précedemment, utiliser une balise en plus d'une classe est contre-productif.</p>
<p>Vous pouvez, si vous le souhaitez, inclure le nom d'une balise dans le nom de classe. Cependant, ceci se fera au détriment de la flexibilité : si des changements sont apportés à la mise en page, tous les noms de classe doivent aussi être changés. Nous vous conseillons d'utiliser plutôt des désignations adaptés au sens de votre page, car une feuille de style devrait rester flexible.</p>
<dl style="margin: 1em 12.5%"> <dt><span style="color: rgb(128, 0, 0); ">Éviter</span></dt> <dd><code>treecell.indented {…}</code></dd> <dt><span style="color: rgb(153, 204, 0); ">Plutôt</span></dt> <dd><code>.treecell-indented {…}</code></dd> <dt><span style="color: rgb(51, 153, 102); ">Préférer</span></dt> <dd><code>.hierarchy-deep {…}</code></dd>
</dl>
<h4 name="Try_to_put_rules_into_the_most_specific_category_you_can.21">Utiliser la catégorie de règles la plus précise possible</h4>
<p><strong>La principale cause de ralentissement est l'abondance de règles dans la catégorie des balises</strong>. Vous pouvez, en ajoutant un attribut de classe à vos éléments, les diviser en classes, et ainsi éliminer le temps perdu à essayer d'attribuer des règles à une balise.</p>
<dl style="margin: 1em 12.5%"> <dt><span style="color: rgb(128, 0, 0); ">Éviter</span></dt> <dd><code>treeitem{{ mediawiki.external('mailfolder=\"true\"') }} &gt; treerow &gt; treecell {…}</code></dd> <dt><span style="color: rgb(51, 153, 102); ">Préférer</span></dt> <dd><code>.treecell-mailfolder {…}</code></dd>
</dl>
<h4 name="Avoid_the_descendant_selector.21">Se méfier du sélecteur descendant</h4>
<p><strong>Le sélecteur descendant est le sélecteur le plus gourmand du CSS</strong>. Il est incroyablement lourd, en particulier si le sélecteur est dans la catégorie des balises ou la catégorie universelle.</p>
<p>Vous aurez besoin, le plus souvent, du <strong>sélecteur fils</strong>. S'il vous faut un autre argument pour vous convaincre, sachez que le sélecteur descendant est tout simplement interdit dans les fichiers CSS de l'interface utilisateur de Firefox, et ce sans aucune justification. Vous devriez en faire de même dans vos pages internet.</p>
<dl style="margin: 1em 12.5%"> <dt><span style="color: rgb(128, 0, 0); ">Éviter</span></dt> <dd><code>treehead treerow treecell {…}</code></dd> <dt><span style="color: rgb(153, 51, 0); ">Mieux, mais toujours non optimal (lisez la suite)</span></dt> <dd><code>treehead &gt; treerow &gt; treecell {…}</code></dd>
</dl>
<h4 name="Tag-categorized_rules_should_never_contain_a_child_selector.21">Les règles de balise ne devraient jamais avoir de sélecteur fils</h4>
<p><strong>Évitez d'utiliser le sélecteur fils avec des règles de catégories</strong>. Ceci ralentira par trop le traitement par la machine à chaque élément listé. Cet effet est d'autant plus fort qu'il est probable que la règle soit appliquée.</p>
<dl style="margin: 1em 12.5%"> <dt><span style="color: rgb(128, 0, 0); ">Éviter</span></dt> <dd><code>treehead &gt; treerow &gt; treecell {…}</code></dd> <dt><span style="color: rgb(51, 153, 102); ">Préférer</span></dt> <dd><code>.treecell-header {…}</code></dd>
</dl>
<h4 name="Question_all_usages_of_the_child_selector.21">Posez-vous la question de l'utilisation du sélecteur fils</h4>
<p><strong>Utilisez le sélecteur fils avec précaution</strong>, et, si possible, ne l'utilisez pas.</p>
<p>Le sélecteur fils est trop souvent utilisé lors du parcours des arbres RDF et des menus, comme par exemple:</p>
<dl style="margin: 1em 12.5%"> <dt><span style="color: rgb(128, 0, 0); ">Éviter</span></dt> <dd><code>treeitem{{ mediawiki.external('IsImapServer=\"true\"') }} &gt; treerow &gt; .tree-folderpane-icon {…}</code></dd>
</dl>
<p>Sachez que les attributs REF peuvent être copiés dans un modèle de document! Profitez-en, par exemple en copiant les propriétés RDF des éléments fils d'un élément XUL, et en les sélectionnant sur leurs attributs.</p>
<dl style="margin: 1em 12.5%"> <dt><span style="color: rgb(51, 153, 102); ">Préférer</span></dt> <dd><code>.tree-folderpane-icon{{ mediawiki.external('IsImapServer=\"true\"') }} {…}</code></dd>
</dl><h4 name="Rely_on_inheritance.21">Utiliser l'héritage</h4>
<p>Sachez quelles sont les propriétés transmises par héritage, et abusez-en!</p>
<p>Par exemple, les gadgets XUL sont configurés pour que les règles <code>list-style-image</code> ou <code>font</code> filtrent jusqu'à un contenu anonyme. Ne perdez donc pas de temps sur des règles qui portent sur le contenu anonyme.</p>
<dl style="margin: 1em 12.5%"> <dt><span style="color: rgb(128, 0, 0); ">Évite</span></dt> <dd><code>#bookmarkMenuItem &gt; .menu-left { list-style-image: url(blah) }</code></dd> <dt><span style="color: rgb(51, 153, 102); ">Préférer</span></dt> <dd><code>#bookmarkMenuItem { list-style-image: url(blah) }</code></dd>
</dl>
<p>Dans l'exemple ci-dessus, la recherche de l'élément anonyme (sans prendre en compte l'héritage de <code>list-style-image</code>) a fait passer la règle dans la catégorie classe, alors qu'elle devrait être dans la catégorie d'identifiants, c'est-à-dire la catégorie la plus restreinte!</p>
<p><strong>Pense-bête</strong>: tous les éléments ont la même classe, et en particulier les éléments anonymes!</p>
<p>La « mauvaise règle » ci-dessus va vérifier pour chaque élément que celui-ci est bien un élément du menu des marques-pages. C'est très coûteux, car il existe de nombreux menus. A contrario, la « bonne règle » limite la recherche aux éléments du menu des marques-pages.</p><h4 name="Use_-moz-image-region.21">Utilisez la propriété <code>-moz-image-region</code>!</h4>
<p>Groupez plusieurs images dans une grande image et sélectionnez-en une partie avec <code>{{ Cssxref("-moz-image-region") }}</code>. Ceci fonctionne beaucoup plus vite que si chaque image est dans son propre fichier.</p><h4>Use scoped stylesheets</h4>
<p>If you specify a stylesheet as an XBL resource, the styles only apply to the bound elements and their anonymous content. This reduces the inefficiency of universal rules and child selectors because there are fewer elements to consider.</p>
Revenir à cette révision