CSS:如何在不指定高度的情况下将两个元素叠放在一起?

156

我有两个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
1
是的,position:absolute 感觉不太对。什么样式才是正确的呢? - Andrew
.layer1.layer2元素的尺寸已知吗? - mu is too short
不,它们也有未知的大小。 - Andrew
9个回答

171
实际上,即使不使用绝对定位并且不指定高度,也可以实现这一点。您只需要在父元素上使用 display: grid,并将后代放置在同一行和列中即可。
请查看下面的示例,基于您的HTML。我仅添加了 和一些颜色,以便您可以看到结果。
您还可以轻松更改每个后代元素的 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>


这比下面的flex解决方案要好得多,因为(与inline-grid结合使用)它允许您在彼此之上创建内联文本元素(例如在化学式中):<p>HPO<span style="display:inline-grid; font-size:0.7em; vertical-align:middle"><sup style="grid-column: 1; grid-row: 1;">2–</sup><sub style="grid-column: 1; grid-row: 2;">4</sub></span></p> - mheim

97
首先,您真的应该在绝对定位元素上包含位置,否则您将遇到奇怪和令人困惑的行为; 您可能希望向两个绝对定位元素的CSS添加top:0;left:0。如果您希望绝对定位的元素相对于其父级而不是文档的主体进行定位,您还需要在.container_row上添加position:relative

如果元素具有“position:absolute”,则包含块由具有“position”为“absolute”、“relative”或“fixed”的最近祖先建立...

您的问题是position:absolute将元素从正常流中移除

它完全从正常流中删除(对后面的兄弟没有影响)。 绝对定位的框为普通流子代和绝对(但不是固定)定位的后代建立新的包含块。 但是,绝对定位元素的内容不会在任何其他框周围流动。

这意味着绝对定位元素对其父元素的大小没有任何影响,您的第一个<div class="container_row">将具有零高度。

如果您不知道绝对定位元素的高度(或者等效地,您可以指定其高度),则无法使用绝对定位元素来实现您要尝试的操作。如果您可以指定高度,则可以在.container_row上放置相同的高度,这样一切都将对齐;您还可以在第二个.container_row上放置margin-top以留出空间供绝对定位元素使用。例如:

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


非常好的答案,谢谢!我想我可能需要使用JavaScript动态地计算高度。我只是希望不必这样做。 =[ - Andrew
@Andrew:是的,欢迎来到CSS的垂直大小/位置/对齐系统:如果您不知道事物的具体大小,通常就会很难处理。水平方向的东西更容易处理,但大部分仍然像是由“固定布局印刷人员”而非“动态布局人员”设计的。 - mu is too short

30

这里提供另一种解决方案,使用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>


@Knightwalker 因为 margin-left: -100%,而元素的宽度恰好为 100%。 - Bartłomiej Sobieszek
显而易见,因为margin-left为-100%,所以这个技巧才能起作用。我之前是在问是否有人可以解释这个技巧的确切原理。然而,由于我的初始问题已被删除,我不再渴望详细的解释。 - Knightwalker
这比绝对和相对路径更好用,特别是如果你正在使用一些类库,比如可分页的。 - l3est

23

"mu is too short"的回答非常好。 我也在寻找同样的解决方案,阅读了您的帖子后,我找到了适合我的问题的解决方案。

我有两个完全相同大小的元素,想要将它们叠放在一起。 由于它们的大小相同,我可以这样做:

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

只在最后一个元素上应用定位。这样第一个元素就可以正确插入并“推动”父级的高度,而第二个元素则置于顶部。

希望这可以帮助其他试图叠放具有相同(未知)高度的两个或更多元素的人们。


1
使用这种方法,你仍然需要知道哪个元素更高,这样才能将“其他”元素 position: absolute 定位。 - Alec

22

这里是一些可重复使用的CSS,它将保留每个元素的高度,而不需要使用position: absolute

这是一些可重用的CSS代码,可以在不使用position: absolute的情况下保留每个元素的高度。

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

你的stack中的第一个元素是背景,第二个元素是前景。


5
我需要设置:
容器高度 = 元素1高度 = 元素2高度
.Container {
    position: relative;
}

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

.ElementOne {
    position:absolute;
}

.ElementTwo{
    position:absolute;
}

您可以使用z-index来设置哪个元素在顶部。


2

由于绝对定位会将元素从文档流中移除,因此 position: absolute 不是解决问题的正确方法。根据您想要创建的确切布局,您可以使用负边距、position:relative 或甚至 transform: translate 来成功实现。请给我们展示您想要做什么的样本,我们可以更好地帮助您。


1
当然,问题在于如何恢复高度。但如果您事先不知道高度,该怎么办呢?嗯,如果您知道要给容器什么纵横比(并保持响应性),则可以通过向容器的另一个子元素添加作为百分比表达的填充来恢复高度。
您甚至可以向容器添加一个虚拟的
元素,并设置类似padding-top: 56.25%这样的内容,以使虚拟元素的高度成为容器宽度的比例。这将推出容器并为其提供一个纵横比,在本例中为16:9(56.25%)。
填充和边距使用宽度的百分比,这才是关键。

1
经过多次测试,我已经确认原问题已经正确;只是缺少一些设置:
  • container_row 必须有 position: relative;
  • 子元素 (...) 必须有 position: absolute; left:0;
  • 为了确保子元素 (...) 完全重叠,container_row 应该有额外的样式:
    • height:x; line-height:x; vertical-align:middle;
    • text-align:center; 也可能有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接