I am having trouble properly stacking my divs using CSS z-index. In my code, if I set .nose::before and .nose::after to z-index: -1, it puts the two divs at the very back of the stack. However, I just these divs to sit behind the .nose div. Here's my code:
*, *::after, *::before {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body { height: 100%; }
body {
background: #44BBA4;
}
.head {
position: absolute;
margin: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
height: 375px;
width: 400px;
background: #df9e27;
border-radius: 50%;
border: 10px solid #000;
}
.head::before, .head::after {
content: "";
position: absolute;
height: 90px;
width: 90px;
background: #df9e27;
border-radius: 50%;
border: 10px solid #000;
z-index: -1;
}
.head::before {
top: -30px;
left: 40px;
}
.head::after {
top: -30px;
right: 40px;
}
.eye {
position: absolute;
top: 150px;
height: 25px;
width: 25px;
background: #000;
border-radius: 50%;
}
.eye.left {
left: 90px;
}
.eye.right {
right: 90px;
}
.eye::before {
content: "";
position: absolute;
top: -50px;
left: -37px;
height: 100px;
width: 100px;
border-radius: 50%;
border: 12px solid transparent;
border-top: 12px solid #000;
}
.nose {
position: absolute;
margin: auto;
right: 0;
left: 0;
bottom: 130px;
height: 30px;
width: 30px;
background: #000;
border-radius: 50%;
}
.nose::before, .nose::after {
content: "";
position: absolute;
height: 68px;
width: 73px;
background: #fff;
border-radius: 50%;
border: 10px solid #000;
z-index: -1;
}
<div class="head">
<div class="eye left"></div>
<div class="eye right"></div>
<div class="nose"></div>
</div>
In short: Set z-index on your head element. Move ears out of the head element.
Here is why.
z-index has stacking contexts. Each of those contexts has a root element (just any html element). Now, to become a root element it must comply with any of the following rules:
be <html> element
position other than static and z-index other than auto
opacity less then 1
So the default stacking context is with the <html> element as a root.
Once the element is inside a scope (in other words, child of a root element), it can only be positioned relative to the elements inside the scope.
Think about it as a nested list.
Wrap here is a root element, as it has position set to relative and z-index to 1. And all of its children are now inside a stacking scope with the Wrap as a root.
So, like in a nested list, children of a particular element cannot appear before its root. For example, Child2 cannot appear before the Wrap, since it is scoped inside of it. But it can appear before the Child1.
Now, in your case the structure is as follows:
Notice that the head is not a root, because it doesn't comply with the rules for becoming one (positioned elements must also have z-index other than auto). Therefore when you assign z-index of -1 to the Nose::before and ::after you get this:
The elements have been positioned all the way behind the Head, because they are in the same stacking scope. But they appear on top of Head::before, since when elements have the same z-index, they are stacked according to the order of appearance in html.
Now, to prevent head children from appearing behind it, you must add z-index to it. This will make it a root element of new stacking scope.
But this creates another problem. Now ears are positioned on top of the head. This is not possible to solve with css alone, since they are inside a stacking scope of the head. And root always lies behind every of its children.
To solve it, you must move the ears out of the head. So, it means, you won't be able to use pseudoelements (before & after) anymore. I suggest creating ear elements outside of the head and wrapping everything in some other element (named bear?) with position relative. Wrapper is needed if you still want to position ears relative to the head.
The answer is mostly inspired by this article.
Related
For some reason, when an element's pseudo child node is added, its z-index is higher than its child nodes, even though its a ::before element, which appears before the relative child nodes, but doesn't display that way. Why does this happen, and is there a way to fix it?
Here's an example where the child <h1> node should appear as if it's hovering over the black pseudo element, but that isn't the case.
https://jsfiddle.net/9u33vko0/
Is my understanding just fundamentally wrong?
div {
width: 100%;
padding: 40px 0;
border: 1px solid #DDD;
text-align: center;
color: #FFF;
position: relative;
}
div::before {
content: "";
position: absolute;
top: 0;
left: 0;
height: 100%;
background-color: #000;
width: 100%;
}
<div>
<h1> <!-- should appear above the black ::before element -->
Hello, World!
</h1>
</div>
Even though the :before pseudo element appears before the h1 element in the DOM, it will still overlap the h1 element because it establishes a stacking context due to the fact that it is positioned (with position: absolute).
Here is a relevant quote from the CSS2 specification on stacking contexts (painting order; point 8)
All positioned descendants with z-index: auto or z-index: 0, in tree order. For those with z-index: auto, treat the element as if it created a new stacking context ...
Therefore you could establish a stacking context with the h1 element by positioning it (i.e., by adding position: relative). In doing so, the h1 element will be placed above the :before pseudo element because it appears after the pseudo element in the DOM and both elements are positioned with a z-index of auto.
Updated Example
h1 {
position: relative;
}
div {
width: 100%;
padding: 40px 0;
border: 1px solid #DDD;
text-align: center;
color: #FFF;
position: relative;
}
div::before {
content: "";
position: absolute;
top: 0;
left: 0;
height: 100%;
background-color: #000;
width: 100%;
}
h1 {
position: relative;
}
<div>
<h1>Hello, World!</h1>
</div>
Of course, you could also just give the pseudo element a negative z-index, but that's besides the point. When it comes down to it, establishing a stacking context is enough since the :before pseudo element appears before the h1 element in the DOM (as you have already pointed out).
I am trying to create a relative-positioned element with overflow:hidden that contains a few fixed-position elements. The goal is to have the fixed child elements become hidden as the parent element moves, sort of like if they were part of a background-image with attachment:fixed on the parent element.
By all accounts on StackOverflow and elsewhere on the web, this is not possible, because a fixed element only regards the browser window and ignores its parent element. However, for whatever reason it actually works as intended in Chrome only: http://jsfiddle.net/x6avvhuf/
Here's what the fiddle looks like, view it in Chrome vs. IE/Firefox to see the difference:
HTML
<body>
<div id = "headwrapper">
I am the relative parent element
<div class = "fixedchild">
I am a fixed child element
</div>
</div>
<div id = "content">
This is the main content portion of the page<br>
<!-- Repeat until the page scrolls -->
This is the main content portion of the page<br>
</div>
CSS
body {
background-color: yellow;
}
#headwrapper {
position: relative;
height: 300px;
width: 100%;
overflow: hidden;
z-index: -1;
background-color: black;
color: white;
text-align: center;
}
.fixedchild {
position: fixed;
width: 75%;
height: 40px;
z-index: 48;
top: 22.5%;
left: 50%;
margin: 0 0 0 -37.5%;
text-align: center;
color: red;
background-color: pink;
}
What is an alternative solution for this? I have read that it is possible to make an absolute element behave like a fixed element with CSS, but I have been unable to make this work so far. Thanks in advance for any help or advice! :)
UPDATE
Sometimes the best solutions are the most simple. Given the code you posted all you would have to do is set a background-color on #content (ex: yellow in this instance to match the body) since your fixed element has z-index: -1 and will sit behind it anyways:
#content{
background: yellow;
width: 100%;
}
CSS EXAMPLE 1
OR
You could set #content to position:relative which would allow you to order this and your fixed div with z-index (this is probably better, using z-index: -1 is kind of a hack):
CSS
.fixedchild {
position: fixed;
width: 75%;
height: 40px;
z-index: 1; //set to 1
top: 22.5%;
left: 50%;
margin: 0 0 0 -37.5%;
text-align: center;
color: red;
background-color: pink;
}
#content{
background: yellow;
width: 100%;
position: relative; //add
z-index: 2; //set higher
}
CSS EXAMPLE 2
(previous answer):
DISCLAMIER: This is not a CSS solution.
There may be a CSS solution for this. I don't happen to know one off the top of my head, but I do know this can be done pretty easily with Jquery
JS
$(window).scroll(function(){
var scrolled = $(this).scrollTop()+100; //offset starting position which I hard coded to top: 100px - you can change as needed
$(".fixedchild").css({"top": scrolled+"px"});
});
CSS
.fixedchild {
position: absolute;
width: 75%;
height: 40px;
z-index: 48;
top: 100px;
left: 50%;
margin: 0 0 0 -37.5%;
text-align: center;
color: red;
background-color: pink;
}
JS EXAMPLE
My Fiddle
http://jsfiddle.net/yjw46/2/
My Goal
I have this beautiful wheel of colors as a PNG. (I also have it as an SVG). When one of the colors is clicked, I want the WHOLE circle to change to that color. For example, if red is clicked, I want the whole wheel to turn red instead of colorful.
How I Intended to do it
I wanted to have a transparent (in the Fiddle it's semi-transparent, for debugging purposes) div in the shape of a circle (using border-radius) that will be DIRECTLY ON my color-wheel-image. When a color is pressed, I planned for the div to stop being tranparent, and (in a beautiful transition) turn to that color, making it look like the whole wheel has changed color.
Problem
I cannot get the div to cover the image.
So
I'd be glad to hear either why my technique didn't work, or a better technique, if you have one.
You was very close, simply chanage position: relative; to position: absolute; (on the div you want to have over the image) to fix the problem.
Now remember we need to have the parent as position: relative; or the absolute positioned div will not sit in the parent. You have already set this so its good to go.
Find more on position: absolute; here.
Demo here
#circleCover {
width: 300px;
height: 300px;
position: absolute;
top: 0px; left: 0px;
z-index: 2;
border-radius: 150px;
background-color: rgba(0, 0, 0, 0.2);
}
Here is a little demo to show what will happen without the relative position being set on the parent with the child having absolute.
Demo Without Relative
So you can see that the child is not staying within the parent.
And here is the parent with relative position.
Demo With Relative
As here the child does stay within the parent. This should help you understand why that is needed for the task you are trying to accomplish. Any questions please do just leave a comment and I will get back to you.
<div id="circleWrap">
<img src="http://y.emuze.co/circle.png" id="colorCircle"/>
<div id="circleCover" >
</div>
</div>
I have kept Your div one above the other
#colorCircle {
position: relative;
top: 0px; left: 0px;
z-index: 1;
width: 300px;
height: 300px;
top:0px;
}
#circleWrap {
position: relative;
top: 0px;
width: 300px;
height: 300px;
margin: 0 auto;
}
#circleCover {
width: 300px;
height: 300px;
position: relative;
top: -302px; left: 0px;
z-index: 2;
border-radius: 150px;
background-color: rgba(0, 0, 0, 0.2);
}
Here it is in action: http://jsfiddle.net/yjw46/7/
Change your CSS slightly.
#circleCover {
top:-304px;
}
Fiddle
Just add position:absolute in #colorCircle
#colorCircle {
position: relative;
top: 0px; left: 0px;
z-index: 1;
width: 300px;
height: 300px;
position:absolute;
}
I am trying to use absolute positioning to position a div containing a blue square. For some reason, I am unable to get it where i want it to go.
JSFIDDLE: http://jsfiddle.net/qkF3Z/
My Code:
#share-area-arrow {
position: absolute;
height: 10px;
width: 10px;
background-color: blue;
}
How it should look:
What could I be doing wrong?
There are 2 pieces. Position absolute will use the coordinate system of the closest relatively positioned parent. So you need to add position relative to the parent:
#share-something {
margin-right: auto;
margin-left: auto;
margin-bottom: 40px;
height: auto;
width: 540px;
overflow: auto;
position:relative;
}
and then position the arrow:
#share-area-arrow {
position: absolute;
top:10px;
left:70px;
height: 10px;
width: 10px;
background-color: blue;
}
http://jsfiddle.net/qkF3Z/6/
A really great explanation between the different position types can be found here: http://alistapart.com/article/css-positioning-101. The gist is when you want the element to maintain it's space within the dom, but appear in another location, use position relative. If you want to completely move the element use position absolute.
This creates the expected result:
jsFiddle here
Updated CSS - I used relative positioning instead.
#share-area-arrow {
position: relative;
height: 10px;
width: 10px;
background-color: blue;
top: 20px;
left: 70px;
}
Alternatively, if you feel you need absolute positioning, use:
#share-area-arrow {
position:absolute;
top: 30px;
left: 192px;
}
jsFiddle here - same result in current context
Ok I am running into a little problem positioning an image inside a DIV.
<div id="wholePage">
<img src="theImages/header_shadow_flip.png" id="hF" />
<div id="pageWrapper"><img src="theImages/header_shadow.png" id="bF" />
</div>
</div>
I have the following CSS for both DIVs
#wholePage {
position: relative;
width: 1000px;
padding: 0 10px;
padding-top: 35px;
margin: 0 auto;
}
#pageWrapper {
position: relative;
width: 960px;
padding: 0 10px;
padding-top: 37px;
margin: 0 auto;
}
The CSS for the top shadow, which works just fine. no need to change, is:
img#hF {
position: absolute;
left: 50px;
top: 56px;
z-index:2;
}
But the bottom footer image is giving me issue and the css is:
img#bF {
position: absolute;
left: 50px;
top: 1657px;
z-index:2;
}
Two examples of the page is below:
www.interfaithmedical.com/CheckSite/index.html
www.interfaithmedical.com/CheckSite/ms_gynecology.html
How do I align the bottom shadow image to match the pageWrapper DIV so it is positioned right below it? and doesn't position based on the page itself like it did on the second link. (On the second link, you can see it uses the original spacing and extends beyond page content)
Instead of setting the top: property of bF, try setting the bottom: property of bF to -4px. That way you aren't tied to your page being 1657px tall every time.
img#bF {
left: 50px;
position: absolute;
bottom: -4px;
z-index: 2;
}