I'm a web developer noob and hoping someone with more experience can help.
<div id="domain-background-container">
<div class="domain-hotspots">
<div id="hotspot">
<p class="bubble">I'm red on hover</p>
</div>
</div>
</div>
<div id="page-nav" >
<p>I'm red on hover</p>
</div>
html, body { /* <--- (1) */
height: 100%; }
#domain-background-container {
position: fixed;
z-index: -10; } /* <--- (2) */
.domain-hotspots {
width: 100vw;
height: 100vh;
position: fixed;
background: blue; }
#hotspot {
width: 2em;
height: 2em;
background: green; }
#hotspot:hover .bubble {
background: red; }
#page-nav {
width: 100%;
text-align: center;
background: yellow; }
#page-nav:hover p {
color: red; }
Here's the jsfiddle.
The problem is that #hotspot (that is the green square) doesn't enter the hover state when the mouse cursor is placed over it.
I'm looking to have four things explained:
I'd really appreciate any knowledge people can share on this! I'm stumped. I'm not even sure what I should google for to research the issue, as I don't know what's causing this behaviour.
If an element is transparent and the element with z-index:-1; is 'under' it. This stops the hover effects. Z-index can you see as elevations in a building, and you watching it from birdseye. You can't reach the basement if there is a floor above it, even if its build from glass.
The z-index CSS property sets the z-order of a positioned element and its descendants or flex items. Overlapping elements with a larger z-index cover those with a smaller one.
z-index only works on positioned elements (relative, absolute, fixed, sticky) so if you set a z-index on an element with a static position, it won't work.
Can someone provide or point me to a detailed explanation of the mechanics preventing
#hotspot
from entering the hover state?
<body>
is covering it up.
This can be seen by using the "Inspect element" function of a browser's dev tools.
(Due to the way z-index
works though, giving it a background
does not put that background in front of the div.)
Removing CSS ruleset (1) [height: 100% for html and body] allows
#hotspot
to enter the hover state. This isn't a viable solution in my project, but for curiosity's stake, why does this make a difference.
With height: 100%
:
Without height: 100%
:
[...] to my understanding elements with unmodified z-index which follow .domain-hotspots in the html file should be rendered on top of
.domain-hotspots
in the viewport.
From the CSS Level 2 draft, § 9.9.1:
Within each stacking context, the following layers are painted in back-to-front order:
- the background and borders of the element forming the stacking context.
- the child stacking contexts with negative stack levels (most negative first).
- the in-flow, non-inline-level, non-positioned descendants.
- the non-positioned floats.
- the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
- the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
- the child stacking contexts with positive stack levels (least positive first).
#page-nav
is category 3 due to the default display: block
on any <div>
.#domain-background-container
is category 2 due to position: fixed
, which removes it from the flow and creates a child stacking context, and due to its negative z-index
.Category 3 gets rendered over category 2, so #page-nav
is in front of #domain-background-container
.
Now when you remove the z-index
from #domain-background-container
, or make it 0 or positive, it becomes category 6 or 7, thus being rendered after (i.e. over) #page-nav
.
Theoretically I could position and raise the z-value of #page-nav. While that would work for this simple jsfiddle I'm loath to do that for a bigger project where I'd have to apply that to every element following .domain-hotspots. [...] I can't use the two "solutions" I just mentioned, so what solution remains?
You don't actually have to raise its z-value
, you merely have to position it. position: relative
will do, even.
And applying that to every element following #domain-background-container
is no miracle either:
#domain-background-container ~ * {
position: relative;
}
Works quite well:
html, body { /* <--- (1) */
height: 100%; }
#domain-background-container {
position: fixed;
/*z-index: -10;*/ } /* <--- (2) */
#domain-background-container ~ * {
position: relative; }
.domain-hotspots {
width: 100vw;
height: 100vh;
position: fixed;
background: blue; }
#hotspot {
width: 2em;
height: 2em;
background: green; }
#hotspot:hover .bubble {
background: red; }
#page-nav {
width: 100%;
text-align: center;
background: yellow; }
#page-nav:hover p {
color: red; }
<div id="domain-background-container">
<div class="domain-hotspots">
<div id="hotspot">
<p class="bubble">I'm red on hover</p>
</div>
</div>
</div>
<div id="page-nav" >
<p>I'm red on hover</p>
</div>
Admittedly though, there are situations where it is not feasible to position all those elements.
Another solution though, is to simply position the body
element, which then allows you to give it a z-index
of its own:
body {
position: relative;
z-index: -11;
}
Demo:
html, body { /* <--- (1) */
height: 100%; }
body {
position: relative;
z-index: -11; }
#domain-background-container {
position: fixed;
z-index: -10; } /* <--- (2) */
#domain-background-container ~ * {
position: relative; }
.domain-hotspots {
width: 100vw;
height: 100vh;
position: fixed;
background: blue; }
#hotspot {
width: 2em;
height: 2em;
background: green; }
#hotspot:hover .bubble {
background: red; }
#page-nav {
width: 100%;
text-align: center;
background: yellow; }
#page-nav:hover p {
color: red; }
<div id="domain-background-container">
<div class="domain-hotspots">
<div id="hotspot">
<p class="bubble">I'm red on hover</p>
</div>
</div>
</div>
<div id="page-nav" >
<p>I'm red on hover</p>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With