Compendium CSS pour XML

Université de Montréal, EBSI
BLT6131 Informatique documentaire avancée
Copyright © 2005-2006 Yves MARCOUX


Introduction

Tous les exemples montrés ont été réalisés avec Firefox. C'est un des meilleurs outils pour le CSS avec du XML. Nous utilisons dans nos exemples le document XML suivant:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE mémo SYSTEM "memo.dtd">
<?xml-stylesheet href="memo.css" type="text/css" ?>
<mémo>
<auteur>Julia Royer</auteur>
<destinataires>
   <nom courriel="picardj@enterprise.org">Jean Picard</nom>
   <nom>Émilie Dugré</nom>
   <nom courriel="ap@ap.com">Alex Poitras</nom>
</destinataires>
<cc>
   <nom>Luc Roy</nom>
   <nom>Léa Martin</nom>
</cc>
<sujet>Invitation</sujet>
<corps>
   <para>La prochaine réunion se tiendra le 27 septembre 2012.</para>
   <para>Avisez-moi au plus tôt en cas d'absence.</para>
</corps>
</mémo>

Comme on peut voir, ce document est lié à une DTD dont le nom de fichier est memo.dtd. Nous supposons que le contenu de ce fichier est comme suit:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!ELEMENT mémo
  (auteur, destinataires, cc?, sujet, corps)>
