Why is filter(drop-shadow) causing my SVG to disappear in Safari?
Asked Answered
S

6

18

I am developing an app using D3.js. I was sidetracked for a while, and recently came back to it. Today I found that, though it worked fine in the past, the SVG map in the app no longer displays on mobile Safari (iOS 9.3.1) or desktop Safari (v9.1 (11601.5.17.1) ).

I extracted the SVG and a single style rule and put them on CodePen to illustrate what happens. In Chrome, this pen will look fine. In Safari, it will be completely blank.

https://codepen.io/Kirkman/pen/pyKzeX

If you inspect the DOM in Safari, you find that the paths are there, and they are the right shapes. They just seem invisible. Unchecking the style rules in the inspector causes the entire map to magically appear (without the drop shadow, obviously)

The style rule is very straightforward:

svg {
    -webkit-filter: drop-shadow( 2px 2px 4px rgba(0,0,0,.4) );
    filter: drop-shadow( 2px 2px 4px rgba(0,0,0,.4) );
}

Can anyone suggest why this isn't working? Did I do something wrong, or has something changed in Safari?

Shakespeare answered 18/4, 2016 at 22:20 Comment(1)
I filed a bug report with Apple back in 2016, and they said they fixed the issue in iOS 11. bugreport.apple.com/web/?problemID=25788891Shakespeare
I
32

Probably is a little late, but just in case I will leave you my answer. I had the same problem with Safari and I figured out that this seems to be a Safari issue/bug. You can work around this bug just wrapping your SVG tag with another HTML tag like a div and apply to this element the drop-shadow filter as you did in your example. Here you have your example modified with the wrapper element

https://codepen.io/mauromjg/pen/rLaqWG

<div class="svg-wrapper">
    <svg>...</svg>
</div>

//CSS
.svg-wrapper {
    -webkit-filter: drop-shadow( 2px 2px 4px rgba(0,0,0,.4) );
    filter: drop-shadow( 2px 2px 4px rgba(0,0,0,.4) );
}

Hope that helps!

Iene answered 2/6, 2016 at 1:35 Comment(7)
This seems like the perfect workaround. I'll give it a try, and probably select this as the answer.Shakespeare
this worked nicely for me. It should be the accepted answerTulipwood
Thanks a lot for this solution, super ease and super clean. Should be the accepted answer.Intricacy
On iOS (in web views or Safari itself--tested under 11.3), it seems this workaround can cause some intermittent corruption effects and screen tearing similar to what's described here that aren't immediately obvious. Just a heads up.Gibbosity
This doesn't appear to be a workaround (or at least anymore). Putting the styles on the svg instead of the wrapper in your codepen results in the same blurry svg when zoomed in. codepen.io/sarahannnicholson/pen/abvYvEp vs codepen.io/mauromjg/pen/rLaqWG result in the same blurry svg in Safari mobile.Caramel
Wow I can't believe that worked. Fixed scroll lag for me on Safari Desktop, trying to apply a drop-shadow directly to an SVG. Just applied it to the containing div instead! CheersSheelah
Thanks works great in Safari (had an issue with the shadow cutted on the edges of the SVG).Parvati
L
2

Browsers calculate things differently and for some reason Safari hates you. Lol.

However you should be using SVG Filters instead. They are much more reliable.

SOURCE - w3schools

 <svg height="140" width="140">
  <defs>
    <filter id="f3" x="0" y="0" width="200%" height="200%">
      <feOffset result="offOut" in="SourceAlpha" dx="20" dy="20" />
      <feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
      <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
    </filter>
  </defs>
  <rect width="90" height="90" stroke="green" stroke-width="3"
  fill="yellow" filter="url(#f3)" />
</svg> 

Hope that helps!

Lottery answered 18/4, 2016 at 22:39 Comment(2)
With a few tweaks, this code works. But the result is not as clean as the CSS solution. One issue is that some of my SVG's polygons are filled with stripes rather than solid colors, which causes the shadow to look lighter near those particular polys.Shakespeare
A similar but slightly better technique can be found here. Still has the lightness issue, but it's not as pronounced if you use a gray shadow instead of a black one.Shakespeare
J
2

I had a similar issue with Safari: SVG objects such as lines would disappear as soon as a filter effect was applied. The same code worked fine in Chrome and Firefox. The code was part of an Angular app. It turns out the problem was triggered by Angular employing the "base" tag.

It appears that Safari applies the base tag to fragment names within embedded SVG images, whereas Chrome and Firefox do not. This code illustrates the issue:

<html>
 <head>
  <base href="/">
 </head>
 <body>
  <svg>
   <filter filterUnits="userSpaceOnUse" id="glow">
      <feGaussianBlur stdDeviation="1.5"></feGaussianBlur>
   </filter>
   <line x2="99" y2="99" stroke="red" filter="url(#glow)"></line>
   <line y1="99" x2="99" stroke="green" filter="url(/_display/#glow)"></line>
  </svg>
 </body>
</html>

On Safari, only the green line will show, whereas Chrome and Mozilla with show both red and green line.

jsfiddle demonstrating the problem

Joiejoin answered 20/3, 2019 at 1:0 Comment(2)
This turned out to be what was breaking svg filters for me. Did you figure out a work-around for this? It would be nice to be able to use both <base> and svg filters in Safari, too.Madox
The only workaround I'm aware of is to specify an absolute path in the filter url (as shown in the second example). If the filter is created in Javascript, you can simply prefix the relative path with window.location to make it absolute. I did submit a bug report to Apple, but haven't heard back yet.Joiejoin
P
0

In my case, I was using an SVG Filter, so I couldn't really apply the CSS solution. Instead, I was able to get the SVG to show up by applying a CSS transformation via Javascript after the page loads. Here's an example in plain JS:

setTimeout(function(){
 document.getElementById("svg-element").style.display = "block";
},10);

If you want to know if this will work, see if the SVG shows up after you resize the browser or modify a CSS style rule using the inspector.

Pin answered 18/1, 2017 at 14:27 Comment(0)
C
0

I also had loading indicator never stopping to rotate when this happened. Also when SVG with a style tag which set the shadow was opened in a separate window, there was no shadow. The solution was to use an SVG filter, and make sure to duplicate the element on which it was set, so that if the image is resized, the mobile safari would not pixelate it. E.g., as described here https://mcmap.net/q/670008/-svg-drop-shadow-filter-pixelates-svg-on-mobile-safari

Compensable answered 10/9, 2018 at 1:58 Comment(0)
H
-1

I had the same issue in our Angular app since we use the <base> tag.

I added this to the controller:

$scope.basePath = window.location.href;

Then in the template I added the base path to the filter:

<g ng-attr-filter="url({{basePath}}#filter1_d)">

Hopefully this helps anyone who's using Angular. Check out this comment in Github for more information: https://github.com/airbnb/lottie-web/issues/360#issuecomment-320243980

Hilar answered 11/9, 2019 at 23:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.