It seems I'm hitting a lower limit on font-size or text in SVG. I can't seem to find anything about it in the docs, though.
I have a huge div, that contains a huge SVG part of which is filling the viewport completely. As a result my font-size can be less than 0.0105pt. At which point the text just disappears!
See this jsfiddle: https://jsfiddle.net/wc95t4dk/30/
<div style="position:absolute;top:-100000px; left: -100000px; width: 200000px; height:200000px">
<svg width="100%" height="100%" viewbox="0 0 100 100">
<text x="50.1" y="50.1" font-size="0.1pt" stroke="red" stroke-width="0.01" fill="red">My text</text>
<text x="50.15" y="50.15" font-size="0.011pt" stroke="green" stroke-width="0.001" fill="green">My text2</text>
<text x="50.25" y="50.15" font-size="0.01pt" stroke="blue" stroke-width="0.001" fill="blue">My text2</text>
</svg>
</div>
The red and green text displays fine but the blue one doesn't!
I am not sure about all browsers, but neither Chrome nor Firefox will render text whose font size is less than 0.5 screen pixels.
See: http://jsfiddle.net/vsxgy3fq/5/
However things get more complicated when there are SVG viewBox transforms (and other transforms) involved. I know that browsers have (or had) bugs related to this size check.
According to this answer https://stackoverflow.com/a/27165622/227507
it is caused by implementation detail where only 8 bits of precision (1/256) are reserved for decimal digits
Related
What I want on my site is a single line of gradient filled text. I want to be able to modify the text, adding and removing characters, without worry about how it will fit or align on a single line. Even if someone's device fails to load the font I design the text with, the overall width of the text should not change, which the the docs promise I can do with textLength:
By using textLength, you can ensure that your SVG text displays at the same width regardless of conditions including web fonts failing to load (or not having loaded yet).
Rather than show you my whole site, I threw together a toy site to illustrate what I am trying to accomplish. Here's a screenshot of it rendering properly in desktop chrome.
Below is the code:
<html>
<head>
<style>
svg{
width:800px;
height:960px;
background-color:#cccccc;
}
</style>
</head>
<body>
<svg viewBox="0 0 100 120">
<linearGradient
id="grad"
x1="0" x2="0" y1="0" y2="100%"
gradientUnits="objectBoundingBox"
>
<stop stop-color="cyan" offset="15%"/>
<stop stop-color="blue" offset="40%"/>
<stop stop-color="magenta" offset="65%"/>
<stop stop-color="red" offset="80%"/>
</linearGradient>
<text
textLength="100"
lengthAdjust="spacingAndGlyphs"
font-size="20"
x="0"
y="20"
fill="url(#grad)"
>
This line will shrink if "textLength" is set to a small enough value
</text>
</svg>
</body>
</html>
In my <text> tag I use textLength="100" and the viewbox is also set to width 100: viewBox="0 0 100 120", which is why everything fits neat and tidy on one line even though I crammed way to many characters in there.
It all fails when I go to the toy site on my iphone, however, as you can see in this screenshot.
Chrome, safari, firefox- it doesn't matter, they all fail and look the same. What was once around 80 characters of text, appears to be clipped down to 13 characters. The weird thing is, the clipping appears to occur in the middle of the SVG viewbox, while the visible letters appear to be scrunching/compressing properly, as though the textLength property is doing it's job.
I did some pretty extensive testing, and ended up throwing together this other not-so-toy site that compares various combinations of the textLength and fill attributes` to come to the conclusion that the only time things get messed up is when gradient fill and textLength are used in combination, as the result of browser specific mis-rendering with no documented explanation.
Is there anyway I can change my code above to make my toy site render properly or will I have to resort to JavaScript and wait on other browsers to get on the ball?
Is it possible to dynamically resize an SVG image (using HTML or CSS) to match the baseline and height of the surrounding text?
Something like this (the SVG image being the Windows logo in this situation):
Image 1
Image 2
The context is probably clear from the images; I want the SVG image to match the size of the text no matter what font face or font size the viewer of the page is using.
If possible, it should also still match the size of the text even if the user zooms in the page using their browser’s Zoom Text Only feature (like this one):
support.mozilla.org/en-US/kb/font-size-and-zoom-increase-size-of-web-pages#w_how-to-only-change-the-size-of-the-text
I suppose that, effectively, I want the browser to treat the SVG image as if it’s text.
…I realize that using a web font may actually be the optimal solution in this scenario, but I’d rather avoid it if I can help it. Other than it being a bit of an ugly solution to the problem, it also creates new issues, like:
even if I create the web font myself, the height of the logo won’t (exactly) match an em in every font in existence (although, at the very least, the sizes will probably be close)
there’s a higher chance that the user will have web fonts blocked over images
etc.
The naive answer would be to set the height of the SVG to 1em. But, of course, you want to match the X-height of the font, not the em height.
The good news is that X-height is consistent for a particular font, no matter how large it is. So once you find the right em value to set your SVG size to, it will work whatever font size you choose.
Demo
svg.keyicon
{
width: 0.8m;
height: 0.8em;
}
.small
{
font: 24px Arial;
color: black;
}
.large
{
font: 36px Arial;
color: blue;
}
<div class="small">
Press the
<svg viewBox="0 0 100 100" class="keyicon">
<circle cx="50" cy="50" r="50" fill="currentColor"/>
</svg>
key...
</div>
<div class="large">
Press the
<svg viewBox="0 0 100 100" class="keyicon">
<circle cx="50" cy="50" r="50" fill="currentColor"/>
</svg>
key...
</div>
I wrote an HTML page where I needed to embed certain sections of an image with hyperlinks. For this I used SVG tags so that I don't have to use image map tags, since they cannot scale well with the screen.
This is what the page looks like in chrome
<svg id="mySVG" style="width:100%;height:100%;" version="1.1" viewbox="0 0 2000 2000" xmlns="http://www.w3.org/2000/svg">
<image style="width:inherit;height:inherit;" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="Image URL">
</image>
<a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="Image URL">
<circle cx="45%" cy="33%" r="120" stroke="black" stroke-width="3" opacity="0" fill="#fff">
</circle>
</a>
.
.
//More <a> tags representing the various clickable points in the image
.
.
.
</svg>
Basically the image in the IMAGE tags don't load and the screen takes the color of the background. I know that chrome is much more lenient with the rules but I don't think I have made any errors. This code works perfectly well with Chrome, but in any other browser, the images don't load. The image links like 'Wallpaper', 'Button', 'poster' although open separately in new tabs if I click the point in the paper where they are supposed to be but otherwise they don't work.
An SVG <image> tag must have width and height attributes in SVG 1.1, CSS properties are not allowed.
Chrome is experimenting with implementing SVG 2 CSS Properties for width and height which is why it works there. The SVG 2 specification is unfinished and no other UA currently implements this feature. I imagine as the specification nears completion more UAs will implement this functionality though.
I have got svg with flexible height and width.
I'm trying to produce code equivalent to this:
<div id="svg-container">
<svg width='100%' height='100%' viewBox="0 0 100 100" preserveAspectRatio="none" style='background-color: yellow'>
<path
style="fill:none;stroke:blue;stroke-width:5;"
d="M0% 10% L50% 10% L50% 90% L100% 90%" <-here is the problem
/>
</svg>
</div>
So when I scale #svg-container i will get:
But since I can't create path with percent coordinates the best I can do is: (JSFiddle)
<div id="svg-container">
<svg width='100%' height='100%' viewBox="0 0 100 100" preserveAspectRatio="none" style='background-color: yellow'>
<path
style="fill:none;stroke:blue;stroke-width:5;"
d="M0 10 L50 10 L50 90 L100 90"
/>
</svg>
</div>
Which gives me this results:
On the second picture you can see problem with stretched stroke-width.
My question is: how to achieve behavior like on the first picture?
I'm not looking for JavaScript answers and breaking path.
Seems like you want a style of vector-effect: non-scaling-stroke
Note that not all UAs implement this but Chrome and Firefox certainly do.
I am sorry to say I think you will only be able to do this with JavaScript, even if this is not the answer that you're looking for. What is happening is that you are first generating the SVG path, then resizing it afterward so the image becomes stretched.
To use JavaScript you can use (browser.width/100)*10 to get 10%, for example, and this should work for all sizes of browser screen.
How are you re-scaling the image (i.e. is it a CSS #media query)? It might be possible to draw the path after the re-scale, but again I feel this will need JS as you will need to load the content after the browser load.
Sorry to answer in opposition to what you have asked, but unless there is an alternative I think this is the only way you can do this.
This is my first time using SVG so apologies if this is a stupid question but I am trying to create a clickable continent map on my site and have acquired an SVG image with the continents mapped out correctly from wikipedia.
http://commons.wikimedia.org/wiki/File:Continents.svg
However, this image is 585 x 299 pixels and I require an image that is 292 x 137 pixels. I've read online that these images are scalable and that all you need to do is modify the width and height value in the svg definition so I have done so here:
<svg width="292" height="137" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet">
However, this only scales the canvas as such and does not scale the internal areas. How do I get the areas to scale to the modified dimensions of the image?
The SVG will be any size you tell it to in the CSS
JSfiddle Demo
CSS
svg {
width:292px;
height:137px;
border:1px solid grey
}
This works with or without the dimensions stated in the SVG. the important item is the 'viewbox' which sets the co-ordinate structure for the SVG.
The only way I have found so far is to wrap all of my areas in a tag and they apply a scale of
<g transform="scale(0.68)">
Use a viewBox like this :
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.0"
width="292pt" height="137pt"
viewBox="0 0 468 239"
preserveAspectRatio="xMidYMid meet"
>
<g
transform="translate(0,239) scale(0.016963,-0.016963)"
fill="#000000"
stroke="none"
>
http://jsfiddle.net/Vac2Q/4147/
Add a viewBox attribute (viewBox="0 0 585 299" is probably what you want) to the svg element. We can simulate what that would look like by using a fragment identifier which will impose a viewBox on the original file e.g.
http://upload.wikimedia.org/wikipedia/commons/9/95/Continents.svg#svgView(viewBox(0,0,529,290))
That sure displays differently in Firefox.