New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Starred by 41 users

Issue metadata

Status: Fixed
Closed: Apr 2016
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 2
Type: Bug-Regression

Blocked on:
issue 521364
issue 597758

Sign in to add a comment

Issue 596382: Inconsistent image raster at small scale changes

Reported by, Mar 21 2016

Issue description

Chrome Version       : 49+
URLs (if applicable) :
Other browsers tested:
  Add OK or FAIL, along with the version, after other browsers where you
have tested this issue:

What steps will reproduce the problem?

What is the expected result?
Smooth animation, as in v48

What happens instead?
See above

Please provide any additional information below. Attach a screenshot if
Showing comments 29 - 128 of 128 Older

Comment 29 by, Mar 24 2016

I filed about using the <img> tag backend optimizations for background-image, which would have the side effect of making this look better without fixing rasterization problems. But is maybe (probably?) a harder thing to merge to M50.

Comment 30 by, Mar 24 2016

Some preliminary notes:

1) only occurs with software rasterization, which may explain why the issue is reported against specific GPUs (when Ganesh is disabled/blacklisted?)

2) @danakj how did you capture the SKP and whack the matrix?  I wouldn't put too much faith in the Skia Qt debugger being accurate, or are you talking about the paint debugger build into FrameViewer/Timeline?  Depending on how you've captured the SKP, it may not reflect what is really going on in the browser (IIRC printToSkp bypasses vmpstr's image_decode_controller and relies on native/lazy decoding).

3) as an experiment I disabled the image decode controller (hack pasted below, I'm sure there's a better way), and the jankiness went away; the transition is still not as smooth as the layer/accelerated version, but most of the geometric instability seems to be gone.

--- a/cc/playback/
+++ b/cc/playback/
@@ -309,6 +309,7 @@ void DisplayItemList::GetDiscardableImagesInRect(
 bool DisplayItemList::MayHaveDiscardableImages() const {
+    return false;
   return !image_map_.empty();

Still looking, but based on #3 I'm suspecting a problem with CC's image decode controller at this point.

Comment 31 by, Mar 25 2016

> 2) @danakj how did you capture the SKP and whack the matrix? 

I captured it from a trace, by dumping from the DisplayList dot in the frame viewer.

I played with the matrix by using the zoom feature in skia debugger. The tracing frame viewer was not showing anything transformed, and uses a different path entirely anyways, so I'd trust it less if it was working I guess.

I thought about image decoding, but I'm not sure what decode timing would have to do with the pixel output correctness though, maybe it does have something?

> 3) as an experiment I disabled the image decode controller (hack pasted below, I'm sure there's a better way), and the jankiness went away;

Uh.. huh ok! maybe it's when we choose to decode at different scales? vmpstr@ please have a look and confirm/disprove :)

Comment 32 by, Mar 25 2016

Oh, FWIW this problem happened since M49, but image decode controller is new right? But.. Idk how this is all interacting.

Comment 33 by, Mar 25 2016

Disabling IDC certainly seemed to improve the transition for me (maybe someone else can confirm I'm not hallucinating), but you're right that IDC is not present in M49.  We did land some Skia scaling fixes in the meantime, maybe that could explain why ToT%IDC > M49?

Here's my bedtime theory (too late to check now, documenting mostly for my fresh Friday self):

a) Skia's uses Mitchell filtering for scales > 1 and mipmaps + lerp for downscaling

b) this means we're switching scaling algorithms around scale == 1.

c) which is OK for normal transitions (crossing scale == 1 once/rarely)

d) but IDC decodes to the closest int size, and then post-applies the residual scale

e) which can be > 1 or < 1 depending on CTM/rounding

f) this means we're potentially switching between Mitchell/mipmap scaling *every single frame*

If this turns out to be the cause, one possible fix might be to the lower filter quality when applying the residual scale (kLow_SkFilterQuality => force bilerp for both upscaling/downscaling).

Comment 34 by, Mar 25 2016

Most of the above holds, but IDC is already using kLow_SkFilterQuality when drawing prescaled images - so f) is incorrect.

After more experimentation, I'm seeing at least 3 factors affecting the animation smoothness:

1) IDC
2) whether or not the scaled image gets its own composited layer
3) whether or not we're upscaling

I mentioned #1 before.

For #2, the presence of a matrix3d pushes the image into a separate layer and I suspect we're hitting something like  (the layer subpixel phase is not communicated during rasterization and we end up post-filtering the scaled image as the layer is composited).

#3 comes into play after removing the other two variables: when upscaling using kHigh_SkFilterQuality, Skia does something similar to IDC: selects the closest int-size for dest, scales to that size *ignoring subpixel phase*, then applies the residual transform using a bilerp.  So we're essentially filtering twice: once with a HQ bicubic filter producing a cacheable int-sized bitmap, and a second time with bilerp to map this rounded scale to the actual dest matrix.  It's unclear to me whether this approach could ever yield smooth transitions (scaled size snaps from one int to another and bilerp may not compensate for discontinuities, particularly when applied with a different subpixel phase?).  I'm also starting to think this is the same fundamental problem as IDC: we're scaling to int sizes ignoring subpixel positioning (for caching purposes), and then bilerp as a second pass to apply the residual transform.

(#3 is likely what danakj was experiencing, using scale > 1 and HQ)

I've updated the two tests to also include a SVG scaled version of the image, as a way to isolate #2 (SVG scaling doesn't force a composited layer):


(note: the scale for this test is always < 1, so we're not hitting #3)

With IDC disabled the SVG animation looks perfectly smooth to me, while the background-image is significantly blurrier and with some jank.  I blame the difference on #2.


With IDC disabled, the SVG animation is smooth until it gets to scale > 1, when it start hitting #3

So AFAICT there's a lot going on, and I don't think this is fixable in time for M50 (I'm not even sure what the fix would look like short of forcing kLow_SkFilterQuality and scaling directly into dest - but that conflicts with non-animated quality expectations and the IDC architecture).

Comment 35 by, Mar 25 2016

@fmalita: how about using kLow_SkFilterQuality during the animation as a stop-gap for M50? We already do this in software mode via ImageQualityController (though just for the performance reason).

Or would scaling directly also into dest be required? Not sure what that would entail.

Comment 36 by, Mar 25 2016

In terms of getting it into M50, is there any way to just revert to the way things were handled before Chrome 49? This regression seems like a pretty big deal for a lot of people (sprite sheets are very common). I'm sure it's more complicated than just rolling back some code, but anything you can do to get this resolved in the next release would be really appreciated.

Comment 37 by, Mar 25 2016

@chrishtr I can try to see if that helps, but yes, for optimal results I think we need to a) avoid double filtering (meaning we scale directly into dest with full CTM visibility) and b) use kLow (or kMedium - that should also produce continuous transitions)

Comment 38 by, Mar 25 2016

@#36 that would regress a lot of other sites :/

Comment 39 by, Mar 25 2016

Re 37: ok can you try it and let me know?

Comment 40 by, Mar 25 2016

