¿Puedes hacer este diseño HTML sin usar tablas?

102

Ok, tuve un problema de diseño simple hace una semana o dos. Es decir, las secciones de una página necesitaban un encabezado:

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

Cosas bastante simples. La cosa es que el odio a las tablas parece haberse apoderado del mundo web, lo cual recordé cuando pregunté ¿Por qué usar etiquetas de listas de definiciones (DL, DD, DT) para formularios HTML en lugar de tablas? Ahora, el tema general de tablas vs divs / CSS se ha discutido previamente, por ejemplo:

Por lo tanto, esto no pretende ser una discusión general sobre CSS vs tablas para el diseño. Esta es simplemente la solución a un problema. Probé varias soluciones a lo anterior usando CSS, que incluyen:

  • Flota a la derecha para el botón o un div que contiene el botón;
  • Posición relativa para el botón; y
  • Posición relativa + absoluta.

Ninguna de estas soluciones fue satisfactoria por diferentes razones. Por ejemplo, el posicionamiento relativo resultó en un problema de índice Z donde mi menú desplegable apareció debajo del contenido.

Así que terminé volviendo a:

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

Y funciona perfectamente. Es simple, compatible con versiones anteriores (que probablemente funcionará incluso en IE5) y simplemente funciona. No se pierda el posicionamiento o los flotadores

Entonces, ¿alguien puede hacer el equivalente sin tablas?

Los requisitos son:

  • Compatible con versiones anteriores: a FF2 e IE6;
  • Razonablemente consistente: en diferentes navegadores;
  • Centrado verticalmente: el botón y el título tienen diferentes alturas; y
  • Flexible: permite un control razonablemente preciso sobre el posicionamiento (relleno y / o margen) y el estilo.

En una nota al margen, me encontré con un par de artículos interesantes hoy:

EDITAR: Permítanme ampliar el tema de la flotación. Este tipo de obras:

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

Gracias a Ant P por el overflow: hiddenpapel (aunque todavía no entiendo por qué). Aquí es donde entra el problema. Digamos que quiero que el título y el botón estén centrados verticalmente. Esto es problemático porque los elementos tienen diferente altura. Compare esto con:

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

que funciona perfectamente.

cletus
fuente
11
Ok, eso tiene sentido "¿Qué color debo usar para vim?" obtiene una votación a favor, mi problema específico de diseño de CSS se vota en contra.
cletus
puedes hacer lo que quieras sin mesa en cualquier caso. Además, ¿por qué diablos @SamB se enfrentó a esta pregunta de 2 años? DOH +
dinámico
3
@ yes123: bueno, el resaltado de sintaxis era incorrecto ...
SamB

Respuestas:

50

No hay nada de malo en utilizar las herramientas que están disponibles para hacer el trabajo de forma rápida y correcta.

En este caso una mesa funcionó a la perfección.

Personalmente, habría utilizado una mesa para esto.

Creo que las tablas anidadas deben evitarse, las cosas pueden complicarse.

Gregor Brandt
fuente
21
Excepto cuando está utilizando una tabla para el diseño de presentación en lugar de datos tabulares solo porque es más fácil al principio, en cuyo caso se dirige por un camino oscuro y peligroso.
One Crayon
9
Incluso Amazon usa tablas en ciertos casos. Y stackoverflow.com también lo hace. Estoy a favor de las soluciones CSS cuando en realidad funcionan bien.
Nosredna
11
Ni amazon, ahora stackoverflow son la cúspide del diseño web.
Bobby Jack
31
Puede que no lo sean, pero son soluciones funcionales que sirven a decenas de miles de usuarios.
17 del 26 de
22
Este meme anti-mesa es simplemente estúpido. El único administrador de diseño bidimensional para el diseño flexible basado en restricciones es la tabla; y si es solo uno complicado (con una gran cantidad de columnas / filas), o anidados hace poca diferencia. Pero parece que la realidad y los hechos no siempre son armas suficientemente buenas contra el fanatismo.
StaxMan
28

Simplemente flote hacia la izquierda y hacia la derecha y configure para borrar ambos y listo. Sin necesidad de mesas.

Editar: Sé que obtuve muchos votos a favor por esto, y creí que tenía razón. Pero hay casos en los que simplemente necesita tener tablas. Puede intentar hacer todo con CSS y funcionará en los navegadores modernos, pero si desea admitir los más antiguos ... No para repetirme, aquí el hilo de desbordamiento de pila relacionado y despotricar en mi blog .

Edición 2: Dado que los navegadores más antiguos ya no son tan interesantes, estoy usando Twitter bootstrap para nuevos proyectos. Es ideal para la mayoría de las necesidades de diseño y utiliza CSS.

