Paris, photo, humeurs, un peu de HTML/CSS pour faire sérieux. Feinte innocence et vraie naïveté (ou vice-versa). Encore un blog qui agite ses petits bras en couinant "Viens me lire !"
Note de janvier 2008 : cet article traite d'un blog en version 1 d'Overblog, les noms de classe et les identifiants ont changé depuis. L'exemple utilisé est donc périmé, cependant les principes exposés sont généraux et toujours valides.
Pardonnez-moi ce titre vaseux, je n'ai pas pu m'en empêcher – vous comprendrez mieux en lisant l'article.
AnnaK, qui tient un très bon blog d'assistance et tuyaux divers, avait commencé de trafiquer d'améliorer la présentation des titres de ses modules. Tout se passait très bien, la fièvre créatrice était à son sommet, jusqu'à ce qu'elle veuille changer la taille de la police de caractères. Et là, rien. Rébellion du blog, inertie totale. Coup de bol monstrueux, j'ai pu lui procurer une solution et surtout lui expliquer pourquoi cette solution marchait, ainsi que celle qu'elle avait, dans l'intervalle, trouvée par tâtonnements.
En y repensant, je me suis dit que l'occasion était bonne de regarder de plus près la manière dont un navigateur choisit la ou les règles de présentation qu'il applique à une page HTML. C'est ce qu'on appelle la "cascade", autrement dit le "C" de CSS.
Ça vous intéresse ? Attention : comme tous mes articles technicoïdes, celui-ci suppose que vous avez un peu d'expérience, que vous avez déjà tourné en rond une fois ou deux, bref que vous avez vraiment envie de comprendre.
Vous connaissez sûrement ce qui va suivre. Dans le cas contraire, baptisons-le pudiquement "rappel" et n'en parlons plus.
Un fichier CSS ne contient qu'une suite de règles de présentation des divers éléments présents (ou pas) dans une page HTML. Aucun renseignement sur le contenu de la page (c'est le rôle de la page elle-même), aucun renseignement sur ce qui se passe quand on se promène dans la page (c'est le rôle de JavaScript). Petite exception à cette dernière phrase, l'aspect "au survol" des éléments ( a:hover, ça vous dit quelque chose ?) – mais nous n'en parlerons pas dans la suite.
Une règle CSS, dans sa forme la plus élémentaire, se présente ainsi :
sélecteur { propriété : valeur-de-la-propriété } On peut même ne rien mettre entre les accolades ! Ça n'a évidemment aucun effet sur la page HTML, mais ce peut être un aide-mémoire, une façon de se rappeler que "faudra creuser ça plus tard". Attention : même vides, les accolades doivent être là – ou bien on n'écrit rien du tout, ce qui est un assez sûr moyen d'avoir la paix…
Approchons-nous pour mieux voir :
Vous savez sûrement aussi que
Vous savez certainement qu'il existe trois grandes sortes de sélecteurs :
Vous savez de même qu'une règle peut être outrepassée par une autre, plus spécifique ou écrite après.
Vous savez pour finir qu'il existe un mot-clé ! important qui sert à semer la grouille, à attraper des maux de crâne et à supporter Internet Explorer. J'admets que ma présentation est un peu tendancieuse…
S'il vous semble que j'écris en proto-sumérien haute époque, c'est que vous n'êtes pas mûr ! Allez lire les quelques références que je mentionne dans Quelques sites, vous devriez y voir plus clair ensuite.
Tant que j'y pense, voilà un site bien pratique pour traduire un sélecteur en langage (presque) clair :SelectOracle (en anglais ou espagnol, mais vous êtes très fort !)
Ne vous inquiétez pas, ce sera beaucoup plus bref.
AnnaK voulait peaufiner l'aspect des titres de ses modules.
Les modules appartiennent tous à la classe box, et eux seuls appartiennent à cette classe. Leur titre est un h2. Comme il y a d'autres h2 dans la page (les titres des articles, pour ne pas les nommer), le sélecteur doit préciser qu'il s'agit d' "un h2 qui est dans un .box".
En bon dialecte CSS, ça se dit .box h2 {les-propriétés-qui-vont-bien}.
Ô merveille, ça marchait très bien ! Sauf pour la propriété font-size.
Ô désespoir, ô perplexité. Comment s'en sortir ?
Le principe : on va lui mettre les points sur les "i". Puisque tu ne veux pas t'intéresser aux .box en général, on va te les nommer en clair, ces fichus modules ! Avec quelque chose comme ça, pour voir :
#Lien h2, #ArticleRecent h2, #Categorie h2 /*...bref, tout le monde...*/ {font-size:12px} Bingo ! Certes, il est logique que cette règle marche. Mais pourquoi la précédente ne marchait-elle pas ? Et pourquoi seulement pour font-size ? Et qui va gagner les élections ? Pardon, je dérive un peu. N'empêche que c'est inquiétant : il y a encore beaucoup de pièges comme celui-là ? C'est pas des pièges, c'est des finesses – vous allez voir.
Première vérification, l'orthographe et la syntaxe. Tous les noms sont-ils corrects ? J'ai tendance à écrire "artlice" au lieu de "article", par exemple – et ça, aucun logiciel ne peut signaler que c'est une erreur. Autre genre de piège : le module qui contient les lienS s'appelle Lien, sans "s". Dernier piège du même ordre : les majuscules et minuscules. Les points-virgules sont tous là ? Les accolades sont toutes fermées ? Les commentaires sont correctement fermés, eux aussi ? Toutes ces questions sont basiques mais bien réelles. Utiliser un éditeur de texte avec coloration syntaxique (ben oui, ce cher Notepad++, évidemment) fait gagner beaucoup de temps.
Avec l'habitude, on finit par vérifier tout ceci sans y penser, n'en parlons donc plus et admettons que le fichier CSS est, dans sa forme, correct.
Deuxième vérification : le sélecteur désigne-t-il bien ce qu'on veut ? Ma technique banale, simple et rapide est de coller une couleur de fond bien vive et absente de la page telle que, pour mon blog, rose ou cyan.
Il y a d'autres méthodes, mais je trouve à celle-ci les avantages suivants :
Dans notre cas, ce n'est toujours pas ça, et .box h2 désigne bien ce qu'on veut.
Conclusion d'étape : d'autres règles viennent interférer. Le langage CSS est déterministe et il y a une explication à tout ! mais elle est parfois bien planquée, d'accord. On va trouver.
Où peuvent se trouver ces autres règles ? Dans le fichier CSS lui-même bien sûr, mais aussi dans d'autres fichiers CSS mentionnés dans la page HTML. Chez OverBlog, il s'agit de common.css qui à son tour mentionne commonstruct1.css (ou commonstruct2.css ou commonstruct3.css selon le design utilisé pour le blog). Quelque part dans ma série "Ordre et méthode" (qui reste à terminer mais ça viendra) j'explique comment les récupérer, ce n'est pas très compliqué. Ces autres règles peuvent enfin se trouver écrites directement dans le code HTML, un examen du code source suffit pour s'en assurer.
Dans notre cas, tout se joue dans le fichier CSS custom.css géré par l'auteur du blog. Coup de veine et pas besoin de courir chercher toutes ces annexes !
Quelles règles chercher ? Voilà la question délicate – parce qu'il y en un sacré paquet, de ces règles ! Réponse : toutes celles (et seulement celles) dont le sélecteur concerne l'élément étudié. On s'en doutait un peu, mais encore ? On restreint la recherche aux règles qui jouent sur la propriété étudiée, ici font-size, ce qui en élimine un grand nombre.
Il faut aussi garder à l'esprit qu'une page HTML est faite d'éléments emboîtés les uns dans les autres. Puisque, comme dit plus haut, on s'intéresse "au h2 qui est dans un .box", il faut pousser le raisonnement jusqu'au bout : à son tour le .box se trouve dans #leftnav qui se trouve dans #MainTab (selon le design employé) qui se trouve dans etc. qui se trouve dans body et repérer les règles qui s'appliquent à ces divers "conteneurs". Vous comprenez pourquoi on parle de cascade ? Les propriétés d'un contenant "se déversent" sur les contenus successifs.
Mine de rien, nous venons de faire à la main exactement ce qu'un navigateur fait à la machine – et ce n'est pas fini.
Les CSS d'OverBlog étant plutôt bien structurées, notre recherche n'a trouvé que (deux + la nouvelle) règles susceptibles d'influencer la taille de la police des titres de modules. Dans l'ordre (c'est important pour la suite) :
/* Deux règles déjà présentes */ h2 { color: #5675A4; font-size: 13px;} #main1 h2 { margin:0px 0px 10px 0px; padding:0px; font-size:110%; } /* titre des articles */ /* la nouvelle règle */ .box h2 { font-size:120%;} En toute rigueur il y en a d'autres (une règle sur body par exemple) mais, spontanément, vous avez pensé que cette règle très générale était supplantée par les règles plus particulières indiquées ci-dessus. Vous avez raison mais il va falloir approfondir cette question du particulier et du général.
C'est un très joli exemple que nous tenons là, parce qu'on y trouve les trois sortes de sélecteurs : balise HTML, classe et identifiant (voir le "rappel pudique" si vous avez oublié) et des sélecteurs (un peu) complexes.
Restons dans le raisonnement intuitif : le sélecteur "h2" est très général, on comprend facilement que "un h2 dans #main1" ou "un h2 dans un .box" prennent le dessus quand on est dans un de ces cas. Facile. Mais comment arbitrer entre ces deux derniers ? Parce qu'il est vrai que notre titre de module est bel et bien inclus dans #main1. Ben ... 1) dans la page HTML, le .box est inclus dans #main1 et pas l'inverse, donc c'est plus particulier 2) de plus, la nouvelle règle vient après celle sur "#main1 h2" DONC ça doit marcher OR ça ne marche pas.
Gasp. Où est l'erreur ? La réponse gît dans la spécification CSS2 du W3C – quand je vous dis que ce truc est une mine, je sais bien pourquoi ! Bon, d'accord : dans une mine il fait rarement très clair.
D'abord, écartons l'argument numéro 1 (structure de la page HTML) tout simplement parce que le navigateur analyse le fichier CSS AVANT de s'intéresser à la page : il a besoin du CSS pour traiter le texte de la page (= le mettre en forme) et pas l'inverse. Quand il doit choisir entre plusieurs règles, le navigateur ne peut donc s'appuyer que sur les sélecteurs des règles.
Le raisonnement est assez simple. Sans vous donner tous les détails, je me limite à ce qu'on trouve communément dans un CSS de blog : si vous savez utiliser autre chose, vous n'avez pas besoin de mes explications.
Le navigateur fait, pour chaque sélecteur, le compte de trois tas :
Chacun de ces tas emporte le morceau sur les suivants : une règle dont le sélecteur mentionne ne serait-ce qu'un seul identifiant l'emportera toujours sur une règle qui n'en comporte pas, même un truc de la mort genre "table td tr div.box div.box-content h2". De même, un sélecteur qui mentionne une classe l'emportera toujours sur un sélecteur composé uniquement de balises HTML.
Dans un même tas, c'est le nombre d'éléments du tas qui fait la décision : deux identifiants pèsent plus lourd qu'un seul. En cas d'ex-æquo, la décision dépend des tas plus humbles, selon le même procédé (dites "algorithme" si vous voulez faire chic, peu me chaut).
Enfin, c'est seulement en cas d'ex-æquo persistant que l'ordre intervient, et la dernière règle rencontrée remporte la palme.
Ce n'est ni idiot ni arbitraire : puisqu'un identifiant est, par définition, unique dans une page, on comprend que ses indications prennent le pas sur celles d'une classe qui peut exister en plusieurs exemplaires – et encore plus, évidemment, sur celles de la piétaille des balises HTML.
Cette répartition en trois classes, ça rappelle des souvenirs historiques. Dumézil aurait peut-être aimé – mais bon, là je frime comme un malade, n'y pensons plus.
"EurêK !" s'exclama AnnaK qui venait de comprendre son K difficile (pardon madame !). "C'est la règle "#main1 h2" qui étouffe les deux autres !" Exactement. C'est aussi pour ça que les propriétés autres que font-size n'étaient pas concernées, tout simplement parce que la règle "#main1 h2" n'en parle pas et qu'il n'y avait donc pas de conflit pour ces propriétés. Notons cependant qu'AnnaK aurait eu bien du mal à trafiquer ses margin et padding. Elle n'a peut-être pas essayé ?
C'est enfin pour ça que sa solution marchait : "#Lien h2" pèse exactement aussi lourd que "#main1 h2" (un identifiant + une balise) mais, écrite sans y penser après cette dernière, elle l'a supplantée. Si jamais la règle "#main1 h2" émigre vers le bas du fichier CSS, gare !
Il est bien agréable de comprendre ce qui cloche mais il faut penser à l'avenir.
Oublions les bricolages techniques et reprenons la question à neuf. Au fond, on veut faire quoi ? Traiter de manière différenciée les titres h2 disséminés dans la page. Une page de blog s'organise en quelques grands pavés : le haut et le bas de page (#top et #footer), les colonnes de modules (#rightnav et #leftnav), le corps de page (#content), auxquels s'ajoute le bandeau OverBlog tout en bas, qui ne comporte pas d'identifiant particulier et c'est sûrement fait exprès pour empêcher les petits malins de le dissimuler.
Les grands pavés sont à leur tour regroupés dans un autre ou un emboîtement d'autres dont le nom dépend du design utilisé. Ici, c'est #main1.
Question : puisqu'on veut traiter indépendamment les h2 contenus dans les divers pavés, à quoi sert de conserver une règle "lourde" concernant l'ensemble des pavés ? Réponse : à rien d'autre qu'à se compliquer la vie.
C'est pourquoi je propose de supprimer cette règle et de lui substituer
h2 {... des propriétés communes à tous les h2, s'il en existe ...} #top h2, #footer h2, #content h2 {... des propriétés propres aux titres de ces coins-là ...} .box h2 {.. des propriétés propres aux titres de modules....} Ou, encore meilleur car moins inutilement spécifique (et plus vite écrit) :
h2 {... des propriétés communes à tous les h2 ....} .box h2 {...les propriétés particulières des titres de modules ...} Comment choisir ?
La première solution dit "les h2 dans #top, #footer et #content sont comme ci, ceux dans les .box sont comme ça". Sans autre précaution, on risque des surprises dans, par exemple, un écran de saisie de commentaire parce qu'il est organisé autrement et qu'on n'a pas prévu le coup. En compensation, ce qui est écrit est très explicite.
La deuxième dit "Tous les h2 partout sont comme ci SAUF les .box h2 qui sont comme ça". C'est plus général, les cas inattendus tels que la saisie de commentaire sont couverts, mais c'est plus vague.
À vous de choisir le mode de description qui vous convient le mieux : par énumération exhaustive ou par cas général et exceptions.
Une règle d'expérience : on finit toujours par s'en sortir en rajoutant des tonnes de classes et d'identifiants mais c'est très vite lourd à écrire (ben oui, des tonnes…), et difficile à analyser quand ça foire.
Mieux vaut réfléchir un peu et, au contraire, supprimer la graisse inutile. Less is more.
Par ici, c'est le tutoriel du Site du Zéro. Pas encore lu ? Foncez !
Cette fois-ci, vous irez peut-être jeter un coup d'œil à la VF de la spécification CSS2 ?
De la même source, la VF de la spécification HTML 4.01 est d'une lecture plus ardue mais certaines réponses ne se trouvent que là.