<!ELEMENT destinataires (nom+)>
<!ELEMENT cc (nom+)>
<!ELEMENT corps (para*)>
<!ELEMENT auteur (#PCDATA)>
<!ELEMENT sujet (#PCDATA)>
<!ELEMENT nom (#PCDATA)>
<!ATTLIST nom courriel CDATA #IMPLIED>
<!ELEMENT para (#PCDATA)>

On peut voir que le document XML est aussi lié à une feuille de styles CSS dont le nom de fichier est memo.css. Au début de notre périple, ce fichier contiendra seulement ceci:

@charset "iso-8859-1";

Cette unique règle CSS indique que le fichier CSS lui-même utilise le jeu de caractères iso-8859-1. En ce qui concerne le formatage, la feuille CSS est « vide », dans le sens qu'elle ne contient aucune directive de formatage.

Parlant de jeu de caractères, nous supposons que les trois ci-dessus utilisent le jeu iso-8859-1, c'est-à-dire qu'ils ont été sauvegardés (par exemple) dans Bloc-notes en spécifiant le codage ANSI.

Vous êtes invité à copier-coller le contenu de ces trois fichiers à partir de la version Web du présent document et à les sauvegarder respectivement sous les noms memo.xml, memo.dtd et memo.css, dans le même dossier (par exemple C:\tempo). Le plus simple est de coller chaque fichier dans une fenêtre de Bloc-notes, puis à le sauvegarder en spécifiant les noms de dossier et de fichier appropriés, de même que le codage ANSI.

Une fois ces trois fichiers créés, vous pourrez reproduire notre périple CSS comme suit:

  1. Laissez le fichier memo.css ouvert dans une fenêtre de Bloc-notes.
  2. Ouvrez le document memo.xml dans une fenêtre de Firefox.
  3. Chaque fois que nous proposons un ajout ou un changement à la feuille de styles, effectuez la modification dans la fenêtre Bloc-notes, sauvegardez la modification (Ctrl-S), puis contrôlez l'effet sur la présentation du document en basculant à la fenêtre Firefox (Alt-Tab) et en réactualisant l'affichage (F5).

Évidemment, vous n'êtes pas obligé de vous en tenir à ce que nous proposons; vous pouvez effectuer vos propres expérimentations. Ce que nous présentons de CSS est loin d'être exhaustif; cependant, c'est suffisant pour le TP5.

Au départ, l'affichage dans Firefox devrait avoir l'air de ceci (nous avons éliminé certaines barres d'outils pour alléger les images):

*


Généralités

Une feuille de styles CSS est composée d'un ensemble de règles CSS. La forme générale d'une règle CSS est comme suit:

sélecteur { déclaration(s) }

La partie sélecteur indique à quels éléments du document la règle s'applique, et la partie déclaration(s) indique comment ces éléments doivent être formatés.

Ainsi, ceci est une règle CSS:

mémo {color:red;}

Ici, le sélecteur est mémo, indiquant que la règle précisera quel formatage doit être appliqué aux éléments mémo, et la déclaration est color:red;, indiquant que l'entièreté des éléments mémo doivent être présentés en couleur rouge.

D'ailleurs, si on ajoute cette règle à notre feuille CSS, on obtiendra l'affichage suivant:

*

Tout le texte affiché est en rouge, puisque notre document consiste en un unique élément mémo, dont le contenu complet doit donc être affiché en rouge.

La partie déclaration(s) a la forme générale suivante:

propriété1 : valeur1 ;
propriété2 : valeur2 ;
...
propriété_n : valeur_n ;

La présence de sauts de ligne et d'espaces n'a en général aucune importance; utilisez-les donc librement pour augmenter la lisibilité de vos feuilles de styles.

Chaque paire propriété : valeur ; est une déclaration. Une même règle peut comporter plusieurs déclarations, et donc, spécifier la valeur de plusieurs propriétés. Dans notre exemple, une seule propriété était spécifiée, la propriété color, qui recevait la valeur red.

Chaque propriété CSS détermine une partie de la façon dont les divers éléments du document XML sont formatés. L'ensemble des propriétés applicables à un élément détermine le formatage complet qui est appliqué.

Une autre propriété CSS est font-size, qui prend comme valeur (entre autres) une taille en pourcentage (relatif à la police courante). Ainsi, si on ajoute la règle suivante à notre feuille:

mémo {font-size:120%;}

on obtient l'affichage suivant:

*

Notez qu'on obtient exactement le même résultat en combinant les deux propriétés dans la même règle:

mémo {font-size:120%; color:red;}

Le nombre de règle applicables à un élément importe peu; ce qui est déterminant, c'est l'ensemble des valeurs de propriétés applicables.


Division en paragraphes

Par défaut, le contenu textuel de tout le document est présenté en un seul paragraphe. Les balises (incluant les spécifications d'attributs), les sauts de lignes et les espaces multiples sont ignorés.

Un premier formatage que l'on peut appliquer est de spécifier qu'un élément doit faire l'objet d'un paragraphe distinct du reste. Pour ce faire, on attribue la valeur block à la propriété display pour cet élément.

Par exemple, si on spécifie comme feuille de styles:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para {display:block;}

on obtient:

*

Notez que notre sélecteur comporte plusieurs noms d'éléments (auteur, destinataires, cc, sujet et para), séparés par des virgules. Cela veut dire que la règle est applicable à l'ensemble de ces éléments. Notez qu'effectivement, chacun des éléments auteur, destinataires, cc, sujet et para est sur un paragraphe séparé.


Encadrés

Un encadré peut être obtenu autour d'un élément avec la déclaration border:thin solid black;. Ainsi, si on ajoute à notre feuille la règle:

sujet {border:thin solid black;}

on obtient:

*

Si on veut qu'il y ait un certain espace entre le cadre et le texte, on peut spécifier la distance voulue dans la propriété padding. Ajoutons la déclaration padding: 0.5em; à notre règle pour sujet. Notre feuille en est rendue à ceci:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para {display:block;}
sujet {border:thin solid black; padding: 0.5em;}

et l'affichage est comme suit:

*

L'unité de longeur em est une unité relative, qui est la largeur d'une lettre « m » dans la police de caractères courante. C'est une des façons les plus souples et versatiles de spécifier une longueur en CSS. Ici, nous spécifions 0.5em, soit la moitié de la largeur d'une lettre « m ».


Alignement du texte

L'alignement du texte dans un élément est contrôlé par la propriété text-align. La valeur par défaut est left, signifiant que le texte est collé à gauche. Pour centrer le texte, on utilise la valeur center et pour le coller à droite, on utilise la valeur right. Pour justification à gauche et à droite, on utilise justify (l'effet de cette valeur se fait sentir seulement si le texte est plus long qu'une ligne).

Expérimentons un peu; si on ajoute la déclaration text-align:right; pour sujet, on obtient:

*

Si, au lieu, on spécifie text-align:center;, on obtient:

on obtient:

*

Arrêtons notre choix sur center; nous en sommes donc à la feuille suivante:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;}

Marges

Pour les éléments de type block (i.e., ayant la propriété display:block), on peut spécifier des marges à gauche, à droite, en haut et en bas, grâce aux propriétés margin-left, margin-right, margin-top et margin-bottom.

La façon la plus versatile et souple de spécifier une marge gauche ou droite est en pourcentage, qui est alors relatif à la plein largeur disponible. Ainsi, pour laisser une marge de 20% à gauche et à droite pour l'élément sujet, on modifie ainsi notre feuille:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;}

Rappelez-vous que les sauts de ligne et les espaces multiples n'ont pas d'importance. Nous les utilisons pour des fins cosmétiques seulement. On obtient:

*

On peut aussi espacer verticalement; nous utiliserons encore ici le em comme unité:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}

On obtient maintenant:

*

Si on veut espacer un peu l'ensemble du document de l'extrémité gauche de la fenêtre du navigateur, on peut attribuer une marge à l'élément de plus haut niveau du document, dans notre cas, mémo. On ajoutera donc la règle mémo {margin-left:1em;}, et on obtiendra:

*


Intitulés: pseudo-élément :before

On peut ajouter un intitulé avant le contenu d'un élément via un sélecteur spécial (qu'on appelle un pseudo-élément), de la forme:

nom-d'élément:before

Le texte à utiliser comme intitulé est spécifié par la propriété (spéciale elle aussi) content. Ainsi, par exemple, pour insérer l'intitulé « Sujet: » avant le sujet, on utiliserait la déclaration:

sujet:before {content:"Sujet: ";}

Notez l'utilisation des guillements doubles pour délimiter l'intitulé lui-même.

Notre feuille complète en est donc à:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}
mémo {margin-left:1em;}
sujet:before {content:"Sujet: ";}

et notre affichage à:

*

Le pseudo-élément :before peut se voir attribuer d'autres propriétés que content, ce qui permet de formater l'intitulé différemment du contenu de l'élément. Ainsi, pour que l'intitulé soit en gras, on peut ajouter la déclaration font-weight:bold; à la règle pour le pseudo-élément :before:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}
mémo {margin-left:1em;}
sujet:before {content:"Sujet: "; font-weight:bold;}

ce qui donne:

*

En ajoutant ainsi des intitulés aux éléments qui en requièrent, on arrive à la feuille:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}
mémo {margin-left:1em;}
sujet:before {content:"Sujet: "; font-weight:bold;}
auteur:before {content:"De: "; font-style:italic; font-weight:bold;}
destinataires:before {content:"À: "; font-style:italic; font-weight:bold;}
cc:before {content:"Cc: ";}
cc {margin-top:0.5em; font-size:80%;}

