Pouvez-vous faire cette mise en page HTML sans utiliser de tableaux?

102

Ok, j'ai eu un simple problème de mise en page il y a une semaine ou deux. À savoir les sections d'une page nécessitaient un en-tête:

+---------------------------------------------------------+
| Title                                            Button |
+---------------------------------------------------------+

Des trucs assez simples. Le fait est que la haine des tables semble avoir pris le dessus dans le monde du Web, ce qui m'a rappelé quand j'ai demandé Pourquoi utiliser des balises de listes de définitions (DL, DD, DT) pour les formulaires HTML au lieu de tableaux? Maintenant, le sujet général des tables vs divs / CSS a déjà été discuté, par exemple:

Donc, cela ne vise pas à être une discussion générale sur CSS vs tableaux pour la mise en page. C'est simplement la solution à un problème. J'ai essayé différentes solutions à ce qui précède en utilisant CSS, notamment:

  • Flottez à droite pour le bouton ou un div contenant le bouton;
  • Position relative du bouton; et
  • Position relative + absolue.

Aucune de ces solutions n'était satisfaisante pour différentes raisons. Par exemple, le positionnement relatif a entraîné un problème de z-index où mon menu déroulant est apparu sous le contenu.

J'ai donc fini par revenir à:

<style type="text/css">
.group-header { background-color: yellow; width: 100%; }
.group-header td { padding: 8px; }
.group-title { text-align: left; font-weight: bold; }
.group-buttons { text-align: right; }
</style>
<table class="group-header">
<tr>
  <td class="group-title">Title</td>
  <td class="group-buttons"><input type="button" name="Button"></td>
</tr>
</table>

Et cela fonctionne parfaitement. C'est simple, aussi rétrocompatible que possible (cela fonctionnera probablement même sur IE5) et cela fonctionne juste. Pas de soucis avec le positionnement ou les flotteurs.

Quelqu'un peut-il donc faire l'équivalent sans tables?

Les exigences sont:

  • Rétrocompatible: vers FF2 et IE6;
  • Raisonnablement cohérent: sur différents navigateurs;
  • Centré verticalement: le bouton et le titre sont de hauteurs différentes; et
  • Flexible: permet un contrôle raisonnablement précis du positionnement (rembourrage et / ou marge) et du style.

En passant, je suis tombé sur quelques articles intéressants aujourd'hui:

EDIT: Permettez-moi d'élaborer sur la question du flotteur. Ce genre de travaux:

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; overflow: hidden; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-title { float: left; padding: 8px; }
      .group-buttons { float: right; padding: 8px; }
    </style>
  </head>
  <body>
    <div class="group-header">
      <div class="group-title">This is my title</div>
      <div class="group-buttons"><input type="button" value="Collapse"></div>
    </div>
    <div class="group-content">
      <p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
      <p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
      <p>On a side note, I came across a couple of interesting articles today:</p>
    </div>
  </body>
</html>

Merci à Ant P pour le overflow: hiddenrôle (je ne comprends toujours pas pourquoi). Voici où le problème entre en jeu. Disons que je veux que le titre et le bouton soient centrés verticalement. Ceci est problématique car les éléments sont de hauteur différente. Comparez ceci à:

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; overflow: hidden; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-header td { vertical-align: middle; }
      .group-title { padding: 8px; }
      .group-buttons { text-align: right; }
    </style>
  </head>
  <body>
    <table class="group-header">
    <tr>
      <td class="group-title">This is my title</td>
      <td class="group-buttons"><input type="button" value="Collapse"></td>
    </tr>
    </table>
    <div class="group-content">
      <p>And it works perfectly. It's simple, as backward compatibile as it gets (that'll work probably even on IE5) and it just works. No messing about with positioning or floats.</p>
      <p>So can anyone do the equivalent without tables that is backwards compatible to at least FF2 and IE6?</p>
      <p>On a side note, I came across a couple of interesting articles today:</p>
    </div>
  </body>
</html>

qui fonctionne parfaitement.

