Bug 219480 - background-image/webkit-mask-image doesn't update properly with SVG url fragments
Summary: background-image/webkit-mask-image doesn't update properly with SVG url fragm...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: Safari Technology Preview
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-12-02 20:30 PST by Christopher Swasey
Modified: 2020-12-19 11:18 PST (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Christopher Swasey 2020-12-02 20:30:07 PST
In a number of situations, a stacked SVG file + URL fragments as a background image or mask image does not seem to respect changes to the applied style after the initial render. I've reduced the issue to a number of jsfiddle examples. I've tried all examples in Safari 14, the latest Safari TP, and Chrome (to compare.) N.B.: the two Safaris fairly reliably exhibit the buggy behavior, but it can vary... rarely it'll just work as expected on page load; on the flip side, switching windows and switching back usually fixes things, but not 100% of the time.

Case 1 is the simplest. This bug seems to resolve itself fairly consistently after a window switch.

https://jsfiddle.net/9dtugq4n/

- Two classes (`foo` and `bar`) have a `-webkit-mask-image` for the same SVG, with different URL fragments (`#foo-usage` and `#bar-usage`, the `-usage` suffix originates in the webpack plugin used by the actual app I'm working on .)

- Both masks are semicircles; `foo` on the left, and `bar` on the right.

- Two divs each have classes `foo` and `black`

- A 1s `setTimeout` calls `.className = 'bar black'` on both divs.

  Expected behavior: The semicircle switches from left to right for both divs

  Observed behavior: The semicircle switches from left to right only for the first div  


Case 2 does not tend to resolve itself spontaneously:

https://jsfiddle.net/9dtugq4n/1/

- Same setup, except only 1 div with `foo` and `black `. Behavior is the same for the two-div case.

- A 1s `setTimeout` calls `.className = 'bar black'` on the div

- A 2s `setTimeout` calls `.className = 'foo black'` on the div

  Expected behavior: The semicircle switches from left to right after one second. Then it switches back to left after another second.

  Observed behavior: The semicircle switches from left to right after one second. It does not switch back.


Case 3 is similar. I've yet to see it resolve itself in any way.

https://jsfiddle.net/9dtugq4n/3/

- Same setup, back to 2 divs.

- This time, the first div starts with the `foo` class, and the second `bar`. Both still have `black `.

- A 1s `setTimeout` calls `.className = 'bar black'` on the first div

  Expected behavior: The semicircle on the second div starts on the right and stays on the right. The semicircle on the first div starts on the left and switches to the right after one second.

  Observed behavior: The semicircles have the correct initial positions, but there is no change after page load.


Case 4 shows that changing the background color avoids the bug:

https://jsfiddle.net/9dtugq4n/4/

- Same setup, 1 div.

- A 1s `setTimeout` calls `.className = 'bar black'` on the div

- A 2s `setTimeout` calls `.className = 'foo green'` on the div

  Expected behavior: The semicircle switches from left to right after a second. After another second, it switches back to the left and turns green.

  Observed behavior: Behaves as expected.

  Note that the _simultaneous_ background color change trick avoids the bug in all cases, but it isn't a cure... switching masks and colors, and then switching back to the first mask with the second color, doesn't work.


Case 5 demonstrates that only changing the `background-color` explicitly suffices... a combination of `background-color: currentcolor` and changing the `color` does _not_. This tends to resolve after switching windows. NOTE: this seems resolved in the latest TP.

https://jsfiddle.net/9dtugq4n/5/

- Same setup, except using `currentcolor` as the background, and toggling `color`s. 1 div.

- A 1s `setTimeout` calls `.className = 'bar black'` on the div

- A 2s `setTimeout` calls `.className = 'foo green'` on the div

  Expected behavior: The semicircle switches from left to right after a second. After another second, it switches back to the left and turns green.

  Observed behavior: The semicircle switches from left to right after a second, but there is no further change.
Comment 1 Christopher Swasey 2020-12-02 20:38:27 PST
I should clarify: I first reduced this examples locally before copying them into the fiddles. JSFiddle might occasionally mask the appearance of the bug(s), but, so far, the buggy behavior is _always_ present with just a static HTML file.
Comment 2 Christopher Swasey 2020-12-02 21:01:59 PST
The background color change (and the `currentcolor` oddity) seems to have been a bit of a red herring. It turns out that `color`—regardless of whether `background-color` is `currentcolor`—is one of the few CSS properties that don't seem to resolve the bug with a mutation.

So far I've tried `opacity` (different values), `transform` (different scales), `font-size` (different sizes, even though there's no text content), `border-color` (different colors, even with `border-width: 0`) and changing them all suffices to avoid the bug.

So, my work around for my use case (icons), at least: each mask class gets a unique `border-color`.
Comment 3 Smoley 2020-12-07 12:32:26 PST
Thanks for filing, I can reproduce cases 1-4 on Safari 13.1.3 - STP 116. I was not able to reproduce Case 5 even with a local html file on either build.
Comment 4 Radar WebKit Bug Importer 2020-12-07 12:32:37 PST
<rdar://problem/72059090>
Comment 5 Christopher Swasey 2020-12-19 11:18:49 PST
Not sure if this is directly related, possibly a clue, or maybe a separate bug entirely, but I recently noticed—when playing with an app I already had opened in Safari on my iPhone, after leaving the house—that previously "unseen" fragments in an already-loaded SVG file don't render if the original file is inaccessible. Already-seen fragments from the very same file continued to work fine (with my workaround as discussed above.)