Sommaire

  1. Introduction
  2. Méthode classique avec un tableau de mise en page
  3. Afficher les cellules d'un tableau comme des éléments de type bloc
  4. Solutions CSS sans tableau de mise en page
  5. Conclusion

Introduction

La réalisation d'une boite fluide avec des bordures en images ou des coins arrondis, ou encore les deux à la fois, est un sujet récurrent en mise en page CSS. Il n'a (hélas?) pas de réponse évidente, surtout si le cahier des charges est bien gratiné. Par exemple, mettons que nous voulons une boite décorée:

  • avec aussi bien des coins que des bordures en images (par exemple une bordure arrondie avec ombre portée);
  • extensible à la fois en hauteur et en largeur;
  • que l'on peut placer sur des fonds de couleur différentes, sur des images de fond, des motifs, etc.

Bref, la totale.

(Note: dans cet article, je m'intéresse avant tout aux questions de positionnement et d'habillement des blocs. Nous allons utiliser des images PNG avec transparence graduelle. Ce type d'image pose problèmes à certains vieux navigateurs, dont le plus notable est Internet Explorer 6. Je ne m'occuperai pas de ce problème dans cet article.)

Construire ce genre de boite demande d'avoir recours à de nombreuses images, certaines étant placées dans les coins, d'autres répétées horizontalement ou verticalement. Comme CSS 2.1 ne permet pas de placer plusieus images de fond pour un bloc donné, il faut donc travailler avec une série de blocs.

Il faut encore que cette série de blocs soient liés ensemble, afin de s'étendre verticalement ou horizontalement en fonction de leurs contenus respectifs.

À ce stade de la description, vous en êtes sans doute arrivé à la conclusion suivante: ça ressemble furieusement à un tableau de mise en page! Et c'est effectivement le cas.

Méthode classique avec un tableau de mise en page

On suppose que l'on a un bloc doté d'un titre et d'un corps principal, disons quelques paragraphes. Si on travaille avec un tableau de mise en page, on pourra placer le titre soit dans la rangée supérieure, soit dans la rangée du milieu. Allons-y pour la rangée supérieure.

Pour notre premier essai, nous allons travailler avec l'image suivante: boite1.png. Nous n'allons pas découper cette image, mais l'utiliser à chaque fois comme image de fond, en la positionnant avec background-position. Dans la pratique, il y a des cas où on pourra travailler ainsi avec une image unique, et d'autres où il faudra effectuer un découpage de certaines parties au moins de l'image de fond, afin de pouvoir utiliser background-repeat.

Voici le code HTML pour notre tableau de mise en page:

<table class="boite1">
  <tr class="haut">
    <td class="col1"></td>
    <td class="col2">
      <h3>Une boite dessinée à l'aide d'un tableau</h3>
    </td>
    <td class="col3"></td>
  </tr>
  <tr class="milieu">
    <td class="col1"></td>
    <td class="col2">
      <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.</p>
      <p>Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.</p>
      <p>Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.</p>
    </td>
    <td class="col3"></td>
  </tr>
  <tr class="bas">
    <td class="col1"></td>
    <td class="col2"></td>
    <td class="col3"></td>
  </tr>
</table>

