CSS: как расположить два элемента друг над другом без указания высоты?

96

У меня есть два DIV, которые мне нужно расположить точно друг над другом. Однако, когда я это делаю, форматирование оказывается запутанным, потому что содержащий DIV действует так, как будто нет высоты. Я думаю, что это ожидаемое поведение, position:absoluteно мне нужно найти способ расположить эти два элемента друг над другом и растянуть контейнер при растяжении содержимого:

Верхний левый край .layer2должен быть точно выровнен с верхним левым краем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: absoluteтогда не совсем подходящий стиль.
BoltClock
да, position:absoluteне кажется правильным. Какой будет правильный стиль?
Эндрю
Проделайте .layer1и .layer2элементы имеют известный размер?
mu слишком короткий
Нет, у них тоже неизвестный размер.
Эндрю

Ответы:

81

Прежде всего, вам действительно следует включать позицию в абсолютно позиционированные элементы, иначе вы столкнетесь со странным и сбивающим с толку поведением; вы, вероятно, захотите добавить top: 0; left: 0в CSS оба ваших абсолютно позиционированных элемента. Вы также хотите иметь position: relativeна , .container_rowесли вы хотите абсолютно позиционируемые элементы должны быть расположены по отношению к их родителям , а не тело документа :

Если элемент имеет 'position: absolute', содержащий блок устанавливается ближайшим предком с 'position' из 'absolute', 'relative' или 'fixed' ...

Ваша проблема в том, что position: absoluteудаляет элементы из обычного потока :

Он полностью удаляется из обычного потока (не влияет на последующих братьев и сестер). Абсолютно позиционированный блок устанавливает новый содержащий блок для потомков нормального потока и абсолютно (но не фиксированных) позиционированных потомков. Однако содержимое абсолютно позиционированного элемента не обтекает другие блоки.

Это означает, что абсолютно позиционированные элементы никак не влияют на размер их родительского элемента, и ваш первый <div class="container_row">будет иметь нулевую высоту.

Таким образом, вы не можете делать то, что пытаетесь сделать с абсолютно позиционированными элементами, если не знаете, какой они будут высоты (или, что то же самое, вы не можете указать их высоту). Если вы можете указать высоту, то вы можете установить одинаковую высоту для, .container_rowи все выровняется; вы также можете поставить margin-topвторой, .container_rowчтобы оставить место для абсолютно позиционированных элементов. Например:

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

mu слишком короткий
источник
Отличный ответ, спасибо! Думаю, мне может потребоваться динамическое определение высоты с помощью javascript. Я просто надеялся, что до этого не дойдет. = [
Эндрю
@Andrew: Да, добро пожаловать в систему вертикального изменения размеров / положения / выравнивания CSS: если вы не знаете конкретных размеров вещей, вам обычно не везет. С горизонтальным материалом легче справиться, но по большей части он все еще пахнет так, как будто он был разработан «людьми с фиксированным макетом», а не «людьми с динамическим макетом».
mu слишком короткий
1
Нет position: absoluteнеобходимости. Пожалуйста, проверьте: stackoverflow.com/a/51949049/1736186
вместо
64

На самом деле это возможно без absoluteуказания положения и любой высоты. Все, что вам нужно сделать, это использовать display: gridродительский элемент и поместить потомков в одну строку и столбец.

Пожалуйста, проверьте пример ниже, основанный на вашем HTML. Я добавил только <span>и несколько цветов, чтобы Вы могли видеть результат.

Вы также можете легко изменить z-indexкаждый из дочерних элементов, чтобы управлять его видимостью (какой из них должен быть наверху).

.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
Ницца. Но, честно говоря, display: gridсемь лет назад не существовало :)
mu слишком короток
Ниже есть еще один ответ, написанный @Cornelius. Он использует flex, который теперь имеет гораздо лучшую поддержку браузеров.
Олег Черр
20

Отличный ответ: «мю слишком коротка». Я искал то же самое, и после прочтения вашего сообщения я нашел решение, которое соответствовало моей проблеме.

У меня было два элемента одинакового размера, и я хотел их сложить. Поскольку все они имеют одинаковый размер, я мог сделать

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

только на последнем элементе. Таким образом, первый элемент вставляется правильно, «подталкивая» высоту родителей, а второй элемент размещается сверху.

Надеюсь, что это поможет другим людям, пытающимся сложить 2+ элемента с одинаковой (неизвестной) высотой.

Kraenhansen
источник
1
NB: При таком подходе вам все равно нужно знать, какой элемент более высокий, чтобы вы могли position: abosluteиспользовать другой .
Алек
10

Вот еще одно решение, использующее display: flex вместо position: absolute или 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>

Корнелиус
источник
Отличное решение. Спасибо!
Олег Черр
5

Я должен был установить

Container_height = Element1_height = Element2_height

.Container {
    position: relative;
}

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

.ElementOne {
    position:absolute;
}

.ElementTwo{
    position:absolute;
}

Используйте z-index, чтобы установить, какой из них будет наверху.

Арун Прасад ES
источник
4

Вот несколько многоразовых CSS, которые сохранят высоту каждого элемента без использования position: absolute:

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

Первый элемент в вашем stack- это фон, а второй - передний план.

Кен Мюллер
источник
2

Из-за того, что абсолютное позиционирование удаляет элементы из потока документов: absolute не подходит для работы. В зависимости от точного макета, который вы хотите создать, вам удастся использовать отрицательные поля, position: relative или, возможно, даже transform: translate. Покажите нам образец того, чем вы хотите заниматься, и мы можем помочь вам лучше.

Луис Сократе
источник
1

Конечно, проблема в том, чтобы вернуть себе рост. Но как это сделать, если вы заранее не знаете высоту? Что ж, если вы знаете, какое соотношение сторон вы хотите придать контейнеру (и сохранить его отзывчивым), вы можете вернуть свою высоту, добавив отступы к другому дочернему элементу контейнера, выраженному в процентах.

Вы даже можете добавить фиктивный элемент divк контейнеру и установить что-то вроде того, padding-top: 56.25%чтобы дать фиктивному элементу высоту, пропорциональную ширине контейнера. Это вытолкнет контейнер и придаст ему соотношение сторон, в данном случае 16: 9 (56,25%).

Padding и margin используют процент от ширины, вот и весь фокус.

Люк Пуплетт
источник
0

После долгих испытаний я убедился, что исходный вопрос уже верен; отсутствует всего пара настроек:

  • то container_rowдолжны иметьposition: relative;
  • дети (...) ДОЛЖНЫ иметь position: absolute; left:0;
  • чтобы дочерние элементы (...) выровнялись точно друг над другом, у них container_rowдолжен быть дополнительный стиль:
    • height:x; line-height:x; vertical-align:middle;
    • text-align:center; может также помочь.
просто
источник