I agree with comment 34, #3. I also see the same behavior with or without IDC enabled. One thing that helps is instead of doing snapping to the nearest int, we can always round up.

Currently we have this:
We scale to size X, and bilerp up to X + 0.5
The next moment, we scale to size X + 1, and bilerp down to (X + 1) - 0.5

If we do this instead, then it seems to produce smoother results:
Scale to X + 1, and always bilerp down to (X + 1) - fraction.

So instead of smoothness jump happening at 0.5 boundary and bilerp switching from upscaling to downscaling, it would happen at integer boundary and we'd always be bilerping the scaled thing down to the correct subpixel level.

Anyway, I have this patch, so maybe someone can confirm that it looks better?

Switching animated images to use low filter quality would work as well (that's what seems to be happening with the img tag, since it's going through a different layer).

Comment 41 by, Mar 25 2016

Re #40: it's better but still not perfect.

Comment 42 by, Mar 25 2016

Yeah I think to get perfect we either have to scale to the precise subpixel size or to use medium/low filter quality for these cases.

Comment 43 by, Mar 26 2016

Blockedon: 521364
@vmpstr yes, we do get int-snapping + double-filtering for HQ with/without IDC but for exclusive reasons:

  - with IDC, IDC itself does it while Skia gets out of the way (it's not caching the scale result)
  - without IDC, Skia attempts to cache the scale result and does pretty much the same thing

Damned if you do, damned if you don't :)

One difference is that Skia only does this for HQ upscaling, while IDC also does it for HQ downscaling IINM.

@chrishtr: lowering the filter quality does help - but only with issues #1 & #3 in c#34 (neither IDC nor Skia tries to cache/prescale in LQ mode).  We're still left with the composited layer subpixel artifacts (#2) though.

The easiest way to test is using image-rendering: -webkit-optimize-contrast; which forces kLow_SkFilterQuality in Blink.

* Original test, with a LQ column:

Notice that the SVG <image> is now as smooth as the <img> version, but background-image has some blurriness issues.  The difference is that background-image gets its own composited layer => so we're hitting  issue #2  (if you look closely, when the animation settles for a sec and we drop the layer, the image gets noticeably sharped as it snaps back into the base layer).

* JS-only scale test, with a LQ column:

Again, the SVG version is as smooth as <img> (for both scales < 1 and > 1), while background-image suffers from #2.

* JS-only scale test with a LQ column, using matrix instead of matrix3d:

Finally, all three versions look smooth with LQ - because (unlike matrix3d) matrix doesn't force a composited layer for background-image.

So we have a potential author workaround:

  - use transform: matrix instead of transform: matrix3d
  - use image-rendering: -webkit-optimize-contrast

(the first part is a bit fragile: in my testing, background-image layerization appears to also depend on other factors/elements, not just on matrix-vs-matrix3d)

As far as the Chrome fix goes, I think this reinforces our initial thought: use low or medium filter quality for images with animated transforms.  And deal with issue 521364.

The tricky part in my mind is detecting non-declarative/JS-driven animations.  Maybe some of CC's logic removed in could be reused for this purpose?  Or maybe IDC could somehow detect/help with this?

Comment 44 by, Mar 28 2016

Labels: OS-All

Comment 45 by, Mar 28 2016

A friendly reminder that M50 Stable is launching soon! Your bug is labelled as Stable ReleaseBlock, pls make sure to land the fix and get it merged into the release branch by Apr-5. All changes MUST be merged into the release branch by 5pm on Apr-8 to make into the desktop Stable final build cut. Thanks!

Comment 46 by, Mar 28 2016

> The tricky part in my mind is detecting non-declarative/JS-driven animations.  Maybe some of CC's logic removed in 
> could be reused for this 
> purpose?

The logic there was if it ever animates (changes scale) once, consider it animating forever.

Comment 47 by, Mar 30 2016

Yeah, that's a pretty big hammer.  I have an experimental hack based on that idea, clamping the filter quality to kMedium during scale "animations":

It helps (not with problem #2 though), but it feels wrong on several levels.  Someone familiar with CC layer transforms/animations can probably figure a better place to implement the heuristic.  Ideally it should also involve an expiration timer (similar to Blink's ImageQualityController) to inval & re-raster with HQ when the scale stops animating.

Comment 48 by, Mar 30 2016

> Someone familiar with CC layer transforms/animations can probably figure a better place to implement the heuristic.

I think only blink can make any kind of guess (if it can even? based on RAF maybe?). CC just gets a transform set on it each frame.

Comment 49 by, Mar 30 2016

I really appreciate all the effort that has gone into researching this issue. 
I have to admit that most of the tech talk is way over my head.

However, the author-workarounds seem less than ideal

- use transform: matrix instead of transform: matrix3d

very likely that 3d and scale will be animated at same time

  - use image-rendering: -webkit-optimize-contrast

I saw improvement with this setting but it doesn't seem right that authors should need a vendor-specific setting just to get one browser to behave properly for one type of animation. (safari, firefox, edge have no problem)

I'm not sure if it helps but the performance is greatly impacted on larger background-images severely reducing frame-rate.

Here is a video:

<img> looks great:
background-image bad:

Thanks again for all the effort. Very impressed with the attention this is getting.

Comment 50 by, Mar 30 2016

Re comment 49:

1. Using image-rendering: -webkit-optimize-contrast is equivalent to use image-rendering: crisp-edges, which is not prefixed. Blink has not yet implemented the unprefixed version. Controlling 

2. The workaround suggesting non-3D matrices is just until issue 521364 is fixed. We're not claiming this is the end of the bug.

3. image-rendering: -webkit-optimize-contrast will make much faster because it uses a low-quality filter which is much faster. In that example the quality of the image rendering
looks pretty good to me.

Comment 51 by, Apr 1 2016

Blockedon: 597758
Update: even if issue 521364 is fixed according to my plan outlined in that bug, animating with 3D will have subpixel blurring issues. And animating images will have
jitter issues as indicated in this bug. The latter can be addressed by  issue 597758 , which
I should fix also.

Comment 52 by, Apr 3 2016

Comment 53 by, Apr 4 2016

M50 Stable is launching very soon! Your bug is labelled as Stable ReleaseBlock, pls make sure to land the fix and get it merged ASAP. All changes MUST be merged into the release branch by 5pm on Apr-8 to make into the desktop Stable final build cut. Thanks!

Comment 54 by, Apr 5 2016

Labels: -M-50 M-51
Moving to M51, this will not be done in time for M50.

Comment 55 by, Apr 21 2016

Labels: -Pri-1 Pri-2
Status: Fixed (was: Assigned)
We ended up reverting the change that caused this bug. The change was merged into
Chrome 50. The animations you are testing with should now have their original

I'm going to close this bug, but please check out issues 521364 and  600867  for
future changes.

Comment 56 by, Apr 21 2016

I just tested the demos I had provided in 50 and I'm very pleased with the results. 
Big thanks to all that devoted so much effort. I know a lot of people will be happy!

Comment 57 by, Apr 21 2016

Great, glad to hear it.

Comment 58 by, Sep 19 2016

The bug is back in 53.0.2785.116 Win7.

Comment 59 by, Sep 19 2016

We re-launched the change, but this time added an easy way to opt out of it by adding
will-change: transform to your elements. See:

I reached out to a number of developers about it in advance. My apologies if I
missed reaching out to you.

Comment 60 by, Sep 19 2016

So once again we have to trawl through older sites to update everything.
I don't believe I'm alone in thinking this wasn't broke and so why the hell 'fix' it?
Please - 'do no harm...'

Comment 61 by, Sep 19 2016

No matter which way this goes some sites are broken. At least now sites aren't randomly blurry, and have the ability to get the behaviour they want. So, sorry this isn't a case that nothing was broke.

Comment 62 by, Sep 19 2016

The flicker is the issue. I have found will-change to have unusable effects if the scale is too extreme for it.
Everything was fine before v51 I believe so these are issues that were created by subsequent changes.

Comment 63 by, Sep 19 2016

In your use case, I'm sure everything was fine before Chrome 51. We decided
to make this change because it fixes a large number of sites, and this time has
an easy to implement opt-out for sites that want the old behavior.

I sympathize that you need to update a number of existing sites to retain good rendering
for your use case. Sorry about that. We spent a lot of time going through alternate approaches,
and this was the best one.

Comment 64 by, Sep 19 2016

Possibly I missed something earlier up on this lengthy thread but what was the issue that need the attention in the first place?

Comment 65 by, Sep 19 2016

It looks like the new behavior samples the image at its initial transform state instead of at its native (100% scale) size, leading to much blurrier content if there's an initial reduction in scale. For example, if there's a scale(0.4) initially, and then one scales to "1", it's quite blurry even though it ends up at the native size. I'd expect that it'd sample at either the native size or the initial transform, whichever is BIGGER. Am I misunderstanding something? 

I've gotta admit, this new behavior strikes me as very undesirable.

Comment 66 by, Sep 19 2016

The core issue we fixed is not recorded in this bug. Your bug was an
side-effect of the change. The issue we fixed can be demonstrated via this

Before Chrome 53, the "No longer blurry after proposed change" text was also
blurry, and developers would have to do a lot of work to force it to stop being
blurry. In some cases it was nearly impossible to force it to be crisp. This
affected a number of sites, including many that accidentally triggered it. We
fixed it by forcing re-raster by default when you change the scale of a composited
layer, unless will-change: transform is specified.

Comment 67 by, Sep 19 2016

Re comment 65: are you talking about an example with will-change: transform?
Please post the example so we can have the same frame of reference.

Comment 68 by, Sep 19 2016

I think I was referring to the same effect comment #65 mentions.
An element that started the animation with .1 scale retained that blurred appearance at the end of the animation.

Comment 69 by, Sep 19 2016

Yes, if you add  will-change: transform to the animation referenced above, you should see what I mean. Image is very blurry at the end even though it's scale(0.7). I'd expect that anything at or below scale(1) would be razor-sharp.

Comment 70 by, Sep 19 2016

Please, fix this problem on the next version if possible. :)

The use of "will-change" is pre-caching pixel asset. So scaling it from < 1 to 1 will make it pixelated.

use -webkit-perspective: 1000; to avoid the glitching of slowly scaled assets.

Comment 71 by, Sep 19 2016

Re comment 69: you're running into the problem that will-change: transform
never rasters on scale change. We used to have a heuristic to re-raster at
scale 1 (i.e. transform(1)) if scale ever changed. Your options are:

a. start the animation at scale 1
b. More generally: remove (if needed) and re-add will-change transform after a requestAnimationFrame whenever you want it to raster at the current scale.

Comment 72 by, Sep 19 2016

You can remove will-change from the element when you want it to reraster (maybe every 2x scale change or so, or maybe when it goes from <1 to >=1, whatever heuristic you want).

Comment 73 by, Sep 19 2016

(Sorry, remove it for a single frame then put it back to continue not rastering every frame.) This is described in also.

Comment 74 by, Sep 19 2016

WOW, this is very difficult to accept as an "improvement" in any way. Do we really have to mess with removing will-change, letting a tick go by, then adding it back during an animation to make things look acceptable? And this is what the Chrome team thought "enhanced" the most sites in the wild (or caused the fewest problems)? 

So would it be accurate to say that the heuristic that Chrome previously implemented natively to make things look good in the most cases has now been removed and delegated to developers for them to do manually via JavaScript? I'm kinda hoping that I misunderstood.

Comment 75 by, Sep 19 2016

You are correct. We replaced a heuristic that works some of the time and has
unrecoverable quality problems in many cases with a setup that looks good by default and works all of the time with a small amount of additional effort by
developers of animation libraries (such as you).

Comment 76 Deleted

Comment 77 by, Sep 19 2016

Wonder what changes we'll need to make to accommodate the next version?
How exciting...

Comment 78 by, Sep 20 2016

I'm not sure "a small amount of additional effort" accurately describes what this offloads to us. 

This feels VERY hacky to me, almost like an abuse of "will-change". Functionally, it's making it act more like "immediately-rasterize-at-current-state". Is that what the spec dictates? (Doesn't look like it to me). Have all the implementation details been worked out and agreed upon by the major browsers? It's a little scary to work with this because it feels so unpredictable. The sands could shift beneath us (as today's resurfacing of this issue proves).