Ce code est un peu lourd, n'est-ce pas? C'est une des raisons pour lesquelles on cherche généralement à éviter les tableaux de mise en page. Mais ici, cela reste une solution acceptable. Nous allons maintenant appliquer quelques styles CSS à ce tableau, essentiellement pour appliquer les images de fond (ici, l'image de fond unique) aux différents td du tableau. Voici ce que ça donne:

Une boite dessinée à l'aide d'un tableau

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.

Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.

Ici, j'ai fixé la largeur du tableau à 50%. Voyons ce que ça donne à 30em, par exemple (si les deux blocs ont l'air d'avoir la même largeur, redimensionnez la fenêtre de votre navigateur ou modifiez la taille du texte):

Une boite dessinée à l'aide d'un tableau

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.

Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.

Je ne détaille pas ici le code CSS utilisé. Je vous invite à le récupérer dans le code source de cette page.

On remarquera cependant qu'avec le découpage actuellement utilisé (c'est à dire pas de découpage de l'image, mais une image unique et un jeu sur background-position), il suffit de changer l'image de fond pour changer de style de boite! Démonstration:

Une boite dessinée à l'aide d'un tableau

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.

Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.

L'image utilisée cette fois est la suivante: boite2.png

Pour ce dernier tableau, on a dû agrandir un peu les td qui dessinent le cadre, afin que les coins soient bien dessinés (là encore, voir le code source). On obtient alors un design très aéré… peut-être un peu trop? Nous verrons un peu plus loin une technique pour obtenir le même type de design mais avec un contenu moins éloigné des bords.

Afficher les cellules d'un tableau comme des éléments de type bloc

Si on souhaite faire un découpage de l'image de fond en huit ou neuf images séparées (quatre coins, quatre bordures, et peut-être un motif central) afin de pouvoir intégrer certains designs plus compliqués, on devra avoir recours à un tableau à neuf cellules, ou bien à un équivalent en balises HTML et à display: table et display: table-cell. Ces dernières valeurs de la propriété display n'étant pas comprises par Internet Explorer (versions 5 à 7), c'est une solution peu utilisable en pratique.

Pour faire un tableau de mise en page à neuf cellules, on gardera donc un tableau. Pour des mises en page qui peuvent s'accomoder d'un balisage plus léger, par contre, on pourra envisager des solutions CSS.

Avant d'en présenter une ou deux, une petite subtilité au sujet de notre tableau de mise en page. On dit souvent qu'il ne faut pas utiliser les tableaux de mise en page car ils figent les possibilités de mise en page. Ce plutôt vrai, mais pas tout à fait. En utilisant CSS, on peut «remettre à plat» un tableau.

En partant du code HTML donné précédemment pour notre tableau, et sans lui attribuer les styles utilisés jusqu'ici, on peut par exemple faire ceci:

.flat {
  border: solid 1px red;
}
.flat td {
  display: block;
  margin: 5px;
  border: solid 1px blue;
  background: white;
}
.flat td.col1,
.flat td.col3,
.flat tr.bas {
  display: none;
}

Ce qui nous donne:

Une boite dessinée à l'aide d'un tableau

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.

Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.

Elle est pas belle, la vie?

Hmm… faut voir. On peut signaler deux écueils (outre le fait que le code HTML reste assez lourd et donc peut-être un peu moins maintenable):

  1. Tous les navigateurs ne supportent pas display: block sur les cellules de tableau. Supprimer l'affichage de cellules via display: none marche très bien avec tous les navigateurs (houra!), mais passer en affichage de type bloc est une autre paire de manche. Là encore, le mauvais élève est… Internet Explorer (y compris la version 7).
  2. Avec les navigateurs qui supportent pleinement display: block, les possibilités sont plus étendues. Cependant, il faudra prendre en compte les éléments tr (les lignes) du tableau, qui peuvent parasiter la mise en page. On les passera également en display: block si nécessaire, et on tâchera de s'en accomoder, mais c'est une solution qui n'est clairement pas optimale.

Ces possibilités des CSS sont toutefois toujours bonnes à connaitre. Je vous invite également à tenter de reconstituer un tableau à partir de div, span ou même ul et li, grâce aux valeurs table, table-row et table-cell de la propriété display. C'est un exercice intéressant.

Solutions CSS sans tableau de mise en page

Commençons par signaler qu'il existe de multiples solutions pour créer un bloc fluide avec des bordures ou coins en images. Certaines de ces solutions sont simples et plutôt élégantes… mais nécessitent toujours qu'une contrainte donnée soit respectée.

Ruser grâce à des contraintes «facilitantes»

Il suffit par exemple de figer une des deux dimensions du bloc que l'on souhaite décorer (le plus souvent la largeur, parfois la hauteur). On peut alors utiliser la technique suivante: boîte avec bordures en HTML et CSS.

Une autre contrainte facilitante est que les bordures ne soient pas décorées ou puissent être dessinées avec la propriété CSS border. Si on cherche uniquement à placer des coins décorés (le plus souvent des coins arrondis), il existe plusieurs méthodes utilisant un bloc positionné en relatif et des petits blocs de décoration à positionner en absolu dans les coins. On pourra même utliser Javascript afin de générer les éléments que l'on positionnera dans les coins. (Si quelqu'un a un lien de référence, je ne retrouve plus les tutoriels auxquels je pensais…)

La troisième contrainte facilitante à laquelle on a recours est la suivante: il faut que le bloc ait un fond et surtout des bordures opaques. Cela permet d'imbriquer une série d'éléments (le plus souvent des div), et de superposer des images de fond savamment découpées afin de placer les différentes bordures et les coins. Pour éviter d'utiliser huit blocs imbriqués, on pourra utiliser une même image pour dessiner une bordure et un coin adjacent (avec un format d'image comme PNG, pour un certain nombre de motifs simples ou à base de dégradés, cela ne posera pas de problème de poids d'image, même pour une image de 30px de haut et de disons 2000px de large).

Un essai n'exploitant pas ces contraintes

Si on ne peut pas utiliser ces contraintes (en particulier si les images ne peuvent pas se recouvrir), pas de miracle… on peut faire certaines choses sans utiliser de tableau de mise en page, mais au final on s'en rapprochera beaucoup au niveau de la structure du code. À quoi bon remplacer des tr et des td par des div?
(Le lecteur averti pourra répondre: cela améliore un minimum les possibilités de mise en page différente avec Internet Explorer.)

