web-dev-qa-db-fra.com

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

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

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

Des trucs assez simples. La haine des tableaux 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 des tableaux? Maintenant, le le sujet général des tables vs divs/CSS a été discuté précédemment, par exemple:

Il ne s'agit donc pas d'une discussion générale sur CSS par rapport aux tableaux de mise en page. C'est simplement la solution à un problème. J'ai essayé diverses solutions à ce qui précède en utilisant CSS, notamment:

  • Flotter vers la droite pour le bouton ou une div contenant le bouton;
  • Position relative pour le 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 d'index z 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 simplement. Pas de soucis de positionnement ou de flotteurs.

Alors, peut-on faire l'équivalent sans tables?

Les exigences sont les suivantes:

  • 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 de développer 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: hidden partie (mais 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 cela à:

<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.

99
cletus

Il n'y a rien de mal à utiliser les outils dont vous disposez pour effectuer le travail rapidement et correctement.

Dans ce cas, une table fonctionnait parfaitement.

Personnellement, j'aurais utilisé une table pour cela.

Je pense que les tables imbriquées doivent être évitées, les choses peuvent devenir désordonnées.

49
Gregor Brandt

Il suffit de flotter à gauche et à droite et de régler pour effacer les deux et vous avez terminé. Pas besoin de tables.

Edit: Je sais que j'ai reçu beaucoup de votes positifs pour cela, et je pensais avoir raison. Mais il y a des cas où vous avez simplement besoin de 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 ... Pour ne pas me répéter, voici le thread de débordement de pile associé et rant sur mon blog .

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

27
Milan Babuškov

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 pour mémoire que oui, le centrage vertical est difficile en CSS. Quand les gens postent, et cela semble infini 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, une chose en particulier est difficile.

Quelqu'un devrait simplement éditer la question entière en "le centrage vertical est-il problématique en CSS?".

17
AmbroseChapel

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

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

16
user42092

En CSS pur, une réponse de travail sera un jour d'utiliser simplement "display:table-cell". Malheureusement, cela ne fonctionne pas sur les navigateurs A-grade actuels, donc pour autant, vous pourriez aussi bien utiliser un tableau si vous voulez tout de même obtenir le même résultat. 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. Cela ne fera pas de mal.

Si la sémantique et l'accessibilité de l'élément table vous importent vraiment, il existe un brouillon 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, qui ne ferait que remuer l'ensemble text/html contre application/xml débat, alors n'y allons pas.

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

Pour aligner verticalement deux éléments sur leur centre: cela peut être fait de différentes manières, avec quelques hackery CSS obtus.

Si vous pouvez vous adapter aux 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 définis sur une largeur fixe).

Ensuite, vous pouvez utiliser un 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 cela 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 les colonnes afin de remplir 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 faire 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 les deux, sinon les espaces de texte les éloigneront. (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:middle pour 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.

Le IE corrige: Internet Explorer n'affiche le bloc en ligne que pour les éléments en ligne natifs (par exemple span, not div) . Mais, si nous donnons le div hasLayout et que nous l'afficherons ensuite en ligne, il se comportera comme un bloc en ligne. L'ajustement 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) .

7
Andrew Vit

Je recommanderais de ne pas utiliser de table dans ce cas, car il ne s'agit pas de 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 (changer pour un H # différent pour convenir où vous vous trouvez 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, si le texte enveloppe le bouton est toujours aligné au milieu par rapport aux deux lignes de texte), alors vous devez soit faire un tableau ou travailler quelque chose avec position: absolute et les 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, ce qui vous permet de le placer au-dessus d'eux avec z-index, si cela vient à ce sujet.

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

3
One Crayon

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>
2
bendewey
<div class="group-header">
    <input type="button" name="Button" value="Button" style="float:right" />
    <span>Title</span>
</div>
2
Omer Bokhari

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

Vous devez essentiellement aller au 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 justification-conten . L'espace entre est la bonne chose quand vous avez des éléments qui doivent être alignés à la fin, comme dans ce cas (voir lien) ...

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

Ensuite, j'ai ajouté les styles que vous vouliez avant, supprimé le flotteur 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 démo

1
user3522940

Je suis d'accord qu'il ne faut vraiment utiliser des tableaux que pour des données tabulaires, pour la simple raison que les tableaux ne s'affichent pas jusqu'à ce qu'ils aient fini de se charger (quelle que soit la vitesse; 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 du bouton et tout détail supplémentaire peuvent être stylisés à partir de cette forme de base. Toutes mes excuses pour les bad tags.

1
Galen777