How to decide whether to use CSS property "will-change" - css

Recently I've dived into the topic of CSS animations and transitions.
I'm aware of the CSS property will-change which could be used to give a hint to the browser, that the element will change in the near future (which could improve the rendering performance).
There are several examples where developers are using will-change to improve the performance, e.g.:
https://www.android.com/
https://www.cube.eu/
https://www.mrsandmr.com/
But the docs clearly state, that:
Warning: will-change is intended to be used as a last resort, in order to try to deal with existing performance problems. It should not be used to anticipate performance problems.
So, what are essential considerations to make, whether to use will-change - or not?

DigitalOcean made a great post about this that I would highly recommend you check out.
https://www.digitalocean.com/community/tutorials/css-will-change
As someone else stated, will-change creates a new 'layer' in the browser, so to speak. If you have multiple animations or transitions under a specific parent element, it may be a good idea to assign will-change to that parent element while leaving the animated child elements with their standard animations/transitions.
Edit: I should point out that adding will-change in multiple places will increase your paint time as someone else mentioned, which will decrease your site load speed.

Related

How to use and how works CSS' will-change property?

I found CSS will-changeW3.org docs, MDN docs property (which already works in Chrome and is partiali supported by Firefox and Opera) but I'm not really sure how it works.
Does anybody know something more about this mysterious thing?
I have just read that it allows browser to prepare for calculation over the element in the future.
I don't want to misunderstand it. So I have a few questions.
Should I add this property to the element class or its hover state?
.my-class{
will-change: 'opacity, transform'
}
.my-class:hover{
opacity: 0.5
}
.my-class:active{
transform: rotate(5deg);
}
OR
.my-class{
...
}
.my-class:hover{
will-change: 'opacity'
opacity: 0.5
}
.my-class:active{
will-change: 'transform'
transform: rotate(5deg);
}
How can it increase a browser performance? Theoretically, when CSS is loaded, the browser already "knows" what will happen with each element, doesn't it?
If you can add any good example illustrating how to use it efficiently, I will be grateful :)
I won't copy paste the entire article here but here's a tl;dr version:
Specifying what exactly you want to change allows the browser to make better decisions about the optimizations that it needs to make for these particular changes. This is obviously a better way to achieve a speed boost without resorting to hacks and forcing the browser into layer creations that may or may not be necessary or useful.
How to use it:
will-change: transform, opacity;
How not to use it:
will-change: all;
.potato:hover {
will-change: opacity;
opacity:1;
}
Specifying will-change on hover has no effect:
Setting will-change on an element immediately before it changes has
little to no effect. (It might actually be worse than not setting it
at all. You could incur the cost of a new layer when what you’re
animating wouldn’t have previously qualified for a new layer!)
I spent some time on searching how will-change property works and how we use it. I hope, it will be useful summary. Thanks everybody for answers.
1. Layers Hack / Null Transform Hack
In 'ancient times' (like 2 years ago) somebody discovered that you can draw your CSS animation faster.
How does it work?
If you add transform: translateZ(0) to a css selector, it will force a browser to move the element with this selector to the new compositor layer. What is more, it will increase performance (in most situations, use powers of GPU instead CPU) read more here.
2. Bye Bye hacks, welcome "will-change:"
Probably, it's too early to say bye bye to Layer Hack, but this time will come shortly.
The new property will change appeared in specs of CSS and will be a great successor of layer hack.
3. Browser support
For now, it's available in Chrome and Opera and partially supported by Firefox as well.
4. How to use it properly
Don’t use will-change anywhere in your CSS until after you will
complete implementing your animations. Only then should you go back to
your CSS and apply will-change. More
This is probably the most valuable advice that you can get.
There is no point to use it straight before an action begins by e.g. adding it to the :hover state of a selector. Because browser will not have required time to prepare optimization before change occurrence. Browser will need approx. 200ms to apply optimization, so for example it is better to add will-change to a element when a parent element is on hover state. More
Example:
.parent:hover .change{
will-change: opacity;
}
.change:hover{
opacity: .5;
}
You need to use it really sparingly. If you want to optimize everything, the results will be opposite than expected ones. will-change forces browser to keep optimization turned on and reserve resources like memory for changes in the future which may never happen. It is recommended to turn off will-change afterwards, when it is not necessary anymore e.g. when the animation is finished.
You can do it easily using JavaScript document.getElementById('my_element_id').style.willChange = off;
Now with the help of CSS you can do various of animations, and sometimes this animation becomes a bottleneck for a CPU. So instead of doing this job on a CPU, it would be nice to use GPU for this task. And not so long ago people started to use a trick to do this for a 2D transformation by doing something like:
.accelerate {
-webkit-transform: translate3d(0, 0, 0);
}
This made a browser think that it is doing a 3D transformation, and because all 3D transformations are using GPU, this will offload CPU. This looks hacky (because in fact it is) and will-change property is going to change this by informing the browser to look out for changes in the future, and optimize and allocate memory accordingly.
Based on W3C draft,
The will-change CSS property … allows an author to inform the UA ahead
of time of what kinds of changes they are likely to make to an
element. This allows the UA to optimize how they handle the element
ahead of time, performing potentially-expensive work preparing for an
animation before the animation actually begins.
Good idea to use will-change is to let the browser know in advance what changes on an element can be expected. This allows the browser to make the proper optimizations in advance, which leads to quicker rendering.
This information was taken from this excellent explanation about will-change property. The article has additional example when it is nice to use it and when it is useless or even detrimental
As far as I know...
It is an alternative for translate-z:0.
I dont know about hover, but afaik its best to use it on properties that are being changed gradually by JS, changing opacity, position during scrolling etc.
This property shouldnt be overused, especially on phones, tablets, using this on too many
elements can cause performance issues.
It is encouraged to remove/turn-off this property by JS when it is no longer relevant.
So example usage would be applying that at some point of scroll, with scrollTop:400, then gradually animate opacity and at lets say scrollTop:500, disable will-change again.
Source: shoptalkshow podcast - they mention this article - https://dev.opera.com/articles/css-will-change-property/ - which is probably better source of info than my post :D
Thanks to will-change CSS property we can declare to the browser our intention to change an element’s:
contents,
scroll-position,
various tag properties like transform or opacity,
declare multiple values at once: will-change: transform, opacity, top;
or removing the special optimization, using the value auto.
This allows the browser to schedule the use of GPU/Hardware Acceleration instead of the standard CPU usage.
But we have to use it wisely. We need:
to give this to an element that will change,
assign it early early enough before the change occurs,
remove it from the element that has changed and will not be anymore.
Note from MDN web docs:
will-change is intended to be used as a last resort, in order to try to deal with existing performance problems. It should not be used to anticipate performance problems.
They also mention that if we decide to use the will-change property, we should not set it rigidly in the CSS style sheet, because it probably will cause the browser to keep the optimization in memory for much longer than it is needed... It is better to use this property directly from JavaScript (there is also an example with that).
A good additional resource to explore this topic deeper: Everything You Need to Know About the CSS will-change Property.
I'm using react-window package and there is a "will-change: transform;" property on the outer div. The package dynamically render parts of a large set of data in the visible view according to the scroll position, for example only render 10 items of a 100000 length list. Without the will-change property, the list will be blank when scroll. It shows better on slower cpu.
You can see the example here: react-window-fixed-size-list-vertical. Open the developer tool , uncheck this property in styles, slow down the cpu in Performance tab and scroll the list rapidly.list blank between renders
There is also a discussion.https://github.com/bvaughn/react-window/issues/47
The best solution for me:
transform : translate(calc(-50% + 0.5px), calc(-50% + 0.5px));
But, this solution has trouble with calc in ios safari in a fixed position can cause high battery consumption

