¿Cómo hacer que un elemento de bloque en línea llene el resto de la línea?

186

¿Es posible usar CSS y dos etiquetas DIV de bloque en línea (o lo que sea) en lugar de usar una tabla?

La versión de la tabla es esta (se agregaron bordes para que pueda verla):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
<table style="width:100%;">
<tr>
<td style="border:1px solid black;width:100px;height:10px;"></td>
<td style="border:1px solid black;height:10px;"></td>
</tr>
</table>
</body>
</html>

Produce una columna izquierda con un ANCHO FIJO (no un ancho porcentual) y una columna derecha que se expande para llenar EL ESPACIO RESTANTE en la línea. Suena bastante simple, ¿verdad? Además, dado que nada está "flotando", la altura del contenedor principal se expande adecuadamente para abarcar la altura del contenido.

- COMIENCE RANT--
He visto las implementaciones de "solución clara" y "santo grial" para diseños de varias columnas con columna lateral de ancho fijo, y apestan y son complicadas. Invierten el orden de los elementos, usan anchos porcentuales o flotadores, márgenes negativos y la relación entre los atributos "izquierdo", "derecho" y "margen" es compleja. Además, los diseños son sensibles a los subpíxeles, por lo que agregar incluso un solo píxel de bordes, relleno o márgenes romperá todo el diseño y enviará columnas completas a la siguiente línea. Por ejemplo, los errores de redondeo son un problema incluso si intenta hacer algo simple, como poner 4 elementos en una línea, con el ancho de cada uno establecido en 25%.
--END RANT--

Intenté usar "inline-block" y "white-space: nowrap;", pero el problema es que simplemente no puedo obtener el segundo elemento para llenar el espacio restante en la línea. Establecer el ancho en algo como "ancho: 100% - (LeftColumWidth) px" funcionará en algunos casos, pero realizar un cálculo en una propiedad de ancho no es realmente compatible.

Triynko
fuente
1
No creo que haya una forma sensata de hacer esto, excepto convertir esto en una display: table-*construcción que funcione, pero tampoco es realmente "más semántica" (siendo un terrible caso de divsopa) y rompe la compatibilidad con IE6. Personalmente me quedaría con el <table>, a menos que alguien logre tener una idea simple y genial que funcione sin
Pekka
51
Si. Sigo encontrándome con todos estos argumentos de "evitar tablas" desde el comienzo de la era CSS, y están redactados para hacerte sonar como un imbécil perezoso incompetente si todavía usas tablas para diseños. Avance rápido una década, y sigue siendo un sueño idealista. El hecho es que la semántica de diseño de flujo SUCK para diseños fijos pero flexibles como interfaces y formularios de usuario. La verdad es que las personas inteligentes usarán tablas cuando sea conveniente, porque han agotado todas las soluciones CSS posibles y se han dado cuenta de que todas son imperfectas y significativamente más complejas que simplemente usar una tabla.
Triynko
44
Flotadores? Muéstrame el código de trabajo, donde los elementos de fin de línea no se ajustan de forma impredecible y los bordes y márgenes no rompen el diseño. Eso es lo que les pasa. Además, ¿el contenedor principal de tamaño automático se expande correctamente para abarcar elementos flotantes sin los hacks de "solución clara"? No lo creo.
Triynko
Si tiene al menos un elemento no flotante en su contenedor principal, entonces no es realmente un "truco" para eliminar flotantes, ¿verdad? Recuerde que CSS tiene sus raíces en la impresión: consulte css-tricks.com/containers-dont-clear-floats para una buena discusión de por qué no obtiene la limpieza automática.
Chowlett
3
@Triynko: Esto es lo que hice antes: jsfiddle.net/thirtydot/qx32C : creo que alcanza la mayoría de tus puntos. Escucharé tu crítica de la demostración que hice, y trataré de arreglarla después.
thirtydot

Respuestas:

169

Ver: http://jsfiddle.net/qx32C/36/

.lineContainer {
    overflow: hidden; /* clear the float */
    border: 1px solid #000
}
.lineContainer div {
    height: 20px
} 
.left {
    width: 100px;
    float: left;
    border-right: 1px solid #000
}
.right {
    overflow: hidden;
    background: #ccc
}
<div class="lineContainer">
    <div class="left">left</div>
    <div class="right">right</div>
</div>


¿Por qué lo reemplacé margin-left: 100pxcon overflow: hiddenon .right?

EDITAR: Aquí hay dos espejos para el enlace (muerto) anterior:

