Safari trouble positioning SVG feSpotlight filter - svg

I want to use a spotlight effect but it only seems to work in Chrome, looks "just ok" in Firefox, but will not position (x,y,z) in Safari. (Other browsers not tested)
I've tried different filter and primitive units, and while this makes a difference, Safari still cannot seem to position the lighting effect in any case.
In pursuit of understanding what is going on, I've tried lots of workarounds including different userSpaceOnUse/objectBoundingBox combos, and different svg structure but have never been able to find one that works on Safari.
Examples
Default filter/primitive units:
https://jsfiddle.net/localnerve/y470d52v/
objectBoundingBox units:
https://jsfiddle.net/localnerve/uyc7o52k/
A picture is also worth a 1000 words (Safari, Chrome, FF). The spotlight on Safari is rendered off-canvas to the right and bleeds in from the right.
To show the spotlight positions on Safari are "out of whack", here's me nudging them in web inspector so I can see the spotlight render at all:
Here is the code using objectBoundingBox filter and primitive units:
<style>
body {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 16px;
color: #fff;
}
* {
transform-origin: 50% 50% 0;
}
.scene-container {
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
}
.scene-container.content {
position: relative;
width: 100%;
height: 150vh;
background-image: linear-gradient(hsla(240, 90%, 8%, 1) 0%, 99%, hsla(217,24%,71%,0) 100%);
box-shadow: 0px -10px 20px hsl(240, 90%, 8%);
}
.spot {
height: 100%;
width: 100%;
}
</style>
<body>
<div class="scene-container content">
<h2>Here's a spotlight.</h2>
<svg class="spot" viewBox="0 0 2000 3000" preserveAspectRatio="xMidYMid">
<defs>
<filter x="-0.2" y="-0.2" width="1.4" height="1.4" filterUnits="objectBoundingBox" primitiveUnits="objectBoundingBox" id="spotlight">
<feGaussianBlur in="SourceAlpha" stdDeviation="8" result="blur1"></feGaussianBlur>
<feSpecularLighting result="specOut" in="blur1" specularConstant="1.8" specularExponent="5" lighting-color="#ffffff">
<feSpotLight x="0.5" y="-0.4" z="0.03" pointsAtX="0.5" pointsAtY="0.8" pointsAtZ="0" limitingConeAngle="13.7"></feSpotLight>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"></feComposite>
</filter>
<clipPath id="spot-clip">
<rect x="-50" y="2840" width="2200" height="200"></rect>
</clipPath>
<filter id="spot-blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="15">
</feGaussianBlur>
</filter>
</defs>
<g transform="translate(0, -175)" filter="url(#spotlight)">
<ellipse cx="50%" cy="95.333%" rx="27%" ry="130" fill="#fff" clip-path="url(#spot-clip)" filter="url(#spot-blur)"></ellipse>
<rect x="25%" y="43.667%" width="50%" height="50%" stroke="peru" stroke-width="3%" stroke-linejoin="round" fill="#000"></rect>
</g>
</svg>
</div>
</body>
Any insight you can give is greatly appreciated.

There are known bugs in webkit/Safari for light source positioning wrt transforms and oBB units. After the webkit/blink engine schism, no-one at Apple picked these bugs up from the Chrome team.
https://bugs.webkit.org/show_bug.cgi?id=88877
https://bugs.webkit.org/show_bug.cgi?id=113059
The workaround is not to use transforms and oBB units (do any dynamic positioning or sizing via JavaScript)

Related

How to make copied SVGs as clear as they are displayed?

I'm displaying SVGs in <img> tags. With viewBox these images could be scaled without losing clarity. However, when I copy these images (and paste them into PowerPoint, etc.), they won't be as clear as they are displayed.
How could I make copied images clear? And could this be done without using a canvas?
Example SVG markup:
<svg id="mol-638318-0540814976"
xmlns="http://www.w3.org/2000/svg" width="84" height="40" viewBox="0 0 84 40">
<style>
#mol-638318-0540814976 text {
dominant-baseline: central;
text-anchor: middle;
font-size: 16px;
font-family: serif;
fill: black;
}
#mol-638318-0540814976 line {
stroke: black;
}
</style>
<text x="26" y="20">C</text>
<text x="58" y="20">C</text>
<line x1="32" y1="20" x2="52" y2="20"></line>
</svg>
Thanks!

css rotate introduces outline when using SVG clip-path or mask

Is there a way to stop this outline in firefox?
#blob { background: red; width: 500px; height: 500px; clip-path: url(#myClip); transform: rotate(20deg);}
<div id="blob"></div>
<svg>
<defs>
<path d="M320.403196,424.677624 C426.787532,365.585154 447.310044,306.188587 433.45394,197.28033 C419.597836,88.3720737 316.997962,53.8862578 227.347416,40.9086547 C144.650118,28.9375873 104.472702,88.6407456 69.862267,131.812053 C15.52584,199.588564 48.3439099,300.905451 80.8563197,361.757908 C110.80391,417.809872 214.018859,483.770094 320.403196,424.677624 Z" id="path-1"></path>
<clipPath id="myClip"><use href="#path-1"></use></clipPath>
</defs>
</svg>
This renders correctly in other browsers, just need some work around for this firefox bug
same outline appears using either clip-path or mask
As a workaround you could rotate the clipPath instead:
#blob {
background: red;
width: 500px;
height: 500px;
clip-path: url(#myClip);
}
<div id="blob"></div>
<svg viewBox="0 0 397 409">
<defs>
<path d="M320.403196,424.677624 C426.787532,365.585154 447.310044,306.188587 433.45394,197.28033 C419.597836,88.3720737 316.997962,53.8862578 227.347416,40.9086547 C144.650118,28.9375873 104.472702,88.6407456 69.862267,131.812053 C15.52584,199.588564 48.3439099,300.905451 80.8563197,361.757908 C110.80391,417.809872 214.018859,483.770094 320.403196,424.677624 Z" id="path-1" />
<clipPath id="myClip" transform="rotate(20)" transform-origin="center">
<use href="#path-1"></use>
</clipPath>
</defs>
</svg>

