Prevent inline SVG pixel snapping in chrome - html

I have an svg that I'm using to show a wavy edge on a div. The svg needs to display as the same with as the div but due to some sub pixel snapping/rounding the alignment varies as you resize. Firefox seems to work fine. See demo:
https://jsfiddle.net/meojwnLv/
When using the svg as a background image with background-size:100% auto; it scales correctly but I want to be able to change the color so need it to be inline.
How can I prevent this from happening?
Thanks

It looks like Chrome is snapping the height and width of the SVG object to integer values. Since the SVG's width is much larger than its height, every 1px change in the height of the SVG is causing the width to change by about 10px.
viewBox="20 20 900 66"
There's an easy workaround for this — just make the SVG taller:
viewBox="20 20 900 500"
Here's an updated JSFiddle.

Related

Svg renders at a different pixel count than specified

I am trying to get exact pixel counts on an svg, but it seems off. I want it to be 300x56, but for some reason its rendering as 222x41
This is the code
But it seems like the pixels are inconsistent when I inspect:It says 222x41 here
but 300x56 here
How is 222x41 calculated, and why does chrome debugger show both 300x56 and 222x41?
Explaining what you are seeing would require seeing more of the page. We would need to see how the element containing the <svg> is styled.
But here's a quick explainer.
The area of your page that the SVG is displayed in is called the "viewport". The size of the viewport is determined by one of two things:
The width and height of the SVG if they use explicit units - such as px, or
The size of the SVGs parent container if the SVG specifies percentage units.
Your SVG has a viewBox this determines which area of the SVG canvas is displayed in the viewport. The browser will scale the area of the viewBox up of down so it fits in the viewport. Unless you turn it off, the contents will keep its aspect ratio
So since your SVG has a viewBox and its width and height are set to "100%", the SVG viewport will be scaled to fit into the parent container and the SVG contents will be scaled to fit into that viewport.
You said you were trying to make the SVG be 300x56, but it looks like all you did to try and achieve that is set the <rect> to that size. That is not enough because of the reasons stated above. The effect of the viewport and the viewBox will be affecting the size that the rectangle is drawn at.
The viewBox of your SVG is 1500x280. Your rectangle is occupying a small part of that - from (10,10) to (310,66). Since your rectangle is being scaled down to 222.93x41.61, the SVG's parent container must be smaller than the viewBox. We can work out how big it must be:
1500 * (222.93/300) ~= 1115 (if the width is constrained) or
280 * ( 41.61/ 56) ~= 208 (if the height is constrained).
If you want your SVG to be exactly 300x56 always, then what you probably want is to set the SVG's width and height, not the rectangle's.
<svg width="300" height="56">
<rect width="300" height="56" rx="4"/>
</svg>
Now the SVG will behave the same as if it was a 300x56 pixel PNG.

Gap in vertical repeat of svg background

I have a simple div, with an SVG set as background image with vertical repeat. On Chrome and Firefox, depending on the screen size, I see a gap in varying sizes (please resize the window).
https://jsfiddle.net/bartadaniel/ejtvy7po/9/
.bg {
width: 50%;
height: 2000px;
display: block;
background-repeat: repeat;
background-size: contain;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='272' height='171' viewBox='0 0 272 171'> <rect class='cls-1' width='272' height='171' fill='green'/></svg>");
}
<div class="bg"></div>
Is there a reason for this?
That's happening due to a combination of background-size:contain and the pixel dimensions of your svg.
You're seeing the browser try to scale the image so that nothing overflows the bounds of your <div>. When you combine that scaling with image pixel dimensions of 171 (can't be evenly multiplied into 2000px) you get lines showing you the sub pixels you're browser is trying to display.
Simply remove the background-size:contain to solve it.
Edit:
In the case where you need to contain width, there are a few tricks to help get a better result.
Make the background image dimensions multiples of 10. Square would be best with something like 100x100px but it could also be a rectangle (try to get close to your target width) like 1000x100px.
Set background-size: 100% auto instead of contain. This will stretch the image proportionalty to fill the container width.
Use background-repeat: repeat-y to force a vertical repeat so the browser is only doing the math on one axis.
It is a problem of subpixel rendering.
Each browser rounds differently and SVG subpixel rendering is pretty messed up.
I suggest you to edit your SVG content to make it slightly bigger than your viewbox.
<svg xmlns='http://www.w3.org/2000/svg' width='272' height='171' viewBox='0 0 272 171'>
<rect class='cls-1' y='-.5' width='272' height='172' fill='green'/>
</svg>
Obviously this trick doesn't work for all the background SVG, but might be useful in your case.
Unfortunately, the only solution that reliably tackled this issue was to convert the SVG to a pixel-based format, like JPG. Apparently, the browsers have no problem scaling pixels but causes side effects at edges when scaling vector-based formats.
If your SVG will still look acceptable with less anti-aliasing, you can change the anti-aliasing of the shapes in your SVG using the shape-rendering property. Example:
<rect shape-rendering="crispEdges">
You can use this on these elements: <circle>, <ellipse>, <line>, <path>, <polygon>, <polyline>, and <rect>.