cletus
la source
11
Ok, ça a du sens "Quelle couleur dois-je utiliser pour vim?" obtient un vote positif, mon problème de mise en page CSS spécifique est rejeté.
cletus
vous pouvez faire ce que vous voulez sans table dans tous les cas. Aussi pourquoi diable @SamB a-t-il repoussé cette question vieille de 2 ans? DOH +
dynamique
3
@ yes123: eh bien, la coloration syntaxique était fausse ...
SamB

Réponses:

50

Il n'y a rien de mal à utiliser les outils à votre disposition pour faire le travail rapidement et correctement.

Dans ce cas, une table fonctionnait parfaitement.

J'aurais personnellement utilisé une table pour cela.

Je pense que les tables imbriquées devraient être évitées, les choses peuvent devenir compliquées.

Gregor Brandt
la source
21
Sauf lorsque vous utilisez un tableau pour la mise en page de présentation plutôt que des données tabulaires simplement parce que c'est plus facile au début pâle, auquel cas vous vous dirigez sur un chemin sombre et dangereux.
One Crayon
9
Même Amazon utilise des tables dans certains cas. Et stackoverflow.com aussi. Je suis tout à fait pour les solutions CSS lorsqu'elles fonctionnent bien.
Nosredna
11
Ni amazon, ni désormais stackoverflow ne sont des sommets de la conception Web.
Bobby Jack
31
Ce n'est peut-être pas le cas, mais ce sont des solutions fonctionnelles qui servent des dizaines de milliers d'utilisateurs.
17 du 26
22
Ce mème anti-table est tout simplement stupide. Le seul gestionnaire de mise en page bidimensionnel pour la mise en page flexible basée sur des contraintes est la table; et que ce soit juste un compliqué (avec une myriade de col / rowspans) ou imbriqués fait peu de différence. Mais la réalité et les faits ne sont pas toujours des armes suffisantes contre le fanatisme semble-t-il.
StaxMan
28

Flottez simplement à gauche et à droite et réglez pour effacer les deux et vous avez terminé. Pas besoin de tables.

Edit: Je sais que j'ai eu beaucoup de votes positifs pour cela, et je pensais que j'avais raison. Mais il y a des cas où vous avez simplement besoin d'avoir des tables. Vous pouvez essayer de tout faire avec CSS et cela fonctionnera dans les navigateurs modernes, mais si vous souhaitez prendre en charge les plus anciens ... Ne pas me répéter, voici le fil de débordement de pile associé et la diatribe sur mon blog .

Edit2: Étant donné que les anciens navigateurs ne sont plus très intéressants, j'utilise le bootstrap Twitter pour les nouveaux projets. C'est parfait pour la plupart des besoins de mise en page et utilise CSS.

Milan Babuškov
la source
2
Ne gère pas le centrage vertical, donc -1.
SamB
1
J'ai eu un problème similaire où j'avais un logo à gauche et des menus de texte à droite. Les menus devaient être alignés sur la ligne de base du logo. Utilisation de float: right pour les menus ne fonctionnait pas. Cela les a envoyés dans le coin supérieur droit, et ils n'étaient plus alignés verticalement avec la ligne de base du logo.
Jean-François Beauchamp
1
Je pense que vous pouvez résoudre le centrage vertical en définissant la hauteur de ligne du titre sur la même hauteur que celle du bouton.
igors
1
@igors, +1, vous avez raison. Notez que cette question date de 2009.;)
Milan Babuškov
17

C'est une sorte de question piège: cela semble terriblement simple jusqu'à ce que vous arriviez à

Disons que je veux que le titre et le bouton soient centrés verticalement.

Je tiens à préciser que oui, le centrage vertical est difficile en CSS. Quand les gens publient, et cela semble interminable sur SO, "pouvez-vous faire X en CSS", la réponse est presque toujours "oui" et leur gémissement semble injustifié. Dans ce cas, oui, cette chose en particulier est difficile.

Quelqu'un devrait simplement éditer toute la question jusqu'à "Le centrage vertical est-il problématique en CSS?".

