I'm trying to animate a box shadow transition with the aid of CSS pseudo-elements :before
and :after
. In principle, the code provided in the JSFiddle works fine, except that on mousing out of the subdiv
in the lefthand column, its box shadow jumps to the leftparentdiv
. This behavior occurs whenever the window is window is small enough that overflow-y: scroll
kicks in. The problem seems to occur in all browsers that support box shadows.
I guess I'm missing something obvious here, but can't figure out what.
body {
background-color: pink;
}
.subdiv {
width: 25vw;
border: 1px solid;
}
.subdiv:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.30);
transition: all 0.6s ease-in-out;
opacity: 0;
}
.subdiv:hover {
transform: scale(1.1, 1.1);
}
.subdiv:hover:after {
opacity: 1;
}
#leftparentdiv {
position: absolute;
left: 0;
top: 0;
border: 1px solid;
width: 47vw;
padding: 3%;
overflow-y: scroll;
}
#rightparentdiv {
position: absolute;
left: 53vw;
top: 0;
border: 1px solid;
width: 47vw;
padding: 3%;
overflow-y: scroll;
}
<div id="leftparentdiv">
<div class="subdiv">
Blabla;
</div>
</div>
<div id="rightparentdiv">
<div class="subdiv">
Blabla;
</div>
</div>
You have a transform on .subdiv:hover
, but none on .subdiv
. A box with a transform establishes a containing block. This is what allows the pseudo-element (and its shadow) to be painted around .subdiv
when the mouse is over it. But when the mouse leaves the element, the pseudo-element (and its shadow) jumps to .subdiv
's parent because .subdiv
no longer establishes a containing block, so the pseudo-element sizes according to the parent element and not its originating .subdiv
because the parent element does establish a containing block. This is also true when the layout is first rendered, before the cursor ever touches the .subdiv
(you just don't see it because the pseudo-element is invisible).
This behavior actually occurs only when .subdiv
's parent has overflow: visible
. It doesn't occur otherwise. The reason for that is because the pseudo-element's box shadow is actually overflowing the parent element whenever its originating .subdiv
is not :hover
. So a non-visible overflow
clips the shadow away. This isn't immediately apparent because the parent element doesn't scroll — and the reason for that is because box shadows don't affect layout.
Assuming the desired behavior is for .subdiv
to always be the one casting the shadow, all you have to do is position .subdiv
so it establishes a containing block at all times:
body {
background-color: pink;
}
.subdiv {
width: 25vw;
position: relative;
border: 1px solid;
}
.subdiv:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.30);
transition: all 0.6s ease-in-out;
opacity: 0;
}
.subdiv:hover {
transform: scale(1.1, 1.1);
}
.subdiv:hover:after {
opacity: 1;
}
#leftparentdiv {
position: absolute;
left: 0;
top: 0;
border: 1px solid;
width: 47vw;
padding: 3%;
overflow-y: scroll;
}
#rightparentdiv {
position: absolute;
left: 53vw;
top: 0;
border: 1px solid;
width: 47vw;
padding: 3%;
overflow-y: scroll;
}
<div id="leftparentdiv">
<div class="subdiv">
Blabla;
</div>
</div>
<div id="rightparentdiv">
<div class="subdiv">
Blabla;
</div>
</div>