Is there a pure CSS workaround for multiple browser prefixes?

The more and more we venture into the wonderful world of CSS3, the more and more we all get annoyed by the fact that these features require a MASSIVE amount of browser prefixes to allow compatibility with some older browsers. This problem becomes quite apparent even for small sites, where we need 4 or 5 CSS properties for the exact same effect. A common example would be the background property for gradients.
I know that there are scripts that can help with this issue, but before resorting to those, is there a pure CSS fix that would allow you to work around the prefix issue, or at the very least, some sort of method to keep the extra amount of typing to a minimum? That is, combining things, shorthand, whatever. CSS files can easily double with CSS3-rich content.
I totally agree to the excessive code need to accomplish the same effects in CSS3 but that issue is on the browsers side as other comments stated.
One design practice/tool/technique i think best to follow is using LESS when writing css.
I see the The possibility of over coming this issue (for now) with it. Checkout it out here. http://alittlecode.com/handling-multiple-css3-transitions-with-a-less-mixin/.
If you are not sure what is LESS then check this out - http://www.lesscss.org/.
Yes it is pure CSS from my perspective, but no as stated before, it won't reduce the size of files.

Position element relative to cursor using purely CSS3

How can I position an element--such as a complex cursor unsuitable for the cursor property--relative to the mouse position using CSS 3?
I know how to do this with JavaScript, but it appears too choppy; I'd rather use CSS and fall back to jQuery when support is lacking. (Event when I work with elements directly and bypass jQuery, it's too slow.)
JavaScript can be used to make preparations and such, if necessary. While not preferable on principal, JavaScript is acceptable as long as it isn't in charge of updating the element every time the mouse moves.
I kindly request that answers not be used to reason why this cannot be achieved, as CSS is rapidly evolving, and the future potential of solving this problem may change. Feel free to speculate all you want in comments.
I am using Sass (SCSS) with Compass and jQuery, along with my own JavaScript framework.
As of today, CSS does not support positioning elements relative to mouse pointer.
So if you're not satisfied with cursor: url('pointer.cur') (thanks #ilya-streltsyn), then JavaScript is the only solution for you.
Or maybe you shouldn't do that in the first place. When an SWF uses a custom cursor, this freaks me out a lot.