SVG looks ok in browser, but not when included as 'img src=file.svg'

I'm having trouble displaying an svg image correctly on an html page.
I created the image using snapsvg, extracted the svg and added xml and doctype tags.
The svg and the test page code is here:
https://gist.github.com/falconair/ed0fbbc5db4135d0f1b2
When I open the svg in chrome, it looks fine. When I open it in this html, the text at the boddom disappears, replaced by dashes:
<html>
<head></head>
<body>
<img src="/assets/composingcontracts/mappingdiagram.svg" width="850px" height="450px">
<img src="/assets/composingcontracts/mappingdiagram.svg" width="100%" height="100%">
</body>
</html>
Note that I display the image twice, once using 100% height/width and once using explicit values, I get the same result.
What's more, when I include this image in my actual web page (jekyll blog post), no matter what height/width values I use, only the top third of the image shows!
Any ideas?
If you are using a specific size like width="850px" height="450px", then the whole image should show. Unless it is in a container (eg. <div>) which is smaller than that.
However, when you use percentages (width="100%" height="100%"), that is referring to the size of the SVG "viewport", which is normally the parent object. But if you haven't specified a specific size for that parent element, SVG has to do some guessing.
What happens when you specify (100% x 100%) is that SVG sets the width of the SVG to 100% of the parent container. Then it tries to calculate a height based on that width and the aspect ratio of the SVG - which it gets from the viewBox. If there is no viewBox, it falls back to the default height for indeterminate elements, which is 150px. That will be why you are only seeing the top third.
You could fix this issue by adding viewBox="0 0 850 450" to your SVG. However then the SVG size will be controlled by its parent container. Which you will need to at least give a width to, otherwise the SVG will be scaled down to that "indeterminate" height of 150px.
Try exporting the image using the PNG file format and use the 100% height/weight. Hope it works.

SVG taking full height inside a table td

How is it possible to make SVG take the whole height inside a table cell?
The goal is doing this by changing just the code inside the cell () without hardcoding the height in pixels. It's working in firefox and safari, but in IE and chrome it's strange (no size in chrome, big in IE)
- The example in fiddle (you can't see the arrow)
Setting max-height:100% on your <svg> is a known work-around for Chrome.
See: http://jsfiddle.net/DyUGN/7/
Also adding display: block improves rendering further.
SVG {
display: block;
max-height: 100%;
}
See: http://jsfiddle.net/DyUGN/8/
I'm not sure what the hell IE is doing though. I don't know a workaround for that. You might have to use Phrogz's method. Or, if you can live with it, just set the <svg> width and height explicitly:
<svg version="1.1" width="18" height="18" ...
See: http://jsfiddle.net/DyUGN/9/
Here's the best answer I can come up with; it's not elegant. Use JavaScript to compute the height of the cell and set the height of the SVG to fill, minus a bit of arbitrary padding.
Demo: http://jsfiddle.net/DyUGN/6/
window.onresize = function(){
var svg = document.getElementsByTagName('svg')[0];
var td = svg.parentNode;
// No idea why an extra 2px need to be subtracted.
svg.setAttribute('height',(td.offsetHeight-2)+'px');
}
window.onresize();
The demo uses CSS to set the SVG to display:block (so that it does not get any extra 'height' from inline text descender spacing), sets the SVG to initially have a height of 1px (so that it is not initially too tall), and sets the cell specifically for the SVG to have no padding on it.
If you prefer to have padding on your cell, you will need to account for this explicitly in your code (subtracting off the amount of padding). Unfortunately there is no easy way in JS to calculate
the height of an element without its padding, nor to easily calculate the amount of padding applied in pixels.

Why do my HTML5 rectangles appear zoomed in?

Following http://www.html5canvastutorials.com/tutorials/html5-canvas-rectangles/, I have drawn some rectangles side-by-side on a canvas. The problem is that they appear greatly zoomed in; at a zoom of 1.0 they appear approximately five times their original size; they appear correctly sized (if fuzzy around the borders) at a zoom of around 0.16.
I expect I could get a workaround by making the pixel dimensions of the canvas much greater and zooming out, but what is the proper way to get a 1:1 scaling on a canvas? The canvas is styled to width and height of 100%, and the body has a margin of 0. Manually setting the canvas's width and height to the height and width of the window does not alter this behavior.
TIA,
the problem is, you set the width and height of the style for the canvas. You need to set the width and height attributes, not the css style. so something like:
<canvas id='mycanvas' width='800' height='600'></canvas>
More info in a similar question: Canvas is stretched when using CSS but normal with "width" / "height" properties