CSS: Como posicionar dois elementos um sobre o outro, sem especificar uma altura?

96

Tenho dois DIVs que preciso posicionar exatamente um em cima do outro. No entanto, quando eu faço isso, a formatação fica toda confusa porque o DIV que contém age como se não houvesse altura. Acho que esse é o comportamento esperado, position:absolutemas preciso encontrar uma maneira de posicionar esses dois elementos um em cima do outro e fazer com que o contêiner se estique conforme o conteúdo se estende:

A borda superior esquerda de .layer2deve estar exatamente alinhada com a borda superior esquerda 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;
}
Andrew
fonte
1
position: absolutenão é o estilo certo para usar então.
BoltClock
sim, position:absolutenão parece certo. Qual seria o estilo certo?
Andrew
Os elementos .layer1e .layer2têm um tamanho conhecido?
mu é muito curto
Não, eles também têm um tamanho desconhecido.
Andrew

Respostas:

81

Em primeiro lugar, você realmente deve incluir a posição em elementos absolutamente posicionados ou você encontrará um comportamento estranho e confuso; você provavelmente deseja adicionar top: 0; left: 0ao CSS para ambos os elementos absolutamente posicionados. Você também vai querer ter position: relativeativado .container_rowse quiser que os elementos absolutamente posicionados sejam posicionados em relação aos seus pais, em vez do corpo do documento :

Se o elemento tem 'posição: absoluto', o bloco que contém é estabelecido pelo ancestral mais próximo com uma 'posição' de 'absoluto', 'relativo' ou 'fixo' ...

Seu problema é que position: absoluteremove elementos do fluxo normal :

É removido inteiramente do fluxo normal (não tem impacto nos irmãos posteriores). Uma caixa posicionada absolutamente estabelece um novo bloco de contenção para filhos de fluxo normal e descendentes posicionados absolutamente (mas não fixos). No entanto, o conteúdo de um elemento posicionado absolutamente não flui ao redor de nenhuma outra caixa.

Isso significa que os elementos posicionados de forma absoluta não têm nenhum efeito no tamanho do elemento pai e o primeiro <div class="container_row">terá uma altura zero.

Portanto, você não pode fazer o que está tentando fazer com elementos posicionados de forma absoluta, a menos que saiba a altura que eles terão (ou, equivalentemente, você pode especificar sua altura). Se você pode especificar as alturas, então você pode colocar as mesmas alturas no .container_rowe tudo ficará alinhado; você também pode colocar um margin-topno segundo .container_rowpara deixar espaço para os elementos absolutamente posicionados. Por exemplo:

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

mu é muito curto
fonte
Ótima resposta, obrigado! Eu acho que posso precisar descobrir a altura dinamicamente usando javascript. Eu estava apenas esperando que não precisasse chegar a esse ponto. = [
Andrew
@Andrew: Sim, bem-vindo ao sistema de dimensionamento / posição / alinhamento vertical do CSS: se você não sabe os tamanhos específicos das coisas, geralmente está sem sorte. O material horizontal é mais fácil de lidar, mas a maior parte ainda cheira como se tivesse sido projetado por "pessoal de impressão de layout fixo" em vez de "pessoal de layout dinâmico".
mu é muito curto
1
Não é position: absolutenecessário. Verifique: stackoverflow.com/a/51949049/1736186
vez de
63

Na verdade, isso é possível sem posição absolutee especificando qualquer altura. Tudo que você precisa fazer é usardisplay: grid elemento pai e colocar os descendentes na mesma linha e coluna.

Por favor, verifique o exemplo abaixo, com base em Seu HTML. Eu adicionei apenas<span> e algumas cores, então você pode ver o resultado.

Você também pode alterar facilmente z-indexcada um dos elementos descendentes, para manipular sua visibilidade (qual deve estar no topo).

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

em vez de
fonte
11
Agradável. Mas para ser justo, display: gridnão existia há sete anos :)
mu é muito curto
Há outra resposta abaixo, escrita por @Cornelius. Ele usa flex, que tem um suporte de navegador muito melhor hoje em dia.
Oleg Cherr
20

Ótima resposta, "mu é muito curto". Eu estava procurando exatamente a mesma coisa, e após ler sua postagem encontrei uma solução que se encaixava no meu problema.

Eu estava tendo dois elementos exatamente do mesmo tamanho e queria empilhá-los. Como cada um tem o mesmo tamanho, o que pude fazer foi

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

em apenas o último elemento. Desta forma, o primeiro elemento é inserido corretamente, "empurrando" a altura dos pais, e o segundo elemento é colocado no topo.

Espera que isso ajude outras pessoas que tentam empilhar 2+ elementos com a mesma altura (desconhecida).

Kraenhansen
fonte
1
NB: Com esta abordagem, você ainda precisará saber qual elemento é o mais alto, para que possa saber position: abosluteo outro .
Alec de
10

Aqui está outra solução usando display: flex em vez de position: absolute ou 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>

Cornelius
fonte
Ótima solução. Obrigado!
Oleg Cherr
5

Eu tive que definir

Container_height = Element1_height = Element2_height

.Container {
    position: relative;
}

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

.ElementOne {
    position:absolute;
}

.ElementTwo{
    position:absolute;
}

Use pode usar o z-index para definir qual deve estar no topo.

Arun Prasad ES
fonte
4

Aqui estão alguns css reutilizáveis ​​que preservarão a altura de cada elemento sem usar position: absolute:

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

O primeiro elemento em seu stacké o plano de fundo e o segundo é o primeiro plano.

Ken Mueller
fonte
2

Devido ao posicionamento absoluto, remover os elementos da posição de fluxo do documento: absoluto não é a ferramenta certa para o trabalho. Dependendo do layout exato que você deseja criar, você terá sucesso usando as margens negativas, position: relative ou talvez até mesmo transform: translate. Mostre-nos uma amostra do que você deseja fazer para que possamos ajudá-lo melhor.

Luiz sócrate
fonte
1

Claro, o problema é recuperar sua altura. Mas como você pode fazer isso se não sabe a altura com antecedência? Bem, se você sabe que proporção de aspecto deseja dar ao contêiner (e mantê-lo responsivo), pode obter sua altura de volta adicionando preenchimento a outro filho do contêiner, expresso como uma porcentagem.

Você pode até adicionar um manequim divao contêiner e definir algo comopadding-top: 56.25% dar ao elemento fictício uma altura que seja uma proporção da largura do contêiner. Isso empurrará o contêiner e dará a ele uma proporção de aspecto, neste caso 16: 9 (56,25%).

Preenchimento e margem usam a porcentagem da largura, esse é realmente o truque aqui.

Luke Puplett
fonte
0

Depois de muitos testes, verifiquei que a pergunta original já estava certa; faltando apenas algumas configurações:

  • a container_row DEVE terposition: relative;
  • os filhos (...), PRECISA ter position: absolute; left:0;
  • para garantir que os filhos (...) se alinhem exatamente uns sobre os outros, o container_rowdeve ter um estilo adicional:
    • height:x; line-height:x; vertical-align:middle;
    • text-align:center; poderia, também, ajudar.
apenas passando por
fonte