Je vous présente tout de même un essai dont le code HTML est un peu moins chargé que celui du tableau que nous avons utilisé jusqu'ici. Cet essai utilise des blocs imbriqués ne se recouvrant pas totalement, ce qui va nous obliger à faire quelques découpages, hélas. Voici donc le code HTML:

<div class="boite2">
  <div class="haut">
    <h4 class="titre"><span>Une boite dessinée sans l'aide d'un tableau</span></h4>
  </div>
  <div class="milieu-bas">
    <div class="principal">
      <div class="principal-bis">
        <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.</p>
        <p>Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.</p>
        <p>Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.</p>
      </div>
    </div>
  </div>
</div>

Et voici ce que nous obtenons:

Une boite dessinée sans l'aide d'un tableau

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.

Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.

Une fois encore, je ne détaille pas le code CSS. Celui-ci peut être récupéré dans le code source de cette (il devrait être facile à identifier). On peut juste mettre en lumière la manière dont sont positionnés les différents éléments (pour bien mettre en évidence la structure, on a écarté les différents éléments grâce à un peu de padding):

Une boite dessinée sans l'aide d'un tableau

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.

Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.

On imagine bien que joindre tout ça correctement demande un minimum de précision! En particulier, on fera attention à la fusion des marges. On remarquera que les deux seuls vrais conteneurs de cette structure, à savoir le span du titre et div.principal-bis, ont tous les deux un padding-top et un padding-bottom supérieur ou égal à 1, ce qui est un des moyens possibles pour éviter la fusion des marges.

Un autre point important à noter à propos de cette structure: j'ai rusé un peu sur certains points, et j'ai utilisé l'imbrication des éléments, mais pour ce qui est de la lourdeur du code HTML on a un résultat très proche de la solution basée sur un tableau!

Une petite différence: pour cet essai, j'ai utilisé une structure sur deux «lignes» (div.haut et div.milieu-bas) tandis que dans l'essai basé sur un tableau on a trois lignes de cellules. Mais rien n'empêche de reprendre l'essai basé sur un tableau et de l'adapter pour un fonctionnement sur deux lignes.

Simplifions encore un peu

On peut continuer avec la même base que notre essai sans tableau, et simplifier encore un peu. En effet, si nous n'avons besoin que de deux lignes pour placer nos images de fond, il n'y a pas de raison que nous ayons besoin de trois colonnes!

On tranche donc dans le lard et on garde le code HTML suivant:

<div class="boite3">
  <h4 class="titre"><span>Une boite dessinée sans l'aide d'un tableau</span></h4>
  <div class="principal">
    <div class="principal-bis">
      <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.</p>
      <p>Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.</p>
      <p>Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.</p>
    </div>
  </div>
</div>

Avec quelques adaptations des styles CSS (là encore, voir le code source de la page), nous obtenons ceci:

Une boite dessinée sans l'aide d'un tableau

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, ultricies sed, dolor.

Cras elementum ultrices diam. Maecenas ligula massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit amet erat. Duis semper.

Duis arcu massa, scelerisque vitae, consequat in, pretium a, enim.

Là encore, on aurait pu faire strictement la même chose avec un tableau (deux lignes, deux cellules par ligne). L'utilisation d'un tableau nous permet par ailleurs d'éviter de découper notre image de fond.

Conclusion

Alors, quelle méthode choisir?

J'ai évoqué rapidement quelques méthodes assez simples à mettre en place lorsque notre boite répond à au moins une contrainte «facilitante»: largeur ou hauteur fixe, pas d'images pour les bordures, pas besoin de la transparence PNG. Lorsque vous pouvez faire jouer une de ces contraintes pour obtenir facilement une solution sans tableau et relativement rapide à mettre en place, privilégiez cette solution.

Lorsque vous voulez répondre au cahier des charges «la totale», ou lorsque vous avez besoin de découper l'image du cadre en une série d'images répétables en hauteur ou en largeur, vous aurez sans doute besoin d'une structure lourde. Dans ce cas, si vous ne maitrisez pas le positionnement CSS, je vous conseillerais d'utiliser un tableau de mise en page.

À structure équivalente, le tableau de mise en page a pour principal inconvénient de ne pas pouvoir être manipulé facilement via la propriété CSS display dans Internet Explorer. La structure à base de div, par contre, sera sans doute un peu plus longue ou un peu plus compliquée à mettre en place, et obligera à réaliser des découpes précises (ce qui diminue la marge de manœuvre si on souhaite réduire ou augmenter les «bordures», par exemple).

Vous avez les cartes en main, à vous de voir. ;)