et à cet affichage:

*

Notez que les intitulés « À: » et « De: » sont en gras (font-weight:bold;) et en italique (font-style:italic;), et qu'on a appliqué une marge en haut et une taille de police plus petite à l'élément cc.


Texte après: pseudo-élément :after

Tout comme il est possible d'insérer un intitulé avant un élément avec le pseudo-élément :before, il est possible d'insérer du texte après un élément, grâce au pseudo-élément :after. Nous illustrerons cette possibilité en faisant afficher la mention « -30- » à la fin du corps du mémo (comme à la fin des communiqués de presse).

Nous utiliserons donc le pseudo-élément corps:after, avec comme contenu la chaîne « -30- ». Notez que nous voulons que ce texte soit centré. Pour ce faire, nous devrons non seulement spécifier text-align: center; pour le pseudo-élément, mais aussi faire de l'élément corps et du pseudo-élément corps:after des éléments de type block. La façon la plus simple de faire cela est de les ajouter au sélecteur de la règle qui contient la déclaration display:block;.

Nous arrivons à ceci:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para,
        corps, corps:after {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}
mémo {margin-left:1em;}
sujet:before {content:"Sujet: "; font-weight:bold;}
auteur:before {content:"De: "; font-style:italic; font-weight:bold;}
destinataires:before {content:"À: "; font-style:italic; font-weight:bold;}
cc:before {content:"Cc: ";}
cc {margin-top:0.5em; font-size:80%;}
corps:after {content:"-30-"; text-align: center;}