Today, it happens to rasterize at current state in Chrome because that's what the Chrome team decided made sense to them; Maybe Firefox thinks "will-change" should have a completely different behavior to "optimize" performance/display. Maybe Edge's implementation directly conflicts with the others. Yikes! Then library authors are left with yet another whack-a-mole scenario, adding various conditional logic, user agent sniffing, etc. in order to coerce the desired behavior consistently across browsers. Extra code that slows things down, bloats things unnecessarily, etc. "a small amount of additional effort"? Due to implementations like this, it sounds like will-change could actually be the source of a lot of headaches for animators (the very people it was meant to help). 

At the very *least*, I'd suggest ensuring that the rasterization is done at or above native size. So in the example above, if the css is initially scale(0.4), it would capture the raster image at scale(1) anyway, thus when things animate up to 1 they're nice and crisp. After all the whole point of will-change is to make animation look **better**, so shoving a natively-sized raster image to the GPU/compositor would probably make the most sense in most scenarios to drive decent animation performance and aesthetics. Agreed? The current behavior assumes that things will either always be scaled  DOWN (not up) or that the developer will implement logic to keep toggling the will-change value to trigger re-rasterization (which would hurt performance!)

Comment 79 Deleted

Comment 80 by, Sep 20 2016

Sometimes it feels as if both Apple and Google are deliberately making animation for the web more difficult, as if strangling the obvious appetite for animation and bringing back the static web of yore, will make all their devices look better.
It's hard enough explaining to clients why we can not longer achieve animation effects that we could easily do 10 years ago without having to explain why their ads suddenly break from one week to the next!
Surely improving one metric at the expense of another is not improvement at all.

Comment 81 Deleted

Comment 82 by, Sep 20 2016

