在不使用绝对定位的情况下叠加div

70
以下是一段较长的说明,但这是有效传达我要解决的问题的唯一方法...
我正在(有些绝望地,并且完全不成功地)尝试在不使用绝对定位的情况下叠加div。需要的原因源自我通过Javascript将paypal购物车放置在网站上。购物车的自然位置紧贴网页的顶部边缘(而不是其所包含的div,即#wpPayPal,或者该div的包装器#main)。
脚本的作者强烈建议不要自定义购物车的样式表,但我找到了他写的一个教程,它使得可以将购物车插入到一个占位符div中,并提供了容器的定位指令,可以使其正常工作-我能够将购物车定位在网站顶部横幅节的下方。然而...
购物车的HTML表单和每个ul元素在购物车的样式表中具有高度要求,这将页面的主要内容(由容器div#imageWrapper包装)向下推得太远,无法接受。

我曾经试图通过在网站上收集的几个帖子中获得的一些想法来将#imageWrapper定位在#main之上,但没有成功。我尝试了在#imageWrapper上使用绝对定位,但这使页脚可自由浮动。#imageWrapper的高度是可变的,因此我不想通过高度来固定页脚位置,因为为了防止重叠而设置的最小高度会使大部分网站内容的页脚下移太远。

我还尝试从购物车表单的CSS中删除position:relative,但购物车立即浮动回网页的顶部。Margin、top-margin等都无法解决这个问题。

然后我读了一篇关于使用position:relative和z-index叠加divs的article。我先尝试了在#main(包裹paypal购物车的div)上放置z-index: -1,但购物车消失了。也不确定它去了哪里,因为同样被#main包裹的面包屑导航仍然在原地。

然后我将main的z-index设置为0,并将position:relative应用于#imageWrapper,同时设置z-index:100。购物车重新出现了,但仍然把#imageWrapper压住了。

Suggestions are greatly welcomed. I'm not an interface person by any stretch of the imagination, just a guy who knows how to use Google, so thanks in advance for clearly articulating your resolution :) Also, FYI, presently I have the min-height requirement for the cart form set to 0, and set the UL element within to height:auto. With only a single item in the cart, this allows #imageWrapper to move up the page enough to be acceptable, but this is not a viable long-term solution.
Here's an example page - to see the cart, add an item using the dropdown that appears below the main image. In its expanded state, you'll see how #imageWrapper sits against it.
I've included portions of the offending HTML / CSS below:
<div id="main">
    <div id="wpPayPal">
    </div><!--end wpPayPal-->
    <div id="breadcrumbs">
        <span class="B_crumbBox"><span class="B_firstCrumb"><a class="B_homeCrumb" href="/">home</a></span> &raquo;</span></span>
    </div> <!--end breadcrumbs -->
</div><!-- end Main -->

<div id="imageWrapper">
    <div id="imageInnerWrapper">
        <div id="featureImage">
            <div class="filename"><h1>~&nbsp;Bryce Canyon Sunrise | Bryce Canyon | Utah&nbsp;~</h1>
            </div><!--end filename-->

等等...

#main {
    display: inline;
    position: relative;
    z-index: 0;
}

#imageWrapper {
    clear: both;
    width: 840px;
    margin: 0 auto;
    padding: 0;
    position: relative;
    z-index: 100;
}

#imageInnerWrapper {
    width: 840px;
    margin: 0 auto;
    padding: 0;
    position: relative;
    z-index: 100;
}

#featureImage {
    width: 840px;
    margin: 0 auto;
    padding: 0;  
}

#wpPayPal {
    overflow: hidden;
    float: right;
    margin-right: 100px;
    min-width: 365px;
    min-height: 20px;
}

/* Override the default Mini Cart styles */

#wpBody #PPMiniCart form {
    position: relative;
    right: auto;
    width: auto;
    min-height: 0;
}

#wpBody #PPMiniCart form ul {
    height: auto;
}

只需像此解决方案中那样使用负边距即可。 - Dotista
7个回答

99
你也可以用网格来做:

.parent {
  display: grid;
  grid-template-columns: 1fr;
}

.parent div {
 padding: 50px;
 background-color: rgba(0,0,0,0.5);
 grid-row-start: 1;
 grid-column-start: 1;
}
<div class="parent">
  <div class="child1">
  1
  </div>
  <div class="child2">
  2
  </div>
</div>


8
简短、简单,完美无缺。我经常使用CSS网格,但我不知道这个技巧。谢谢分享!翻译如下:简洁易懂、功能完美。我经常使用CSS网格,但之前不知道这个窍门。感谢分享! - Cstyves
2
太棒了!非常适合构建具有未知图像大小并交叉淡入淡出的内联滑块(我正在构建一个Vue组件)。使用absolute将图片放置在彼此上方并动画化不透明度,您会失去它们的宽度,周围的文本会变得混乱。谢谢! - Ivan Ferrer Villa
这个程序既简单又实用,真是美妙绝伦。太棒了! - Eric Norcross
这是在使用任何类型的动画淡入/淡出物品时的正确方法,它会在整个动画过程中填充父元素的高度,而不像使用position: absolute那样。 - Manstie