et à cet affichage:

*


Les listes en un paragraphe

Lorsqu'un élément est répétable est qu'on veut formater l'ensemble des répétitions en un seul paragraphe, il est possible d'obtenir une liste du style:

Pomme, Poire, Orange.

où les virgules et le point sont ajoutés par la feuille CSS. Nous allons illustrer cette technique avec les listes de noms que constituent nos éléments destinataires et cc. Par exemple, nous voulons que le contenu de l'élément cc s'affiche comme ceci:

Luc Roy, Léa Martin.

Nous allons procéder par étapes.

Notons d'abord que chaque nom est dans un élément nom. Nous pouvons donc faire insérer une virgule après chaque nom avec le pseudo-élément nom:after. On ajoute la règle nom:after {content:", ";} et on obtient ceci:

*

Notez la virgule superflue à la fin de chaque liste de noms. Pour nous en débarrasser, nous allons utiliser ce que CSS appelle une pseudo-classe, nommément, la pseudo-classe :last-child. Celle-ci permet de spécifier un formatage différent pour le dernier d'une suite de sous-éléments. C'est bien ce que nous voulons faire ici: spécifier un formatage spécial pour le dernier des noms contenus dans destinataires ou dans cc.

Nous allons donc ajouter la règle:

nom:last-child:after {content:".";}

pour faire en sorte qu'après le dernier nom d'une liste, il y ait non pas une virgule d'insérée, mais plutôt un point. Nous obtiendrons alors:

*

Et voici notre feuille complète à ce stade-ci:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para,
        corps, corps:after {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}
mémo {margin-left:1em;}
sujet:before {content:"Sujet: "; font-weight:bold;}
auteur:before {content:"De: "; font-style:italic; font-weight:bold;}
destinataires:before {content:"À: "; font-style:italic; font-weight:bold;}
cc:before {content:"Cc: ";}
cc {margin-top:0.5em; font-size:80%;}
corps:after {content:"-30-"; text-align: center;}
nom:after {content:", ";}
nom:last-child:after {content:".";}

Notez que la pseudo-classe :first-child existe aussi; elle permet de traiter différemment le premier d'une suite de sous-éléments.


Affichage des valeurs d'attributs

Nous avons un seul attribut dans nos exemples, l'attribut facultatif courriel de l'élément nom. Notons que jusqu'à maintenant, cet attribut a été complètement ignoré par le stylage. Effectivement, en CSS, les attributs sont affichés sur demande seulement.

En fait, on ne peut afficher une valeur d'attribut que dans la propriété content d'un pseudo-élément :before ou :after, et ce via ce qui s'appelle la fonction attr().

La syntaxe de cette fonction est:

attr(nom-d'attribut)

Le résultat de cette fonction est la valeur de l'attribut nom-d'attribut. La fonction attr() peut être combinée avec du texte fixe, comme nous verrons ci-après.

Nous allons illustrer cette technique en faisant afficher l'adresse courriel des personnes (lorsqu'elles en ont une) entre parenthèses après leur nom. Nous allons donc modifier les règles des pseudo-éléments nom:after et nom:last-child:after pour inclure un appel de la fonction attr():

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para,
        corps, corps:after {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}
