Everything You Need to Know About the CSS will-change Property
dev.opera.com
dev.opera.com
But, boy, it feels awkward at first sight. To my eye, it's weird to see what is essentially a low-level optimization instruction as part of CSS (which is usually all about presentation rather than implementation). Also, the article makes it clear that there are a lot of ways that people could mistakenly use this property in unhelpful ways. And I'm still not entirely clear on what they mean by "It’s not possible to remove will-change if it is declared in the style sheet": is this really a CSS property that can be turned on without scripting but never turned off without it? That makes me uncomfortable.
So why isn't this a case where we just need browsers to get smarter? In the same sense that an optimizing compiler can in most cases produce better performance than a human writing machine code by hand realistically could, can't we expect browsers to gradually get better and better at spotting these rendering optimizations? (To take an example from the article, couldn't the browser recognize that there's a transform rule for :active and automatically enable something equivalent to will-change for :hover itself?)
It is nearly impossible to predict changes that some page do in perfectly reasonable ways, especially for changes triggered from Javascript. It's true that in some cases a will-change can be inferred from the style sheet but there are still too many changes triggered from JS events. You wont lose any performance by not using will-change and we will continue improving how we infer them. Once an element is declared as will-change the browser will be able to weight the hint and the platform specific costs of various possible optimization like layerizing the element and ignore it if it isn't suitable for the device.
If we can't predict the change then we're left trying to be ready to change a new element within one vsync interval to avoid any latency. This is fine if you're dealing with a small element but large elements like a fullscreen CSS page flip triggered from JS is going to be nearly impossible to perform without a frame or more of latency.
In the case of HiDPI mobile you typically have 2 millions pixels (8 MB) to deal with on a 1GB/s memory bus with a frame time of 16ms. That means that if you touch 16 MB, or twice the size of the screen, then you have zero chance to perform that change without introducing delays. And this is without even considering the CPU/GPU cost require to perform the change. The situation may also get tough on 4k desktop without a discrete GPU if you have 31MBs per fullscreen surface on a 10GB/sec bus.
These are all theoretical throughput maximums. In practice on Android and Firefox OS where a style change occurs on large and complex elements where rasterization is difficult you can't use SIMD to rasterize the page at memory bandwidth speeds, you instead are bottlenecked on rasterizing complicated content. It's typical to see these complex change cause 100ms latency. Once the rasterization is made then the animations can continue smoothly but you're still left with animations skipping at the beginning.
Was there any consideration of making this feature JS-only? From the linked article (and some of the discussion here), it sounds like using this in an actual stylesheet may not be easy to do well (and is often not recommended). And from what you've said here, it's JS changes that are hardest to predict from within the browser. So why expose this as a CSS feature rather than a JS one?
Imagine you're writing something that does fullscreen page flips in a native app vs. a web app. An example is the android homescreen vs the ffos homescreen but I see web pages that often have a similar effect.
* In a native app you're going to have to decompose your page into texture that you will animate (your widget toolkit will likely make this easier).
* Without will-change you're going to hope that the rendering engine will infer your animations in a reasonable amount of time getting bad performance while you wait and hope that it doesn't fall off that optimization path.
* With will-change on the b2g homescreen we just have to add a one line change.
In the example given with the element:hover and element:active, it would trivial to parse all possible CSS transforms. Then live profiling of the page would give data on the likelihood of particular transforms. The browser could then optimise as necessary given hardware limitations and current resource constraints. Even transforms added via javascript or onhover would be caught via live profiling.
The given use case of stopping flickering when a layer is created should be treated as a bug.
This feels hacky, and likely to be used erroneously or abused - at which point browser will be forced to smartly ignore leaving us with yet more cruft. Performance tuning is a fine art, and browser is in a better position to do it vs your average web developer.
.wide {
transition: width 2s;
width: 300px;
}
but don't apply it to any element, then load a remote JavaScript file that adds that class dynamically, no rendering engine will be able to apply this optimization.Admittedly this would run slow the first few times, until the renderer can get enough data.
I can easily see this leading to more unintended hacks as for example WebKit may be less aggressive than say blink in weighting the hints, and so web developers will then add back the 3d transform hacks in addition to will-change.
The target audience is also web developers many of which are inexperienced and I guarantee that even given all the warnings someone will apply it blindly to *. Hence any production implementation would have to have heuristics to catch abuse; again more complexity that will have to exist forever.
While I'm willing to give the to the benefit of doubt - these guys are super smart and it's got broad support - it just feels so heavyweight to actually change the spec for what seems like a relatively niche problem that can be mostly mitigated. Also by the time it's supported everywhere (ios9?) mobiles will be 2-4x faster.
I believe the renderer is where we'll see major innovation over the next year, it really is the next bottleneck. It's amazing (and depressing) how easy it is to jank modern web browsers even on very powerfull hardware.
'Profiling' or inferring the animation is what engine already do. The problem is as an author you're not getting predictable performance. Imagine making a tweak and then rendering engine X or Y no longer infers the animation and now you have a large performance regression.
However, most of the CSS transforms I write are pre-defined in the CSS and activated by simply adding/removing classes using JS. This seems like something the browser should be perfectly capable of predicting without my help, since the JS isn't actually mutating the CSS.
Automatic preparation would be possible for transforms/animations that are applied in pseudo selectors such as :hover, but not in any other cases.
I was one of the Blink team's initial "reference customers" within Google for this, and we were pretty adamant that if there's any jank at all between when the user taps on a link and when the transition starts firing, it was a no-go for us. We've had launches canceled because they added to user-perceived latency instead of subtracting from it.
The reason it's different from cold CPU caches is that all these sources of jank can cause a user or potential customer to say "Nope, I want a native app that loads instantly." You should care about sources of latency that are perceptible to the user, not ones that are invisible. We ran a number of tests and found that the time required to render a texture to GPU VRAM was user-perceptible on mobile devices.
What this property does is lets us continue doing the same thing, but in a way that the intent is clear ("I'm using this property to make the animation on this element more performant" vs. "I want to add a transform that does nothing"). Furthermore, it lets the browser decide if it wants to add any optimization, and it can decide which sort of optimization is best.
While it would be nice if we didn't have to do this hinting at all, the fact of the matter is that it's hard for the browser to predict what will happen on the page in the future, and we're already having to do this (just in the cryptic null transform way), so it's nice that the web platform is letting us do it in a standardized way that communicates our intent clearly.
[0]: http://aerotwist.com/blog/on-translate3d-and-layer-creation-...
That is a perfect encapsulation of the "OK-ness" he's talking about. Yeah, it works just fine. Yeah, the web doesn't "require" a smart graphics processing engine, it probably didn't "require" videos or the canvas or CSS transitions at all. But "really good" modern platforms have these capabilities, and IMO there's nothing wrong with wanting or trying to push the web to be as good a platform as possible, and it is frustrating (but understandable) that there is so much legacy baggage "holding it back."
One should not assume that all platforms have these capabilities!
Given the constraints, having to add some hints doesn’t seem all that bad to me.
As the article notes, for all but trivial examples, these are likely to be added via Javascript. The static CSS file with ":hover" and ":active" was jsut an example.
In this basic example,
.element:hover {
will-change: transform;
}
.element:active {
transform: rotateY(180deg);
}
it seems very predictable. I don't get why the browser couldn't guess (with some heuristics) what to prepare.Also I feel we will misuse this feature and tend to make the performance worth than if the browser would detect what are the "will-change"s.
It seems to me to know that a rule along the lines of "might-add-class: foo;" would get us back most of that separation of presentation and content.
<section class="animatable" will-change='transition'></section>
section.animatable:active {
// someanimation
}
The above makes more sense to me than the following: section.animatable {
will-change: 'transition';
&.animating {
// Some animation
}
}Thus, the suggestion to use the property through javascript so that it can be applied and then removed. That just seems totally weird to me.
only WebKit and Firefox Nightly builds have implemented [it]
[...] There is also an intent to ship in Blink too.
(Opera is based on Chromium that uses the WebKit fork "Blink")Offtopic: first time in years, I see the opera.com website. There was a lot of useful information in their blog posts, when they still worked on their own browser engine.
Also, especially among web developers there are many people who barely know what they are doing, so it's a good idea to comprehensively cover the context (I know it helped me, since I'm mostly a back-end developer who does some front-end on the side).