Overlay Divs Without Absolute Position
Asked Answered
L

7

74

What follows is a long explanation, but it's the only way to effectively communicate the issue I'm trying to resolve...

I am (somewhat desperately, and entirely unsuccessfully) trying to overlay divs without the use of absolute positioning. The need stems from a paypal cart that I place on the site via a Javascript. The cart's natural position is hard against the top margin of the webpage (not its containing div, which is #wpPayPal, or the wrapper for this div, #main).

The script's author strongly recommends against customizing the cart's stylesheet, but I found a tutorial he wrote that enables insertion of the cart into a placeholder div, with positioning instructions for the container that works - I was able to position the cart below the site's top banner section. However...

The cart's HTML form and a ul element within each have height requirements in the cart's stylesheet, and this pushes the page's main content, wrapped by the container div #imageWrapper, too far down the page to be acceptable.

I tried to position #imageWrapper over #main with several ideas gathered from posts on this site with no success. I've tried absolute positioning on #imageWrapper, but this frees the footer to float beneath. #imageWrapper's height is variable, hence I do not want to hold the footer in place with height, since the min-height to prevent overlap would push the footer down too far for much of the site's content.

I also tried pulling position:relative from the cart form's CSS, but the cart immediately floats back to the top of the webpage. Margin, top-margin, etc.,do not remedy this.

I then read an article on using position:relative and z-index to overlay divs. Tried this, too, first by putting z-index: -1 on #main (the div that wraps the paypal cart), but the cart disappears. Not sure where it goes, either, since the site's breadcrumb nav, also wrapped by #main, stayed put.

I then set the z-index for main to 0 and applied position:relative to #imageWrapper with z-index:100. The cart reappeared but still holds #imageWrapper down.

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

etc...

#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;
}
Lawgiver answered 2/8, 2013 at 23:45 Comment(1)
Just use negative margin like in this solutionMarigolda
R
115

You can do it with grid also :

.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>
Restrict answered 29/4, 2018 at 12:19 Comment(4)
Short, simple, works flawlessly. I use CSS grid often but I didn't knew this trick. Thanks for sharing !Tribe
great! works perfect for building a inline slider with unknown image sizes and crossfading them (I'm building a Vue component). Using absolute for imgs to have them one over the other and animate opacity, you lose their width and the surrounding text goes crazy. Thanks!Hadlock
This is beautiful in both it's simplicity and functionality. Bravo!Galleywest
This is the way to go when fading items in/out with any kinds of animations, it will fill the height of the parent throughout the animation unlike using position: absoluteQuacksalver
V
37

Div background for a block with a dynamic height can be implemented using flexbox without an absolute positioning:

/* 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>

The solution is supported by about 99% of browsers.

Vasti answered 20/2, 2018 at 2:49 Comment(5)
Amazing, this is definitely the most elegant answer at this point in time.Maccarone
@Maccarone Thanks ⁢ ⁢⁢⁢⁢⁢⁢Vasti
I know I shouldn't comment here, but this is genius! Very useful for me to partially overlay a side modal onto a table.Kimmi
Is there any way to make this foreground content "float" on right of background no matter its size?Glume
@LeonardoRick, I'm not sure that I understand you correctly. If you want the foreground to take only the right part of the space (not the whole background), then you can just add padding-left: 50%; to the .foreground CSS. Keep in mind that you can make any layout inside .foreground, you can also set the display CSS property of .foreground to flex, grid, block or whatever.Vasti
G
18

Simple fiddle: Just CSS

Some guy posted another but it had a bunch of extra unnecessary code and some JS Another post had the answer but was missing something

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

Galton answered 1/4, 2014 at 20:38 Comment(2)
That choice of image actually made me laugh out loud at my desk. Thanks.Seymourseys
This solves my issue with parent container height, but the negative margin-top for the overlay div then causes a responsive issue when scaling since the margin-top is a fixed pixel value.Combatant
P
8

Got it!!! :D

Pure Css solution Very Easy. Put the following.

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

Replace whatever you have in css #main with what i have done above.

So remove the following:

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

Explanation: Main idea here is to float the main element, make it of certain height so at no point it pushes everything down. But make overflow of it visible. Overflow of content doesn't affect siblings of main element.

Prunelle answered 4/8, 2013 at 2:21 Comment(3)
lot of bad css code everywhere though...:) by bad i mean it has no effect.Prunelle
Your solution works as expected and avoids JavaScript. Don't know why but when I first tried it, overflow: visible made PPMiniCart floats up on hide (that is why I introduced the custom events). Anyway, OP should accept your answer.Jeanelle
Well, thanks..i think you applied overflow:visible; to #wpPayPal. which i think is made to expand only and hide what's flows out. So when there is nothing in cart script pushes paypal box up using relative. Which puts it outside. When there is something in cart that actually extends PPminicart that make it aslo extend #wpPayPal and not overflows...Prunelle
J
2

None of the previous answers actually help with your requirement, which is to allow PPMiniCart to expand and contract without pushing imageWrapper down.

The trick here is to give wpPayPal a fixed height large enough to hold the contracted version of PPMiniCart (40px will do - this will give the shopping cart enough room, without pushing imageWrapper too far down).

#wpPayPal {
    height:40px;
}

Then give main (the container that holds wpPayPal) a z-index greater than that of imageWrapper so that it overflows over it.

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

Setting imageWrapper z-index to 100 kind of overdoes it, I would recommend 0 like I did above.

You also need some JavasScript to set overflow: visible on wpPayPal after PPMiniCart expands and remove it before it contracts. Fortunately Mini Cart JS exposes a nice event-driven API that allows custom callbacks. Since you are using jQuery in your webpage let's take advantage of that:

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

Please note the careful choice of afterShow and onHide callbacks, if you try to do it any different (setting overflow: visible before PPMiniCart expands or removing it before PPMiniCart contracts) PPMiniCart will "float up" during the transition.


Finally, a working fiddle is worth a thousand words.

Jeanelle answered 3/8, 2013 at 23:26 Comment(0)
H
2

Figured out an elegant solution for your problem without absolute positioning OR floats using flexbox — main advantage is that both div heights are respected when calculating parent height. Very useful for overlaying text on an image:

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>
Hinkley answered 11/12, 2017 at 13:3 Comment(0)
R
1

Also can use flexbox to make a tabs container without absolute position:

/* 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>
Rating answered 30/1, 2018 at 20:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.