Compléments sur les sélecteurs avancés

Alexandre Niveau
GREYC - Université de Caen
durée : ~20 minutes en allant vite et sans :target
TODO :  il faudrait parler de data-* dans un cours…

Résumé

  • On sait sélectionner un élément
    • en fonction de son type
    • en fonction de sa classe
    • en fonction de son identifiant
  • On sait aussi combiner des sélecteurs, pour sélectionner les éléments qui descendent d'un autre élément ou qui sont adjacents
  • On sait aussi sélectionner les éléments qui satisfont des critères dynamiques (survol par la souris…) grâce aux pseudo-classes
  • On sait même sélectionner des éléments qui n'existent pas vraiment, grâce aux pseudo-éléments
  • Ce cours va encore un peu plus loin

Sélecteurs d'attributs

  • [toto] : sélectionne tout élément ayant toto pour attribut, quelle que soit sa valeur
  • [toto="blabla"] : sélectionne tout élément ayant un attribut toto qui a la valeur blabla (attention, les guillemets font partie de la syntaxe)
  • Sert pour différencier des éléments pour lesquels un attribut peut changer l'apparence ou la signification de l'élément

    utile en particulier pour les éléments de formulaire. Ex. : input[type="submit"]

  • autre exemple d'utilisation : donner un style particulier aux éléments ayant un attribut title (« infobulle » qui apparaît au survol)

autres applications/démos intéressantes : img avec alt ou avec width

Sélecteurs d'attributs plus précis

  • [toto^="bla"] : sélectionne tout élément ayant un attribut toto dont la valeur commence par bla
  • [toto$="bla"] : sélectionne tout élément ayant un attribut toto dont la valeur se termine par bla
  • permet par exemple de donner un style différent aux liens externes ([href^="http://"],[href^="https://"]) ou aux liens vers des PDF ([href$=".pdf"])
  • Moins utiles :
    • [toto*="bla"] sélectionne tout élément ayant un attribut toto dont la valeur contient la chaîne de caractères bla
    • [toto~="bla"] sélectionne tout élément ayant un attribut toto dont la valeur contient le mot bla (séparé du reste par des espaces)
  • peuvent être utiles par exemple pour des attributs contenant des données « custom » (attributs data-*)
  • Encore moins utile : [toto|="bla"], peut servir pour sélectionner les éléments suivant une langue (voir la spéc)

Sélection plus fine des fils

On a vu les sélecteurs :nth-child(odd) et :nth-child(even), pour sélectionner les éléments de rang impair ou pair, mais ce sélecteur permet de faire des choses plus générales :
  • :nth-child(5) sélectionne les éléments qui sont le cinquième fils de leur parent
  • :nth-child(3n) sélectionne un fils sur trois — plus précisément, les éléments dont le rang peut s'écrire sous la forme 3×n, avec n un entier
  • :nth-child(2n+3) sélectionne les éléments dont le rang peut s'écrire sous la forme 2×n+3, c'est-à-dire un fils sur deux à partir du troisième fils (compris)

odd est en fait un synonyme de 2n+1, even un synonyme de 2n

Démo : appliquons les styles suivants aux sélecteurs susmentionnés.
:nth-child(5) { border: 10px solid pink; }
:nth-child(3n) { color: goldenrod;  }
:nth-child(2n+3) { background: rgba(127, 255, 212, 0.5); }
afficher cette page avec ce style

Attention, il faut mettre la partie avec n en premier : :nth-child(3+2n) ne sélectionne rien…

Compter les fils en arrière

On peut compter à partir de la fin avec :nth-last-child(4n+2)

:first-child correspond à :nth-child(1)) et :last-child à :nth-last-child(1)

Tout ceci fonctionne de la même façon avec …-of-type au lieu de …-child, sauf que ça ne sélectionne pas les éléments suivant leur rang dans la liste des fils de leur parent, mais dans la liste des fils de même type de leur parent

Cas spéciaux de fils

  • :only-child : sélectionne un élement s'il est le seul fils de son parent
  • :only-of-type : sélectionne un élément s'il est le seul fils de son parent qui a ce type

    par ex., img:only-of-type sélectionne les images qui n'ont pas d'autre image comme élément « frère »

  • :empty : sélectionne un élément s'il n'a aucun fils (attention, du texte compte comme un fils… y compris des espaces !)

Combiner des pseudo-classes

Les pseudo-classes se comportent vraiment comme des classes

rien n'empêche de mettre plusieurs pseudo-classes à un même sélecteur !

Exemples :
  • :hover:first-child sélectionne un élément s'il est survolé et que c'est le premier fils de son parent
  • :not(ul):not(.toto) sélectionne tous les éléments qui ne sont pas des ul et qui n'ont pas la classe toto
  • .menu li:nth-child(n+3):nth-last-child(n+3) sélectionne les items du menu, sauf les deux premiers et les deux derniers (démo)

Sélectionner l'élément ciblé par l'URL

La pseudo-classe :target permet de sélectionner l'élément ciblé par la partie « fragment » de l'URL courante

Idée : permettre de rendre plus explicite la partie de la page représentée par l'URL (surligner le titre par exemple)

Peut être détournée pour faire des pages un peu dynamiques, sans JavaScript

Explications détaillées et démos sur cette page de cours, avec tutorial pour faire une lightbox en CSS :

Tuto lightbox avec :target

Inverse d'un sélecteur

La pseudo-classe :not(X) permet de sélectionner les éléments qui ne sont pas sélectionnés par le sélecteur X

Elle est surtout utile en combinaison avec d'autres sélecteurs :
  • p:not(.youpi) sélectionne tous les paragraphes qui ne sont pas de classe youpi
  • .toto:not(p) sélectionne tous les éléments de classe toto qui ne sont pas des paragraphes
  • a:not(:visited) sélectionne tous les liens qui ne sont pas déjà visités

On ne peut faire la négation que d'un « sélecteur simple », c'est-à-dire qui ne porte que sur une seule caractéristique (type d'élément, classe, identifiant, ou pseudo-classe), mais pas de combinaison : a:not(.youpi:visited) ne fonctionnera pas

Autres pseudo-classes

  • :lang(fr) pour appliquer un style à un élément d'une certaine langue (attribut HTML lang)
  • :checked, :enabled et :disabled, :valid et :invalid, :default, :optional and :required : pour les éléments de formulaire

Génération de contenu

  • On a vu que la propriété content permet d'ajouter du contenu au document, via les pseudo-éléments ::before et ::after
  • Exemple :
    #toto::after {
        content: "je suis le dernier";
    }
    
    ajoute un fils à l'élément d'identifiant toto, qui contient le texte je suis le dernier, et qui est situé après tous les fils de toto.
  • On peut aussi ajouter autre chose que du texte :
    • content: url("mon-image.png"); pour insérer une image
    • content: attr(toto); pour insérer la valeur de l'attribut toto de l'élément
    • plusieurs choses à la fois : content: "du texte" url("mon-image.png") attr(toto) "encore du texte";
  • Exemple :
    a::after {
        content: " [" attr(href) "]";
    }
    ajoute après chaque lien son URL entre crochets (utile pour l'impression).
  • Il y a aussi des mécanismes pour insérer des compteurs et des guillemets
  • Voir détails sur MDN ou dans la spéc, et un tuto dans Smashing Magazine