TP 8 : Sélecteurs avancés

Licence Informatique/Maths 1ère année

Alexandre Niveau — Jean-Marc Lecarpentier

Enseignement des technologies du Web

 

Travail personnel

Objectifs

Le premier exercice vise à vous faire découvrir les sélecteurs avancés avec un exercice très guidé en mode tutoriel. Le second exploite les sélecteurs avancés de manière un peu moins guidée.

Notes de cours

Exercice 1 — Introduction aux sélecteurs avancés #

Cet exercice fait partie de ceux qui seront évalués. La page doit être accessible et fonctionnelle à l'URL suivante :

https://dev-NUMETU.users.info.unicaen.fr/2020/L1-TW1/TP08/ex1/intro-selecteurs-avances.html
(en remplaçant NUMETU par le numéro correspondant). Pensez à vérifier la validité W3C de votre page !

D'autre part, l'élément head doit contenir le code suivant :

<meta name="author" content="NUMETU" />
en remplaçant NUMETU par votre numéro étudiant. (Il faut laisser name="author" tel quel, par contre !) Par exemple, si votre numéro est 21012343, vous mettez <meta name="author" content="21012343" /> dans le head de votre page. Pour cet exercice, il est interdit de travailler en binôme.

Il est conseillé de vérifier que l'exercice a été correctement rendu en utilisant l'application evalweb.

Vous avez jusqu'au début du TP de la semaine suivante pour terminer l'exercice.

