NEW 216701
WebKit incorrectly composites hundreds of elements when using position: relative
https://bugs.webkit.org/show_bug.cgi?id=216701
Summary WebKit incorrectly composites hundreds of elements when using position: relative
Liam DeBeasi
Reported 2020-09-18 09:30:36 PDT
Created attachment 409137 [details] Code Reproduction When an element with a 3d transform is placed in the same scrollable container as elements with position: relative, the elements with position: relative are incorrectly composited. The Layers pane in Safari claims this is due to the relative elements overlapping the transformed element, even when they are not. Removing position: relative from these elements resolves the issue. Additionally, using a 2d transform instead of a 3d transform resolves the issue as well. This issue was observed in STP 113, but can be reproduced in Safari 13 as well. Additionally, this issue can be reproduced on both macOS and iOS. Steps to reproduce: 1. Open the attached code reproduction in Safari. 2. Open dev tools and navigate to the "Layers" tab. The default layout has a div with a 3d transform and a list of divs with position: relative. You should notice that there are over 150 layers rendered. 3. Uncheck the "Use 3D Transform" checkbox. This will use a 2d transform instead. You should observe that there are only 2 layers now. 4. Recheck the "Use 3D Transform" checkbox. 5. Uncheck the "Use div with position: relative" checkbox. This will remove position: relative from the list items. You should observe that there are only 3 layers now. When selecting a list element layer, Safari indicates that it was composited because it "overlaps other compositing elements". The element is overlapping the scrollable container which is composited; however, this additional compositing only happens when the element with a 3d transform is present. In this case, no list item overlaps the element with 3d transform. There are 2 reasons why I think this is a bug: 1. This behavior does not happen in Chrome. Chrome never composites the list items. 2. Given a scrollable list, this issue significantly degrades scrolling performance. It is most noticeable on an iPad.
Attachments
Code Reproduction (1.71 KB, text/html)
2020-09-18 09:30 PDT, Liam DeBeasi
no flags
Better testcase (1.87 KB, text/html)
2020-09-22 15:05 PDT, Simon Fraser (smfr)
no flags
Radar WebKit Bug Importer
Comment 1 2020-09-21 11:48:35 PDT
Simon Fraser (smfr)
Comment 2 2020-09-22 15:05:03 PDT
Created attachment 409404 [details] Better testcase
Simon Fraser (smfr)
Comment 3 2020-09-22 15:07:10 PDT
The relative-positioned elements end up in layers because the scroller is not a CSS stacking context, so conceptually the relative elements render as siblings (not descendants). There's an optimization to avoid this (layer backing sharing) but the transformed element defeats it. If you test with the transformed element in the middle of the list you should see no layers for relative elements that come before it.
Liam DeBeasi
Comment 4 2020-09-22 15:57:06 PDT
Ah ok that's interesting. Thanks for the additional test case -- that clarifies things a bit for me. Would this be another scenario where an optimization could be made by WebKit, or would you consider this to be expected behavior?
Simon Fraser (smfr)
Comment 5 2020-09-22 15:58:13 PDT
It's obviously valuable to optimize but hard to fix given webkit's current compositing architecture.
Liam DeBeasi
Comment 6 2020-09-22 16:04:30 PDT
That's fair. I can dance around the issue for now by using 2d transforms in affected components in Ionic Framework.
Simon Fraser (smfr)
Comment 7 2020-09-22 16:34:12 PDT
Making the scroller a stacking context (will-change: transform or position and z-index) should eliminate this entirely. Maybe a z-index > 0 on the transformed item too.
Liam DeBeasi
Comment 8 2020-09-25 10:58:06 PDT
Adding will-change: transform to the scrolling element solved it for us. Thanks for the suggestion!
Liam DeBeasi
Comment 9 2020-11-11 06:13:51 PST
Wanted to add a note for anyone who stumbles upon this and uses will-change: transform as a workaround: Make sure you only target WebKit as using will-change: transform on a scrollable element will break any position: fixed elements in the scrollable element in Chromium browsers.
Liam DeBeasi
Comment 10 2020-11-11 06:22:55 PST
Actually it looks like this position: fixed behavior is correct according to https://bugs.chromium.org/p/chromium/issues/detail?id=413456. There is an open WebKit issue to address this behavior: https://bugs.webkit.org/show_bug.cgi?id=167600 will-change: transform on a scrollable element is probably not a good solution here, but I will look into other workarounds.
Simon Fraser (smfr)
Comment 11 2020-11-11 10:14:42 PST
Try "position: relative; z-index: 0" on the scroller.
Liam DeBeasi
Comment 12 2020-11-12 13:05:19 PST
That seems to work, thank you!
Note You need to log in before you can comment on or make changes to this bug.