Does this also mean that the way we've gotten GPU-acceleration in the past (by using a matrix3d() or translate3d()) no longer works? The only way to ensure that something gets its own compositor layer is by using will-change? Again, I really hope that's not the case - that would certainly negatively affect a LOT of sites.

Comment 83 by, Sep 20 2016

Here's a failed attempt to toggle will-change at the start of the tween right after temporarily setting transform to native size to get clean rasterization:

Expected behavior: rasterization would happen at native size, getting rid of the blurriness

Actual behavior: rasterization happens at scale(0.4) and is quite blurry.

Please advise. If you say that we must allow a tick to go by before proper rasterization at the just-set value, that will be a deal-breaker for a bunch of reasons (I can elaborate if you need me to).

Comment 84 by, Sep 20 2016

This video shows what we're seeing (and seems to make a pretty strong visual case that this "improvement" is likely a step backwards for Chrome):

Comment 85 by, Sep 20 2016


Thanks for the example and your patience. Please be sure that we are in no way trying to
break any content. Good quality rasterization and performance with compositing is a very
hard problem, especially considering the declarative nature of the web, where explicit control
of rendering is (on purpose) not present.

Here is a tweak of your example that I think looks good. I think you will find that it is a tiny
bit blurrier than the "regular <img>" version. If desired, you can also force a frame of raster
at the end of the animation when it stops moving. While it's animating size, it's often desirable
to have some blur because it can look nice.

This demo re-rasters the content whenever the scale changes more than a threshold (I chose 0.1).

Here are some more answers to your questions:

1. The triggers for compositing have not changed. 3D matrices and will-change: transform are still
both triggers for compositing.

2. It's required to wait for a tick in order for any changes to CSS to take effect. This is why
your demo in comment 83 doesn't quite work. This is not something special to this feature; it's the
way that the web works. In each frame, javascript can make one or more changes to DOM and CSS. Once
javascript releases control to the event loop, the browser draws a new frame with the new values.
Therefore, making a change to a CSS property and then undoing it synchronously before releasing
control will have no effect.

3. Previously, animating a composited layer's scale towards anything other than scale 1 would end
up blurry. In other words,  was present for all scales except 1, for previous 
versions of Chrome. Now, in Chrome 53, you can do this to any size, either (a) by Chrome's new
default behavior to raster at every intermediate scale, or (b) adjusting the raster at desired
intermediate points according to what you want in order to balance quality with speed. I hope and
think you will find that this unlocks more power for your library.

Comment 86 by, Sep 20 2016

I appreciate the detailed response, chrishtr. I have no doubt your team is aiming to improve the way sites render, not degrade them. We've got the same goal. 

The solution you proposed just isn't workable. We place a **HUGE** priority on performance (because animation is the most performance-sensitive aspect of UX) and when I used your exact code, here's a demo that shows how it performs under pressure:

If the goal of this change was to improve the way sites look/render/perform, this is definitely a step backward for animation. Do you have any other recommended solutions that wouldn't kill performance and require manual analysis on every update (60 times per second)? 

1) Are you sure that 3d values trigger compositing? I just checked and it sure looks like that's not working the way it used to - when a translate3d() is set on an element, it's not being properly layerized. This is a big concern performance-wise.

2) You mentioned that it's necessary to wait for a tick to elapse for any CSS to take effect, and I see what you mean in terms of visually being rendered to the screen itself, but I was talking about lower-level. For example, it's easy to change style.width and then run getClientBoundingRect() immediately and it's accurate using the new value. There are many other properties that work exactly like this - it's not like we need to wait for a tick to elapse before the values are reflected. But I also see your point in that what we're talking about here is purely a visual change, thus it'd be hard for you to isolate just that property and have the browser force an internal render and shuttle that new texture to the GPU/compositor. 

Instead, could you maybe implement some other way to tell the browser at what size/scale to perform its rasterization? For example, element.cacheTransform = "scale(1)" would indicate to the browser that when it does its rasterization, it should do so as if the transform was "scale(1)". It could take the same value as any "transform". This gives developers a lot of control and takes the burden off the browser's heuristics. 

I realize that's probably a much more difficult thing for you to push through since it's introducing an entirely new API, so at the very least I'd reiterate the suggestion I made earlier - rasterize at the native size or the current transform, whichever is BIGGER. I think this will solve a lot of the problems the new behavior introduces. Actually, I think it'd be better to revert to the previous behavior until a really solid solution emerges that doesn't cause so many major issues for animators.

I understand that your team thinks this new behavior is a "fix" (overall), but please talk to animators out there and see how they feel about this. I've heard from quite a few people who see this as a significant problem that needs to be fixed ASAP.

Comment 87 by, Sep 20 2016

Re performance: yes, re-rastering slows things down. The optimal thing to do performance-wise for your
particular case is raster at the final scale and then animate frames without rastering. I know that this
can be tricky to use without showing an initial frame at the wrong scale to the user. (*)

Re your performance test: in practice one should implement several more optimizations on top of what
I showed in the demo in comment 85. For example, in your case there is no reason to raster again once
an element has been rastered at a scale suitably close to 1. Keeping track of the maximum scale it's
been rastered at should be straightforward. Also, the pure JS overhead of the 60fps callback function in this case
should not be a big deal since you have JS running on every frame anyway. Before the current version of Chrome,
we would raster this example twice (assuming you don't delete and re-create the composited layer on every animation
repeat): once at 0.4 and once at 1.0. And if there are 500 such elements, each would get rastered twice.
So this is only one more raster. Is that really too expensive?

Re rastering at the larger of native size or current, whichever is bigger: the problem is that rastering at
native size and then scaling that down with bilinear filters in the compositor to something less than 0.5 or so
will start to loop noticeably bad. Therefore, while the most common desired scale, scale 1 is still a heuristic.

Re #1: yes I'm sure. You can check with the "layer borders" feature of the rendering section of DevTools.
You can provide an example if you like and I will double-check it for you.

Re #2: yes we considered ways to specify raster scale. But it may not be so easy to get it right in terms of
expressiveness, and requires new APIs, as you mentioned, and also to define what raster scale means,
which seems quite tricky in general, especially while not over-fitting to current implementation strategies.
That might happen later on (and you're welcome to participate in standards discussions about it).

Also, we can't easily do the same thing as the getClientBoundingRect() example for the reason you
mentioned, that raster pipelines are not synchronous, and that it's a unclear to me what would be
the appropriate question to ask for readback to force a frame, if it's not the rastered buffer itself
(suggestions welcome if you have one).

(*) This indicates a use case for offscreen rastering, which has also been proposed from time to time and will
probably eventually happen for content. An implementation is currently in-progress for Canvas elements.)

Comment 88 by, Sep 20 2016

Again, I really appreciate the discussion and thoughtful responses...

You mentioned that "rastering at native size and then scaling that down with bilinear filters in the compositor to something less than 0.5 or so
will start to look noticeably bad" but how is this any different than if you load a jpg image or something? Clearly Chrome has figured out how to scale things down without terrible artifacts/chunking, so why would it be so hard to apply the same technique to the raster image captured here? Why does every other browser handle this situation beautifully (and Chrome used to as well) if it's so technically difficult? 