Télécharger cette archive, elle contient un fichier HTML et une feuille de style CSS qui lui est associée. Placer ces fichiers au bon endroit sur votre serveur (voir les instructions dans l'encadré rouge ci-dessus). Ouvrez l'URL correspondante sur votre navigateur (NB: l'URL dans la barre d'adresse doit commencer par https://, sinon c'est que vous ne regardez pas la bonne page ; demandez de l'aide).

Dans cet exercice, on va manipuler plusieurs sélecteurs « avancés ». Les règles déjà présentes dans le CSS ne font qu'ajouter des couleurs et des bordures.

Quand l'exercice pose des questions, vous devez y répondre en mettant des commentaires dans le fichier CSS. (Rappel : la syntaxe des commentaires CSS, /* c'est ça */) N'hésitez pas à utiliser l'inspecteur de Firefox (voir TP précédent) pour cocher/décocher les propriétés étudiées, afin de mieux voir les différences.

  1. Observer la structure du HTML : il y a des paragraphes, des articles, et des aside. Chaque aside est dans un article, et donne des compléments d'information sur l'article en question. Il y a un paragraphe en-dehors de tout article (l'introduction), des paragraphes dans les articles, et des paragraphes dans les aside.

    Dans un premier temps, on voudrait donner un style particulier aux paragraphes des articles : on veut qu'ils soient en violet clair (plutôt qu'en blanc), justifiés, avec un alinéa et un gros padding à gauche et à droite. Cependant, on ne veut pas que ce style s'applique aux paragraphes des aside et à l'introduction. On va voir comment faire.

  2. Ajouter la règle suivante dans le fichier CSS :

     p {
       text-indent: 3em;
       text-align: justify;
       padding: 0 5em;
       color: #DCF;
     }

    Observer l'effet de ce changement de style, et constater qu'il s'applique à tous les paragraphes dans la page, ce qui est normal vu le sélecteur utilisé.

  3. Le résultat ne convient pas, car le style s'applique au paragraphe d'introduction et aux paragraphes des aside. Une première idée est d'annuler le style pour les paragraphes en question ; par exemple pour le paragraphe d'introduction on peut ajouter la règle suivante :

     .intro {
       text-indent: unset;
       text-align: unset;
       padding: unset;
       color: unset;
     }

    Essayer, et constater que ça fonctionne : la valeur unset a pour effet d'« annuler » les modifications effectuées, en remettant une propriété à une valeur par défaut intuitive. En particulier, remarquer que la couleur obtenue pour le paragraphe d'introduction est le blanc, et non le noir : c'est parce que color est une propriété héritée. La valeur « par défaut » choisie par unset pour les propriétés héritées est inherit.

    Ça fonctionne, mais ce n'est pas très pratique. En effet :

    • Il faut appliquer cette règle à tous les paragraphes pour lesquels le style « général » n'est pas désiré. Si la page évolue, on peut avoir des surprises.
    • Il faut préciser toutes les propriétés que l'on veut annuler. Si l'on change la règle générale sur les p, il faudra se souvenir d'annuler ses effets dans toutes les « règles d'annulation ».

    En résumé, cette façon de faire n'est pas du tout robuste, et rend le HTML et le CSS difficiles à maintenir. On va faire mieux. Mettre la règle portant sur .intro en commentaire avant de passer à la suite.

  4. On va maintenant écrire le CSS de façon plus logique : au lieu d'écrire une règle trop générale dont on doit annuler les effets ensuite, on va utiliser un sélecteur plus précis pour cibler uniquement les paragraphes qui nous intéressent.

    Lorsque l'on est confronté·e à ce problème, il y a une solution radicale qui est toujours techniquement applicable : utiliser une classe. Dans notre cas, il suffirait d'ajouter une classe paragraphe-dans-article à tous les paragraphes souhaités, et d'ajouter dans le CSS une simple règle portant sur cette classe.

    Ça fonctionnerait, mais ce n'est pas très pratique d'ajouter la classe aux trois quarts des paragraphes de la page ; et d'autre part, si la page évolue, il ne faudra pas oublier d'utiliser cette classe sur les nouveaux paragraphes. Cette solution est plus pratique que la précédente, mais n'est toujours pas idéale en termes de robustesse et de maintenabilité.

    Le bon compromis dans notre cas est d'utiliser une combinaison de sélecteurs, traduisant au mieux notre souhait : on veut sélectionner les paragraphes qui sont dans des articles. Reprendre la règle sur p précédemment introduite, et remplacer le sélecteur (p) par article p. Que se passe-t-il ?

  5. Le sélecteur choisi se lit comme suit : « sélectionner les éléments de type p qui ont pour ancêtre un élément de type article ». Cela exclut bien le paragraphe d'introduction, mais pas les paragraphes des aside. Expliquer pourquoi.

    Remplacer le sélecteur article p par article > p, qui se lit « sélectionner les éléments de type p qui ont pour parent direct un élément de type article ». Constater que cela donne l'effet voulu, et expliquer pourquoi.

  6. On voudrait à présent que les paragraphes qui suivent un titre de section n'aient pas d'alinéa. (C'est une règle typographique courante dans les publications anglophones.) Une nouvelle fois, on pourrait ajouter une classe à tous les paragraphes en question, mais ce n'est pas pratique : ce style dépend uniquement de la structure du texte.

    C'est un cas d'utilisation idéal pour le sélecteur d'adjacence : h3 + p va sélectionner les paragraphes qui suivent immédiatement un h3. Ajouter une règle utilisant ce sélecteur pour retirer l'alinéa des paragraphes en question.

  7. Il existe également un sélecteur d'adjacence plus général, h3 ~ p. Celui-ci va sélectionner les paragraphes qui sont précédés par un h3, mais il peut y avoir d'autres éléments entre les deux (tant qu'on reste dans le même parent). Ce sélecteur est plus rarement utile. On va l'utiliser ici pour donner un style différents aux premiers paragraphes d'un article, avant le premier h3. Noter que ça concerne un paragraphe dans le premier article, deux paragraphes dans le second, et aucun dans le troisième.

    Pour obtenir cet effet, la solution la plus simple est d'abord d'attribuer le style voulu à tous les paragraphes, et de l'annuler derrière pour les paragraphes qui ne doivent pas être concerné. Ajouter une règle pour mettre en gras et italique tous les paragraphes qui sont dans un article, puis ajouter une règle avec le sélecteur h3 ~ p qui annule la mise en gras et italique. Constater que ça fonctionne et expliquer pourquoi.

    NB : l'utilisation de cette technique dans ce contexte est discutable. L'effet obtenu donne l'impression que les paragraphes qui précèdent le premier titre de section font partie d'une introduction ou d'un « chapeau », mais c'est un aspect sémantique, non réductible à la structure du HTML. Pour illustrer le problème : il se pourrait qu'on doive plus tard ajouter des articles ayant à la fois un chapeau et des paragraphes avant le premier titre de section ; notre CSS ne fonctionnerait pas dans ce cas — il n'est pas robuste.

  8. On va maintenant expérimenter les pseudo-classes. Ajouter la règle suivante dans le CSS :

    :hover {
    box-shadow: .6em .2em 1em white;
    border-radius: .5em;
    }

    Faire passer le curseur de la souris un peu partout dans la page. Que se passe-t-il ?

  9. Remplacer le sélecteur par aside:hover (sans espaces). Passer la souris dans la page : que se passe-t-il maintenant ?

  10. Le sélecteur aside:hover est une conjonction de sélecteurs. Il sélectionne les éléments ayant à la fois deux caractéristiques :

    • ils sont de type aside, et
    • ils sont actuellement survolés par le curseur (pseudo-classe :hover).

    La conjonction est obtenue en accolant les deux morceaux sans espace. Si on les sépare avec une espace, la signification est totalement différente ! Tester : modifier le sélecteur en aside :hover (avec une espace avant le deux-points). Essayer de survoler des éléments dans les aside. Pouvez-vous expliquer ce qui se passe ? Comment ce sélecteur est-il interprété ?

    Enlever ensuite l'espace pour remettre le sélecteur dans l'état initial (aside:hover).

  11. Il existe de nombreuses pseudo-classes. Parmi celles qui permettent d'obtenir un comportement dynamique, il y a :active. Ajouter la règle suivante dans le CSS :

     aside:active {
       text-transform: uppercase;
     }

    Essayer de cliquer sur les aside (en gardant le clic enfoncé un petit moment). Que se passe-t-il ? Quel est l'effet de la pseudo-classe :active ?

  12. C'est un peu extrême de mettre tout le texte en majuscules. Remplacer le sélecteur de la règle précédente par aside:active h3. Que se passe-t-il maintenant ? Constater que l'effet obtenu est le même, quel que soit l'endroit où on clique dans un aside (sur le h3 ou non). Expliquer pourquoi en précisant comment le sélecteur est interprété.

  13. D'autres pseudo-classes permettent de sélectionner des éléments en fonction de leur position dans leur parent. Ajouter les règles suivantes au CSS :

     :first-child {
       border-top: 10px solid forestgreen;
     }
     :last-child {
       border-right: 10px solid darkred;
     }

    Observer le résultat, et s'assurer de bien comprendre pourquoi chaque bordure verte ou rouge est apparue. Y a-t-il un ou plusieurs élément(s) qui ont à la fois une bordure verte en haut et une bordure rouge à droite ?

  14. Ajouter maintenant les règles suivantes :

     :first-of-type {
       border-left: 10px solid orange;
     }
     :last-of-type {
       border-bottom: 10px solid lightblue;
     }

    Constater qu'il y a davantage d'éléments avec une bordure orange à gauche ou bleue en bas, que d'éléments avec une bordure verte en haut ou rouge à droite. C'est parce que les pseudos-classes *-of-type considèrent indépendamment les listes d'éléments de chaque type. Par exemple, dans un article, il y a un premier et un dernier p, un premier et un dernier h3, un premier et un dernier aside, etc.

    S'assurer de bien comprendre la présence des bordures des quatre types. Y a-t-il un ou plusieurs élément(s) qui ont les quatre bordures à la fois ?

    Quand vous avez terminé, mettre en commentaire les quatre dernières règles ajoutées.

  15. Pour sélectionner le premier élément d'un certain type, on peut s'appuyer sur la conjonction de sélecteurs. Supposons qu'on veuille mettre le premier paragraphe de chaque article en petites capitales. Laquelle des deux règles suivantes va fonctionner ?

     p:first-child {
       font-variant: small-caps;
     }
    
     p:first-of-type {
       font-variant: small-caps;
     }

    Tester, garder la bonne règle, et expliquer pourquoi l'autre ne marche pas.

  16. On teste maintenant les pseudo-éléments. Ajouter les règles suivantes dans le CSS :

     h1::first-letter {
       color: rebeccapurple;
       font-size: 200%;
       vertical-align: middle;
     }
    
     .intro::first-line {
       font-style: italic;
       font-weight: bold;
       font-size: 140%;
     }
    
     aside::after {
       content: "⁂";
       display: block;
       font-size: 2em;
       text-align: center;
     }

    Expliquer ce que chacune de ces règles fait.

    Quelle est la différence fondamentale de fonctionnement entre :first-child et ::first-line qui fait que le premier sélecteur est une pseudo-classe alors que le deuxième est un pseudo-élément (différence explicitée syntaxiquement par le nombre de deux-points employé) ?

Exercice 2 — Application des sélecteurs avancés #

Cet exercice fait partie de ceux qui seront évalués. La page doit être accessible et fonctionnelle à l'URL suivante :

https://dev-NUMETU.users.info.unicaen.fr/2020/L1-TW1/TP08/ex2/recette.html
(en remplaçant NUMETU par le numéro correspondant). Pensez à vérifier la validité W3C de votre page !

D'autre part, l'élément head doit contenir le code suivant :

<meta name="author" content="NUMETU" />
en remplaçant NUMETU par votre numéro étudiant. (Il faut laisser name="author" tel quel, par contre !) Par exemple, si votre numéro est 21012343, vous mettez <meta name="author" content="21012343" /> dans le head de votre page. Pour cet exercice, il est interdit de travailler en binôme.

Il est conseillé de vérifier que l'exercice a été correctement rendu en utilisant l'application evalweb.

Vous avez jusqu'au début du TP de la semaine suivante pour terminer l'exercice.

Récupérer cette page HTML (archive) et l'utiliser pour tester les différents sélecteurs avancés en répondant aux questions suivantes, sans changer le code HTML (sauf pour mettre vos numétus dans l’entête).

  1. Pour commencer, réduire la largeur du body, par exemple à 40 em, ce qui permet d'avoir des lignes d'environ 80 caractères quelle que soit la taille de la police.
  2. Mettre en valeur la première lettre de chaque paragraphe, soit en modifiant sa taille ou sa couleur, soit en en faisant une lettrine (drop cap).
    1. Mettre en gras la première ligne de chaque paragraphe.
    2. Modifier votre règle pour que seule la première ligne du premier paragraphe de chaque partie soit en gras.
  3. Faire en sorte que l'alignement des titres soit alterné, une fois à gauche, une fois à droite. Les paragraphes doivent rester en place.
  4. Le dernier paragraphe contient uniquement une formule consacrée.
    1. Le mettre en valeur comme vous le voulez (centré, italique…).
    2. Est-ce que la méthode que vous avez employée vous semble correcte (c'est-à-dire propre, robuste, sémantique…) ? Si vous aviez le droit de modifier le HTML, auriez-vous choisi la même solution ?
  5. Ajouter le caractère de décoration suivant : « ✽ » au début et à la fin de chaque titre de partie. (NB : vous pouvez le copier tel quel dans le CSS, c'est un caractère comme un autre.)
  6. Mettre ce caractère de décoration en vert.
  7. Faire en sorte qu'au survol d'un paragraphe, la couleur du texte qu'il contient change.
  8. Faire en sorte que lorsque l'on clique sur un titre (sans relâcher), un cadre de couleur apparaisse autour, et que le titre se retrouve centré dans ce cadre.
  9. Faire en sorte que lorsque l'on survole un paragraphe, les éléments em qu'il contient soient mis en majuscules.
  10. Faire en sorte qu'au survol d'un paragraphe, sa couleur de fond et celle du paragraphe suivant (dans la même partie) changent.
  11. (Optionnel) En n'utilisant qu'une seule règle CSS, faire en sorte que tous les titres apparaissent en petites capitales, sauf lorsqu'ils sont survolés. (j'avais oublié d'enlever cette question que vous ne pouvez pas faire avec seulement ce qu'on a vu en cours)
  12. (Optionnel) Faire en sorte qu'au survol d'un titre, les paragraphes de cette partie changent de couleurs de texte et de fond, mais pas les autres. Attention, la solution est simple, mais pas évidente à trouver ; ne pas hésiter à demander de l'aide. (Indice : ce n'est pas faisable avec une seule règle.)