Overblog Suivre ce blog
Editer l'article Administration Créer mon blog
10 juin 2008 2 10 /06 /juin /2008 01:32

détail du 'Dragon' de Max Escher

Un fichier CSS ça grossit rapidement et on a vite fait de s'y perdre, comme dans tout code informatique. Comment maîtriser la croissance du bébé ? Je n'ai pas de recette-miracle à proposer, désolé, juste quelques éléments de choix, quelques idées, un peu d'expérience.

Blogs OB : selon les options retenues, la date de création du blog, etc. il peut y avoir un ou plusieurs fichiers CSS. Peu importe pour cet article.

Il ne s'agit pas ici de technique comme dans mes papiers habituels mais d'organisation (et défense de sourire pour ceux qui me connaissent !). Seulement, comme cette organisation s'applique à de la technique, il m'a semblé utile d'en chercher d'abord des justifications rationnelles (première partie de l'article) avant de donner des recettes (deuxième partie).

Jeu pour appâter les littéraires fermés à la technique (qu'ils disent) : Molière et Rimbaud sont cachés dans le paysage, sauras-tu les trouver ?

B-A BA CSS

Oui je sais : je dis toujours que ça va être facile et indolore. Et si c'était vrai, mmh ?

Anatomie de HTML

La structure d'un fichier HTML c'est pauvre : du texte, dans lequel on délimite des blocs bornés par des balises. Ces blocs peuvent être juxtaposés ou emboîtés, ils ne peuvent pas se chevaucher. On peut ajouter des commentaires. Et c'est fini.

Bien sûr, il y a tout un tas de balises, on n'emboîte pas n'importe quoi dans n'importe quoi, etc. Mais tout cela n'est que variations raffinées sur un schéma très simple :  Mourir vos beaux yeux, belle marquise, d'amour me font .

Seul point utile pour la suite : nous pouvons augmenter le  vocabulaire  de balises. Non pas en définissant de nouvelles balises, mais en attribuant des class ou un id à certains blocs de notre choix.

Ah ?  Augmenter le vocabulaire  ? On me dit dans l'oreillette que c'est du chinois ?

Meuh non : si le Père Noël vous offrait une balise enigme, vous écririez quelque chose comme :

 Je ne pige pas <enigme>augmenter le vocabulaire</enigme> 
… et vous le mettriez en forme par une règle CSS enigme {font-weight:bold}

Sans le Père Noël, en définissant une classe bien à vous, vous exprimez la même chose avec :

 Je ne pige pas <span class="enigme">augmenter le vocabulaire</span> 
… que vous mettez en forme par une règle CSS .enigme {font-weight:bold} (merci mebahel – voir les commentaires)

Anatomie de CSS

La structure d'un fichier CSS c'est pauvre : des règles, dans lesquelles on indique la présentation des blocs du fichier HTML. Ces règles s'écrivent l'une après l'autre. On peut ajouter des commentaires. Et c'est fini.

Bien sûr, il y a un tout un tas de propriétés, et tout un tas de possibilités de sélecteur. Mais tout cela…

Anatomie d'une règle CSS

La forme d'une règle CSS c'est simple :

 sélecteur {propriété:valeur;} 

Le sélecteur désigne un type d'élément du fichier HTML et la règle dit seulement que tous les éléments de ce type s'il en existe utilisent telle valeur pour telle propriété. La règle CSS ne dit rien et n'exige rien quant à la présence effective de ces éléments dans le fichier HTML. Tourné autrement : le sélecteur décrit le  champ d'application  possible de la règle dans le document HTML.

Tant que nous y sommes, retenez l'existence d'un sélecteur universel, noté *.

Il y a au début de mon CSS cette règle (ou à peu près) :

 * {border:0px solid gray} 

Elle dit que tout ce qu'il y a dans le blog est doté d'une bordure continue, large de 0px et de couleur grise.

Concrètement, donc, pas de bordure. Quel intérêt ? D'abord, il ne faudra que la largeur pour définir une bordure particulière : économie. Ensuite et surtout : cette couleur grise, que je veux générale, ne figure qu'une seule fois dans le CSS. Donc, si elle change, je suis certain que tous les petits trucs dispersés adopteront la nouvelle couleur et cela sans toucher une seule autre règle : sécurité

Économie et sécurité, on gagne sur les deux tableaux. Plus court on fait et mieux on se porte, ce principe resservira.

Regroupement de règles CSS

On peut mentionner plusieurs propriétés pour un même sélecteur :

 #top {font-size: 2em;} #top {background-color:blue;} 
… s'écrit plus vite en :
 #top {font-size: 2em; background-color:blue;} 

On peut aussi regrouper des règles qui donnent le même aspect à plusieurs éléments :

 #top {font-size:2em} #footer {font-size:2em} 
… s'écrit plus vite en :
 #top, #footer {font-size:2em} 

Enfin, certaines propriétés se laissent regrouper en une seule :

 .box {margin-top:1em; margin-right:1.5ex; margin-left:10px; margin-bottom:2em;} 
… sera plus bref si vous le dites
 .box {margin:1em 1.5ex 2em 10px;} 

Ça va toujours ?

Si ce qui précède est neuf ou difficile pour vous (et c'est bien possible, et ce n'est pas honteux), il est trop tôt. Laissez tomber cet article, reportez-vous au très bon tutoriel du site du Zéro pour y comprendre quelque chose, puis mettez un tout petit peu les mains dans le cambouis et revenez ensuite.

Si vous n'êtes pas largué, nous aborderons encore deux ou trois finesses techniques, puis verrons ce que nous pouvons tirer de tout ça.

Sélecteurs CSS

On l'a dit, le sélecteur, avant les accolades, désigne ce à quoi à s'applique la règle.

Il peut être  simple  (un seul  mot ) ou  composé  (assemblage de plusieurs  mots ).

Un sélecteur simple, outre le sélecteur universel déjà vu, peut être une balise HTML (écrite sans les chevrons autour), une classe (écrite avec un point devant) ou un identifiant (avec un dièse devant).

Sélecteurs composés : il y a plusieurs manières de composer les sélecteurs, toutes ne sont hélas pas comprises par tous les navigateurs – suivez mon regard… Ce qui marche partout, c'est

  1. plusieurs sélecteurs, séparés par des blancs.
    .article p span , par exemple, désigne tout span contenu dans un paragraphe, lui-même contenu dans  quelque chose  de classe article. Il peut y avoir des niveaux intermédiaires entre le  quelque chose  et le paragraphe, tout comme entre le paragraphe et le span.
  2. accoler un nom de classe et/ou un identifiant à un sélecteur.
    p.special désigne tout paragraphe de classe special, img.GcheTexte.special désigne toute image de classe GcheTexte et special. On peut en effet donner plusieurs classes à un même élément, ici ce serait <img class="special GcheTexte" src="tagada.jpg" />, et l'ordre des classes ne joue pas.

Reportez-vous au chapitre 5 de la spécification CSS2 pour une présentation complète.

Priorités entre règles

Là, je vais peut-être vous apprendre quelque chose et qui, de plus, sera bon à savoir.

Il est très fréquent que plusieurs règles concernent la même propriété d'un même élément. Laquelle va s'appliquer ?

Si vous savez déjà ce qu'est la  cascade  ne perdez pas de temps avec cette section un peu longue, sinon cliquez ici.

Petit exemple en forme de blog OB ultra-simplifié. HTML…

 <div id="top"> Le bandeau <p>Un paragraphe dans le bandeau</p> <p class="special">Un paragraphe spécial dans le bandeau</p> </div> <div class="article"> <p>Un paragraphe dans l'article</p> <span class="special">Un span spécial dans l'article</span> <p class="special">Un paragraphe spécial dans l'article</p> <p class="special" id="gazon" >Un peu de verdure</p> </div> 
…et son fichier CSS, assez mal fichu mais c'est exprès  :
 /* r1 */ .special {background:cyan} /* r2 */ p {background:yellow} /* r3 */ #gazon {background:green} /* r4 */ span.special {background:blue} /* r5 */ .article .special {background:red} /* r6 */ .article p.special {background:gray} 

Essayons de trouver ce qui va se produire :

  • pour le texte  Le bandeau , aucun sélecteur ne convient. Sa présentation est donc définie  ailleurs , à savoir dans le CSS du modèle OB utilisé ou, à défaut, dans le CSS du navigateur.
  • pour le  paragraphe dans le bandeau , délimité par des balises <p> et </p>, aucune ambiguïté : seule r2 peut le concerner, son fond sera donc jaune.
  • pour le  paragraphe spécial dans le bandeau , ça se corse puisque r1 et r2 sont candidates. Laquelle prévaut ? Le  gros bon sens  dit que ce serait la règle  special  r1, sinon à quoi bon avoir pris la peine de l'écrire ? La  logique  objectera que la règle  à fond jaune  r2 est écrite après l'autre et que ça peut avoir son importance, non ? Réponse bientôt.
  • pour le  span spécial dans l'article , on trouve r1, r4 et aussi r5. On pressent que r1 ne pèsera pas lourd, mais les deux autres ?
  • pour le  paragraphe spécial dans l'article , n'en jetez plus : r1, r2, r5 et r6.
  • enfin le paragraphe  gazon , qui est aussi de classe  special , semble le pire : à r1, r2, r5 et r6 comme tout à l'heure s'ajoute évidemment r3.

Pour choisir entre plusieurs candidates, le navigateur s'appuie sur les sélecteurs et l'ordre d'écriture des règles. Ni la propriété ni sa valeur n'ont d'influence : il n'y a pas de de valeur  plus forte  que les autres.

En examinant le sélecteur, le navigateur commence par compter toutes les balises HTML ( p ou span dans notre exemple). Il compte aussi les classes et pseudo-classes (telles que :hover). Il compte enfin les identifiants présents dans le sélecteur. Le sélecteur * ne compte pas.

Premier point : les identifiants l'emportent sur les classes et pseudo-classes, qui elles-mêmes l'emportent sur les simples balises. Un sélecteur comportant un identifiant l'emporte toujours sur ceux qui n'en ont pas. C'est assez logique : les balises sont ce qu'on fait de plus banal, les classes indiquent le désir de distinguer un cas particulier, un identifiant indique le désir d'un cas encore plus particulier puisqu'unique dans le document.

Deuxième point : si deux sélecteurs comportent, par exemple, des classes et pas d'identifiant, c'est celui qui comporte le plus de classes qui l'emporte, sans tenir aucun compte des éventuelles balises HTML. C'est seulement en cas d'ex-aequo sur les classes qu'on compte les balises pour décider.

Dernier point : c'est seulement si deux sélecteurs sont complètement ex-aequo (mêmes nombres d'identifiants, de classes, de balises) que le dernier écrit l'emporte.

Application à l'exemple précédent :

  •  paragraphe spécial dans le bandeau  : r1 et r2 sont candidates, r1 l'emporte car son sélecteur comporte une classe alors que celui de r2 n'est qu'une balise ;
  •  span spécial dans l'article  : r1, r4 et r5 sont candidates. r5 l'emporte car son sélecteur comporte deux classes alors que les deux autres n'en mentionnent qu'une ;
  •  paragraphe spécial dans l'article  : r1, r2, r5 et r6. r5 et r6, avec deux classes dans leur sélecteur, l'emportent. r6, ex-aequo en nombre de classes avec r5, l'emporte parce qu'elle comporte une balise HTML et pas r5
  • le paragraphe  gazon  : les mêmes plus la règle r3. Comme le sélecteur de r3 est le seul qui contient un identifiant, r3 l'emporte sur toutes les autres. Ce cas était, en dépit des apparences, le plus facile à trancher !

J'ai déjà pondu un article, ancien et plus fouillé, sur cette question : Des titres en cascade si ça vous intéresse.

Entracte : revenons sur terre

L'objectif est d'une part d'en écrire le moins possible, d'autre part de ne pas avoir à se gratter le crâne pour comprendre ce que fait le fichier CSS.

Voici donc maintenant quelques tuyaux très classiques : sur la manière d'écrire chaque règle, sur la manière de les ordonner, sur les commentaires et enfin sur les tests.

Rédaction des règles

Faire des sélecteurs aussi simples que possible

En effet, à quoi bon écrire ul li, ol li {margin:0} puisqu'un élément li est forcément inclus dans un ul ou un ol ? li {margin:0} suffit donc. Un sélecteur ul li n'a d'intérêt que si l'on veut distinguer la présentation des listes numérotées de celle des listes à puces, et dans ce cas on écrira deux règles.

Autre exemple, à propos des blogs OB : il y a des liens en haut et en bas d'un article (la catégorie,  ajouter un commentaire , etc.), il peut aussi y en avoir dans l'article lui-même et on peut vouloir leur donner des tailles de caractères différentes. Si on écrit :

 .article .option a {font-size:85%} .article .contenuArticle a {font-size:110%} 
… ça marche mais c'est lourd. De plus, si l'on veut que le lien  Recommander  ait encore une autre taille, il faudra écrire au moins
 .article a.linkRecommend {font-size:120%} 
… pour que cette règle ne soit pas  squeezée  par le mécanisme de cascade.

Une possibilité plus simple (parmi d'autres) serait :

 .option a {font-size:85%} a.linkRecommend {font-size:120%} .contenuArticle a {font-size:110%} 

Penser à utiliser les propriétés condensées

Il est bien clair que p {margin:1em 0} est plus vite écrit et compris que

 p {margin-top:1em; margin-bottom:1em; margin-right:0;margin-left:0} 
… sans même parler du besogneux
 p {margin-top:1em} p {margin-bottom:1em} p {margin-right:0} p {margin-left:0} 

Ne pas abuser des propriétés condensées

Il ne faut pas, pour autant, s'interdire l'emploi des propriétés développées.

Par exemple p {padding:1em; padding-left:0} est un moyen clair et rapide de mettre 1em de padding sur tous les côtés sauf à gauche. Ici l'ordre d'écriture compte : nous écrivons deux règles en une seule, avec exactement le même sélecteur, c'est donc la dernière écrite qui l'emporte… Si on avait écrit padding-left en premier, la deuxième règle (qui définit les quatre paddings d'un coup) aurait  écrasé  la valeur de padding-left.

C'est spécialement utile avec les polices de caractères : la ou les quelques polices usuelles sont définies en début de CSS avec la propriété font, par la suite on n'utilise plus que font-size ou font-style.

L'idée est, comme dans l'exemple précédent avec les padding, de n'utiliser les propriétés développées que pour retoucher les propriétés condensées. Toujours avec l'exemple des padding, si on en vient à écrire p {padding:1em; padding-left:0; padding-right:0.5em } il vaudra sans doute mieux passer à la forme condensée p {padding:1em 0.5em 1em 0}.

Mais choisissez ce que vous comprenez le mieux, après tout c'est votre bébé.

Ordonner les propriétés

On se repère plus vite si on prend l'habitude de regrouper les propriétés par  affinités  et de les écrire toujours à peu près dans le même ordre. J'ai trouvé confortable de procéder ainsi :

  1. tout ce qui concerne la présence même dans la page : display, visibility
  2. tout ce qui concerne le placement dans la page : position, float, clear, top/left/bottom/right
  3. tout ce qui concerne les dimensions de la boîte : width, height, margin, padding, border (ou seulement border-width s'il suffit)
  4. la typographie : color, éventuellement background si c'est juste une couleur, font ou seulement font-size et/ou font-style, text-align, line-height, text-decoration, etc.
  5. le fond s'il y a une image
  6. et je crois bien que c'est tout.

Remarquez que les propriétés les plus susceptibles de chambouler l'aspect de la page sont en tête de liste et la pure décoration à la fin.

Ces blocs sont rarement tous présents à la fois, mais je m'efforce de respecter cet ordre : les vérifications sont plus rapides.

Dans le même ordre d'idées : quand la règle est longue chaque bloc commence sur une nouvelle ligne.

Rester homogène

Quelles que soient vos préférences, restez-y fidèle. Réservez les exceptions dans la présentation aux tests ou aux contorsions pour s'accommoder d'  un certain navigateur .

Ordre des règles : principes généraux

Rien que de très classique.

Aller du général au particulier

Toujours utile, ne serait-ce que pour ne pas se faire piéger par la cascade

Écrivez d'abord les règles (s'il y en a) qui portent sur le sélecteur universel, puis celles qui ne comportent que des balises HTML, ensuite celles qui définissent des classes d'emploi très général, enfin seulement la description des sections du document. C'est d'ailleurs ce que fait OB, qui définit par exemple .GcheTexte avant de se plonger dans le détail de la mise en page.

L'idée est de se conformer au fonctionnement de la cascade, au moins dans ses grandes lignes : les sélecteurs les plus  lourds  (identifiants) et les plus composés après les plus  légers  (balises puis classes) et les plus simples. On le fait souvent sans y penser, par exemple en écrivant a:hover après a, il est sage de le faire en y pensant !

Tenir compte de la structure du document

Techniquement, rien ne l'impose : l'interprétation du fichier CSS ne dépend pas de la structure du document. Si un sélecteur n'a pas de sens dans le document, hé bien la règle n'a aucun effet et voilà tout.

Mais il est assez naturel de mettre ensemble les règles qui concernent une même zone de la page, il est naturel aussi d'écrire les règles qui décrivent le haut de la page avant celles qui en décrivent la fin.

Ordre des règles : savoir décomposer une règle

Qu'est-ce à dire ? En première approche, il ne sert à rien que plusieurs règles aient le même sélecteur. Exemple simple :

 body {color:black} #top {color:gray} #top {font-size:2em; } #top {text-align:center} .box {margin:1em 0} .box {color: gray} 
… s'écrit bien mieux comme ceci :
 body {color:black} #top {font-size:2em; text-align:center; color:gray} .box {margin:1em 0; color: gray} 

Mais, si l'on veut garantir que le haut de page et les modules soient toujours écrits de la même couleur(= du gris), le plus sûr est de n'écrire ce code de couleur qu'une seule fois. Il peut donc être sensé dele  mettre en facteur , d'extraire sa définition des diverses règles pour créer une règle ne définissant que cette couleur, et de s'interdire de parler de couleur ailleurs.

Concrètement, avec un petit commentaire explicatif (pour résister à la tentation de tout regrouper plus tard) et un saut de ligne pour aérer :

 /* Définition des couleurs */ body {color:black} #top, .box {color:gray} #top {font-size:2em; text-align:center} .box {margin:1em 0} 

De cette manière chaque couleur n'est mentionnée qu'une seule fois : la maintenance ultérieure sera plus simple et plus sûre.

On peut ainsi monter une ou plusieurs sections, chacune consacrée à un aspect particulier.

Les commentaires

Ça, c'est capital. L'utilité des commentaires est qu'un autre lecteur, mis en présence du monstre, puisse s'y orienter.  Autre lecteur ? Mais il n'y a que moi pour mettre le nez là-dedans !   Voui – connaissez-vous le théorème de Rimbaud ? Passé huit jours,  je est un autre  et ne sait plus ce qu'il voulait dire, c'est prouvé par l'expérience !

Évitez donc les simples paraphrases :

 p {background:yellow} /* fond jaune pour les paragraphes */ 
… c'est idiot et n'apprend rien.

Utilisez plutôt les commentaires pour préciser votre intention,

 p {background:yellow /* même fond que les modules */} 
… pour signaler une acrobatie technique :
 p:first-child {background:grey} /* first-child ne marche pas sous IE */ .article a:hover {position:relative; left:1em!important; left:2em; /* 2em sous IE, 1em sinon*/ } 
… et bien sûr, combinés à des lignes vides, pour délimiter les sections du fichier.

Les commentaires, ça se hiérarchise. Pardon ? J'ai pris l'habitude de jouer avec des  tirets  plus ou moins gros, de marquer les principales sections de mon fichier par ce genre de ligne :

 /*== GRANDE SECTION */ 
… les plus petites sections par ce genre de ligne :
 /*-- Section */ 
… et les toutes petites sections par ça :
 /* section remarquable */ 

Ce système facilite la navigation dans le CSS (on cherche /*== ou /*-- pour naviguer rapidement), j'évite d'employer des lignes complètes de tirets : ça mange vite des Koctets.

Les notes sur une propriété précise sont au plus près de cette propriété :

 .trucmuche img {margin:0;position:relative;z-index:5/*pour être par-dessus .trucmuche*/;border:2px dotted red} 

Radotons : le  style  d'écriture ici décrit n'est pas forcément le meilleur, ce n'est que le mien. Mais j'en ai l'habitude, je le comprends et il me fait gagner du temps. L'important est de mettre le vôtre au point et de vous y tenir.

Tester une modification

Tout dépend de l'ampleur de la modification testée.

S'il ne s'agit que d'essayer un ou deux petits changements, il suffira d'écrire la nouvelle valeur et de mettre temporairement l'ancienne en commentaire :

 .box {margin-bottom : /*20px*/ 10px} 

Une fois la décision prise, vous garderez l'une ou l'autre valeur et il n'y aura plus de commentaires.

Pour des travaux plus étendus, il est conseillé de créer une section propre aux tests et de la mettre en fin de fichier afin de 1- la retrouver rapidement et 2- ne pas se prendre le chou avec la cascade.

Mais n'oubliez pas, une fois les tests terminés, de remonter les modifications à leur place  normale  dans le fichier… et de tester encore une fois.  Normale  signifie ici : en accord avec vos principes d'organisation.

Exemple immodeste

Voilà mon propre fichier CSS global (c'est un vieux blog, il a encore un CSS global et je trouve ça bien commode) et le CSS article.

Ce n'est nullement un idéal de CSS, juste un specimen très perfectible. Vous verrez au moins que j'applique à peu près ce que je prêche.

Peut-être jugerez-vous ce fichier hideux, trop dense ? Bien possible, il y a tout de même (au moment où j'écris cet article) presque 600 lignes ! Un truc pareil ne se gère pas  en direct , j'en ai une copie sur mon micro, copie que je travaille avec Notepad++ et avec, tout de même, un certain succès.

Bonnes lectures

Il existe une masse incroyable d'articles sur la question. En voici deux, en français, trouvés sur l'excellent site pompage.net :

Et, plus encore que d'habitude, je vous renvoie à la spécification CSS2.

commentaires

mebahel 10/06/2008 21:09

Nan mais d'accord, les balises ça sert à borner.
Comme quoi, je suis super balisée, en fait, dans la riheule laïfe.

Aïe mes doigts ! 11/06/2008 10:26


Brillante synthèse ! :-D


mebahel 10/06/2008 21:06

Hhhhhhheeeeeiinnn?
Non mais laisse béton, même pas je sais ce que c'est une balise.
en fait, vje cale donc à la phrase d'avant qui évoque la chose.
C'est déséspéré, je sais.
Mais chacun son domaine de compétences, s'pas.....

Sevenmind 10/06/2008 13:51

Merci beaucoup pour ces lignes d'explication.

Bonne plume et bonne pédagogie!

Reste plus qu'a mettre les mains dans le cambouis.

Aïe mes doigts ! 10/06/2008 16:41


"lignes d'explication" = la réponse au comm' précédent ? Bon, ben c'est ajouté à l'article. S'il en faut d'autres demandez, bonnes gens :-)


mebahel 10/06/2008 12:00

voilà, à partir de ça:
"Seul point utile pour la suite : nous pouvons enrichir le vocabulaire de balises."
je décroche.
Mon css v1 va rester comme il est :p

Aïe mes doigts ! 10/06/2008 13:28


Oh...j'apprécie l'effort, sans rire ! Ca m'apprendra à trop condenser.

Si je te dis que
je décroche

répond au même besoin que
je décroche

Note : j'ai rajouté cet éclaircissement dans l'article, merci maîcresse !

balise qui n'existe pas (quelle lacune...) est-ce que tu me comprends mieux ?
Ou bien s'agit-il d'une allergie générale ?


christina 10/06/2008 01:51

Oh lala... juste quand j'allais enfin me coucher, un oeil sur la boite mail, le temps que le lit chauffe... bon, je reviendrai lire ça en juillet (je me relève à 6h, pas de mumuse avec l'ordi - en ce moment je suis dans les bols pour St Sulpice :
http://christina.guwang.over-blog.fr/article-17818381.html#expos )
Au plaisir
(en vrai à cette occasion ?)

Aïe mes doigts ! 11/06/2008 10:48


Rien ne presse pour la lecture :)
Saint-Sulpice, pourquoi pas ?


Archives