Regarding the performance demo, there could certainly be some further optimizations but my point is that none of that should be necessary at all. I also feel like the amount of work is being unrealistically minimized, like it's no big deal, but it's extra logic being run for every single tweening element on every single tick, and it has to store extra values too (increasing memory usage). Sure, for a simple animation where one thing is being scaled, it's not going to be noticeable, but we build our platform to handle crazy amounts of stress because quite frankly sometimes that's what the project requires. Our users aren't satisfied with an answer like "well, yeah, it's 15% slower but hey, it's not too bad...maybe just animate less." I literally hunt for even the smallest optimizations inside the code because they all add up. It's quite painful to think about adding in all this extra logic that [in my opinion] should be handled natively by the browser or at least it should be possible to optimized in a much more intuitive/simple way. Flipping on and off "will-change" at various intervals strikes me as exceedingly unintuitive, hacky, and cumbersome. (I don't mean any of that as an insult to you or your team at all...I know you've got a difficult job and you've thought long and hard about this decision).

As for the readback thing, it feels like a place where there should be a Bitmap or BitmapData API so that you could do element.willChange = "auto", and then var bitmap = element.getBitmapData() or something like that. It'd force the browser to do the rasterization at that time (if any changes were made, of course). I imagine that chunk of data could be super useful to feed into <canvas> stuff. Pixel-level access to how the browser renders DOM. Yummy.

Comment 89 by, Sep 20 2016

Re scaling down: yes, Chrome has code to make that look good. But doing so requires rastering to that scale. The
situation we're discussing is what happens when you put will-change: transform on a composited layer (or,
what Chrome did for composited layers prior to version 53 no matter what), which means that raster no longer
happens when it changes scale, but instead just a bilinear filter when drawing to the screen. Allowing the
developer to request raster at a small scale during or after animation is a new feature in this release, for
such use cases.

I don't want to minimize the work needed for you. I know it will not be totally trivial, but hope it won't be
too bad. And even if isn't extremely hard to implement, I realize we are creating work for you. Unfortunately
that is the price we have to pay sometimes for advancing the overall platform's capabilities and performance.
If it makes you feel better, I have spent a whole lot of time on the concerns and code surrounding this issue. :)

The reason we consider will-change: transform as not a hack is that the intention of will-change is to give
a hint to the browser that the referenced property is going to be animated, and for the browser to take steps
to optimize performance for that use case. This is why will-change: transform creates a composited layer:
because animating transform afterward will therefore not later have the startup cost and per-frame of creating
the composited layer and rasterizing it. Following this logic, further extending the meaning of will-change:
transform to not re-raster on scale change is similar, because it will make it faster.

Thought about another way, consider animating a 2D vs 3D transform, *without* will-change. From the point of view
of a consistent platform, the raster quality on every frame should be identical if possible for equivalent matrices,
(*), since it's just a 4x4 vs 3x3 matrix. But prior to Chrome 53, it was not, because 3D transforms stopped rastering 
(except at the magic scale 1) on scale change. With Chrome 53, "transform" just means transform, and
"will-change: transform" means "please optimize the transform for speed". This also allows us to stop compositing 
on 3D transform in the future, for cases when we know that it won't be faster. (**)

The above considerations are all reasons we ended up with the current system.

(*) There are actually some edge case bugs in that at present that we are trying to fix, such as

(**) Examples we anticipate include if 3D transform is on an element which doesn't have a very large texture backing, and
we are using GPU-accelerated rasterization, which is often much faster than "software" raster, and often overall faster
than the bookkeeping necessary to handle multiple textures.

Comment 90 by, Sep 21 2016

The extra work for me isn't a big deal - it's the least of my worries. My primary concerns are:

- performance

- aesthetics (things should look sharp...without developers suddenly having to update their sites because things look terrible now in Chrome)

- Browser inconsistencies and quirks (Chrome is the *only* one who handles things this way, and I have yet to hear from anyone outside the Chrome team who thinks this new behavior is an improvement)

