CSS: Jak ustawić dwa elementy jeden na drugim bez określania wysokości?


100

Mam dwa DIV, które muszę ustawić dokładnie jeden na drugim. Jednak kiedy to robię, formatowanie zostaje zepsute, ponieważ zawierający DIV działa tak, jakby nie było żadnej wysokości. Myślę, że jest to oczekiwane zachowanie, position:absoluteale muszę znaleźć sposób na umieszczenie tych dwóch elementów jeden na drugim i rozciągnięcie kontenera podczas rozciągania zawartości:

Lewa górna krawędź .layer2okna powinna być dokładnie wyrównana z lewą górną krawędziąlayer1

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

1
position: absolutenie jest wtedy odpowiednim stylem do użycia.
BoltClock

tak, position:absolutenie czuję się dobrze. Jaki byłby właściwy styl?
Andrew,

Czy elementy .layer1i .layer2mają znany rozmiar?
mu jest za krótkie

Nie, mają też nieznany rozmiar.
Andrew,

Odpowiedzi:


82

Po pierwsze, naprawdę powinieneś uwzględniać pozycję na absolutnie pozycjonowanych elementach, inaczej natkniesz się na dziwne i mylące zachowanie; prawdopodobnie chcesz dodać top: 0; left: 0do CSS oba elementy pozycjonowane absolutnie. Będziesz także chciał mieć position: relativewłączone, .container_rowjeśli chcesz, aby elementy pozycjonowane absolutnie były pozycjonowane względem ich rodzica, a nie ciała dokumentu :

Jeśli element ma `` położenie: bezwzględne '', zawierający blok jest ustanawiany przez najbliższego przodka z `` pozycją '' na `` bezwzględną '', `` względną '' lub `` ustaloną '' ...

Twój problem polega na tym, że position: absoluteusuwa elementy z normalnego przepływu :

Jest całkowicie usuwany z normalnego przepływu (nie ma to wpływu na późniejsze rodzeństwo). Pole pozycjonowane absolutnie ustanawia nowy blok zawierający elementy potomne o normalnym przepływie i absolutnie (ale nie ustalone) pozycjonowane elementy potomne. Jednak zawartość absolutnie pozycjonowanego elementu nie opływa żadnych innych pudełek.

Oznacza to, że absolutnie pozycjonowane elementy nie mają żadnego wpływu na rozmiar elementu nadrzędnego, a Twój pierwszy <div class="container_row">będzie miał wysokość zero.

Nie możesz więc zrobić tego, co próbujesz zrobić z elementami pozycjonowanymi absolutnie, chyba że wiesz, jak wysokie będą (lub, równoważnie, możesz określić ich wysokość). Jeśli możesz określić wysokości, możesz ustawić te same wysokości .container_rowi wszystko się ułoży; można też umieścić margin-topdrugą, .container_rowaby zostawić miejsce na absolutnie ustawione elementy. Na przykład:

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


Świetna odpowiedź, dzięki! Myślę, że być może będę musiał obliczyć wysokość dynamicznie za pomocą JavaScript. Miałem tylko nadzieję, że do tego nie dojdzie. = [
Andrew,

@Andrew: Tak, witamy w pionowym systemie wymiarowania / pozycji / wyrównania CSS: jeśli nie znasz konkretnych rozmiarów rzeczy, zazwyczaj nie masz szczęścia. Z poziomymi rzeczami łatwiej sobie poradzić, ale większość z nich nadal pachnie tak, jakby została zaprojektowana przez „ludzi zajmujących się drukiem o stałym układzie”, a nie „ludzi z dynamicznym układem”.
mu jest za krótkie

1
Nie position: absolutepotrzeba. Sprawdź: stackoverflow.com/a/51949049/1736186
zamiast tego

67

Właściwie jest to możliwe bez położenia absolutei określania dowolnej wysokości. Wszystko, co musisz zrobić, to użyć display: gridelementu nadrzędnego i umieścić potomków w tym samym wierszu i kolumnie.

Sprawdź poniższy przykład oparty na Twoim HTML. Dodałem tylko <span>i trochę kolorów, więc możesz zobaczyć efekt.

Możesz również łatwo zmienić z-indexkażdy z elementów potomnych, aby manipulować jego widocznością (który powinien być na górze).

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


11
Ładny. Ale żeby być uczciwym, display: gridnie istniał siedem lat temu :)
mu jest za krótkie

