Reputation:
Browser: Chrome 60
**TLDR: ** It seems that using a transition with a filter on a child of a div
with a clipping path applied causes strange behavior (take a look at the live code example and the pictures). However, this only happens when the background child has a blur
filter on it too.
I am trying to create a scroll triggered animation using jQuery and CSS transitions. I have two div
s on the page: a fixed div on the left side with a slanted edge (made using clipping path), and a right div containing content:
When the page detects that the user scrolls past a certain point in the page, it will add a class to the text in the left div
, making it blur out. This all works fine, until I add transition: filter 0.5s;
to the text - this causes the clipping path to break (randomly jumps up by around 100px
) while the transition is occuring:
Take a look at a live example (code included):
https://codepen.io/sunnylan/full/eEWKYX
I have tried to isolate where the problem comes from, but I am having trouble, since it seems as if a combination of multiple elements are causing the problem. For example, the problem disappears when I remove the clipping path. It also goes away when I remove the transitions from the navigation list items. More specifically, here are the problem areas (removing any of them will fix the problem):
Adding a clipping path to the sidebar
clip-path: polygon( // line 191
0 0,
100% 0,
100% - $sidebar-angle 100%,
0 100%);
Adding a blur filter to the sidebar background:
filter: blur(20px); //line 201
Adding a transition to the nav items:
transition: filter $animation-speed ease, opacity $animation-speed ease; // line 222
Upvotes: 2
Views: 1865
Reputation: 1339
That's a tricky one. Looks like it's something specific to Chrome, seeing as FF works OK minus a few oddities.
It looks like the specific cause to the problem is animating the nav-bar
when the selected
class is applied to it. If you don't do that then the clip-path animates correctly, but then there's no opacity/blur animation. You can see that when the selected
class is applied, the clip-path messes up for the duration of the transition, and then goes the way you want when it's done. I'm guessing this is rendering from the innermost child outwards.
The fix, is to separate the two, instead of nesting them.
$(window).scroll(function () {
var s = $(window).scrollTop(),
d = $(document).height(),
c = $(window).height();
var percent = s.map(0, d - c, 0, 100);
if (percent > 15) {
$('.nav-bar-wrapper .nav-bar').css('top', s.map(0, d - c, 10, -10) + '%');
$('.sidebar').addClass('closed');
$('.nav-bar-wrapper').addClass('closed');
$('.nav-item').addClass('selected');
} else {
$('.nav-bar-wrapper .nav-bar').css('top', '40%');
$('.sidebar').removeClass('closed');
$('.nav-bar-wrapper').removeClass('closed');
$('.nav-item').removeClass('selected');
}
});
.sidebar {
background: black;
//fix on left side of page
position: fixed;
left: 0;
top: 0;
bottom: 0;
//initial width
width: $sidebar-open;
//make slanted edge
clip-path: polygon(
0 0,
100% 0,
100% - $sidebar-angle 100%,
0 100%);
//background picture layer
.background {
@include fill-parent-bg;
background-image: url('/img/cb-colour-nightsky.jpg');
filter: blur(20px);
background-size: cover;
z-index: -1;
}
//center sliding nav bar
@include flex;
justify-content: center;
//animate it!
transition: width $animation-speed ease;
&.closed {
width: $sidebar-closed;
}
}
//moving component
.nav-bar-wrapper {
top: 0;
left: 0;
bottom: 0;
position: fixed;
width: $sidebar-open;
transition: width $animation-speed ease;
&.closed {
width: $sidebar-closed;
}
.nav-bar {
background: gray;
//keep component where it is, unless modified by jQuery
position: absolute;
top: 40%; //default vertical position
left: 50%;
transform: translateX(-50%);
//animate it!
transition: top $animation-speed ease;
.nav-item {
//fade in/out animations
transition: filter $animation-speed ease, opacity $animation-speed ease;
filter: blur(15px);
opacity: 0.5;
&.selected {
opacity: 1;
filter: blur(0);
}
}
}
}
<div class="sidebar background"></div>
<div class="nav-bar-wrapper">
<div class="nav-bar">
<h1 class="nav-item" style="color:white; height: 100px;">Test content</h1>
</div>
</div>
Here's your CodePen modified: https://codepen.io/anon/pen/RZVBNJ
With this, though, it looks like for a moment the text gets rendered twice, even though it's only on there once. Again, this is a Chrome-specific issue.
Upvotes: 0