What are the downsides of using text-shadow for font anti-aliasing?

I found this method:
.fontSmooth { text-shadow: 0 0 1px rgba(51,51,51,0.5); }
and it works perfectly! but in some places it is said that it's a bad solution (with no further explanation), why is that?
It'll probably work, though there are two main issues.
First off, as coreyward originally pointed out (though he apparently deleted the post after one downvote), the text-shadow property is part of an ever-changing HTML5 spec. It's relatively new on the scene, and its syntax and implementation are liable to be extremely different across browsers and may change even further over the next few years.
The more short-term issue here, though, is that blurring a text shadow takes serious work on the part of the browser. It's fine for maybe headers and the like, but if you're planning to apply this to your whole page, please bear in mind that it will run much slower in older computers, and even scrolling up and down will be laggy. So, be careful in deciding to what extent such smoothing is appropriate.
I'd also like to point out that, if the user hasn't enabled anti-aliasing system-wide, it's quite possible that the user doesn't want it. It's just kinda silly to use CSS tricks to override a platform-level setting.
Normally you should not try to fix that kind of things that are responsibility of users-side. It might work well under certain conditions, but as shadows were not meant for that, you cannot be sure its visual impact on different conditions.

Best practice for CSS3 backgrounds and support for older browsers?

My colleague and I are having a tough time deciding on a best practices approach for ie6, ie7 support for a site we're building. The site is for an older crowd, so not supporting these browsers is out of the question.
At the same time, we're trying to start incorporating modern coding practices into our work so we can get practice and fully understand capabilities. A specific area I want to touch on with you guys is handling fall backs for CSS3 backgrounds.
We have 2 choices here, if we're to use CSS3 backgrounds and not add extraneous wrapping tags for backgrounds:
Use :after, :before etc. pseudo elements for adding multiple backgrounds to elements. (this is the choice we've made for now)
Use CSS3 multiple background specifications
This produces more elegant markup and is certainly a step in the right direction. But what about browsers that don't support these features?
Modernizr.js tells us to check for specific support and then write fallbacks:
Modernizr.load({
test: Modernizr.geolocation,
yep : 'geo.js',
nope: 'geo-polyfill.js'
});
However, we're not given much guidance on the actual fallbacks for specific features. So, in the case of something like CSS3 backgrounds, what would be an effective fallback strategy?
Would we (for example) use jQuery to wrap those extra tags we need (ie btn-container, nav-container, etc.) around nav items, buttons and containers in order to have extra elements to add style attributes to?
About the CSS3 multiple backgounds and/or background gradients I think there is an approach better than those you proposed: CSS3 Pie.
This way you will be able to use all those nice effects also in IE6, 7 and 8 (including also border-radious) without any JavaScript intervention.
1. Fail gracefully. Certain complex elements can be hidden with CSS and revealed upon page-load with JavaScript depending on the browser as one example.
2. Conditional style-sheets or JavaScript fixes. Spend a lot of time fixing each problem in each browser and write a style-sheet just for it. Also, you could try various JavaScripts that claim to bring older browsers into compliance. I've tried this JavaScript but it seemed to conflict with jQuery. CSS Pie is another option to bring rounded corners to older browsers.
3. Ignore older browsers. Do nothing special for older browsers. People on IE6/7 already see the world differently than everyone else. Alternatively, do nothing special for older browsers but actively avoid overly complex functions & features. Optionally, you can add a nifty "upgrade notification" message with little effort.
Would we (for example) use jQuery to wrap those extra tags we need (ie btn-container, nav-container, etc.) around nav items, buttons and containers in order to have extra elements to add style attributes to?
That is certainly one valid fallback approach. Depending on the design and the elements in question, though, you might find that simply supplying the primary background is enough to yield a decent-looking and perfectly functional, though not visually identical, component.
"Supporting" older browsers shouldn't always mean "taking great pains/writing tons of extra code to insure a near visual match." It is difficult but not impossible to ramp up a QA team so that they understand the concept of Progressive Enhancement as it can be applied to aspects of pure visual presentation.

Resources