Thirtydot
fuente
6060
Si te llamas desarrollador web, debes hacer clic en ese enlace. Lo hice, y me sentí como Jasmine en una alfombra mágica.
Chris grita el
2
@ChrisShouts, esa es probablemente la mejor manera de describir esto. Este método simplemente no tiene sentido, pero de nuevo ... Una maravillosa solución para algo que debería poder hacer explícitamente.
mjvotaw
14
El desbordamiento oculto no es una solución. Suponga que no desea que se oculte el desbordamiento del contenedor correcto. Esto no hace que el tamaño del contenedor correcto llene el espacio restante en la línea. Este es un ejemplo de una pregunta de dos años para la que todavía no he marcado una respuesta, porque todavía no hay una respuesta satisfactoria.
Triynko
3
Triynko: aunque esté usando 'overflow: hidden', generalmente no se ocultará nada (al menos si solo tiene texto allí). El texto / elementos dentro del div se organizarán para que quepan dentro del div (a menos que tenga un elemento que sea más grande que el div, por supuesto).
CpnCrunch
1
@RMorrisey: Probablemente solo necesite algo box-sizing: border-boxen el divs. Solo una suposición, ya que no proporcionó una demostración que muestre el comportamiento que describe. Dicho esto, la display: tablesolución basada en la mayoría de las veces es mejor . Esta es una pregunta muy antigua, pero creo que estaba tratando de evitar algo relacionado con las tablas en esta pregunta debido al comportamiento de OP.
thirtydot
65

Una solución moderna con flexbox:

.container {
    display: flex;
}
.container > div {
    border: 1px solid black;
    height: 10px;
}

.left {
   width: 100px;
}

.right {
    width: 100%;
    background-color:#ddd;
}
<div class="container">
  <div class="left"></div>
  <div class="right"></div>
</div>

http://jsfiddle.net/m5Xz2/100/

Panu Horsmalahti
fuente
44
mostrar flex y ancho 100% ..
tengo
10
cuando se usa flex, ¿por qué no usar en flex: 1lugar de width: 100%?
Itai Bar-Haim
Para aquellos nuevos en flexbox : flex: 1es la abreviatura de flex-grow: 1. Es un atributo de combinación: flex: <grow> <shrink> <basis>.
tanius
1
Solo una nota rápida que muestra: flex no es compatible en IE <11, y muy defectuoso en 11.
Eric Shields
1
@EricShields esto no debería impedir que nadie use Flexbox. Hoy en día te tenemos flexbugssabes.
Neurotransmisor el
47

Compatible con navegadores modernos comunes (IE 8+): http://jsfiddle.net/m5Xz2/3/

.lineContainer {
    display:table;
    border-collapse:collapse;
    width:100%;
}
.lineContainer div {
    display:table-cell;
    border:1px solid black;
    height:10px;
}
.left {
    width:100px;
}
 <div class="lineContainer">
    <div class="left">left</div>
    <div class="right">right</div>
</div>

Z escarchado
fuente
9
El argumento en contra del uso de tablas no tiene nada que ver con sus características de presentación. Tiene que ver con marcado inmanejable, confusión de estilo / documento y semántica inadecuada. Ninguno de estos argumentos se aplica a display:table.
Rich Remer
Esto no responde cómo inline-blockrellenar el resto de la línea.
Neurotransmisor el
1
@TranslucentCloud Estoy de acuerdo en que mi respuesta no responde exactamente el título de la pregunta, pero proporciona una forma de llenar el ancho disponible usando divs, como se pregunta en el cuerpo de la pregunta.
Frosty Z
1
Me gusta mucho esta solución. No está obligado a usar algunos estilos extraños que surgen de la lógica oculta de CSS (como el desbordamiento oculto).
Chaoste
4

Puede usar calc (100% - 100px) en el elemento fluido, junto con display: inline-block para ambos elementos.

Tenga en cuenta que no debe haber espacio entre las etiquetas, de lo contrario, también tendrá que considerar ese espacio en su cal.

.left{
    display:inline-block;
    width:100px;
}
.right{
    display:inline-block;
    width:calc(100% - 100px);
}


<div class=“left”></div><div class=“right”></div>

Ejemplo rápido: http://jsfiddle.net/dw689mt4/1/

SuperIRis
fuente
1

He usado la flex-growpropiedad para lograr este objetivo. Vas a tener que conjunto display: flexde contenedor primario, entonces usted necesidad de fijar flex-grow: 1para el bloque que desea rellenar el espacio restante, o simplemente flex: 1como Tanius mencionado en los comentarios.

Vladislav Kovechenkov
fuente
0

Si no puede usar overflow: hidden(porque no quiere overflow: hidden) o si no le gustan los hacks / soluciones alternativas de CSS, puede usar JavaScript en su lugar. Tenga en cuenta que puede no funcionar tan bien porque es JavaScript.

var parent = document.getElementsByClassName("lineContainer")[0];
var left = document.getElementsByClassName("left")[0];
var right = document.getElementsByClassName("right")[0];
right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
window.onresize = function() {
  right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
}
.lineContainer {
  width: 100% border: 1px solid #000;
  font-size: 0px;
  /* You need to do this because inline block puts an invisible space between them and they won't fit on the same line */
}

.lineContainer div {
  height: 10px;
  display: inline-block;
}

.left {
  width: 100px;
  background: red
}

.right {
  background: blue
}
<div class="lineContainer">
  <div class="left"></div>
  <div class="right"></div>
</div>

http://jsfiddle.net/ys2eogxm/

Nick Manning
fuente