IE11 defaults SVG to 100% width - how to refactor this code?

I am not aware of alternatives to adding width: 1em to the SVG in order to fix the IE11 issue (please see comment in the code). Play with the code in the codepen. Appreciate any help! Thanks :)
https://codepen.io/ambrwlsn90/pen/zjZYpb
<div class="box">
<span class="handle--draggable">
<svg class="handle--icon" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 10 32">
<circle cx="2" cy="2" r="2" />
<circle cx="8" cy="2" r="2" />
<circle cx="2" cy="9" r="2" />
<circle cx="8" cy="9" r="2" />
<circle cx="2" cy="16" r="2" />
<circle cx="8" cy="16" r="2" />
<circle cx="2" cy="23" r="2" />
<circle cx="8" cy="23" r="2" />
<circle cx="2" cy="30" r="2" />
<circle cx="8" cy="30" r="2" />
</svg>
</span>
</div>
.box {
position: relative;
width: 400px;
height: 100px;
border: 3px solid black;
background-color: white;
top: 50px;
left: 100px;
padding: 15px;
line-height: 1.5em;
}
.handle--draggable {
position: absolute;
cursor: move;
left: -26px;
top: -3.5px;
}
/**
* 1. Magic number added to fix visual bug in IE: 11
*/
.handle--icon {
fill: black;
background-color: grey;
padding: 3.5px;
height: 37px;
width: 1em; /* 1. */
position: relative;
&:hover {
left: -5px;
border-right: 5px solid grey;
}
}
The SVG tag needs some basic attributes in order to be rendered as expected. If you read the W3C documentation according the outermost svg tag you will find the answer:
For embedded ‘svg’ elements, the width of the rectangular region into which the ‘svg’ element is placed.
A negative value is an error (see Error processing). A value of zero disables rendering of the element.
If the attribute is not specified, the effect is as if a value of '100%' were specified.
So you will need to specify the width and height attributes of the SVG tag, or it will be rendered at 100% width.
The opening svg tag should look like this:
<svg class="handle--icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 32" width=“10” height=“32”>
Then the SVG will look the same crossbrowser.
Having the width and height attributes defined on your svg element you can discard the ugly Internet Explorer 11 hack.

SVG backgrounds are getting cut off in IE11 when zooming

We are trying to display SVG backgrounds in internet explorer. Our images are always getting cut off when a zoom other than 100% is used. This can be reproduced using the following code:
with this svg
<svg xmlns="http://www.w3.org/2000/svg" height="100" width="100" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="48" stroke="black" stroke-width="3" fill="red" />
</svg>
div {
width: 14px;
height: 14px;
background-size: 14px 14px;
background-repeat: no-repeat;
background-image: url("data:image/svg+xml;charset=utf-8,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' height='100' width='100' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='48' stroke='black' stroke-width='3' fill='red'%3E%3C/circle%3E%3C/svg%3E");
}
<div></div>
The result looks like this:
In all other browsers it renders fine. Has anyone else ever experienced this bug? Is there a workaround?
I have found one workaround which requires very little work:
Make the SVG image 2X size of the actual content (this would make the circle look like this:
<svg xmlns="http://www.w3.org/2000/svg" height="200" width="200" viewBox="0 0 200 200">
<circle cx="50" cy="50" r="48" stroke="black" stroke-width="3" fill="red" />
</svg>
Then use the :after pseudo element to create an inside element with 2x the desired size. So the html would be
<div class="circle"></div>
And the css would be
.circle {
width: 14px;
height: 14px;
position:relative;
}
.circle:after {
position: absolute;
top: 0;
left: 0;
content: ' ';
width: 28px;
height: 28px;
background-size: 28px 28px;
background-repeat: no-repeat;
background-image: url('circle.svg');
}
The extra space in the :after pseoudoelement gives IE spare canvas to draw on, but both the visible icon and the space occupied by the original container remain the same.

SVG gaussian blur filter causing an unexpected greenish glow

Yello!
I have a strange occurence when using a gaussian blur filter on an SVG text element in Firefoxy. I tried searching the web for solutions but I haven't even been able to find anything mentioning this issue. Here's a reproducible example (and the JSFiddle):
<svg id="svg1" width="100%" height="1000" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<defs>
<filter id="filterBlur">
<feGaussianBlur in="SourceGraphic" stdDeviation="3" result="blurOut" />
<feBlend in="SourceGraphic" in2="blurOut" />
</filter>
</defs>
<text class="link" x="100" y="100">Hello World</text>
</svg>
And the CSS
body {background-color:black;}
text {
font-family: "Arial";
fill: white;
}
.link {
font-size: 20px;
opacity: 0.90;
letter-spacing: 3px;
font-weight: bold;
filter: url(#filterBlur);
}
I have tried several fonts but they all exhibit the same greenish glow. In Chrome the blur works just fine. Any ideas?
D
A fix for this is coming in Firefox 29. You can download the beta now if you want to try it.

Resources