37

使用 flexbox 可以实现一个动态高度的块的背景,而不需要使用绝对定位:

/* Every rule not marked by "required" is optional and used only to decorate the example */
.block {
    margin: 10px 50px;
    display: flex; /* required */
    flex-flow: row nowrap; /* required */
}
.block .background,
.block .foreground {
    box-sizing: border-box; /* required */
    width: 100%; /* required */
    flex: none; /* required */
}
.block .background {
    background: #9ff;
    color: #fff;
    padding: 15px;
    font-size: 30px;
}
.block .foreground {
    padding: 15px;
    border: solid 1px;
    margin-left: -100%; /* required */
}
.block .foreground .outside {
    position: absolute;
    top: 5px;
    left: 8px;
}
<div class="block">
    <div class="background">
        Background
    </div>
    <div class="foreground">
        <div>
            <div class="outside">Outside</div> <!-- The "outside" div is also optional -->
            <div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odio incidunt perspiciatis sapiente aspernatur repellat delectus atque quae optio nam? Pariatur explicabo laboriosam dolores temporibus molestiae error ipsa sunt molestias doloremque odio nemo iure similique quae exercitationem, adipisci, ullam dicta esse numquam beatae qui velit asperiores. Dolore, quo illum necessitatibus tempora earum nihil cumque corporis aut error eius voluptatibus quia, pariatur.</div>
        </div>
    </div>
</div>

该解决方案得到约99%的浏览器的支持。

真是太棒了,这绝对是目前为止最优雅的答案。 - TSga
@TSga 谢谢。 - Finesse
3
我知道我不应该在这里评论,但这太厉害了!对我来说非常有用,可以将侧边弹出框部分叠加到表格上。 - M3RS
有没有办法使前景内容“浮动”在背景的右侧,无论其大小如何? - Leonardo Rick
1
@LeonardoRick,我不确定我是否正确理解您的意思。 如果您希望前景只占用空间的右侧部分(而不是整个背景),那么您可以在.foreground CSS中添加padding-left: 50%;。 请记住,您可以在.foreground内制作任何布局,您还可以将.foregrounddisplay CSS属性设置为flexgridblock或其他任何选项。 - Finesse

18

一个简单的示例: 只需CSS

有人发布了另一个示例,但它包含了很多额外、不必要的代码和一些JS。另一篇帖子中有答案,但缺少了一些东西。

.over {
  background: rgba(230, 6, 6, .5);
  float: right;
  height: 460px;
  margin-top: -500px;
  margin-right: 159px;
  overflow: visible;
  position: relative;
  width: 560px;
  color: #FFFFFF;
  /* Just for looks*/
  z-index: 1000;
  padding: 20px/* Just for looks*/
}

.over span {
  position: relative;
  /* Just for looks*/
  top: 15px;
  /* Just for looks*/
}

.this {
  width: 560px;
  height: 460px;
  color: #FFFFFF;
  /* Just for looks*/
  padding: 20px;
  /* Just for looks*/
  background-image: url("http://www.tshirtvortex.net/wp-content/uploads/dramaticchipmunk.jpg");
  /* Just for looks*/
}
<div class="this">To BE UNDER</div>
<div class="over"><span>..or not To BE UNDER</span></div>

http://jsfiddle.net/3WDf7/


9
那个图像的选择让我在办公桌前大声笑了起来,谢谢。 - Urbycoz
谢谢你!这绝对救了我的一天 :) - António Ribeiro
这解决了我的父容器高度问题,但是遮罩层div的负margin-top会在缩放时导致响应问题,因为margin-top是固定像素值。 - Nick W

8

纯CSS解决方案非常容易。只需放置以下内容。

#main {
float: right;
overflow: visible;
position: relative;
z-index: 1000;
height: 177px;
width: 100%;
}

用我上面所做的内容替换你在css中的#main

所以删除以下内容:

display: inline;
position: relative;
z-index: 0;

说明: 这里的主要思想是将主要元素浮动,使其具有一定高度,以便在任何时候都不会将所有其他内容顶下去。但要让溢出内容可见。溢出内容不会影响主元素兄弟元素


到处都是很多糟糕的 CSS 代码... :) 我所说的糟糕是指它没有任何效果。 - Muhammad Umer
你的解决方案按预期工作,并避免了JavaScript。不知道为什么,但当我第一次尝试时,overflow: visible 会使 PPMiniCart 在隐藏时浮起来(这就是为什么我引入了自定义事件)。无论如何,楼主应该接受你的答案。 - Anthony Accioly
1
好的,谢谢。我想你在#wpPayPal上应用了overflow:visible;,这个属性只会扩展并隐藏超出部分。所以当购物车为空时,脚本使用相对定位将Paypal框推上去,使其超出范围。当购物车中有物品时,它实际上会扩展PPminicart,从而也扩展了#wpPayPal,不会溢出... - Muhammad Umer