mémo {margin-left:1em;}
sujet:before {content:"Sujet: "; font-weight:bold;}
auteur:before {content:"De: "; font-style:italic; font-weight:bold;}
destinataires:before {content:"À: "; font-style:italic; font-weight:bold;}
cc:before {content:"Cc: ";}
cc {margin-top:0.5em; font-size:80%;}
corps:after {content:"-30-"; text-align: center;}
nom:after {content:" (" attr(courriel) "), ";}
nom:last-child:after {content:" (" attr(courriel) ").";}

Sur ce, on obtient:

*

Le seul problème est que les parenthèses s'affichent même si l'attribut courriel n'est pas spécifié.

On peut régler ce problème en utilisant une forme de sélecteur qui ne va s'appliquer que si l'attribut est spécifié. Il s'agit d'ajouter après le nom de l'élément l'indication:

[nom-d'attribut]

par exemple:

nom[courriel]:after

spécifiera un pseudo-élément à n'utiliser pour les éléments nom que si l'attribut courriel est spécifié.

Il suffit donc de qualifier nos deux règles relatives à l'insertion de l'adresse courriel de façon à ce qu'elles ne s'appliquent qu'en présence de l'attribut courriel, et réintroduire les anciennes règles (sans l'insertion de l'adresse courriel, mais avec insertion de la ponctuation) pour les cas où l'attribut n'est pas spécifié:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para,
        corps, corps:after {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}
mémo {margin-left:1em;}
sujet:before {content:"Sujet: "; font-weight:bold;}
auteur:before {content:"De: "; font-style:italic; font-weight:bold;}
destinataires:before {content:"À: "; font-style:italic; font-weight:bold;}
cc:before {content:"Cc: ";}
cc {margin-top:0.5em; font-size:80%;}
corps:after {content:"-30-"; text-align: center;}
nom:after {content:", ";}
nom:last-child:after {content:".";}
nom[courriel]:after {content:" (" attr(courriel) "), ";}
nom[courriel]:last-child:after {content:" (" attr(courriel) ").";}

Ce qui nous donne un affichage satisfaisant:

*


Formatage en fonction d'un élément parent

Supposons que l'on voudrait formater les noms différemment, selon qu'ils sont dans la liste des destinataires directs ou dans la liste des récipiendaires de copies conformes. Il est possible de spécifier un sélecteur qui ne va s'appliquer qu'aux éléments qui sont « enfants » d'un certain élément particulier. Ainsi, on pourrait spécifier un formatage s'appliquant uniquement aux éléments nom qui sont hiérarchiquement en-dessous d'un élément cc.

La forme générale de ce sélecteur est:

parent élément

par exemple:

cc nom

est un sélecteur qui s'applique uniquement aux nom qui sont enfants (directement ou indirectement) de cc.

Nous allons illustrer cette technique en soulignant les noms des récipiendaires de copies conformes. Le soulignement est obtenu en attribuant la valeur underline à la propriété text-decoration; il nous faut donc ajouter la règle:

cc nom {text-decoration:underline;}

qui nous donne:

*

Notez que seuls les noms des récipiendaires de copies conformes sont soulignés, pas les noms des destinataires directs (élément destinataires).

Notre feuille de styles CSS finale est:

@charset "iso-8859-1";
auteur, destinataires, cc, sujet, para,
        corps, corps:after {display:block;}
sujet {border:thin solid black; padding: 0.5em; text-align:center;
       margin-left:20%; margin-right:20%;
       margin-top:1em; margin-bottom:1em;}
mémo {margin-left:1em;}
sujet:before {content:"Sujet: "; font-weight:bold;}
auteur:before {content:"De: "; font-style:italic; font-weight:bold;}
destinataires:before {content:"À: "; font-style:italic; font-weight:bold;}
cc:before {content:"Cc: ";}
cc {margin-top:0.5em; font-size:80%;}
corps:after {content:"-30-"; text-align: center;}
nom:after {content:", ";}
nom:last-child:after {content:".";}
nom[courriel]:after {content:" (" attr(courriel) "), ";}
nom[courriel]:last-child:after {content:" (" attr(courriel) ").";}
cc nom {text-decoration:underline;}

Valid HTML 4.0!Valid CSS!