An SVG background is appearing Blurry in Chrome and other Blink/webkit based browsers:
Screenshot of a portion of the SVG in Chrome:
Screenshot of a portion of the SVG in Firefox:
This only happens when displaying the SVG with "background-repeat: true" and "background-size: contain" CSS values. We'd like to repeat the SVG background height as many times as is necessary, since the page height is dynamic and stretching the vector image would look poor.
The SVG is displayed inline in the CSS in the sample page below, but the issue happens in the same way when I link to the external SVG image.
Here's a test page which shows this behavior:
https://august-13-2020-test-canvas.bubbleapps.io/version-test/pagemaker-test-original-2
(log in with "username" and "password", we're required to put this authentication here).
A test page with a properly displayed (crisp/smooth edged) SVG is here: https://august-13-2020-test-canvas.bubbleapps.io/version-test/pagemaker-test-online-1
A version with crisp/smooth edges is displayed in exactly the same way - the only difference is the content of the SVG.
Here's a link to the background SVG for the blurry page: https://dd7tel2830j4w.cloudfront.net/d44/f1588704991659x396570736162959360/background.svg
All the SVGs I tested from this page had crisp edges: https://www.svgbackgrounds.com/#flat-mountains (the bottom-right one is the one used in the above link)
In the process of trying to fix this issue or identify the cause of it within the SVG code, I've edited the SVG quite a bit, attempting the following:
Converting all SVG point values (path's d attributes) to integers
Adding "PreserveAspectRatio" to the SVG's opening tag
Removing the height and width from the opening declaration of the SVG
Removing the "linear gradients" from the SVG and replacing them with static colors
Doubling the size of the SVG shapes to see if the blurriness decreases with a larger initial width and height
Adding the "crispEdges" property to the SVG paths
Optimizing the SVG (using SVGomg)
Additionally, I've attempted to change the CSS a bit, but couldn't get it working.
Some ideas I have for workarounds are the following:
Using multiple background images to repeat the display of the SVG (display it 5-10 times in the background, mimicking the background-repeat: repeat-y effect but by including multiple background images)
Using JS to draw the SVG inline on the page (where this bug doesn't happen), creating an HTML that is exactly the same height as our group's dynamic height (which can change at any time without triggering a JS event) and repeating the SVG somehow within that group.
Asking a designer for a different SVG background, and hoping that the blurriness issue will not repeat.
Any help here would be much appreciated, I'm pulling my hair out on this and wasn't able to fix the issue after consulting several developers on CodeMentor.io.
Blink seems to apply a faulty algorithm, first rendering the SVG at a wrong size and then scaling the resulting raster image. This is tricky to work around, as two scaling mechanisms are involved, SVG viewBox and CSS background-size.
I can only offer a partial solution, working in Chrome and Edge (both engines), but failing in Firefox.
It moves the responsibility for scaling and repetition from the CSS background properties to the SVG itself with a <pattern> element. The complete content of the SVG image is moved inside this element, including setting the viewBox attribute to the same values.
Then, the width and height values for pattern repetition are set to width="100vw" height="504vw". This fills the viewport width and keeps the aspect ratio for the height. (Firefox seems not to be able to interpret vw units in this context).
Finally, a <rect> with width = height = 100% is defined and filled with the pattern, and the root <svg> element, without a viewBox attribute, is similarly set to width = height = 100%.
<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
<pattern id="pt" width="100vw" height="504vw" x="0" y="0" viewBox="0 0 1440 7258" patternUnits="userSpaceOnUse" preserveAspectRatio="xMinYMin meet">
<rect width="1440" height="7258" fill="white"/>
<path d="M-137 1749L1546 1994.95V2870L-137 2624.64V1749Z" fill="#F7F8FF"/>
<path d="M-137 3776L1546 4021.95V4897L-137 4651.64V3776Z" fill="url(#paint0_linear)"/>
<path d="M-137 3969L1546 4214.95V4900L-137 4654.64V3969Z" fill="url(#paint1_linear)"/>
<path d="M1319 2764L1545 2796.96V2870L1319 2837.12V2764Z" fill="#264CE9"/>
<path d="M-53 2645L96 2666.68V2744L-53 2722.37V2645Z" fill="#FBE89F"/>
<path d="M-29 2571L307 2620.13V2699L-29 2649.99V2571Z" fill="#54A5F2"/>
<path d="M1209 2820L1545 2869.13V2948L1209 2898.99V2820Z" fill="#6AD2F6"/>
<path d="M-147 4649L307 4715.42V4891L-147 4824.74V4649Z" fill="#6AD2F6"/>
<path d="M-137 -233L1546 12.9461V688L-137 442.638V-233Z" fill="url(#paint2_linear)"/>
<g style="mix-blend-mode:multiply">
<path d="M987 -144L2119 21.4151V388L987 222.978V-144Z" fill="#6AD2F6"/>
</g>
<path d="M-137 27L1546 272.946V948L-137 702.638V27Z" fill="url(#paint3_linear)"/>
<path d="M-258 455L490 564.509V794L-258 684.751V455Z" fill="url(#paint4_linear)"/>
</pattern>
<linearGradient id="paint0_linear" x1="43.9999" y1="3807" x2="458.5" y2="4665" gradientUnits="userSpaceOnUse">
<stop stop-color="#264CE9" stop-opacity="0.06"/>
<stop offset="1" stop-color="#F7F8FF" stop-opacity="0.26"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="43.9999" y1="4000" x2="1229" y2="5099" gradientUnits="userSpaceOnUse">
<stop stop-color="#264CE9" stop-opacity="0.06"/>
<stop offset="1" stop-color="#F7F8FF" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear" x1="194" y1="87.4999" x2="1671" y2="300" gradientUnits="userSpaceOnUse">
<stop offset="0.270833" stop-color="#264CE9"/>
<stop offset="1" stop-color="#6AD2F6"/>
</linearGradient>
<linearGradient id="paint3_linear" x1="194" y1="347.5" x2="1671" y2="560" gradientUnits="userSpaceOnUse">
<stop stop-color="#264CE9"/>
<stop offset="1" stop-color="#6AD2F6"/>
</linearGradient>
<linearGradient id="paint4_linear" x1="-108" y1="550.5" x2="490" y2="638" gradientUnits="userSpaceOnUse">
<stop stop-color="#264CE9" stop-opacity="0.43"/>
<stop offset="1" stop-color="#264CE9"/>
</linearGradient>
<rect width="100%" height="100%" fill="url(#pt)" />
</svg>
I have simplified the markup a bit, but these changes are all cosmetic, including the removal of the clipPath - it is applied for pattern elements, anyway.
Never found a solution to this issue (or at least failed to implement the solution presented by ccprog).
We chose to edit the SVG files to be longer. Our SVG files are being used as the background for web pages that have dynamic lengths, and theoretically have no limit in their height.
By repeating an SVG that is ~8000px tall 5 times, it covers up until a web page would reach 40000px height, which should be fine for our use case. I used inkscape to go in and copy the content of each SVG and then replicate that content several times, making the final SVGs 5x taller than the original ones.
Related
I have created this Instagram icon in Illustrator. I am trying to get it to display properly on an HTML page but it's not working properly. After exporting the svg image I copy the svg code generated by Illustrator into my HTML and it scales funny; cutting out some edges and making the strokes much thicker. It appears to be independent of parent element.
Scaling the svg using its height and width property or transform doesn't do anything and the viewBox dimensions match that of the image. Check out the screenshots.
Generated svg code:
<svg viewBox="0 0 22 22">
<g id="Shape">
<path class="cls-1" d="M16,22.2H6.41A6.21,6.21,0,0,1,.2,16V6.41A6.22,6.22,0,0,1,6.41.2H16a6.21,6.21,0,0,1,6.2,6.21V16A6.21,6.21,0,0,1,16,22.2ZM6.41,2.2A4.22,4.22,0,0,0,2.2,6.41V16a4.21,4.21,0,0,0,4.21,4.2H16A4.2,4.2,0,0,0,20.2,16V6.41A4.21,4.21,0,0,0,16,2.2Z"/>
<path class="cls-1" d="M11.2,17A5.78,5.78,0,1,1,17,11.2,5.79,5.79,0,0,1,11.2,17Zm0-9.56A3.78,3.78,0,1,0,15,11.2,3.79,3.79,0,0,0,11.2,7.42Z"/>
<circle class="cls-1" cx="17" cy="5.14" r="1.25"/>
</g>
</svg>
How it looks in the browser:
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?
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
does anybody know if the following image could be made in CSS? Light and dark lines could and should be equal width and edges fade in to darker color so that overall background would be dark color (dark blue in this case).
Any help is well appreciated. My google skills didn't provide any help on this kind of effect, only 'starburst stickers / badges kind of things' was found.
No. Sadly, the css3 generated image specs do not include conical/angular gradients (though they might come out in the next revision!) which would be the most likely way to do this using only css. However, you can do this using css+svg. I actually had this svg document sitting around from an experiment I did once:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="512px" height="512px" viewBox="-256 -256 512 512" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Burst</title>
<defs>
<g id="burst">
<g id="quad">
<path id="ray" d="M0,0 -69,-500 69,-500 z" />
<use xlink:href="#ray" transform="rotate(30)"/>
<use xlink:href="#ray" transform="rotate(60)"/>
<use xlink:href="#ray" transform="rotate(90)"/>
</g>
<use xlink:href="#quad" transform="rotate(120)"/>
<use xlink:href="#quad" transform="rotate(240)"/>
</g>
<radialGradient id="grad" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop offset="0%" stop-color="white" stop-opacity="0.65"/>
<stop offset="100%" stop-color="black" stop-opacity="0.65"/>
</radialGradient>
<!-- a circle mask -->
<mask id="m"><circle r="256" fill="white"/></mask>
</defs>
<!-- added a mask and scaled it to a different aspect ratio below. scale(x,y) -->
<g mask="url(#m)" transform="scale(1, 0.75)">
<use xlink:href="#burst" fill="lightslateblue"/>
<use xlink:href="#burst" fill="darkslateblue" transform="rotate(15)"/>
<circle r="360px" fill="url(#grad)" />
</g>
</svg>
Set that as your background-image, and set the css background-size: cover. That's it. Here's a fiddle using this image in a data url.
Yes, it's possible.
But it takes some work.
I had this exact same question, and could not find any examples of this effect being done with pure CSS. And so, I decided to tinker around with it.
After a lot of experimentation, I finally came up with a solution that not only were in CSS, but also one that is rather portable (relatively speaking).
I started off with creating just the top half and the bottom half separately, using linear-gradient trickery on ::before and ::after pseudo elements, and the second step (which by far was the most time consuming step) was merging the two halves into a single element.
Working demo: http://codepen.io/pestbarn/pen/aBybeK
(the original poster wanted a vignette effect, which I've created separately in the above demo, using a div overlay with a radial gradient)
I've provided both the vanilla CSS and a Sass mixin at github.com/pestbarn/starburst.css, and you'll find some examples at the official demo page.
Is this cross-browser?
As far as I can tell, yes. You can see the current browser support in the repository.
Can I animate it?
Yes, like you would animate any other elements. Try it out for yourself!
Are there any caveats?
Alas, there is. Using two colors that are substantially different from another (e.g. in brightness) will create jagged edges. I'd therefore recommend using colors that are quite similar to one another.
Also, since the effect is created using pseudo elements, you will in some cases need to explicitly set the element's height and width.
Feel free to experiment!
There is an experimental property in a draft for CSS4 by Lea Verou:
div
{
repeating-conical-gradient(black, black 5%, #f06 5%, #f06 10%)
}
But as far as I understand, this is just a proposal and is not possible in CSS3 alone. Just stick with a background image, or you could try using triangle images in rotated elements.
With the addition of conic-gradient() to the CSS spec, it is now possible to create the effect using CSS that is intended for that type of effect.
Essentially, you'll set gradient stops like this:
background-image: conic-gradient( circle,
black 0%, black 5%,
white 5%, white 10%,
black 10%, black 15%,
...
);
Here's a working fiddle
And here's an animated version :-) The animation is a bit choppy on my browser, though. It could maybe be optimized a bit.
Note that this only works in WebKit browsers; that is, Chrome and Safari. But honestly, that covers the lion's share of users, and I'm sure the rest will add support for it soon enough.
There is currently a better solution than the "conic-gradient ()" method to extend the "marcus erronius" answer. There is a repeating-conic-gradient, which creates an image consisting of a repeating gradient.
div {
height: 500px;
background: repeating-conic-gradient(
hsl(0deg 0% 80% / 31%) 0deg 15deg,
hsla(0,0%,100%,0) 0deg 30deg
) #3c1c32
}
<div></div>
You read more about it at W3 CSS Image Values.
This property is not compatible with all browsers. Check caniuse for more information.
For some reason, only the top half of a button appears in Internet Explorer. The button renders fine in Firefox, Chrome, and Safari.
We are using "filter:progid:DXImageTransform" to apply a CSS gradient to the button with CSS.
Here's the site: http://www.tekiki.com. (There is only one button on the page right now.)
Any clues?
Couple of things:
1) I'd recommend trying out CSS3PIE, it allows you to use gradients etc and will have sorted out many issues that you might face.
2) IE9 doesn't have the filter support, so if you want it to work there you will need to use either an image, or a datauri of an SVG image like this:
background-image: url("data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%0A%20%20%20%20%20%3Csvg%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%20%20%20%20%20%3Cdefs%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3ClinearGradient%20id%3D%22grad%22%20x1%3D%220%22%20y1%3D%2250%25%22%20x2%3D%220%22%20y2%3D%22100%25%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23ff0000%22%20%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23000000%22%20%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FlinearGradient%3E%0A%20%20%20%20%20%20%20%20%20%3C%2Fdefs%3E%0A%20%20%20%20%20%20%20%20%20%3Crect%20x%3D%220%22%20y%3D%220%22%20width%3D%22100%25%22%20height%3D%22100%25%22%20style%3D%22fill%3Aurl%28%23grad%29%22%20%2F%3E%0A%20%20%20%20%3C%2Fsvg%3E%0A");
That's made by urlencoding an svg that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="grad" x1="0" y1="50%" x2="0" y2="100%">
<stop offset="0" stop-color="#ff0000" />
<stop offset="1" stop-color="#000000" />
</linearGradient>
</defs>
<rect x="0" y="0" width="100%" height="100%" style="fill:url(#grad)" />
</svg>
That has the advantage of working in Opera as well.
This means you'd do the normal grad, then that, then the filter to cover modern browsers, IE9, Opera and IE8 and down.
At this point, you may decide to write a script that generates an image of a grad for you, like this one: http://www.bradshawenterprises.com/blog/2010/dynamically-drawing-gradients-with-php/