AmbroseChapelle
la source
11
C'est un peu mon problème avec l'argument des "haters de table": CSS peut faire tout ce que les tables peuvent faire ... sauf pour certains cas assez simples, courants et raisonnables (comme le centrage vertical). CSS semble juste comme une promesse électorale qui a mal tourné.
cletus
4
Mon point était que le centrage vertical est à peu près la SEULE chose qui soit vraiment difficile.
AmbroseChapel
3
CSS n'est pas destiné à remplacer les tables; il est simplement destiné à vous permettre de résoudre la plupart des problèmes de mise en page courants sans tableaux. Si une table fonctionne, utilisez une table, tout comme vous utiliseriez un stylo pour dessiner au lieu d'une masse.
Aaron Digulla
16

Titre flottant à gauche, bouton flottant à droite et (voici la partie que je n'ai jamais connue jusqu'à récemment) - faites le conteneur des deux {overflow:hidden}.

Cela devrait éviter le problème de z-index, de toute façon. Si cela ne fonctionne pas et que vous avez vraiment besoin du support IE5, allez-y et utilisez le tableau.


la source
+1 Whoa, qu'est-ce que le débordement est caché? Cela fait une différence. Je ne sais pas pourquoi.
cletus
Pour être honnête, je ne comprends pas non plus et je n'ai trouvé aucune mention à ce sujet dans les spécifications. Quelqu'un m'a dit que c'était la «bonne» façon de le faire, après avoir répondu à une autre question suggérant qu'ils utilisent un élément effacé pour le faire. Cela me semble une bonne idée.
Les éléments flottants doivent encore être effacés pour que le contenu qui les suit se déroule correctement. débordement caché; ne concerne que la hauteur du conteneur.
Zack The Human
2
"overflow: hidden" est un hack pour atteindre à la fois la hauteur 'expansion' et le dégagement. Les éléments suivants effaceront cette case (dans les navigateurs qui implémentent correctement cette partie de la spécification, au moins).
Bobby Jack
1
-1 pour ne pas gérer le centrage vertical, mais +2 pour overflow:hidden.
SamB
7

En CSS pur, une réponse de travail sera un jour de simplement utiliser "display:table-cell". Malheureusement, cela ne fonctionne pas dans les navigateurs actuels de qualité A, donc pour tout cela, vous pouvez aussi bien utiliser un tableau si vous voulez simplement obtenir le même résultat de toute façon. Au moins, vous serez sûr que cela fonctionne assez loin dans le passé.

Honnêtement, utilisez simplement une table si c'est plus facile. Ça ne fera pas mal.

Si la sémantique et l'accessibilité de l'élément table sont vraiment importantes pour vous, il existe un brouillon de travail pour rendre votre table non sémantique:

http://www.w3.org/TR/wai-aria/#presentation

Je pense que cela nécessite une DTD spéciale au-delà de XHTML 1.1, ce qui ne ferait qu'attiser tout le débat text/htmlvs application/xml, alors n'allons pas là.

Alors, passons à votre problème CSS non résolu ...

Aligner verticalement deux éléments sur leur centre: cela peut être fait de différentes manières, avec un piratage CSS obtus.

Si vous pouvez tenir compte des contraintes suivantes, il existe un moyen relativement simple:

  • La hauteur des deux éléments est fixe.
  • La hauteur du conteneur est fixe.
  • Les éléments seront suffisamment étroits pour ne pas se chevaucher (ou peuvent être réglés sur une largeur fixe).

Ensuite, vous pouvez utiliser le positionnement absolu avec des marges négatives:

.group-header { height: 50px; position: relative; }
.group-title, .group-buttons { position: absolute; top: 50%; }
# Assuming the height of .group-title is a known 34px
.group-title { left: 0; margin-top: -17px; }
# Assuming the height of .group-buttons is a known 38px
.group-buttons { right: 0; margin-top: -19px; }

Mais c'est inutile dans la plupart des situations ... Si vous connaissez déjà la hauteur des éléments, vous pouvez simplement utiliser des flotteurs et ajouter suffisamment de marge pour les positionner selon vos besoins.