The more testing I do around this new behavior, the more baffled I have become. For example, try applying a simple transform: scale(0.48) and will-change:transform to both an <img> and a <div> that uses a background-image. They look VERY different (see attached) (codepen link: Is this expected? It sure seems undesirable and awfully frustrating as a developer/designer. The <img> looks great, and clearly Chrome is using an algorithm that produces the desired result, so why use a totally different (fuzzy) algorithm on the <div>? Again, all other browsers render the two consistently and beautifully. Chrome seems to botch the background-image. Am I missing something? 

I see what you mean about extending the intent of will-change to not re-rasterize in order to improve performance; I just think it was taken too far. Yes, the intent is to improve performance. I'd totally understand will-change:transform triggering a composite layer (great!). BUT, reasonable measures should be taken to preserve clarity. For example, by the same reasoning, why not turn off antialiasing altogether? It's faster. Why not downsample to a fraction of the resolution and push those pixels around? That'd save memory and make it faster. Clearly there are things you're choosing to do in order to reasonably maintain visual fidelity - why not extend that here? Instead of having developers manually flip on/off/on/off will-change for every 0.1 scale delta, why not do something like that natively in the browser? At least some minimal levels of effort could be expended to keep clarity when scale is below 1. If scale starts out at 0.1 and then I scale to 1, wouldn't it just make sense that the pixels shouldn't be blown up to 10x normal size?
8.0 KB View Download

Comment 91 by, Sep 21 2016

Uggh... this is not a good option.

Performance-wise, anyone who built sites using sprite sheets... including some of Google sites will be impacted by this "feature". This forces developers to not optimize their site using sprite sheets. You may inadvertently cause more net requests.

And in terms of aesthetics... It just plain looks awful. User test this. Show it to people and ask them if it looks degraded.

Comment 92 by, Sep 21 2016

Responding to comment 90:

The issue reported in is actually unrelated
to this bug. I filed  to investigate.

Re why doesn't the browser itself re-raster every so many scale changes: we considered that as well, and went so
far as to prototype some of it. However, we ended up abandoning that approach because we concluded it would be
very difficult to do it in a performant way, because it's impossible for the browser to be sure of the intent of the
web developer in terms of the quality/performance tradeoff. It also introduced a lot more complexity into the
composited rendering subsystem.

Re comment 91: please provide an example.

Comment 93 by, Sep 21 2016

The new bug you opened ( ) seems to indicate the problem is with <img> but it's the opposite - the <img> looked good whereas the <div> with background-image looked quite bad (see the attachment in comment 90)

In fact, this is making it almost impossible for us to implement a workaround in GSAP, because no matter how often we're forcing a re-rasterization (by toggling will-change back to "auto") on an element with any 3d transform, when it reaches its resting state at scale(1) and does the final toggle to will-change: auto and we remove the 3d transform, there's a **drastic** pixel-shift. Look at my screen-shot that was attached in #90 - it's like it's suddenly changing from the bottom image (blurry) to the top one (crisp). Jarring. Animators will not be happy. 

So once again, it seems there's a Chrome bug in the way this rasterizing is being implemented, and we can't seem to work around it elegantly (...or at all, really). I've already got a patched version GSAP but due to the funky rasterization stuff in Chrome, it feels pretty unusable.


You said you tried to implement the re-rasterizing natively and then abandoned the approach because it was too complex and it was impossible to do in a performant way, nor could you accurately determine the developer's quality/performance intent. But then you say that it's a "small amount of additional effort" for us to do this same type of thing in our JS library? And that performance-wise, it's pretty much a non-issue to do at the JS level? Please help me understand the contrast. I'd certainly think native code could run much faster than JS...and what information do we have access to that you don't? 

You whipped together an algorithm for me that, whenever a scale change is made, just checks it against when it was last re-rasterized and if it exceeds a certain threshold, it triggers the re-rasterization. Why not do that natively? Wouldn't it be much faster than layering it on in the JS level and flipping back-and-forth between will-change values (which, again, seems very odd to do during an animation where CLEARLY things are definitely going to change, yet we're telling the browser "just really, I will, I won't...yes I will...nope...I can't make up my mind!"(?) It certainly doesn't feel like it's at all in line with the intent of the will-change spec to turn it OFF in the middle of changing (animating)!

Comment 94 by, Sep 21 2016

The attachment in comment 90 is I think actually the same thing as .
The core rastering system is getting things wrong. I think you will find that Chrome
53 did not regress this (though I am still investigating).
The reason it looks good in an <img> tag in that case is that we have special code just for
<img> compositing.

You can work around  by making sure that the element does not lose its
composited backing at the end of the animation (by leaving will-change: transform for

Re why was it hard for us but easy for you: because you can know exactly the intent of
the system and the desired tradeoff. Though since you are writing a general animation
library, you do indeed have a harder time than if you were writing a specific site, and
I expect you will face some of the same challenges as we do in providing a framework for

Native code is not really so much faster than JS that it's always better to bake things in.
If there is already JS running on each frame, then it's not a problem to run a little bit extra.
It's not at all obvious to Chrome as a rendering engine when JS is animating transform - we'd
have to implement complex heuristics which will sometimes be wrong, and end up with a very
complex system that is still not ideal. We think it's better instead to give the JS developer

Note also that the web and Chrome does in fact also support declarative animations that run on
the compositor thread (CSS transitions and web animations), in order to support use
cases similar to yours. (I know you've chosen not to use this system, which I am aware is limited
in some ways.) In such cases, Chrome chooses performance-quality tradeoffs because it
knows what the animation is doing and can plan in advance. For example, if you set up
a CSS transition of the transform property to animate between a scale of 0.4 and 1, Chrome will
raster at scale 1 and then animate up to it. Chrome can do that because the animation in question
was explained in advance to the rasterization subsystem.

This is analogous to your library, it's just that your library animates from JS. And
I know it's somewhat harder for you, because you can't control raster precisely except via
will-change: transform.

Comment 95 by, Sep 22 2016

I can't make the argument as intelligently as Greensock has, but Chrome team, PLEASE PLEASE PLEASE revert what you've done in v53 that degrades the rendering of background images during scale animations. After reading all the back and forth from the past few days, I still don't understand what the upside actually was. And weighed against the very noticeable negative effect, it doesn't seem like it was a worthwhile change.

Comment 96 by, Sep 22 2016

Re comment 95: please provide an example, and why the recommended change we
are asking for to your site does not work.

Comment 97 by, Sep 22 2016

This isn't really adding anything different than has been demonstrated above, but here's my own codepen for testing background-image animation rendering. Looks good in all my other browsers...just not so hot in Chrome v53 (but it was working very nicely in v52).

Comment 98 by, Sep 22 2016

"we have special code just for <img> compositing." - please implement that consistently  everywhere. (Not sure why you'd use a different algorithm for <img>)


"You can work around  by making sure that the element does not lose its
composited backing at the end of the animation (by leaving will-change: transform for
example)." - This is unacceptable for the following reasons: 

1) It's fuzzy/blurry

2) It can unnecessarily hog memory/resources. My understanding is that it's not good practice to just layerize everything - the GPU has limited memory. The "solution" recommended here means that as soon as an element gets animated once, it'll forever be on its own compositor layer (or else risk the jarring pixel-shift, blurry-to-sharp jump)


"we'd have to implement complex heuristics which will sometimes be wrong, and end up with a very complex system" - is it more complex than simply "if the scale changes more than X delta, re-rasterize"? It really doesn't seem that hard. What am I missing? 


You mention CSS transitions and Web Animations uniquely being able to communicate intent to the compositor and in the case of scale(0.4) > scale(1) it rasterizes at 1...why is this hidden from JS developers? Why can't I say (via JS) "rasterize at 1" without hacks that require waiting for a frame to elapse, toggling "will-change" (which, again seems to directly conflict with what that property is signaling and I have yet to hear a response to my questions/comments about that)? I'd love to be able to tap into native WAAPI or CSS but both have far too many limitations that make it impossible. 

Again, I'd really appreciate a response to my previous comment/question: "[toggling will-change back and forth] seems very odd to do during an animation where CLEARLY things are definitely going to change, yet we're telling the browser "just really, I will, I won't...yes I will...nope...I can't make up my mind!"(?) It certainly doesn't feel like it's at all in line with the intent of the will-change spec to turn it OFF in the middle of changing (animating)!" 


Comment 99 by, Sep 22 2016

I agree that it would be helpful, as a matter of discovery, to know what bugs were fixed in order to bring this bug into existence. Everyone on the Greensock side is well aware of the capabilities and importance of the library in pushing web animations forward - a mission that Greensock shares with Chrome. 

As a front-ender, the particulars of compositors and rastering aren't really in my wheelhouse, but if previous Chrome versions (51, 52?) were rendering thousands of website elements/ads unacceptably glitchy (or otherwise disabled/fractured), it may help us animators understand the kinds of tradeoffs that the Chrome team is weighing in their decision to go one way or another. Perhaps there's an army of previously irate developers on the other side of this adjustment that are now completely satisfied with the changes.

If that isn't the case, though, I wonder if we can explore a solution that makes everybody happy and keeps animation moving smoothly forward. I understand that the Chrome team is not obligated to cater their development to the squeakiest wheels - but we've rewound this tape before without too much fallout, right? 

Thanks to everyone on both sides for your hard work exploring the best outcomes here.

Comment 100 by, Sep 22 2016

Re comment 97: this is how to change it to make it work: a one-liner in your

Comment 101 Deleted

Comment 102 by, Sep 22 2016

I notice if I add to the child elements parent with the background-image and transform scale(), the following CSS properties, the blur is gone. Except maybe for a slight faint blur at the beginning of the animation without using will-change:

.parent_of_child_with_transform_scale {
     -webkit-backface-visibility: hidden;
     -webkit-perspective: 1000;

Is this expected behavior that works (maybe slightly) with the above CSS properties and without will-change?

Comment 103 by, Sep 22 2016

@chrishtr, thanks! Going forward, this seems like a simple enough extra step. Only worry, now, is how past animations didn't include this CSS property. That's not a trivial concern. Perhaps the default state will-change:auto should behave like will-change:transform; ?

Comment 104 by, Sep 22 2016

Re comment 100: Here's what happens when the suggested fix is applied to the same animation, but going from 0.1 to 1 instead of 1 to 0.5:

Does the Chrome team plan to tell animators "please go back and edit your sites in cases where there are any scale tweens that are going **up** instead of down; now you'll need to add will-change:transform and the toggle back and forth to will-change:auto during the animation to make it look decent...oh, and at the end make sure you don't remove 3d transforms or you'll get the funky pixel-shift...and sorry about it being blurry...unless it's an <img> in which case it should be okay." (?)

Again, I really don't mean for any of this to sound disrespectful of your team or the hard work you put in. I have no doubt you're diligently trying to find a way to solve a bunch of problems in the most efficient/logical way. I hope you don't mind some dialog about it and a little push-back. Obviously I feel pretty strongly that this is a big step backward, but I'm trying to be open to reconsidering. Thus far I'm still scratching my head.

Comment 105 by, Sep 23 2016

@chrishtr, I've run into my first real-world test of will-change and it's not pretty. Here are links demonstrating the ill effects of will-change on a background image. 

Link 1 (will-change left undefined):

Link 2 (will-change:transform):

Because of the degraded image quality produced by will-change (seen in the animated text in Link 2), I think I'm better off leaving that out and just accepting the shakier motion that comes from leaving will-change undefined.

Really, this all brings me back to my original plea; please restore the old background image behavior.

Comment 106 by, Sep 23 2016

Side note, everything still looks just as good as it used to in v53 of the iOS browser.

Comment 107 by, Sep 28 2016

Please let me know if anything is inaccurate in this blog post that summarizes this issue:

Comment 108 by, Sep 28 2016

Labels: -ReleaseBlock-Stable

Thank you for continuing to try to find a good solution. I have one update, one clarifying point,
and one question, all related to your blog post:

1. Update:  issue 649046  was just fixed (see also comment 92). This is the issue of a down-scaled background
image with compositing looking blurry relative to the same image without compositing, and I think this is
also the case you are demonstrating in your blog post in the "gotcha: never de-layerize" section.
You will be able to verify whether it fixes it for you in tomorrow's Chrome Canary. I'd also like to note
that my suggestion to never de-layerize was a workaround while we fix this bug, not a long-term solution.

2. Clarifying point: you say in the "before Chrome 53" section that no hoops needed to be jumped through.
That is only true for your use case, where you were happy with the scale 1 second-raster behavior.
Chrome never did a good job at other scales. We have received a number of bugs about that restriction
over time from other developers.

3. Question: were you able to make things work in the end, albeit with more effort? I know we have a
disagreement about whether the Chrome 53 implementation choice is a good one, but we are listening
and want to fix any and all bugs that prevent good animations. I hope us fixing  issue 649046  demonstrates
that, and helps your use case.

Comment 109 by, Sep 28 2016

Thanks for the clarifications. I've updated the article accordingly. 

As for question #3, no, I wasn't able to make things work in an acceptable way. The two big reasons were mentioned in the article. I was able to do the toggling back-and-forth of will-change to get better clarity, but still ran into that pixel-shifting at the end of the tween when we returned to a 2D matrix on background-image stuff, so it didn't feel like a solid solution. Now that you're planning to fix that background-image stuff, it certainly helps but doesn't solve everything. 

The performance tradeoff really bothers me and I worry about how these Chrome-specific tweaks will eventually affect other browsers. Obviously I feel pretty strongly that the will-change spec needs consensus on implementation details, otherwise this is dangerous for developers. It'd be a huge loss if we have to start doing user agent sniffing again. 

I've offered some solutions that I really hope your team re-considers moving forward. Happy to chat more about any of those if you guys are interested. 

Thanks again for engaging in the discussion and working toward positive solutions. Very happy that you guys are listening and eager to fix bugs.

Comment 110 by, Sep 28 2016

I think the fix to  issue 649046  will resolve the pixel-shifting problem you observed.
If you don't mind, could you try on Chrome Canary tomorrow and verify? It sounds like that
is the only definite blocker.

Comment 111 by, Sep 30 2016

I miss you, Flash...we had many great times together and your replacement just keeps regressing. Consistency is our holy grail and now, years into the web browser wars, we still don't have parity, and in cases like this we are going backwards.

Comment 112 by, Oct 3 2016

I have filed  issue 652448  to track trying to apply raster behavior similar to
those we have for <img>, for background-image.

Comment 113 by, Oct 4 2016

Per your request, we tested the latest Chrome Canary. Here's how things compare:

Better than Chrome 53, but certainly not "good". Still jittery and there's a noticeable shift when it goes from layerized 3d transform to 2d. 

Unfortunately, with this jittery and blurry-to-sharp delayerization inconsistency, as well as the danger of will-change behaving differently in various browsers (due to lack of implementation detail in the spec), we're kinda stuck and unable to apply a solid patch to GSAP that'd work around all these things. 

Again, even if you fix the background-image rendering bugs, I'd implore you to reconsider the will-change behavior (and arduous workarounds) in favor of stepping back and getting implementation consensus from all the browser vendors and spec authors before re-approaching it later. As it stands now, we're headed toward another age of user agent sniffing and browser-specific hacks that really shouldn't be necessary.

Comment 114 by, Oct 4 2016

Thanks.  Issue 649046  was just about things being unreasonably blurry in some
cases. It seems like that was fixed. The snapping of pixels when exiting
compositing is yet another issue to do with differences in non-composited and
composited rendering, which is known to be suboptimal in various cases involving
fractional translate or scale. (Issue 521364 tracks improving this, though it may
not improve your use case, which involves scale). I should also note that issue
521364 is a different issue than the will-change raster behavior we changed in
Chrome 53, and has been around forever.

Comment 115 by, Jun 9 2017

So I'm just a guy trying to make a website with animations that scale smoothly and don't jitter. All this stuff about triggering "will-change: transform;" and "will-change: auto;" I just don't know how to do.

Look... all I want is for my animations to look smooth. I spent day just trying to figure out what the problem was. Every JavaScript library I've tried yields jittery animations when scaling, but CSS is buttery smooth. Are you telling me that the only way I can fix this is to literally go into the source code and make a change that will make my animations perform worse?

Comment 116 by, Jun 9 2017

Re comment 115: if you have an example where the animation should be smooth
but is not, please file a new bug with a reduced testcase (on jsbin or
codepen or similar) that demonstrates the issue. You're welcome to post the
id of the bug here so I can make sure to see it.

Comment 117 by, Jun 9 2017

Chrome team (chrishtr?), can you summarize the recent changes to the rendering algorithms and how will-change affects them? It seems like there's a pretty radical difference in the latest release (59.0.x) that resolves some of the old funkiness but also seems pretty CPU-intensive. Did you guys decide to make sure that the baseline raster is sampled at a minimum of scale:1 or something like that? (to avoid all the fuzziness when an element started scaled way down and then scaled up)

Comment 118 by, Jun 9 2017

We made a number of changes with Chrome 59, but modifications to how
will-change behaves is not one of them. It sounds like you have
examples. Could you file a new bug with known examples so I can

Comment 119 by, Jun 9 2017

Re comment 118: Please see (I'm not saying it's necessarily a "bug" - I'm trying to gain clarity about what changes were made, why, and what we can expect down the road since Chrome's behavior seems to be changing back and forth quite a bit with rasterization). Thanks!

Comment 120 by, Jun 10 2017

Re comment 115: As far as this thread seems to reveal, it doesn't appear that this is a bug, but rather intended behaviour which I just don't understand. See for a CodePen of how different methods of animating a scale appear on my computer. The effect is more easier seen on a low resolution monitor. Using "will-change: transform;" on any of the JavaScript library animations causes them to be blurry when they are scaled up.

All I'm trying to do is make the JavaScript library powered scale animations nice and smooth without blur or jitter, just like the CSS one. Do I really have to go and play with source code I don't understand to accomplish this? It seems like such a simple expectation.

Comment 121 by, Jun 21 2017

Notice the vibrating text in this animation:

Looks terrible in Chrome. If I enable will-change, it solves the vibration problem but anything that starts at a very small scale turns into a blurry mess. Help? This seems related to this bug, but perhaps it needs to be filed separately? 

So there are two issues: 
1) the text shouldn't vibrate while scaling
2) The elements shouldn't turn into a blurry mess when will-change: transform is applied.