Milán Babuškov
fuente
2
No maneja el centrado vertical, entonces -1.
SamB
1
Tuve un problema similar en el que tenía un logotipo a la izquierda y algunos menús de texto a la derecha. Los menús tenían que estar alineados con la línea de base del logo. Usar float: right para los menús no funcionó. Los envió a la esquina superior derecha y ya no estaban alineados verticalmente con la línea de base del logotipo.
Jean-François Beauchamp
1
Creo que puede resolver el centrado vertical configurando la altura de la línea del título para que sea la misma que la altura del botón.
igors
1
@igors, +1, tienes razón.
Tenga en
17

Esta es una especie de pregunta capciosa: parece terriblemente simple hasta que llegas a

Digamos que quiero que el título y el botón estén centrados verticalmente.

Quiero dejar constancia de que sí, el centrado vertical es difícil en CSS. Cuando la gente publica, y parece interminable en SO, "¿puedes hacer X en CSS?", La respuesta casi siempre es "sí" y su quejido parece injustificado. En este caso, sí, esa cosa en particular es difícil.

Alguien debería simplemente editar toda la pregunta hasta "¿es problemático el centrado vertical en CSS?".

AmbrosioCapilla
fuente
11
Ese es mi problema con el argumento de los "enemigos de las tablas": CSS puede hacer todo lo que pueden hacer las tablas ... excepto en algunos casos bastante simples, comunes y razonables (como el centrado vertical). CSS simplemente parece una promesa electoral que salió mal.
cletus
4
Mi punto fue que el centrado vertical es lo ÚNICO que es realmente difícil.
AmbroseChapel
3
CSS no está destinado a reemplazar tablas; solo está destinado a permitirle resolver la mayoría de los problemas de diseño comunes sin tablas. Si una mesa funciona, use una mesa, al igual que usaría un bolígrafo para dibujar en lugar de un mazo.
Aaron Digulla
16

Flota el título a la izquierda, el botón flotante a la derecha y (aquí está la parte que nunca supe hasta hace poco): haz el contenedor de ambos {overflow:hidden} .

Eso debería evitar el problema del índice z, de todos modos. Si no funciona y realmente necesita el soporte IE5, siga adelante y use la tabla.


fuente
+1 Whoa, ¿qué pasa con el desbordamiento oculto? Eso hace una diferencia. Aunque no tengo idea de por qué.
cletus
Para ser honesto, tampoco lo entiendo y no pude encontrar ninguna mención al respecto en la especificación. Sin embargo, alguien me dijo que esa es la forma "correcta", después de que respondí otra pregunta sugiriendo que usaran un elemento autorizado para hacerlo. Me parece una buena idea.
Los elementos flotantes aún deben limpiarse para que el contenido que los sigue fluya correctamente. desbordamiento: oculto; solo aborda la altura del contenedor.
Zack The Human
2
"overflow: hidden" es un truco para lograr TANTO la 'expansión' de altura como la limpieza. Los siguientes elementos borrarán esa casilla (en los navegadores que implementan esa parte de la especificación correctamente, al menos).
Bobby Jack
1
-1 para no manejar el centrado vertical, pero +2 para overflow:hidden.
SamB
7

En CSS puro, un día una respuesta funcional será simplemente usar "display:table-cell". Desafortunadamente, eso no funciona en los navegadores actuales de grado A, por lo que, para todo eso, también puede usar una tabla si solo desea lograr el mismo resultado de todos modos. Al menos estarás seguro de que funciona lo suficiente en el pasado.

Honestamente, solo use una mesa si es más fácil. No dolerá.

Si la semántica y la accesibilidad del elemento de la tabla realmente le importan, hay un borrador de trabajo para hacer que su tabla no sea semántica:

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

Creo que esto requiere un DTD especial más allá de XHTML 1.1, lo que agitaría todo el debate text/htmlfrente a él application/xml, así que no vayamos allí.

Entonces, a su problema de CSS no resuelto ...

Para alinear verticalmente dos elementos en su centro: se puede hacer de diferentes maneras, con algún truco CSS obtuso.

Si puede ajustarse a las siguientes limitaciones, existe una forma relativamente sencilla:

  • La altura de los dos elementos es fija.
  • La altura del contenedor es fija.
  • Los elementos serán lo suficientemente estrechos como para no superponerse (o se pueden establecer en un ancho fijo).

Entonces puedes usar el posicionamiento absoluto con márgenes negativos:

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

Pero esto no tiene sentido en la mayoría de las situaciones ... Si ya conoce la altura de los elementos, puede usar flotadores y agregar suficiente margen para colocarlos según sea necesario.

Aquí hay otro método que utiliza la línea base de texto para alinear verticalmente las dos columnas como bloques en línea. El inconveniente aquí es que debe establecer anchos fijos para que las columnas completen el ancho desde el borde izquierdo. Debido a que necesitamos mantener los elementos bloqueados en una línea de base de texto, no podemos simplemente usar float: right para la segunda columna. (En cambio, tenemos que hacer que la primera columna sea lo suficientemente ancha para empujarla).

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