Voici une autre méthode qui utilise la ligne de base du texte pour aligner verticalement les deux colonnes en tant que blocs en ligne. L'inconvénient ici est que vous devez définir des largeurs fixes pour que les colonnes remplissent la largeur à partir du bord gauche. Parce que nous devons garder les éléments verrouillés sur une ligne de base de texte, nous ne pouvons pas simplement utiliser float: right pour la deuxième colonne. (Au lieu de cela, nous devons rendre la première colonne suffisamment large pour la pousser.)

<html>
  <head>
    <title>Layout</title>
    <style type="text/css">
      .group-header, .group-content { width: 500px; margin: 0 auto; }
      .group-header { border: 1px solid red; background: yellow; }
      .valign { display: inline-block; vertical-align: middle; }
      .group-content { border: 1px solid black; background: #DDD; }
      .group-title { padding: 8px; width: 384px; }
      .group-buttons { padding: 8px; width: 84px; text-align: right; }
    </style>
    <!--[if lt IE 8]>
    <style type="text/css">
      .valign { display: inline; margin-top: -2px; padding-top: 1px; }
    </style>
    <![endif]-->
  </head>
  <body>
    <div class="group-header">
      <div class="valign">
        <div class="group-title">This is my title.</div>
      </div><!-- avoid whitespace between these! --><div class="valign">
        <div class="group-buttons"><input type="button" value="Collapse"></div>
      </div>
    </div>
    <div class="group-content">
      <p>And it works perfectly, but mind the hacks.</p>
    </div>
  </body>
</html>

Le HTML: Nous ajoutons des wrappers .valign autour de chaque colonne. (Donnez-leur un nom plus «sémantique» si cela vous rend plus heureux.) Ceux-ci doivent être conservés sans espace entre eux, sinon les espaces de texte les sépareront. (Je sais que ça craint, mais c'est ce que vous obtenez en étant "pur" avec le balisage et en le séparant de la couche de présentation ... Ha!)

Le CSS: Nous utilisons vertical-align:middlepour aligner les blocs sur la ligne de base du texte de l'élément d'en-tête de groupe. Les différentes hauteurs de chaque bloc resteront centrées verticalement et repousseront la hauteur de leur conteneur. Les largeurs des éléments doivent être calculées pour s'adapter à la largeur. Ici, ils sont 400 et 100, moins leur rembourrage horizontal.

Les corrections d'IE: Internet Explorer n'affiche que le bloc en ligne pour les éléments en ligne nativement (par exemple, span, pas div). Mais, si nous donnons le div hasLayout puis l'afficherons en ligne, il se comportera comme un bloc en ligne. Le réglage de la marge consiste à corriger un écart de 1px en haut (essayez d'ajouter des couleurs d'arrière-plan au .group-title pour voir).

Andrew Vit
la source
1
Hmm l'affichage: les balises table-X semblent avoir pour but de faire la mise en page à l'aide de tableaux, uniquement sans utiliser de balises de table?
Danubian Sailor
3

Je recommanderais de ne pas utiliser de tableau dans ce cas, car ce ne sont pas des données tabulaires; c'est purement présentationnel d'avoir le bouton situé à l'extrême droite. Voici ce que je ferais pour dupliquer la structure de votre table (passez à un H # différent en fonction de votre position dans la hiérarchie de votre site):

<style>
  .group-header { background: yellow; zoom: 1; padding: 8px; }
  .group-header:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
  /* set width appropriately to allow room for button */
  .group-header h3 { float: left; width: 300px; }
  /* set line-height or margins to align with h3 baseline or middle */
  .group-header input { float: right; }
</style>

<div class="group-header">
  <h3>This is my title</h3>
  <input type="button" value="Collapse"/>
</div>

Si vous voulez un véritable alignement vertical au milieu (c'est-à-dire que si le texte enveloppe le bouton est toujours aligné au milieu par rapport aux deux lignes de texte), vous devez soit créer un tableau, soit travailler avec position: absoluteet des marges. Vous pouvez ajouter position: relativeà votre menu déroulant (ou plus probablement à son parent) afin de le placer dans le même niveau de classement que les boutons, vous permettant de le faire passer au-dessus d'eux avec z-index, le cas échéant.

Notez que vous n'avez pas besoin width: 100%du div car il s'agit d'un élément de niveau bloc et zoom: 1que le div se comporte comme s'il avait un clearfix dans IE (les autres navigateurs prennent le clearfix réel). Vous n'avez pas non plus besoin de toutes ces classes superflues si vous ciblez des choses un peu plus spécifiquement, bien que vous ayez peut-être besoin d'un div ou d'un span wrapper sur le bouton pour faciliter le positionnement.

Un crayon
la source
Votre solution ne fonctionne pas sur IE6 en raison de la pseudo-classe: after.
Sebastian Hoitz
1
Cela fonctionne dans IE 6, grâce à zoom: 1in .group-header, qui déclenche hasLayout et oblige IE 6 à se comporter de la même manière que si l'élément: after était actif.
One Crayon le
2

Faites un double float dans un div et utilisez le clearfix. http://www.webtoolkit.info/css-clearfix.html Avez-vous des restrictions de remplissage / marge?

<div class="clearfix">
   <div style="float:left">Title</div>
   <input type="button" value="Button" style="float:right" />
</div>
Bendewey
la source
J'ai une exigence de centrage vertical (et un petit rembourrage supplémentaire). Je pense avoir clarifié cela après votre publication.
cletus le
2
<div class="group-header">
    <input type="button" name="Button" value="Button" style="float:right" />
    <span>Title</span>
</div>
Omer Bokhari
la source
1

J'ai choisi d'utiliser Flexbox, car cela a rendu les choses beaucoup plus faciles.

Vous devez essentiellement vous rendre chez le parent des enfants que vous souhaitez aligner et ajouter display:box(préfixé bien sûr). Pour les faire asseoir sur les côtés, utilisez justify-content . L'espace entre les deux est la bonne chose lorsque vous avez des éléments qui doivent être alignés à la fin, comme dans ce cas (voir lien) ...

Puis le problème d'alignement vertical. Parce que j'ai créé le parent des deux éléments, vous souhaitez aligner une Flexbox. C'est maintenant facile à utiliser align-items: center.

Ensuite, j'ai ajouté les styles que vous vouliez auparavant, supprimé le flottant du titre et du bouton dans l'en-tête et ajouté un rembourrage:

.group-header, .group-content {
    width: 500px;
    margin: 0 auto;
}
.group-header{
    border: 1px solid red;
    background: yellow;
    overflow: hidden;
    display: -webkit-box;
    display: -moz-box;
    display: box;
    display: -webkit-flex;
    display: -moz-flex;
    display: -ms-flexbox;
    display: flex;
    -webkit-justify-content: space-between;
    -moz-justify-content: space-between;
    -ms-justify-content: space-between;
    -o-justify-content: space-between;
    justify-content: space-between;
    webkit-align-items: center;
    -moz-align-items: center;
    -ms-align-items: center;
    -o-align-items: center;
    align-items: center;
    padding: 8px 0;
}
.group-content{
    border: 1px solid black;
    background: #DDD;
}
.group-title {
    padding-left: 8px;
}
.group-buttons {
    padding-right: 8px
}

Voir la démo

user3522940
la source
1

Je suis d'accord pour dire qu'il ne faut vraiment utiliser les tableaux que pour les données tabulaires, pour la simple raison que les tableaux ne s'affichent pas tant qu'ils n'ont pas fini de se charger (peu importe la vitesse à laquelle cela est; c'est plus lent que la méthode CSS). Je pense cependant que c'est la solution la plus simple et la plus élégante:

<html>
    <head>
        <title>stack header</title>
        <style type="text/css">
            #stackheader {
                background-color: #666;
                color: #FFF;
                width: 410px;
                height: 50px;
            }
            #title {
                color: #FFF;
                float: left;
                padding: 15px 0 0 15px;
            }
            #button {
                color: #FFF;
                float: right;
                padding: 15px 15px 0 0;
            }
        </style>
    </head>

    <body>
        <div id="stackheader">
        <div id="title">Title</div>
        <div id="button">Button</div>
        </div>
    </body>
</html>

La fonction de bouton et tout détail supplémentaire peuvent être stylisés à partir de cette forme de base. Toutes mes excuses pour les mauvaises balises.

Galen777
la source