CSS: ¿Cómo colocar dos elementos uno encima del otro, sin especificar una altura?

96

Tengo dos DIV que necesito colocar exactamente uno encima del otro. Sin embargo, cuando hago eso, el formato se estropea porque el DIV que lo contiene actúa como si no hubiera altura. Creo que este es el comportamiento esperado, position:absolutepero necesito encontrar una manera de colocar estos dos elementos uno encima del otro y hacer que el contenedor se estire a medida que el contenido se estira:

El borde superior izquierdo de .layer2debe estar exactamente alineado con el borde superior izquierdo delayer1

<!-- HTML -->
<div class="container_row">
    <div class="layer1">
        Lorem ipsum...
    </div>
    <div class="layer2">
        More lorem ipsum...
    </div>
</div>
<div class="container_row">
    ...same HTML as above. This one should never overlap the .container_row above.
</div>

/* CSS */
.container_row {}

.layer1 {
    position:absolute;
    z-index: 1;
}

.layer2 {
    position:absolute;
    z-index: 2;
}
Andrés
fuente
1
position: absoluteno es el estilo correcto para usar entonces.
BoltClock
sí, position:absoluteno se siente bien. ¿Cuál sería el estilo correcto?
Andrew
¿Los elementos .layer1y .layer2tienen un tamaño conocido?
mu es demasiado corto
No, también tienen un tamaño desconocido.
Andrew

Respuestas:

81

En primer lugar, debería incluir la posición en elementos absolutamente posicionados o se encontrará con un comportamiento extraño y confuso; probablemente desee agregar top: 0; left: 0al CSS para ambos elementos absolutamente posicionados. También querrá tener position: relativeactivado .container_rowsi desea que los elementos absolutamente posicionados se coloquen con respecto a su padre en lugar del cuerpo del documento :

Si el elemento tiene 'posición: absoluta', el bloque contenedor lo establece el antepasado más cercano con una 'posición' de 'absoluta', 'relativa' o 'fija' ...

Tu problema es que position: absoluteelimina elementos del flujo normal :

Se elimina por completo del flujo normal (no tiene ningún impacto en los hermanos posteriores). Un cuadro absolutamente posicionado establece un nuevo bloque contenedor para los hijos de flujo normal y los descendientes posicionado absolutamente (pero no fijo). Sin embargo, el contenido de un elemento absolutamente posicionado no fluye alrededor de otras cajas.

Esto significa que los elementos absolutamente posicionados no tienen ningún efecto en el tamaño de su elemento padre y el primero <div class="container_row">tendrá una altura de cero.

Por lo tanto, no puede hacer lo que está tratando de hacer con elementos absolutamente posicionados a menos que sepa qué tan altos serán (o, de manera equivalente, puede especificar su altura). Si puede especificar las alturas, puede poner las mismas alturas en el .container_rowy todo se alineará; también puede poner un margin-topen el segundo .container_rowpara dejar espacio para los elementos absolutamente posicionados. Por ejemplo:

http://jsfiddle.net/ambiguous/zVBDc/

mu es demasiado corto
fuente
Gran respuesta, gracias! Supongo que es posible que deba calcular la altura dinámicamente usando javascript. Solo esperaba que no tuviera que llegar a eso. = [
Andrew
@Andrew: Sí, bienvenido al sistema de alineación / posición / tamaño vertical de CSS: si no conoce los tamaños específicos de las cosas, generalmente no tiene suerte. Las cosas horizontales son más fáciles de manejar, pero la mayoría todavía huele a que fue diseñado por "personas de impresión de diseño fijo" en lugar de "personas de diseño dinámico".
mu es demasiado corto
1
No es position: absolutenecesario. Consulte: stackoverflow.com/a/51949049/1736186
lugar de ello, el
63

En realidad, esto es posible sin posición absolutey sin especificar ninguna altura. Todo lo que necesita hacer es usar display: gridel elemento principal y colocar los descendientes en la misma fila y columna.

Por favor, consulte el siguiente ejemplo, basado en su HTML. Agregué solo <span>y algunos colores, para que puedas ver el resultado.

También puede cambiar fácilmente z-indexcada uno de los elementos descendientes para manipular su visibilidad (cuál debería estar en la parte superior).

.container_row{
  display: grid;
}

.layer1, .layer2{
  grid-column: 1;
  grid-row: 1;
}

.layer1 span{
  color: #fff;
  background: #000cf6;
}

.layer2{
  background: rgba(255, 0, 0, 0.4);
}
<div class="container_row">
    <div class="layer1">
        <span>Lorem ipsum...<br>Test test</span>
    </div>
    <div class="layer2">
        More lorem ipsum...
    </div>
</div>
<div class="container_row">
    ...same HTML as above. This one should never overlap the .container_row above.
</div>

en lugar
fuente
11
Agradable. Pero para ser justos, display: gridno existía hace siete años :)
mu es demasiado corto
Hay otra respuesta a continuación, escrita por @Cornelius. Él usa flex, que tiene un soporte de navegador mucho mejor en la actualidad.
Oleg Cherr
20