2

之前的回答都没有帮助到你的需求,即允许PPMiniCart在不推动imageWrapper下移的情况下展开和收缩。

这里的诀窍是给wpPayPal一个固定的高度,足以容纳PPMiniCart的收缩版(40px就可以了 - 这将为购物车提供足够的空间,而不会把imageWrapper 推得太低)。

#wpPayPal {
    height:40px;
}

然后给包含 wpPayPal 的容器 main 设定一个比 imageWrapper 更高的 z-index,这样它就会溢出到上面。

#main {
    z-index: 1;
}
#imageWrapper {
    z-index: 0;
}

imageWrapper 的 z-index 值设置为 100 有点过了,我建议像上面那样设置为 0。

此外,您需要一些 JavaScript 代码来在 PPMiniCart 展开后为 wpPayPal 设置 overflow: visible,并在它收缩之前将其删除。幸运的是,Mini Cart JS 提供了一个很好的基于事件驱动的 API,允许自定义回调函数。由于您的网页中正在使用 jQuery,因此让我们利用它:

PAYPAL.apps.MiniCart.render({
    parent: 'wpPayPal',
    events: {
        afterShow: function () {
            $("#wpPayPal").css("overflow", "visible");
        },
        onHide: function () {
            $("#wpPayPal").css("overflow", "");
        }
    }
});

请注意,afterShowonHide回调函数的谨慎选择,如果您尝试以任何不同的方式实现它(在PPMiniCart扩展之前设置overflow: visible或在PPMiniCart收缩之前删除它),PPMiniCart将在转换过程中“浮起来”。
最后,一个可工作的代码片段胜过千言万语。

2

使用Flexbox而不是绝对定位或浮动,为您的问题找到了一种优雅的解决方案 - 主要优点是在计算父元素高度时同时考虑两个div的高度。非常适用于在图像上叠加文本:

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

.container {
  max-width: 500px;
  /*border: 1px solid lime;*/
}

.card {
  display: flex;
  /*border: 1px solid red;*/
  overflow: hidden;
}

.box {
  position: relative;
  min-width: 100%;
  width: 100%;
  flex-basis: 100%;
  flex-grow: 1;
}

.box--image {
  z-index: 1;
  overflow: hidden;
}

.box--image.box--heightrestricted {
  max-height: 300px;
}

.box--text {
  z-index: 2;
  margin-left: -100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  color: red;
}

.box--text h3 {
  margin: 0;
  padding: 1rem;
}
<div class="container">

  <button onclick="document.getElementById('imagebox').classList.toggle('box--heightrestricted')">toggle image max-height</button>
  <br>
  <br>

  <div class="card">

    <div id="imagebox" class="box box--image box--heightrestricted">
      <img src="https://placeimg.com/640/640/4" alt="" />
    </div>

    <div class="box box--text">
      <h3>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris in urna porta, maximus velit vitae, suscipit eros. Praesent eleifend est at nisi laoreet auctor. Nunc molestie fringilla magna et dictum. Nam ac massa nec erat consequat lacinia in in leo. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas sollicitudin nibh nisl, sed molestie lorem lobortis in. Nulla eget purus a risus scelerisque cursus. Praesent nisl dolor, varius eget faucibus sit amet, rutrum non lorem. Ut elementum sapien sed facilisis tempus. Morbi nec ipsum sed lacus vulputate sodales quis ut velit. Quisque id ante quis leo pharetra efficitur nec at mauris. Praesent dignissim hendrerit posuere. Vestibulum venenatis urna faucibus facilisis sodales. Suspendisse potenti. Proin a magna elit. Aenean vitae aliquam est, quis fringilla lectus.</h3>
    </div>

  </div>

</div>


1
也可以使用 flexbox 来创建一个无需绝对定位的选项卡容器:

/* Flex Overflow */
section {
  display: flex;
  width: 100%;
  overflow: hidden;
}

section article {
  flex: 100% 0 0;
  order: 0;
}

section article:target {
  order: -1;
}

/* UI */
section { background-color: #ecf0f1; }
section article { 
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ecf0f1;
  font-size: 20px;
  min-height: 8em;
  visibility: hidden;
  opacity: 0;
  transition: visibility .5s ease, opacity .5s ease;
}
section article:first-child,
section article:target {
  visibility: visible;
  opacity: 1;
}
section article#zoneA { background-color: #2980b9; }
section article#zoneB { background-color: #16a085; }
section article#zoneC { background-color: #f39c12; }
section article#zoneD { background-color: #8e44ad; }
<ul>
  <li><a href="#zoneA">Zone A</a></li>
  <li><a href="#zoneB">Zone B</a></li>
  <li><a href="#zoneC">Zone C</a></li>
  <li><a href="#zoneD">Zone D</a></li>
</ul>

<section>
  <article id="zoneA">A</article>
  <article id="zoneB">B</article>
  <article id="zoneC">C</article>
  <article id="zoneD">D</article>
</section>


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