El HTML: Agregamos envoltorios .valign alrededor de cada columna. (Déles un nombre más "semántico" si le hace más feliz.) Estos deben mantenerse sin espacios en blanco entre ellos o, de lo contrario, los espacios de texto los separarán. (Sé que apesta, pero eso es lo que obtienes por ser "puro" con el marcado y separarlo de la capa de presentación ... ¡Ja!)

El CSS: Usamos vertical-align:middlepara alinear los bloques con la línea base del texto del elemento de encabezado de grupo. Las diferentes alturas de cada bloque permanecerán centradas verticalmente y empujarán hacia afuera la altura de su contenedor. Los anchos de los elementos deben calcularse para ajustarse al ancho. Aquí, son 400 y 100, menos su relleno horizontal.

Las correcciones de IE: Internet Explorer solo muestra el bloque en línea para los elementos en línea de forma nativa (por ejemplo, span, no div). Pero, si le damos el div hasLayout y luego lo mostramos en línea, se comportará como un bloque en línea. El ajuste del margen es para arreglar un espacio de 1px en la parte superior (intente agregar colores de fondo al título .group para ver).

Andrew Vit
fuente
1
Hmm, la pantalla: las etiquetas table-X parecen tener el propósito de hacer un diseño usando tablas, solo que sin usar etiquetas de tabla.
Marinero del Danubio,
3

Recomendaría no usar una tabla en este caso, porque no son datos tabulares; es puramente presentativo tener el botón ubicado en el extremo derecho. Esto es lo que haría para duplicar la estructura de su tabla (cambiar a un H # diferente para adaptarse a dónde se encuentra en la jerarquía de su sitio):

<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 desea una verdadera alineación vertical en el medio (es decir, si el texto envuelve, el botón todavía está alineado en el medio con respecto a ambas líneas de texto), entonces necesita hacer una tabla o trabajar algo con position: absolutemárgenes. Puede agregar position: relativea su menú desplegable (o más probablemente a su padre) para colocarlo en el mismo nivel de orden que los botones, lo que le permite subirlo por encima de ellos con el índice z, si se trata de eso.

Tenga en cuenta que no necesita width: 100%en el div porque es un elemento a nivel de bloque y zoom: 1hace que el div se comporte como si tuviera un clearfix en IE (otros navegadores recogen el clearfix real). Tampoco necesita todas esas clases extrañas si está apuntando a cosas un poco más específicamente, aunque es posible que necesite un div contenedor o span en el botón para facilitar el posicionamiento.

Un crayón
fuente
Sin embargo, su solución no funciona en IE6 debido a la pseudoclase: after.
Sebastian Hoitz
1
Sí funciona en IE 6, gracias a zoom: 1in .group-header, que activa hasLayout y hace que IE 6 se comporte de la misma forma que si tuviera el elemento: after activo.
One Crayon
2

Haz un doble flotador en un div y usa clearfix. http://www.webtoolkit.info/css-clearfix.html ¿Tiene alguna restricción de margen / relleno?

<div class="clearfix">
   <div style="float:left">Title</div>
   <input type="button" value="Button" style="float:right" />
</div>
bendewey
fuente
Tengo un requisito de centrado vertical (y un poco de relleno adicional). Creo que lo aclaré después de que publicaste.
cletus
2
<div class="group-header">
    <input type="button" name="Button" value="Button" style="float:right" />
    <span>Title</span>
</div>
Omer Bokhari
fuente
1

Elegí usar Flexbox porque facilitó mucho las cosas.

Básicamente, debe ir al padre de los niños que desea alinear y agregar display:box(con prefijo, por supuesto). Para hacer que se sienten a los lados, use justify-content . El espacio entre medio es lo correcto cuando tienes elementos que deben alinearse hasta el final, como en este caso (ver enlace) ...

Luego, el problema de la alineación vertical. Como hice el padre de los dos elementos, desea alinear un Flexbox. Ahora es fácil de usaralign-items: center .

Luego agregué los estilos que deseaba antes, eliminé el flotador del título y el botón en el encabezado y agregué un relleno:

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

Ver demostración

usuario3522940
fuente
1

Estoy de acuerdo en que realmente solo se deben usar tablas para datos tabulares, por la sencilla razón de que las tablas no se muestran hasta que se terminan de cargar (no importa qué tan rápido sea; es más lento que el método CSS). Sin embargo, creo que esta es la solución más simple y elegante:

<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 función del botón y cualquier detalle adicional se pueden diseñar desde esta forma básica. Disculpas por las malas etiquetas.

Galen777
fuente