SVG rendering blurry in all browsers except chrome - css

I have an SVG file that is using a pattern to make the background of a schedule. In Google Chrome, this renders as expected, with every line not being anti-aliased. However, in Firefox, Safari, and Internet Explorer, it renders with every line being 2px that are semi-transparent.
What I Tried
After many hours of searching and trying different approaches, I have come to the following conclusions:
The blurriness is in part caused by the fact that the svg has a dynamic width and is solved when a viewBox attribute is applied, however this looses all scalability which defeats the purpose of using an svg.
When there is only one svg on the page, it appears to look normal (or close enough to normal), however when there are multiple in succession, every other one (or sometimes randomly) will appear with each 1px line appearing as 2px anti-aliased line (looks bad).
Offsetting the x and/or y-values by .5 pixels does not change anything and can make the rendering look even worse sometimes.
Adding shape-rendering: crispEdges; to the style of each line can either a) make the lines disappear completely or just not have any effect whatsoever or b) make the colors in the 2px lines darker, but not actually making the lines 1 pixel.
The enable-background attribute appears to have no effect on the
Again, none of these problems appear in Chrome, but do in all other modern browsers
The SVG in question
<svg width="100%" height="500" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="day" width="100%" x="0" height="40" patternUnits="userSpaceOnUse">
<line x1="0" y1="0" x2="100%" y2="0" style="stroke:#bbb;stroke-width:1" />
<line x1="0" y1="20" x2="100%" y2="20" style="stroke:#ccc;stroke-width:1" stroke-dasharray="3,3" />
</pattern>
<pattern id="hours" width="100%" x="0" height="40" patternUnits="userSpaceOnUse">
<line x1="0" y1="0" x2="100%" y2="0" style="stroke:#000;stroke-width:1" />
</pattern>
</defs>
<rect x="0" width="5%" height="500" fill="url(#hours)" />
<rect x="7%" width="17%" height="500" fill="url(#day)" />
<rect x="26%" width="17%" height="500" fill="url(#day)" />
<rect x="45%" width="17%" height="500" fill="url(#day)" />
<rect x="64%" width="17%" height="500" fill="url(#day)" />
<rect x="83%" width="17%" height="500" fill="url(#day)" />
</svg>
Images of Renderings
VIEW FULLSCREEN TO SEE EFFECT
Chrome (reference):
http://i.imgur.com/BMjFmH6.png
Firefox (with shape-rendering: crispEdges;):
http://i.imgur.com/4cgZjq7.png
Firefox (with .5px renderings, after multiple included svg's. Note, image rendered at different size than previous ones.)
(Can't post 3 links, but use this id after imgur.com):
JiuswRF.png
Any help on this problem would be greatly apreciated.
Thanks!

If you want to stay with pattern, I'd recommend rewriting all those units in absolute OR relative units, or to dynamically switch your viewBox dimensions in JavaScript.
An alternative is to generate a pattern using Filters. This displays crisply in Chrome and Firefox (although IE is still buggy)
<filter id="better" primitiveUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
<feFlood x="0%" y="0%" width="100%" height="0.2%" flood-color="#B00" result="redline"/>
<feFlood x="0%" y="3.9%" width="1%" height="0.2%" flood-color="#0B0" result="stroke-dash"/>
<feFlood x="0%" y="3.9%" width="2%" height="0.2%" flood-color="#FFF" result="stroke-dash2"/>
<feComposite operator="over" in="stroke-dash" in2="stroke-dash2" result="full-dash"/>
<feTile in="full-dash" x="0%" y="3.9%" width="100%" height="0.1%" result="green-stroke"/>
<feComposite x="0%" y="0%" height="8%" width="100%" operator="over" in="redline" in2="green-stroke" result="one-tile"/>
<feTile in="one-tile" x="0%" y="0%" height="100%" width="100%"/>
</filter>
http://codepen.io/mullany/pen/CLsxv

Related

svg - keep fill texture original size when resizing a path

I define a svg <pattern> like this:
<svg height="10" width="10" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<pattern id="circles-1_4" patternUnits="userSpaceOnUse" width="10" height="10">
<image xlink:href="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIxMHB4IiBoZWlnaHQ9IjEwcHgiIHZpZXdCb3g9IjAgMCAxMCAxMCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMTAgMTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxjaXJjbGUgY3g9IjEuMjUiIGN5PSIxLjI1IiByPSIxLjI1Ii8+PHJlY3QgZmlsbD0ibm9uZSIgd2lkdGg9IjEwIiBoZWlnaHQ9IjEwIi8+PC9zdmc+"
x="0" y="0" width="10" height="10">
</image>
</pattern>
</defs>
</svg>
visually, this is the equivalent of this:
So then I call my css for svg as a fill like this:
svg #VISUEL-3 * {fill: url(#circles-1);}
I get a pretty good result:
But when I display my graphic smaller (1/4 in this i.e), the fill adapt like this
It's difficult to see on the screenshots because the scale is broken due to the width 100% of stackoverflow but the vector-effect:non-scaling-stroke works perfectly so the strokes have the same size between the first and the second screenshot and the number "1,2,3,4,5,6" as well.
So as you can see the fill has adapted...
Is it possible to keep the same pattern size (same size of dots) like in css? That look messy visually when I have two graphics that are not of the same size and are next to each other.
Is my method right to obtain that? (I'm ready to change my method..)
The pattern elements are applied to the referencing element before transformations on the element or one of its parents are applied - so the pattern size gets transformed as well. The only way to counteract this is to write a seperate pattern element for each scale you us it at, including a patternTransform with the inverse scale. Fortunately, there is a mechanism for cloning patterns with a xlink:href attribute.
.simple {
fill: url(#dots);
}
.quarter {
fill: url(#quadrupleDots);
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" height="150">
<defs>
<pattern id="dots" patternUnits="userSpaceOnUse" width="10" height="10">
<circle r="1.25" cx="1.25" cy="1.25" />
</pattern>
<pattern id="quadrupleDots" xlink:href="#dots" patternTransform="scale(4)" />
</defs>
<rect id="shape" class="simple" x="20" y="20" width="100" height="100" />
<rect class="quarter" x="800" y="80" width="100" height="100" transform="scale(0.25)" />
</svg>

Creating a linear gradient SVG filter

Essentially I'm trying to create an gradient alpha mask in using SVG and CSS (like this), and since the mask property is no longer on the standards track I'm exploring the filter route.
I've created a vertical alpha mask in Sketch, with the top being 0% #000000 and the bottom being 100% #000000, then exported it as an SVG and tweaked it using guidance from this O' Reilly article. It now looks like this:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<!-- Start by creating our vertical linear gradient -->
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="alphaLinear">
<stop offset="0%" style="stop-color: #000000; stop-opacity: 0%;" />
<stop offset="100%" style="stop-color: #000000; stop-opacity: 100%;" />
</linearGradient>
<!-- Create a rectangle and apply the gradient as its fill -->
<rect id="boxRect" x="0" y="0" width="100%" height="200" style="fill: url(#alphaLinear);" />
<!-- Using that rectangle, we'll create a filter -->
<filter id="alphaGrad">
<feImage xlink:href="#boxRect" result="grad"/>
<feDisplacementMap scale="10" xChannelSelector="R" yChannelSelector="G" in="SourceGraphic" in2="grad"/>
</filter>
</defs>
<use id="gradientBox" fill="url(#alphaGradient)" xlink:href="#boxRect"></use>
</svg>
My knowledge of SVG isn't the greatest so I'm suspecting this is where I've gone wrong.
Next, I applied the filter using filter (and -webkit-filter) along with referencing the filter ID #alphaGrad:
-webkit-filter: url('http://blahblah.com/alphagradient.svg#alphaGrad');
But, of course, this it doesn't work. Can anyone help me get the hang of this? Or is this even possible? If not, can someone recommend a method of how to achieve this?
Thanks in advance!
Update: here's a pretty basic fiddle of what I'm doing...
There are many errors and misconceptions in your example (why did you think a displacementMap would help you?)
Why don't you start from the code below - pure SVG using an SVG mask and an SVG image.
<svg width="600px" height="600px" viewbox="0 0 600 600">
<defs>
<linearGradient id="alphaLinear">
<stop offset="0%" stop-color="#FFFFFF" stop-opacity="0%" />
<stop offset="100%" stop-color="#999999" stop-opacity="100%" />
</linearGradient>
<mask id="Mask">
<rect x="0" y="0" width="600" height="600" fill="url(#alphaLinear)" />
</mask>
</defs>
<image xlink:href="http://upload.wikimedia.org/wikipedia/commons/7/71/Anadama_bread_(1).jpg" width="600" height="600" x="0" y="0" preserveAspectRatio="xMinYMin meet" mask="url(#Mask)"/>
</svg>
Few remarks:
SVG (and CSS) opacity value is not percertentual range but 0.0 - 1.0 range.
Mentioned mask property appears to be just prefixed in Webkit and unprefixed in Gecko.
If your target environment is HTML + CSS, you might not necessarily need SVG: you could get similar effect using linear-gradient and RGBA
background-image: linear-gradient(to bottom, rgba(0,0,0,1) 0%,rgba(0,0,0,0) 50%); on some overlay (pseudo) element. pointer-events: none; could be useful then.

How do I use svg patterns in a cross browser consistent way?

I want a SVG image (prerendered, but inserted with js in an svg tag, to allow for some further manipulation) to be able to use a predefined pattern, using the "pattern" tag. Sounds simple enough, doesn't it? Well, turns out Chrome (Webkit?) behaves a bit different from any other browsers, and now I'm not sure what the best way would actually be to achieve this.
My svg looks like this:
<svg>
<defs>
<pattern id="specialPattern">...</pattern>
</defs>
<path class="special"></path>
</svg>
and I want paths with the class special to have "pattern" as fill.
Attempt one: Works in Chrome, not in FF or Opera
My first attempt was to simply put this in my css:
.special { fill:url("#specialPattern");}
This actually works in Chrome, though when you think about it, it probably shouldn't. The other browsers I tried interpret this url as relative to the file it's in (the css file), which makes more sense.
Attempt two: Works in FF and Opera, not in Chrome
Next attempt: Provide an absolute url to the pattern.
.special { fill:url("//example.com/styles/svgWithStyleDeclaration.svg#specialPattern");}
While this works as expected in FF and Opera, Chrome now resets the fill instead (I have no idea where it is actually looking for that style)
Attempt three: Works, kind of
Inlining the style in the SVG works everywhere it seems: style="fill:url('#specialPattern')"
And though I guess this is a case where the lines between content and presentation is blurred, in my case at least it would be much better to keep style decclarations elsewhere (not least because this would make my SVG need to be much bigger)
Attempt four: Works (?) but dirty
I haven't tested a lot of browsers, so I'm not sure about how water proof it is, but it seems to me like using a css hack to detect webkit browsers would work:
#media screen and (-webkit-min-device-pixel-ratio:0) {
.special {fill: url("#specialPattern");}
}
.special { fill:url("//example.com/styles/svgWithStyleDeclaration.svg#specialPattern");}
Now, there MUST be a more elegant way to solve this. How should it be done?
Edit: Turns out that IE behaves like Chrome here, so you would also need to make sure IE<=9 has 'fill: url(#specialPattern)'
Here's a Fiddle that I did for manipulating patterns and masks. It's a ratings display in svg xml, in which I wanted to be able to use a percentage for the rating bar.
Fiddle: http://jsfiddle.net/cnLHE/296/
By changing the last line to "width="50", and pressing Run, you can see the rating bar resizes.
<svg width="100%" height="100%" viewBox="0 0 100 20" version="1.1">
<defs>
<pattern id="pattern1" x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="5" style="fill:white" />
</pattern>
<pattern id="pattern2" x="0" y="0" width="20" height="20"
patternUnits="userSpaceOnUse" >
<circle cx="10" cy="10" r="9" style="fill:white" />
<circle cx="10" cy="10" r="7" style="fill:black" />
</pattern>
<mask id="mask1" x="0" y="0" width="100" height="20" >
<rect x="0" y="0" width="100" height="20"
style="stroke:none; fill: url(#pattern2)"/>
</mask>
<mask id="mask5" x="0" y="0" width="100" height="20" >
<rect x="0" y="0" width="100" height="20"
style="stroke:none; fill: url(#pattern1)"/>
</mask>
</defs>1<rect x="0" y="0" width="500" height="20" fill="url(#pattern2)" style="fill:#2498c7; mask: url(#mask1)"/>
<rect x="0" y="0" width="50" height="20" style="fill:#2498c7; mask: url(#mask5)"/>
</svg>
I didn't have any cross browser issues, BUT, I did have issues with the SVG disappearing intermittently in grid layouts. In webkit with multiple instances in page, they weren't always showing.
Further info available at css-tricks: http://css-tricks.com/using-svg/

Different Viewbox behaviour for inline vs embedded svg

I have an SVG image that I would like to keep as a separate file to my main html file. I am trying to make it work as an embed tag but have problems with different view box behaviour.
Below is the code that works as I would like. The viewbox takes up as much space as possible without overflowing the window
<!DOCTYPE html>
<body style="overflow:hidden; margin:0" bgcolor="#E6E6FA">
<div>
<!-- <embed src="example.svg" type="image/svg+xml" /> -->
<svg
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
viewBox="0 0 400 600">
<g stroke-width="2">
<rect height="600" width="400" stroke="#FF0" y="0" x="0" fill="#808080"/>
<rect height="80" width="100" stroke="#808080" y="80" x="40" fill="#F60"/>
<rect height="120" width="160" stroke="#808080" y="250" x="160" fill="#FC0" onclick="alert('one')"/>
</g>
</svg>
</div>
</body>
When I replace this with the embed tag that references this exact same text. The viewbox fills the width so that overflows the vertical dimension of the window.
I have worked out the answer. By moving from a width attribute to setting the width in the style attribute the problem is resolved.
html file contains a div and embed with style set widths.
<body style="overflow:none; margin:0" bgcolor="#E6E6FA">
<div style="height:100%">
<embed src="example.svg" type="image/svg+xml" style="height:100%;width:100%"/>
</div>
</body>
And the SVG file contains the view box
<svg
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
viewBox="0 0 400 600">
<g stroke-width="2">
<rect height="600" width="400" stroke="#FF0" y="0" x="0" fill="#808080"/>
<rect height="80" width="100" stroke="#808080" y="80" x="40" fill="#F60"/>
<rect height="120" width="160" stroke="#808080" y="250" x="160" fill="#FC0" onclick="alert('one')"/>
</g>
There are still some odd behaviours when shrinking the window (it only resizes properly when the width is changed with the height) so if anyone has a better answer I would be keen to hear it

Scaling SVG rect on hover using CSS transform

It seems that applying the same CSS transform on hover to an HTML or SVG element does not create the same effect. As you can see in the following fiddle, the p and rect do not behave the same way while scaling, and that is precisely my problem.
http://jsfiddle.net/rKD7T/2/
How could I make the rect behave exactly as the p and scale properly?
I tried scaling the rect with a matrix - taking into account the origin point - but it did not seem to work either, or I did it wrong.
I'd like to stick to CSS solutions here but JS ones might also be an option.
Thanks for your help.
This seems about right.
<div>
<p></p>
<p></p>
<p></p>
<p></p>
</div>
<svg>
<g transform="translate(20, 40)">
<rect x="-20" y="-40" width="50" height="100"/>
<g transform="translate(55, 0)" >
<rect x="-20" y="-40" width="50" height="100"/>
</g>
<g transform="translate(110, 0)" >
<rect x="-20" y="-40" width="50" height="100"/>
</g>
<g transform="translate(165, 0)" >
<rect x="-20" y="-40" width="50" height="100"/>
</g>
</g>
</svg>
It works in Firefox trunk but doesn't seem to work with Firefox 16. I haven't tested Firefox Beta or Aurora to see in exactly when it's fixed.

Resources