<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Border-Labs &#187; CSS</title>
	<atom:link href="http://border-labs.fr/?cat=30&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://border-labs.fr</link>
	<description>... souvent à la limite</description>
	<lastBuildDate>Fri, 04 Mar 2011 16:36:17 +0000</lastBuildDate>
	<language>fr-FR</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.8.41</generator>
	<item>
		<title>Un pyjama efficace pour Internet Explorer</title>
		<link>http://border-labs.fr/?p=162</link>
		<comments>http://border-labs.fr/?p=162#comments</comments>
		<pubDate>Wed, 02 Mar 2011 14:05:16 +0000</pubDate>
		<dc:creator><![CDATA[BlackAdder]]></dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[CSS 3]]></category>
		<category><![CDATA[Internet Explorer]]></category>

		<guid isPermaLink="false">http://border-labs.fr/?p=162</guid>
		<description><![CDATA[En termes d’ergonomie, on conseille souvent d’implanter dans ses tables HTML des « pyjamas », c&#8217;est-à-dire des couleurs de lignes alternées. Cela permet de faciliter la lecture : l’œil peut plus facilement suivre les lignes. En CSS 3, il existe une solution tout &#8230; <a href="http://border-labs.fr/?p=162">Continuer la lecture <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>En termes d’ergonomie, on conseille souvent d’implanter dans ses tables HTML des « pyjamas », c&rsquo;est-à-dire des couleurs de lignes alternées. Cela permet de faciliter la lecture : l’œil peut plus facilement suivre les lignes.</p>
<div style="width: 173px" class="wp-caption aligncenter"><img title="Une table avec pyjama" src="http://border-labs.fr/Samples/Article%20pyjama/table%20avec%20pyjama.gif" alt="Une table avec des lignes de couleurs alternées" width="163" height="343" /><p class="wp-caption-text">Une table avec pyjama</p></div>
<p>En CSS 3, il existe une solution tout à fait satisfaisante, utiliser la pseudo classe <code>nth-child</code> qui permet de sélectionner le nième fils d’un nœud DOM.</p>
<p>Cette pseudo classe accepte une syntaxe du type an+b où n représente le fils sélectionné et accepte deux mots clefs odd (pour les fils dont l’index est impair) et even (pour les fils dont l’index est pair). On a :</p>
<ul>
<li><code>nth-child(2n)</code> correspond à <code>nth-child(even)</code></li>
<li><code>nth-child(2n+1)</code> correspond à <code>nth-child(odd)</code></li>
</ul>
<p>On peut donc directement utiliser cette pseudo classe pour sélectionner les lignes paires et impaires (c&rsquo;est-à-dire les nœuds de type TR) en fonction de la parité de leur index. Il est bien sûr possible d’utiliser nth-child pour mettre en place des couleurs alternées de plus de 2 couleurs voire mettre en place des <a href="http://www.w3.org/Style/Examples/007/evenodd">couleurs de colonnes alternées</a> (en utilisant la balise <code>COL</code>).</p>
<p>Si on veut ne mettre des couleurs de lignes alternées qu’aux lignes situées dans les balises <code>TBODY</code>, et pas sur celles qui sont situées dans le <code>THEAD</code> et le <code>TFOOT</code> , on utilisera des CSS telles que :</p>
<p><code>TBODY tr:nth-child(odd) {<br />
background-color: #aaa;<br />
}<br />
</code></p>
<p><code>TBODYtr:nth-child(even) {<br />
background-color: #9CF;<br />
}<br />
</code><br />
Une feuille de style de ce type marche parfaitement sur les navigateurs récents… sauf sous Internet Explorer, où même dans la version IE9, <a title="Matrice de compatibilité CSS/Internet Explorer" href="http://msdn.microsoft.com/en-us/library/cc351024(v=vs.85).aspx">le sélecteur nth-child n’est toujours pas implanté</a>.</p>
<p>Du coup, il existe même des librairies javascript pour résoudre de façon générique ce problème, par exemple : <a title="Librairie CSS 3 selectivizr" href="http://selectivizr.com/">http://selectivizr.com/</a>.</p>
<h2>Mise en œuvre d’une solution pour Internet Explorer</h2>
<p>Nous nous contenterons ici, d’une solution <em>ad hoc</em> simplifiée.</p>
<p>Pour Internet Explorer, une solution est d’associer un attribut class différent selon qu’il s’agit d’une ligne paire ou d’une ligne impaire. Par exemple:</p>
<p><code>&lt;TR class="impair"&gt;&lt;TD&gt;…&lt;/TD&gt;&lt;/TR&gt;</code></p>
<p><code> </code></p>
<p><code>&lt;TR class="pair"&gt;&lt;TD&gt;…&lt;/TD&gt;&lt;/TR&gt;</code></p>
<p><code> </code></p>
<p><code>&lt;TR class="impair"&gt;&lt;TD&gt;…&lt;/TD&gt;&lt;/TR&gt;</code></p>
<p>…</p>
<p>Il est même <a title="Article alistapart sur les tables Zebra" href="http://www.alistapart.com/articles/zebratables">plus simple</a> de n’associer que les attributs pairs (ou impairs) et de faire gérer l’autre valeur par le style par défaut.</p>
<p><code>TR { background-color: #9CF }</code></p>
<p>Et</p>
<p><code>TR.impair { background-color: #AAA;}</code></p>
<p>En ne marquant que les lignes impaires</p>
<p><code>&lt;TR class="impair"&gt;&lt;TD&gt;…&lt;/TD&gt;&lt;/TR&gt;</code></p>
<p><code> </code></p>
<p><code>&lt;TR&gt;&lt;TD&gt;…&lt;/TD&gt;&lt;/TR&gt;</code></p>
<p><code> </code></p>
<p><code>&lt;TR class="impair"&gt;&lt;TD&gt;…&lt;/TD&gt;&lt;/TR&gt;</code></p>
<p>…</p>
<p>On obtient alors un affichage identique à celui procuré en CSS 3 par :</p>
<p><code>TR:nth-child(odd) { background-color: #9CF }</code></p>
<p><code> </code></p>
<p><code>TR:nth-child(even) { background-color: #AAA }</code></p>
<p>Il reste à déterminer comment marquer ces lignes impaires. Si la table HTML est générée par le serveur (par exemple une taglib), le plus simple est que le serveur génère lui-même les attributs class correspondant.</p>
<p>Par contre, si c’est javascript qui doit rajouter le « pyjama » à une table préexistante, il faut itérer sur les lignes pour rajouter le nom de class correspondant. Noter que çà veut dire que dans un premier temps, la table s’affiche sans pyjama, celui-ci étant créé plus tard via javascript.</p>
<p>Cela donne par exemple une boucle telle que :<br />
<code><br />
function createPyjama(table) {</code></p>
<p><code> </code></p>
<p><code>// Récupération des tbodies de la table<br />
var tableBodies = table.getElementsByTagName("<code>TBODY</code>");</code></p>
<p><code>// Itération sur chaque <code>TBODY</code><br />
for (var i = 0; i &lt; tableBodies.length; i++) {<br />
var tableRows = tableBodies[i].rows;</code></p>
<p><code> </code></p>
<p><code>// Marquage des lignes impaires<br />
for (var j = 1; j &lt; tableRows.length; j+=2) {<br />
tableRows[j].className += " impair";<br />
}<br />
}<br />
}<br />
</code><br />
Une telle méthode donne le résultat attendu si la table à laquelle elle s’applique ne possède pas des rangées possédant déjà la classe impair.</p>
<h2>Gérer les suppressions de ligne</h2>
<p>Malheureusement, si on donne la possibilité de modifier au <em>runtime</em> la table en question, par exemple en supprimant ou en rajoutant une ligne, il est nécessaire de mettre à jour le « pyjama » (sous Internet Explorer, les browsers supportant les CSS 3 n’ont pas ce problème puisque le pseudo sélecteur nth-child fait tout le travail).</p>
<p>Dans ce cas, si on a ajouté (ou supprimé) un nombre impair de lignes, il est nécessaire de recalculer les attributs class de la table pour toutes les lignes suivantes.</p>
<h3>Version simplifiée : on recalcule toute la table</h3>
<p>La solution la plus simple consiste à recalculer l’intégralité du pyjama. Il suffit de prendre la précaution pour les lignes qui doivent être modifiées de :</p>
<ul>
<li>Retirer la class impair des lignes qui le contenait</li>
<li>Ajouter la class impair aux autres lignes</li>
</ul>
<p>Cela donne par exemple :<br />
<code><br />
function alternate(table) {</code></p>
<p><code> </code></p>
<p><code>var tableBodies = table.getElementsByTagName("<code>TBODY</code>");<br />
for (var i = 0; i &lt; tableBodies.length; i++) {<br />
var tableRows = tableBodies[i].rows;<br />
var pair=true;<br />
for (var j = 0; j &lt; tableRows.length; j++) {<br />
var theTableRow=tableRows[j];<br />
var theClassName=theTableRow.className;<br />
if ( pair  ) {<br />
if ( (theClassName.indexOf('impair') != -1) ) {<br />
theTableRow.className = theClassName.replace('impair', '');<br />
}<br />
} else {<br />
if ( (theClassName.indexOf('impair') == -1) ) {<br />
theTableRow.className += " impair";<br />
}<br />
};<br />
pair=!pair;<br />
}<br />
}<br />
}<br />
</code></p>
<h3>Version optimisée</h3>
<p>Pour être encore plus efficace, l’idée est de ne modifier que les lignes qui sont situées en dessous de la ligne supprimée. On peut ainsi ajouter un argument qui est l’index de la première ligne supprimée (ajoutée). Cela permet de ne pas refaire le calcul pour les premières lignes, qui n’ont pas besoin d’être touchées. Sur des navigateurs très peu performants comme Internet Explorer 6, cela peut faire une réelle différence.</p>
<p>La première étape est de déterminer l’index de la ligne supprimée. Il ne semble pas avoir de méthode standard pour déterminer quel est l’index d’un nœud DOM parmi tous ses frères (les autres nœuds fils du même nœud père). On peut enchaîner des appels à <code>nextSibling</code> pour itérer de ligne en ligne (balise <code>TR</code>) mais çà n’est pas forcément le plus performant. Cela peut poser problème par exemple quand on sélectionne une ligne à la souris pour la détruire. Il est facile de récupérer le nœud DOM TR correspondant à la ligne cliquée via le handler d’événement. Mais comment connaître son index parmi tous les TR ? En plus, la méthode indexOf, introduite avec Javascript 1.6 n’est disponible que sur une instance d’Array javascript, pas sur une HTMLCollection (les nœuds fils d’un nœud DOM forment une HTMLCollection, pas une Array). Et de toutes façons indexOf n’est pas disponible sous Internet Explorer 6.</p>
<p>Heureusement, il existe deux attributs supportés par la plupart des navigateurs et en tout cas, par les <a title="attributs rowIndex et sectionRowIndex" href="http://msdn.microsoft.com/en-us/library/ms534621(v=vs.85).aspx">différentes versions d’Internet Explorer</a>. Il s’agit des attributs <code>rowIndex</code> et <code>sectionRowIndex</code>. Ici, c’est la propriété <code>sectionRowIndex</code> qui nous intéresse : elle donne l’index de la ligne au sein de la section courante, ici un <code>TBODY</code>.</p>
<p>On peut donc implanter une méthode utilisant cet index pour ne recalculer que le « pyjama » des lignes suivantes. Mais attention, il faut tenir compte du fait qu’une table peut avoir plusieurs balises <code>TBODY</code>. La parité des lignes doit donc être transmise d’un <code>TBODY</code> à l’autre.</p>
<p>Au chargement, les lignes ont la couleur définie par la CSS s’appliquant par défaut sur les <code>TR</code> :</p>
<p><code>TR { color: black ; background-color: #9CF }</code></p>
<p>Il y a aussi la déclaration de la classe impair :</p>
<p><code>TR.impair { color: white ; background-color: #aaa }</code></p>
<p>C’est seulement via javascript que l’attribut class sera positionné à impair. Cela veut dire que si javascript n’est pas actif, les lignes restent de la couleur d’origine. Il vaut donc mieux que le style par défaut correspond à la couleur la plus claire. On garantit ainsi que la table sera plus facilement lisible même si javascript est désactivé.</p>
<h3>Démonstration</h3>
<p>Dans cette <a title="Démo table pyjama" href="./Samples/Article%20pyjama/Demo pyjama v1.html">démonstration</a>, un clic sur une cellule de la table supprime la ligne correspondante.</p>
<p>La table comporte un <code>THEAD</code>, un <code>TFOOT</code> et deux balises <code>TBODY</code>.</p>
<p>La démo comporte 2 boutons permettant de supprimer par programme la deuxième et la troisième ligne.</p>
]]></content:encoded>
			<wfw:commentRss>http://border-labs.fr/?feed=rss2&#038;p=162</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
