What is the criteria?
In the following example, I am animating CSS transform
, and when you click anywhere (while in Google Chrome) the animation is blocked by a 2-second-long while
loop.
Why is the CSS transform
animation blocked?
EDIT: Lately Chrome no longer blocks the transform
while the main thread is blocked, indicating that they have moved the sort of animation in the following example off main thread.
Animating transform can happen on a separate thread, but it isn't clear exactly when. Sometimes it works.
In this first example, separate-thread transform animation does not happen (click on it to block the main thread and therefore pause the animation):
window.addEventListener('click', kill)
function kill() {
var start = +new Date;
while (+new Date - start < 2000){}
}
html, body, div {
width: 100%; height: 100%;
margin: 0; padding: 0;
/* background: #364659; */
/* background: #293442; */
background: #1E2630;
overflow: hidden;
}
@keyframes ShimmerEffect {
0% { transform: translate3d(-15%, -15%, 0) }
100% { transform: translate3d(-60%, -60%, 0) }
}
.shimmerSurface {
/* overflow: hidden; */
/* perspective: 100000px */
}
.shimmerSurfaceContent {
transform-style: preserve-3d;
background: linear-gradient(
-45deg,
rgba(0,0,0,0) 40%,
rgba(244,196,48,0.6) 50%,
rgba(0,0,0,0) 60%
);
background-repeat: repeat;
background-size: 100% 100%;
width: 400%; height: 400%;
animation: ShimmerEffect 1.8s cubic-bezier(0.75, 0.000, 0.25, 1.000) infinite;
}
<div class="shimmerSurface">
<div class="shimmerSurfaceContent"></div>
</div>
What is the criteria?
In the following example, I am animating CSS transform
, and when you click anywhere (while in Google Chrome) the animation is blocked by a 2-second-long while
loop.
Why is the CSS transform
animation blocked?
EDIT: Lately Chrome no longer blocks the transform
while the main thread is blocked, indicating that they have moved the sort of animation in the following example off main thread.
Animating transform can happen on a separate thread, but it isn't clear exactly when. Sometimes it works.
In this first example, separate-thread transform animation does not happen (click on it to block the main thread and therefore pause the animation):
window.addEventListener('click', kill)
function kill() {
var start = +new Date;
while (+new Date - start < 2000){}
}
html, body, div {
width: 100%; height: 100%;
margin: 0; padding: 0;
/* background: #364659; */
/* background: #293442; */
background: #1E2630;
overflow: hidden;
}
@keyframes ShimmerEffect {
0% { transform: translate3d(-15%, -15%, 0) }
100% { transform: translate3d(-60%, -60%, 0) }
}
.shimmerSurface {
/* overflow: hidden; */
/* perspective: 100000px */
}
.shimmerSurfaceContent {
transform-style: preserve-3d;
background: linear-gradient(
-45deg,
rgba(0,0,0,0) 40%,
rgba(244,196,48,0.6) 50%,
rgba(0,0,0,0) 60%
);
background-repeat: repeat;
background-size: 100% 100%;
width: 400%; height: 400%;
animation: ShimmerEffect 1.8s cubic-bezier(0.75, 0.000, 0.25, 1.000) infinite;
}
<div class="shimmerSurface">
<div class="shimmerSurfaceContent"></div>
</div>
(codepen link)
EDIT: seems the example's animation is not blocked in Safari (though it chops the gradient), but is blocked only in Chrome and Firefox. How can we unblock the animation in Chrome and Firefox?
In next example, when you click anywhere to block the main thread (in Chrome), you will see that transform
is animated on a separate thread because it continues to animate, while the stroke-offset
animation is frozen because apparently stroke-offset
animation is happening on the main thread:
window.addEventListener('click', kill)
function kill() {
var start = +new Date;
while (+new Date - start < 2000){}
}
.loader {
--path: #2F3545;
--dot: #5628EE;
--duration: 3s;
width: 44px;
height: 44px;
position: relative;
}
.loader:before {
content: "";
width: 6px;
height: 6px;
border-radius: 50%;
position: absolute;
display: block;
background: var(--dot);
top: 37px;
left: 19px;
transform: translate(-18px, -18px);
-webkit-animation: dotRect var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
animation: dotRect var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
}
.loader svg {
display: block;
width: 100%;
height: 100%;
}
.loader svg rect,
.loader svg polygon,
.loader svg circle {
fill: none;
stroke: var(--path);
stroke-width: 10px;
stroke-linejoin: round;
stroke-linecap: round;
}
.loader svg polygon {
stroke-dasharray: 145 76 145 76;
stroke-dashoffset: 0;
-webkit-animation: pathTriangle var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
animation: pathTriangle var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
}
.loader svg rect {
stroke-dasharray: 192 64 192 64;
stroke-dashoffset: 0;
-webkit-animation: pathRect 3s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
animation: pathRect 3s cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
}
.loader svg circle {
stroke-dasharray: 150 50 150 50;
stroke-dashoffset: 75;
-webkit-animation: pathCircle var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
animation: pathCircle var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
}
.loader.triangle {
width: 48px;
}
.loader.triangle:before {
left: 21px;
transform: translate(-10px, -18px);
-webkit-animation: dotTriangle var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
animation: dotTriangle var(--duration) cubic-bezier(0.785, 0.135, 0.15, 0.86) infinite;
}
@-webkit-keyframes pathTriangle {
33% {
stroke-dashoffset: 74;
}
66% {
stroke-dashoffset: 147;
}
100% {
stroke-dashoffset: 221;
}
}
@keyframes pathTriangle {
33% {
stroke-dashoffset: 74;
}
66% {
stroke-dashoffset: 147;
}
100% {
stroke-dashoffset: 221;
}
}
@-webkit-keyframes dotTriangle {
33% {
transform: translate(0, 0);
}
66% {
transform: translate(10px, -18px);
}
100% {
transform: translate(-10px, -18px);
}
}
@keyframes dotTriangle {
33% {
transform: translate(0, 0);
}
66% {
transform: translate(10px, -18px);
}
100% {
transform: translate(-10px, -18px);
}
}
@-webkit-keyframes pathRect {
25% {
stroke-dashoffset: 64;
}
50% {
stroke-dashoffset: 128;
}
75% {
stroke-dashoffset: 192;
}
100% {
stroke-dashoffset: 256;
}
}
@keyframes pathRect {
25% {
stroke-dashoffset: 64;
}
50% {
stroke-dashoffset: 128;
}
75% {
stroke-dashoffset: 192;
}
100% {
stroke-dashoffset: 256;
}
}
@-webkit-keyframes dotRect {
25% {
transform: translate(0, 0);
}
50% {
transform: translate(18px, -18px);
}
75% {
transform: translate(0, -36px);
}
100% {
transform: translate(-18px, -18px);
}
}
@keyframes dotRect {
25% {
transform: translate(0, 0);
}
50% {
transform: translate(18px, -18px);
}
75% {
transform: translate(0, -36px);
}
100% {
transform: translate(-18px, -18px);
}
}
@-webkit-keyframes pathCircle {
25% {
stroke-dashoffset: 125;
}
50% {
stroke-dashoffset: 175;
}
75% {
stroke-dashoffset: 225;
}
100% {
stroke-dashoffset: 275;
}
}
@keyframes pathCircle {
25% {
stroke-dashoffset: 125;
}
50% {
stroke-dashoffset: 175;
}
75% {
stroke-dashoffset: 225;
}
100% {
stroke-dashoffset: 275;
}
}
.loader {
display: inline-block;
margin: 0 16px;
}
html {
-webkit-font-smoothing: antialiased;
}
* {
box-sizing: border-box;
}
*:before, *:after {
box-sizing: border-box;
}
body {
min-height: 100vh;
background: #F5F9FF;
display: flex;
justify-content: center;
align-items: center;
}
body .dribbble {
position: fixed;
display: block;
right: 20px;
bottom: 20px;
}
body .dribbble img {
display: block;
height: 28px;
}
<div class="loader">
<svg viewBox="0 0 80 80">
<circle id="test" cx="40" cy="40" r="32"></circle>
</svg>
</div>
<div class="loader triangle">
<svg viewBox="0 0 86 80">
<polygon points="43 8 79 72 7 72"></polygon>
</svg>
</div>
<div class="loader">
<svg viewBox="0 0 80 80">
<rect x="8" y="8" width="64" height="64"></rect>
</svg>
</div>
Why does the first example's transform
animation run on the main thread, while the second example's transform
animation runs on a separate thread?
What are the criteria under which a transform
is guaranteed to run in a separate thread (at least, in Chrome)?
- 2 I believe things are opposite: CSS animation does not block main thread. but can be blocked by main thread. – skyboyer Commented Apr 4, 2019 at 4:54
- 1 @MasoudKeshavarz Yes, the main thread freezes, but in Safari the animation continues running (on another CPU thread) even while the JS is frozen. It only does not work in Chrome or Firefox (although I read a bunch of other places that it should work). – trusktr Commented Apr 4, 2019 at 16:08
- 2 In short, that is because CSS animations take place on the UI thread. On desktop/iOS Safari and Android Chrome, these browsers have since moved CSS animations (positing) away from using the UI thread, which means that they will not be affected by the 2-second infinity loop invoked by the click event callback. – Terry Commented Apr 6, 2019 at 20:38
- 2 At the time of this ment your example is no longer blocking animation when clicking the page. This makes the question unanswerable. Voting to close it, since the issue appears to have been fixed. – tao Commented Jan 7, 2022 at 23:26
- 1 To better debug transform issues see "Layers" tab in Devtools -> [three dots in the upper right corner] -> More tools -> Layers – irdkwmnsb Commented Apr 25, 2022 at 13:20
1 Answer
Reset to default 3Browser Threads
Each browser has at least three threads; precisely what is run on each depends on the browser. Modern browsers all have more than three now, but they still have three categories of threads that will always be separate. Why? One will always be entirely separate and only accessible by the browser to handle things like scrolling, opening a new tab etc... At least one will always be for things like calculating and parsing and so will be run on the CPU. And at least one thread will run on the GPU as it is required for something to be shown on your screen.
Layers
For the GPU to know what it's showing on the screen it needs the layout rasterised in a bitmap format. But as things move around the screen it's best if we send the GPU a few bitmaps that can move around. We call these layers.
as @irdkwmnsb has pointed out we can use the layers
tab in the developer tools to see exactly which elements have been split into separate bitmaps.
Explicitly Creating A Layer
For any HTML or SVG element that we know will transform, we can add the following CSS rule to ensure the element is separated into a separate bitmap layer and the transition shouldn't be blocked by other activity on the main thread:
will-change: transform
so adding the CSS rule
.shimmerSurfaceContent {
will-change: transform;
}
should stop the transition from being blocked in your first example.
Why Only In Some Browsers?
The reason some browsers may not automatically split this element into a separate layer is that there is a performance issue with creating too many bitmap layers so they are careful not to create too many. Also, some things don't look good when created as separate bitmaps and moved around so the browser may avoid it.
But for this example specifically, we can see from the two bitmap layers in this image that the top one has a semi-transparent edge. Things like this have previously caused aliasing problems for the GPU as it calculates the various shaded of yellow.
This may have been a reason for chrome to previously avoid separating it into a new bitmap layer.
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744265800a4565858.html
评论列表(0条)