Il n'y a pas que class et id dans la vie

Quid des autres sélecteurs ?

Les sélecteurs d'attributs et de parenté sont rarement employés. Ce sont pourtant de puissants sélecteurs, maniables, lisibles — parfois bien plus pertinents que des classes et moins stricts que des ID.

Ce sont également de merveilleux obstacles pédagogiques, générant des situations d'apprentissage intéressantes en induisant une corrélation entre le HTML et le CSS.

À contre-courant

Mais la tendance va vers l'utilisation de classes partout, pour tout.
Avec un objectif : un graphique de spécificité qu'on devrait confondre avec un électro-encéphalogramme plat.
Genre, la mort.

Un électro-encéphalogramme défilant à un rythme régulier
La vie, c'est globalement mieux.

Démystifions

La contre-performance des sélecteurs

La rumeur court depuis plusieurs années que les sélecteurs universels, d'attributs ou d'adjacence seraient mauvais pour les performances — et seraient par conséquent à éviter.

C'est faux. Et c'est prouvé par Ben Frain en 2014 .

La différence  — qui, certes, existe — est absolument négligeable. En revanche, soyez prudents avec les propriétés que vous utilisez.

Démystifions encore

La séparation du fond et de la forme

C'est devenu un axiome désormais. Pourtant dans le web, sa seule portée pratique pertinente est de ne pas utiliser d'attributs de présentation dans le HTML ni de balises sémantiques pour leur aspect visuel.

Pour tous les autres cas : la forme dépend du fond.

J'en ai parlé plus en détail dans « Le sens de la sémantique ».

Les sélecteurs pestiférés

Or donc, la mode en ce moment est de n'utiliser que des classes.
Les autres sélecteurs sont « à manipuler avec précaution ».

Voyons nos vilains petits canards :

  1. Le sélecteur universel : * ;
  2. Les sélecteurs d'attributs complexes : [attr*=""] ;
  3. Les sélecteurs d'adjacence et de parenté : * + *, * > *, * ~ * ;
  4. Les sélecteurs d'élément surqualifiés : html[class=""].

Moi, je les aime beaucoup. Ils sont rigolos.
Allez, jetons un œil à quelques exemples que j'espère pertinents, et voyons comment on peut s'en servir de manière intelligentes.

Les micro-données

Les aficionados du SEO les connaissent bien : elles ont vocation à enrichir la sémantique HTML.

Si d'aventure vous les utilisez, ne perdez pas de temps à définir des classes qui signifieraient la même chose : ciblez les directement.

  
    [itemprop="author"] {
        font-variant: small-caps;
    }
  

Ce sélecteur présente les mêmes avantages que si vous employiez une classe .author, mais vous y ajoutez une dimension sémantique utile au SEO.

Notez qu'à l'origine, [class] devait servir à étendre la sémantique. Je vous invite à lire l'article de Karl Dubost sur le sujet.

ARIA

ARIA est un ensemble d'attributs qui permet de rendre accessibles certains motifs de conception et les interactions qui y sont associées.

C'est un peu la version bio des plugins jQuery de votre enfance.

Pourquoi utiliser des classes quand vous disposez d'une panoplie complète d'attributs — que vous manipulez en JS de toute façon ?

  
    [role="tabpanel"][aria-hidden="true"] {
        display: none;
    }
  

Et voilà ! Avec ça, un nouvel intervenant comprendra que le motif repose sur ces attributs et pourra s'y familiariser plus facilement.

L'économique de répétition

Les sélecteurs d'attributs peuvent fonctionner comme des expressions régulières. Et ça, c'est vachement pratique pour mettre en place des motifs — et s'appliquer à nommer et abstraire son barda.

  
    [class*="btn"] {
      border-width: .25em;
    }

    [class*="primary"] {
      background-color: #032c36;
      color: #efeee3;
    }

    [class*="-xs"] {
      font-size: smaller;
    }
  

Vous le faites déjà avec des méthodologies comme BEM, SMACSS ou OOCSS.

La chouette lobotomisée

Ces smileys vont sûrement vous faire crier, mais ils s'avèrent utiles si vous mettez en place un système graphique défini, par exemple.

  
    main * + * {
        margin-top: 1.5rem;
    }
  

Crédit à Heydon Pickering sur AListApart.

La chouette dubitative et la chouette duck face

Le sélecteur d'adjacence directe est pratique, mais celui d'adjacence indirecte également (* ~ *) — et celui de parenté (* > *), je vous raconte même pas ! Utile lorsque l'affichage d'un enfant direct dépend de celui d'un prédécesseur, par ex. :

  
    main > *:target ~ * {
        display: none;
    }
  

Ici le mécanisme d'affichage repose autant sur CSS que sur JS, ce que je pense bénéfique pour l'accessibilité.

Devinez quoi ? Cet exemple aussi est d'Heydon Pickering, sur SmashingMagazine cette fois.

Le garde-fou

Progressons dans l'hérésie : et si nous ajoutions futilement du poids à nos sélecteurs, pour rigoler ?

L'astuce du box-sizing sur html

Vous la trouvez par exemple dans Foundation et dans Bootstrap V4.

Imaginez un peu si ces frameworks ne copiaient pas bêtement cette astuce, mais y ajoutaient un seul, tout petit attribut [lang].

  
    html[lang] {
      box-sizing: border-box;
    }

    *, *::after, *::before {
      box-sizing: inherit;
    }
  

Une des erreurs d'accessibilité les plus courantes serait tout à coup menacée d'extinction !

L'autre garde-fou

Les images sont un point particulièrement sensible du web : vecteur d'information, mode d'affichage, RWD

Le coup du max-width: 100%; sur img

On le trouve dans Knacss, dans Röcssti et, certes un peu mieux caché, dans Bootstrap.

Mes deux centimes : ne l'appliquer que si l'attribut alt est présent :

  
    img[alt] {
        max-width: 100%;
    }
  

Croyez-moi, plus personne dans votre équipe n'omettra une alternative.

Une armée de garde-fous !

Voici quelques idées de sélecteurs permettant de protéger des attributs maltraités :

  • label[for]
  • abbr[title]
  • iframe[title]
  • video[controls]
  • audio[controls]

Et je relance avec les balises sensibles :

  • figure > figcaption
  • table > caption:first-child
  • fieldset > legend:first-child

Et je suis persuadé que vous pourrez en trouver plein d'autres !

Mise en œuvre

Sans alourdir la prod

Une idée simple est de n'utiliser ces sélecteurs que sur un environnement de développement.

Je tire mon chapeau à une implémentation par Dan Eden pour Scooter, terriblement simple — et donc géniale :

  
    html {
      @include assert-selector(
        '[lang]'
      );
      box-sizing: border-box;
    }
  

Vous pouvez également appeler une feuille de styles dédiée sur votre environnement de développement ou dans votre navigateur : c'est l'objectif d'a11y.css, par exemple.

Conclusion

J'y vois un excellent moyen d'attirer l'attention sur le HTML en communiquant avec mes collègues. C'est aussi une façon détournée d'enseigner le HTML et le CSS — et l'accessibilité, sans la mettre en avant ; un commentaire bien placé avant lesdits sélecteurs auront tôt fait d'expliquer au lecteur de la feuille de styles le pourquoi du comment.

Le mot de la fin

Certains attributs et motifs sont indispensables dans le HTML, pourquoi s'en passer dans le CSS ?

Merci

Et à bientôt ☺

Crédits