Gran respuesta, "mu es demasiado corto". Estaba buscando exactamente lo mismo, y después de leer tu publicación encontré una solución que se ajustaba a mi problema.

Tenía dos elementos del mismo tamaño exacto y quería apilarlos. Como todos tienen el mismo tamaño, lo que pude hacer fue hacer

position: absolute;
top: 0px;
left: 0px;

sólo en el último elemento. De esta forma se inserta correctamente el primer elemento, "empujando" la altura de los padres, y el segundo elemento se coloca en la parte superior.

Espera que esto ayude a otras personas que intentan apilar más de 2 elementos con la misma altura (desconocida).

Kraenhansen
fuente
1
NB: Con este enfoque, todavía necesitará saber qué elemento es el más alto, para que pueda saber position: abosluteel otro .
Alec
10

Aquí hay otra solución que usa display: flex en lugar de position: absolute o display: grid.

.container_row{
  display: flex;
}

.layer1 {
  width: 100%;
  background-color: rgba(255,0,0,0.5);  // red
}

.layer2{
  width: 100%;
  margin-left: -100%;
  background-color: rgba(0,0,255,0.5);  // blue
}
<div class="container_row">
    <div class="layer1">
        <span>Lorem ipsum...</span>
    </div>
    <div class="layer2">
        More lorem ipsum...
    </div>
</div>
<div class="container_row">
    ...same HTML as above. This one should never overlap the .container_row above.
</div>

Cornelio
fuente
Gran solucion ¡Gracias!
Oleg Cherr
5

Tuve que establecer

Container_height = Element1_height = Element2_height

.Container {
    position: relative;
}

.ElementOne, .Container ,.ElementTwo{
    width: 283px;
    height: 71px;
}

.ElementOne {
    position:absolute;
}

.ElementTwo{
    position:absolute;
}

Use puede usar el índice z para establecer cuál debe estar en la parte superior.

Arun Prasad ES
fuente
4

Aquí hay algunos CSS reutilizables que preservarán la altura de cada elemento sin usar position: absolute:

.stack {
    display: grid;
}
.stack > * {
    grid-row: 1;
    grid-column: 1;
}

El primer elemento de tu stackes el fondo y el segundo es el primer plano.

Ken Mueller
fuente
2

Debido al posicionamiento absoluto que quita los elementos de la posición del flujo de documentos: el absoluto no es la herramienta adecuada para el trabajo. Dependiendo del diseño exacto que desee crear, tendrá éxito utilizando márgenes negativos, posición: relativa o incluso transformar: traducir. Muéstranos una muestra de lo que quieres hacer, podemos ayudarte mejor.

Luiz Sócrate
fuente
1

Por supuesto, el problema es recuperar la altura. Pero, ¿cómo puedes hacer eso si no sabes la altura de antemano? Bueno, si sabe qué relación de aspecto desea darle al contenedor (y mantenerlo receptivo), puede recuperar su altura agregando relleno a otro elemento secundario del contenedor, expresado como un porcentaje.

Incluso puede agregar un muñeco dival contenedor y configurar algo como padding-top: 56.25%para darle al elemento simulado una altura que sea una proporción del ancho del contenedor. Esto empujará el contenedor y le dará una relación de aspecto, en este caso 16: 9 (56,25%).

El relleno y el margen usan el porcentaje del ancho, ese es realmente el truco aquí.

Luke Puplett
fuente
0

Después de muchas pruebas, he verificado que la pregunta original ya es correcta; faltan solo un par de configuraciones:

  • el container_rowdebe tenerposition: relative;
  • los hijos (...), DEBEN tener position: absolute; left:0;
  • para asegurarse de que los niños (...) se alineen exactamente entre sí, container_rowdeben tener un estilo adicional:
    • height:x; line-height:x; vertical-align:middle;
    • text-align:center; también podría ayudar.
solo invitado
fuente