Comment 122 by, Jun 22 2017

Re comment 119: the example gave there does not use will-change transform, so it's re-rastering on every
frame of scale change. I don't think anything changed with Chrome 59, except perhaps that we improved
subpixel jitter during scale.

Re comments 120 and 121: I discussed this at some length with two other engineers this morning.
We agree that it's hard to implement these examples well with a JS-driven animation right now.
I think that the workaround in comment 73 should work, but also agree that the ergonomics of that
solution are not so great. However, we really want to avoid footguns, code complication, and heuristics
in the Chrome compositor.

We came up with another approach that seems to work well, and would like your feedback on: add
a declarative CSS animation with keyframes, to give the browser the ability to reason about the
sizes of the animation and choose a good raster scale.

For the example in, add the following

@keyframes scale {
    from {
        transform: scale(0.5); /* or whatever minimum scale exists in the animation */
    to {
        transform: scale(1); /* or whatever maximum scale exists in the animation */

#quote div{
    animation-name: scale;
    /* declare an animation that will start so far in the future that it never runs */
    animation-duration: 0.1s;
    animation-delay: 100000s;

@greensockjs: What do you think? I think it should work well, but would like your feedback.

The above CSS will have the effect that Chrome's compositor can determine the optimal scale for rastering.
Currently, it chooses the maximum scale over all keyframes.

This is the same reason that, in, example #1 ("css animation") has
perfect rendering but the other examples do not.

If this approach works well, we could change the CSS animations spec to allow declaring an animation without having
to specify animation-duration, and say that such a declaration is a hint to the browser that there will be an
animation between the declared keyframes at some point in the future, which may be driven by JS.

Finally, we tested the above approach (with keyframes) on Edge and Firefox, and neither help the quality of the animation.
It appears that they have the same issue as Chrome, but also don't optimize CSS animations well enough yet for 
that to help.

Comment 123 by, Jun 22 2017


Comment 124 by, Jun 23 2017

I really appreciate the prompt response and the fact that you took the time to discuss it with your team. 

That said, I see some significant problems with the proposed "solution":

  1) In order to adequately render JavaScript animations, one must create CSS keyframe animations...which don't even run? Quite counter-intuitive. JavaScript animations shouldn't depend on CSS animations. 

  2) JS animations are typically very dynamic, but this solution seems to require a declarative approach that assumes it's possible to predict the maximum/minimum scale values. What if the values are randomized or change based on user input? Should the keyframes constantly be updated via JavaScript somehow? Yuck.

  3) This is totally non-standard and browser-specific (unreliable). What happens if everyone starts implementing this "hack" (just to make things work acceptably in Chrome) and then at a later date Chrome decides to interpret things differently and changes the algorithms?

  4) How might this affect WAAPI (which from what I understand taps into the exact same engine under the hood)? For example, if we start dynamically shoving 100000000s-delayed animations onto elements, will the root timeline become absurdly long and confuse people? Like if they create a 1-second long WAAPI animation somewhere on a page that has this hack implemented, and then they query the root timeline's duration, might it break stuff (or at least be confusing) if it's insanely long instead of just 1 second? 

