Overblog Tous les blogs Top blogs Photographie
Editer l'article Suivre ce blog Administration + Créer mon blog
MENU

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 !"

Publicité

[CSS] Des titres en cascade

détail du 'Dragon' de Max Escher

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.


1 - B-A-BA de CSS

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 :

sélecteur
désigne l'élément de page auquel s'applique la règle. Par exemple, "h2" renvoie à TOUS les titres h2 présents dans la page, compris entre des balises <h2> et </h2>. Si aucun élément de la page ne correspond au sélecteur, la règle est tout simplement inutile et ne cause aucun dégât.
propriété
le nom de la propriété de cet élément sur laquelle on veut agir. Nombre de ces propriétés, comme margin ou padding, ont un sens pour tous les éléments de la page, d'autres comme border-collapse ou list-style ne s'appliquent qu'à certains éléments (respectivement tables ou listes, dans le cas présent).
valeur-de-la-propriété
information indispensable ! Les valeurs possibles dépendent évidemment de la propriété concernée : indiquer un code couleur en guise de font-size (taille de police), bof…

Vous savez sûrement aussi que

  • on peut écrire plusieurs règles pour le même sélecteur (il faut répéter le sélecteur au début de chaque règle).
    Quid en cas de conflit ou d'ambigüité ? C'est justement l'objet de cet article, patience !
  • on peut indiquer plusieurs propriétés dans une même règle, en séparant les couples "propriété-valeur" par des points-virgules. Notez que le point-virgule ne sert qu'à séparer les couples, pas à les terminer : il n'est pas obligatoire après le dernier couple, je n'en ai d'ailleurs pas mis dans mon exemple. Il est tout de même prudent de s'habituer à le mettre systématiquement : ça ne cause aucun dommage et ça évite des erreurs quand on remanie la règle.
  • il existe des propriétés "synthétiques" qui en regroupent plusieurs.
    Par exemple margin : 5px 10px plutôt qu'un fastidieux margin-top:5px; margin-bottom:5px; margin-left:10px; margin-right:10px;.
    Ou encore, et c'est bien commode, background qui regroupe background-color, background-image, background-repeat, background-attachment et background-position.
  • on peut utiliser des sélecteurs composés : "les liens qui sont dans un h2", par exemple, se dit h2 a.
    Oui mais si j'ai aussi des règles qui parlent des liens tout simples ? Patience encore, c'est toujours l'objet de cet article.
  • on peut enfin indiquer qu'une même règle concerne plusieurs sélecteurs.
    Il suffit d'écrire ces "plusieurs sélecteurs" les uns après les autres, en les séparant par des virgules : h2,h3,h4 {color:yellow} écrira tous les h2, tous les h3 et tous les h4 en jaune. C'est exactement équivalent à l'écriture de trois règles séparées. Attention ! Pas de virgule après le dernier sélecteur !

Vous savez certainement qu'il existe trois grandes sortes de sélecteurs :

les balises HTML "nature"
p, h2, body, a… bref, toute la clique.
les classes
leur nom, dans un fichier CSS, est précédé d'un point.
Exemple OverBloggien : .GcheTexte et .DrteTexte sont souvent utilisées pour disposer les images, mais rien n'interdit de s'en servir pour autre chose. De même, .article désigne tous les articles figurant sur une page. Autre exemple bien connu : .box désigne les modules (tiens, tiens, ça se précise…)
les identifiants
leur nom, dans un fichier CSS, est précédé d'un dièse.
Exemples OverBloggiens : #articleAccueil pour l'article d'accueil et #Lien pour le module de liens.
On dit souvent que "un identifiant c'est comme une classe sauf qu'il n'y en a qu'un seul dans la page" et on ne sait, du coup, pas toujours quelle solution choisir.
Il est parfaitement exact qu'un identifiant DOIT être unique (sinon, comment voulez-vous qu'il identifie quoi que ce soit ?) mais ça a des conséquences dont nous parlerons aussi.

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 !)

2 - Le problème

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 ?

3 - Solution empirique

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.

4 - Démerd Démêlons un fichier CSS

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 :

  • elle est facile à mettre en œuvre – et aussi à neutraliser puisqu'elle saute aux yeux quand on relit le fichier CSS ;
  • la géométrie de la page n'est pas perturbée, contrairement à ce qui se passe quand on ajoute des bordures ;
  • le texte reste lisible ;
  • l'encombrement de l'élément ressort nettement, ce qui est commode pour ajuster margin et padding ;
  • elle se combine bien avec une image de fond lorsque, par exemple, on veut voir nettement où celle-ci est coupée.

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.

5 - Résultat, dissertation, fiat lux

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 :

  • les identifiants #quelquechose
  • les classes .quelquechose et les pseudo-classes telles que :hover
  • les balises HTML banales. Le sélecteur universel * compte pour zéro.

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 !

6 - Autre(s) solution(s) et règles pratiques

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à.

Publicité
Retour à l'accueil
Partager cet article
Repost0
Pour être informé des derniers articles, inscrivez vous :
Commenter cet article
A
Bonjour Brendufat :) j'ai 2 nouvelles :<br /> 1) la bonne : c'est que c'est très clair<br /> 2) la mauvaise : certaines lignes du CSS changent en V2, ainsi <br /> les #main disparaissent et deviennent des #ln_1 (je simplifie)<br /> les h2 deviennent des .box-titre h2 span<br /> les #Lien  deviennent des .liens<br /> Je suis sûr que tu vas t'amuser comme un fou avec la V2 :)<br /> PS :'la géométrie de la page n'est pas perturbée, contrairement à ce qui se passe quand on ajoute des bordures ; "---> tu as remarqué aussi :(<br />  
Répondre
A
Merci d'être passée.1) c'est clair ? Tant mieux, c'était l'essentiel.2) la CSS  v2 n'est pas celle de la v1 ? Pas très grave : l'objet premier de ce papier n'est pas de faire un cours sur la v1 ou la v2 ou les divers designs, mais d'expliquer le mécanisme (général) de cascade en partant d'un exemple (particulier, concret et parlant pour les overbloggeurs). L'exemple sera bientôt périmé ? Ca ne change rien au fond de l'histoire. Et je serais bien étonné que la v2 ne provoque aucune prise de tête du même genre ! :-DPS : j'avais remarqué aussi, c'est pourquoi j'ai cru bon d'argumenter un peu en livrant  ma petite recette ... Puisque je proclame mon horreur des solutions toutes faites pour amputés du cerveau, il faut bien donner l'exemple !