Poniżej jest inna odpowiedź, napisana przez @Cornelius. Używa flex, który obecnie ma znacznie lepszą obsługę przeglądarek.
Oleg Cherr

@muistooshort, ale istnieje teraz, a to pytanie ma wiele wyświetleń
boroboris

@boroboris Dlatego jedno z tych upvotes jest moje.
mu jest za krótkie

20

Świetna odpowiedź: „mu jest za krótkie”. Szukałem dokładnie tego samego, a po przeczytaniu twojego postu znalazłem rozwiązanie, które pasowało do mojego problemu.

Miałem dwa elementy tego samego rozmiaru i chciałem je ułożyć. Ponieważ każdy ma ten sam rozmiar, mogłem zrobić

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

tylko na ostatnim elemencie. W ten sposób pierwszy element jest wstawiony poprawnie, „wypychając” wysokość nadrzędną, a drugi element jest umieszczony na górze.

Mam nadzieję, że pomoże to innym osobom próbującym układać 2+ elementy o tej samej (nieznanej) wysokości.


1
UWAGA: Z takim podejściem, będziesz jeszcze trzeba wiedzieć, który element jest wyższy jeden, tak aby można było position: aboslutew inny jeden.
Alec,

12

Oto inne rozwiązanie wykorzystujące display: flex zamiast position: bezwzględne lub 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>


Świetne rozwiązanie. Dzięki!
Oleg Cherr

5

Musiałem ustawić

Container_height = Element1_height = Element2_height

.Container {
    position: relative;
}

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

.ElementOne {
    position:absolute;
}

.ElementTwo{
    position:absolute;
}

Użyj może użyć indeksu z, aby ustawić, który z nich ma być na górze.


4

Oto kilka plików CSS wielokrotnego użytku, które zachowają wysokość każdego elementu bez użycia position: absolute:

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

Pierwszy element w twoim stackto tło, a drugi to pierwszy plan.


2

Ze względu na pozycjonowanie bezwzględne, usuwanie elementów z pozycji przepływu dokumentów: bezwzględne nie jest odpowiednim narzędziem do pracy. W zależności od tego, jaki dokładnie układ chcesz stworzyć, odniesiesz sukces przy użyciu ujemnych marginesów, pozycji: względna, a może nawet transform: przetłumacz. Pokaż nam próbkę tego, co chcesz zrobić, a my pomożemy Ci lepiej.


1

Oczywiście problem polega na odzyskaniu wzrostu. Ale jak możesz to zrobić, jeśli nie znasz wysokości z wyprzedzeniem? Cóż, jeśli wiesz, jakie proporcje chcesz nadać kontenerowi (i zachować jego responsywność), możesz odzyskać swój wzrost, dodając wypełnienie do innego elementu podrzędnego pojemnika, wyrażone w procentach.

Możesz nawet dodać atrapę divdo kontenera i ustawić coś podobnego padding-top: 56.25%do nadania atrapie wysokości, która jest proporcjonalna do szerokości kontenera. Spowoduje to wypchnięcie pojemnika i nadanie mu proporcji, w tym przypadku 16: 9 (56,25%).

Dopełnienie i margines używają procentu szerokości, to jest naprawdę sztuczka.


0

Po wielu testach upewniłem się, że pierwotne pytanie jest już prawidłowe; brakuje tylko kilku ustawień:

  • container_rowMUSI miećposition: relative;
  • dzieci (...) MUSZĄ mieć position: absolute; left:0;
  • aby dzieci (...) były dokładnie ustawione względem siebie, container_rowpowinny mieć dodatkową stylizację:
    • height:x; line-height:x; vertical-align:middle;
    • text-align:center; może też pomóc.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.