I think it'd be much, much better to implement 2 changes: 

  a) Rasterize at the native size or the current transform, whichever is **BIGGER**. This will solve a lot of the problems since they almost always arise when an element is rasterized *below* scale(1). 

  b) Introduce an official API for telling the browser what the minimum scale is for the rasterization of an element. For example, element.cacheTransform = "scale(1)" would indicate to the browser that when it does its rasterization, it should do so as if the transform was "scale(1)". It could take the same value as any "transform". This gives developers a lot of control and takes the burden off the browser's heuristics. 

Please consider at least "a)" above. 

Thanks again for all your efforts.

Comment 125 by, Jun 24 2017

(a) is a good idea, we're trying that now.

Re many of the other comments, I think you missed my point that specifying keyframes
is an idea, which would end up standardized if it works out. I am as aware as you
that the approach is not interoperable at present. At present, interoperability
is weak in this area.

Comment 126 by, Jun 24 2017

Excellent, glad to hear you're at least trying (a). 

Regarding standardization, I really hope that this idea of requiring keyframe animations won't become standardized as the way developers are supposed to control how things are rasterized (for all the reasons I mentioned above). The main problem is *not* that other browsers haven't adopted it - even if it was universally adopted tomorrow, I think it'd cause many other problems, especially for JavaScript-driven animation libraries that handle things dynamically.

Again, thanks for trying (a). Please let us know how that goes and when it might land in a release.

Comment 127 by, Jun 27 2017

Project Member
The following revision refers to this bug:

commit e17b1bcf1010c97436fadf6e58e9235b977c74ea
Author: Vladimir Levin <>
Date: Tue Jun 27 20:46:10 2017

cc: Make sure to use at least the device scale when will-change: transf.

When we have a will-change: transform hint we keep whatever the current
scale is. Make sure that we use at least device scale to ensure that
content looks crisp when going from low scale to high.,

Bug:  596382 
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I49780cac9f95eef4cbc324f85a7efddccfb67729
Reviewed-by: enne <>
Reviewed-by: Chris Harrelson <>
Commit-Queue: Vladimir Levin <>
Cr-Commit-Position: refs/heads/master@{#482739}

Comment 128 by, Jun 29 2017

The latest Chrome Canary has the commit in comment 127 in it. The demo
modified to use will-change: transform, looks much better.
Showing comments 29 - 128 of 128 Older

Sign in to add a comment