I have a layout containing two columns. The left column scrolls vertically and the right column is fixed. The right column contains multiple sections.
At some point, an overlay will be displayed. I want it to cover all content except for the first section in the right column (<aside class="one">...</aside>).
Right now, when the overlay is displayed it covers everything, including the aside.one element even though it has a higher z-index value.
HTML:
<!-- ... -->
<section id="sidebar">
<aside class="one">...</aside>
<aside class="two">...</aside>
</section>
<!-- ... -->
<div class="overlay"></div>
CSS:
#sidebar {
position: fixed;
}
.one {
z-index: 3;
}
.overlay {
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: 2;
}
Here is a jsFiddle illustrating a more complete example of my problem: http://jsfiddle.net/ncSWz/10/
I know I will need to change some of my HTML structure to get this working, but I'm unsure exactly where to start.
Thanks in advance.
There's actually a bit of stacking context that's involved in this problem.
The idea is essentially, you need to have both the .overlay and aside.one in the same stacking context. You can accomplish that by moving the .overlay into the #sidebar (since it is position: fixed - this creates a stacking context).
Next, you need to create a couple more nested stacking contexts inside the sidebar. By changing the positioning on aside.one to relative and .overlay to fixed, you create another 2 stacking contexts that allow you to play with z-indexing of the elements.
Finally, you need to change the z-index on #header so that its below the overlay.
the root element (HTML),
positioned (absolutely or relatively) with a z-index value other than "auto",
elements with an opacity value less than 1.
on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is "auto"
Source: MDN: The stacking context
Updated jsFiddle: http://jsfiddle.net/ncSWz/17/
HTML
<section id="sidebar">
<!-- Should be on top of the overlay -->
<aside class="one">...</aside>
<aside class="two">...</aside>
<!-- Should cover all elements except for aside.one -->
<div class="overlay"></div>
</section>
CSS
header {
z-index: 0;
}
...
.one {
position: relative;
width: 100%;
z-index: 3;
}
.overlay {
bottom: 0;
display: none;
left: 0;
position: fixed;
right: 0;
top: 0;
z-index: 1;
}
Put position: absolute on both one and two, and set the top of two; since their parent is fixed, they're absolutely positioned to it.
Running Demo
CODE ADDED
.one {
position: absolute;
}
.two {
position: absolute;
top: 25px;
}
Related
This question already has answers here:
Why does position:relative; appear to change the z-index?
(2 answers)
Closed 2 years ago.
I was building a modal, and I was having problems keeping the background behind the main content.
They were on the correct hierarchy for them being painted correctly: the ones behind comes first.
The problem was that the absolute position background was "hidding" the content, despite the content should be painted after and therefore in front.
Suddenly I realised that adding position relative to the content make it render on top of the background, so the background-color of the background was not "masking" it anymore.
Here is a fiddle where you can see how the content with the position absolute has the correct colors, while the one with normal position has it's colors tinted red.
.main {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
}
.background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(100, 0, 0, 0.55);
}
.content {
background-color: lightblue;
padding: 1rem;
position: relative;
}
.norelative {
background-color: lightblue;
padding: 1rem
}
<div>
Just some basic text
</div>
<div class="main">
<div class="background"></div>
<div class="content">Content</div>
<div class="norelative">No relative</div>
</div>
https://jsfiddle.net/danielo515/x3u2Lth7/11/
How is this possible? How can position relative affect this layering problem?
It's all about stacking contexts. Using a position property that isn't static (the default) makes the element render on top of anything else that is static. So, your background renders on top of the static norelative div, but since the relative div isn't static, it follows the normal rendering order and renders on top of the background.
See stacking context for more details.
Please see this very simple snippet to illustrate my question below:
#container {
position: relative;
padding: 20px;
border: 2px solid gray;
}
#back {
position: absolute;
top: 0;
bottom: 50%;
left: 0;
right: 0;
background-color: #bbb;
}
<div class="col-sm-12" id="container">
<div id="back"></div>
<h1>Some Text</h1>
</div>
The h1 tag is after the back element, in the HTML code.
As I don't change its position property, it must be static.
And, as far as I know, static elements are positioned according to the flow of the page.
So… Why is the absolute-positioned div is shown above its sibling h1?
I am expecting to see it behind the h1 since it comes first.
Note that I know how to correct this behaviour, I'm just asking why!
Snippet with correction:
#container {
position: relative;
padding: 20px;
border: 2px solid gray;
}
#back {
position: absolute;
top: 0;
bottom: 50%;
left: 0;
right: 0;
background-color: #bbb;
}
/* Adding the below corrects this behaviour */
h1 {
position: relative;
}
<div class="col-sm-12" id="container">
<div id="back"></div>
<h1>Some Text</h1>
</div>
… And why using position: relative on the h1 corrects this behaviour?
This is how the painting order works. As described here you have the following order:
For all its in-flow, non-positioned, block-level descendants in tree order: If the element is a block, list-item, or other block
equivalent:
In this step you will print the background and border of the h1 element
Otherwise: first for the element, then for all its in-flow, non-positioned, block-level descendants in tree order:
In this complex step you will print the content of the h1 element
All positioned, opacity or transform descendants, in tree order that fall into the following categories:
All positioned descendants with 'z-index: auto'
And in this step you will print the positioned element #back; thus it will be on the top of h1 even if in the DOM it's before.
In other words, we first consider the in-flow elements then the postioned ones. Of course, changing z-index and/or other properties will affect the order because more steps can be consider.
For example adding a negative z-index to #back will trigger this rule:
Stacking contexts formed by positioned descendants with negative z-indices (excluding 0) in z-index order (most negative first) then
tree order.
This will make the #back to be behind since h1 is printed later in the step (4) and (7).
Adding position:relative (or absolute or fixed) to h1 will make it a positioned element so like #back it will trigger the (8) and in this case the tree order will decide.
You may also notice that both background and content are printed in 2 different steps and this may also lead to some non intuitive painting behavior.
Try following. Add style for h1 as follows
#container {
position: relative;
padding: 20px;
border: 2px solid gray;
}
#back {
position: absolute;
top: 0;
bottom: 50%;
left: 0;
right: 0;
background-color: #bbb;
}
#container h1 {
position : relative;
z-index: 1;
}
<div class="col-sm-12" id="container">
<div id="back"></div>
<h1>Some Text</h1>
</div>
static elements do not have a z-index, however, the others default to 0 that is why it stays at the bottom most layer of html and the non-static element covers it. If you wish to show them above, set the position of static elements to relative and give any positive z-index value.
The top, right, bottom, left, and z-index properties have no effect for position: static which is the default value for elements, in your case which h1 tag is. When position is set to relative it creates a new stacking context when the value of z-index is other than auto.
For more read on stacking context:
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
I have this code
#mtitle {
display: inline-block;
margin: 0;
background-color: #000000;
z-index: 999;
}
#tsub {
display: inline-block;
margin-left: 0;
left: 0;
position: absolute;
font-size: 85px;
z-index: 0;
}
<header>
<h1 id="mtitle">Tepid Beans</h1>
<div id="tsub"><span>- Games</span>
</div>
</header>
#tsub is appearing on top of #mtitle, and I do not know why.
z-index works on positioned elements, but with CSS3 elements which are flex items or grid items can use z-index when elements are static
From MDN
The z-index property specifies the z-order of an element and its
descendants. When elements overlap, z-order determines which one
covers the other. An element with a larger z-index generally covers an
element with a lower one.
For a positioned box, the z-index property specifies:
The stack level of the box in the current stacking context.
Whether the box establishes a local stacking context.
Applies to positioned elements
Set position:relative to parent header and position:absolute to #mtitle and change z-index value
body {
margin: 0
}
header {
position: relative
}
#mtitle {
display: inline-block;
background-color: #000000;
position: absolute;
margin:0;
z-index: 0;
color: #fff
}
#tsub {
display: inline-block;
left: 0;
position: absolute;
font-size: 85px;
z-index: -1;
background: red
}
<header>
<h1 id="mtitle">Tepid Beans</h1>
<div id="tsub">- Games</div>
</header>
Although other answers posted here solve the problem, they are not entirely correct.
The following statements are false:
z-index only works on positioned elements.
z-index only works on elements that are positioned.
z-index only works on elements which are not position:static ie the default position.
In many cases an element must be positioned for z-index to work. But this is not true for all cases.
Elements that are flex items or grid items can create stacking contexts with z-index, even when position is static (see demo).
In terms of this specific question, the reason #tsub is appearing on top of #mtitle is because:
div#tsub comes after h1#mtitle in the HTML, AND
the z-index property applied to #mtitle is being ignored since #mtitle is not positioned, nor is it a flex or grid item.
Here are two possible solutions:
change z-index: 0 on #tsub to z-index: -1, OR
add position: relative to #mtitle
#mtitle {
display: inline-block;
margin: 0;
background-color: aqua; /* changed for illustration purposes */
z-index: 999;
}
#tsub {
display: inline-block;
margin-left: 0;
left: 0;
position: absolute;
font-size: 85px;
z-index: -1; /* adjustment here */
}
<header>
<h1 id="mtitle">Tepid Beans</h1>
<div id="tsub"><span>- Games</span>
</div>
</header>
z-index only works on elements that are positioned. So if you add position: relative; to #mtitle the z-indexing will work.
concerning the last part of your question,
tsub is appearing on top of #mtitle, and I do not know why.
elements with position: absolute are "taken out" of the regular flow of elements, they don't take up any space in their parent elements (which need a position setting other than static for that to work), they are only anchored to them (= will move with them). But that way they can overlap other elements.
Among several absolutely positioned elements, the z-index will determine which one is on top of another one..
I want to make this shopping cart's div follow the user's viewport (http://testshop.michaelkenji.com/), so I tried to simply injecting div { position:fixed} to it's stylesheet, it worked, but there are complications which I am here to ask.
Q: Given two fixed elements, and they collide, which one will be on top?
Q: How do I make an element be the absolute "top" (with only css)
When you want to overlap the element in top, you should use a higher z-index value for eg:
div{
position: fixed;
top: 0;
width: 100%;
z-index: 1;
}
div{/*this div will be on top layer of previous div*/
position: fixed;
top: 0;
width: 100%;
z-index: 2;/*because of higher z-index*/
}
I'm trying to layer 2 div's so that the content of one is above another, and the other has an opacity setting to make it translucent. However, no matter which way around I put the HTML for the layers the translucent layer is always above the content. This is the way I would assume to be correct in HTML ordering:
<div id="translucent"></div>
<div id="content">...</div>
However it doesn't seem to be working - The basic styling I'm using to overlap the layers is here - This works to put one over the other, but the translucent one seems to stay above the other one
<style>
#content
{
margin-top:-525px;
}
#translucent
{
height:525px;
opacity:0.8;
}
</style>
Any Ideas?
Why don't you use position and z-indexes? It should work like this:
#content {
margin-top:-525px;
// positioning something allows you to do more accurate placements
position: relative;
// adding a z-index allows you to play with the layers (because... z-axis.)
z-index: 1;
}
#translucent {
height:525px;
opacity:0.8;
position: relative;
z-index: 0;
}
Basically, the HTML DOM works as following: if it's later in the DOM, it is on top of items earlier in the DOM. Turning the opacity down makes the element transparent, but not non-existent. The best way to do this is add z-index and a position, or just use display: block; and display: none; To hide one of yours DIVs (but you want the transparency, so I guess thats not an option).
However if you'd use position: absolute; you could place the elements in the same place without doing the margin. Then wrap it in another element (say #wrapper) and then you can move both boxes at the same time. Add a width and height of 100% for both boxes and you can use the wrapper to define both boxes' height and width and the same time! Ahh. CSS Magic.
<div id="wrapper">
<div id="content">...</div>
<div id="translucent"></div>
</div>
Heres the CSS:
#wrapper {
position: relative;
}
#content {
position: absolute;
left: 0;
top: 0;
z-index: 1;
}
#translucent {
height:525px;
opacity:0.8;
position: absolute;
left: 0;
top: 0;
z-index: 0;
}