using SVG from sprite in a background - html
My goal is to use SVG in repeated background, but I need to be able to change its fill color in CSS for usage in the different parts of the website.
As far as my understanding of the SVG, it can't be laoded as an external file (background:url(image.svg)), because then I am not able to change the CSS property like fill proeprty of it. On the other hand, SVG can't be inlined in HTML (<svg>...</svg>) as then I am not able to use/reference it in background property.
Please correct me if I am wrong, or do you have any solution for this?
As far as my understanding of the SVG, it can't be laoded as an
external file (background:url(image.svg)), because then I am not able
to change the CSS property like fill proeprty of it.
Consider using CSS filters to change svg coloration instead of fill
In the example below the svg file is loaded as an external file:
background-image:url(https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/android.svg);
and its color will be changed on hover using a combination of css filters
You can get the desired combination of filters for a specific color using the utility
https://codepen.io/sosuke/pen/Pjoqqp
Hover to change color
.android {
display:inline-block;
width:96px;
height:105px;
background-image:url(https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/android.svg);
}
.android.blue:hover {
filter: invert(8%) sepia(99%) saturate(7454%) hue-rotate(248deg) brightness(100%) contrast(143%);
}
.android.red:hover {
filter: invert(25%) sepia(100%) saturate(7420%) hue-rotate(6deg) brightness(98%) contrast(122%);
}
.android.gold:hover {
filter: invert(50%) sepia(31%) saturate(3357%) hue-rotate(113deg) brightness(99%) contrast(101%);
}
<div class="android blue">
</div>
<div class="android red">
</div>
<div class="android gold">
</div>
Ok so it's not super simple but, it can be done with some work to the SVG itself. if you look at the simple example you will see inside the tag under the you can essentially make a pattern of any SVG elements like a circle,rect, or a path.
So make the pattern as
<pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
make sure the width and height are the same as your SVG or it will cut it off
then outside of the defs you can make a rect object with the fill of your pattern fill="url(#dots)" this must use the id of the pattern
Simple example
.pattern {
background-color: #2e4057;
height: 100vh;
}
<div class="pattern">
<svg width="100%" height="100%">
<defs>
<pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
<circle fill="#bee9e8" cx="50" cy="50" r="25">
</circle>
</pattern>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="url(#dots)"></rect>
</div>
More advanced SVG
.pattern {
background-color: #2e4057;
height: 100vh;
}
<div class="pattern">
<svg width="100%" height="100%">
<defs>
<pattern id="duck" x="0" y="0" width="209" height="209" patternUnits="userSpaceOnUse">
<g>
<path fill="red" d="M105.572,101.811c9.889-6.368,27.417-16.464,28.106-42.166c0.536-20.278-9.971-49.506-49.155-50.878
C53.041,7.659,39.9,28.251,36.071,46.739l-0.928-0.126c-1.932,0-3.438,1.28-5.34,2.889c-2.084,1.784-4.683,3.979-7.792,4.308
c-3.573,0.361-8.111-1.206-11.698-2.449c-4.193-1.431-6.624-2.047-8.265-0.759c-1.503,1.163-2.178,3.262-2.028,6.226
c0.331,6.326,4.971,18.917,16.016,25.778c7.67,4.765,16.248,5.482,20.681,5.482c0.006,0,0.006,0,0.006,0
c2.37,0,4.945-0.239,7.388-0.726c2.741,4.218,5.228,7.476,6.037,9.752c2.054,5.851-27.848,25.087-27.848,55.01
c0,29.916,22.013,48.475,56.727,48.475h55.004c30.593,0,70.814-29.908,75.291-92.48C180.781,132.191,167.028,98.15,105.572,101.811
z M18.941,77.945C8.775,71.617,4.992,58.922,5.294,55.525c0.897,0.24,2.194,0.689,3.228,1.042
c4.105,1.415,9.416,3.228,14.068,2.707c4.799-0.499,8.253-3.437,10.778-5.574c0.607-0.509,1.393-1.176,1.872-1.491
c0.87,0.315,0.962,0.693,1.176,3.14c0.196,2.26,0.473,5.37,2.362,9.006c1.437,2.761,3.581,5.705,5.646,8.542
c1.701,2.336,4.278,5.871,4.535,6.404c-0.445,1.184-4.907,3.282-12.229,3.282C30.177,82.591,23.69,80.904,18.941,77.945z
M56.86,49.368c0-4.938,4.001-8.943,8.931-8.943c4.941,0,8.942,4.005,8.942,8.943c0,4.931-4.001,8.942-8.942,8.942
C60.854,58.311,56.86,54.299,56.86,49.368z M149.159,155.398l-20.63,11.169l13.408,9.293c0,0-49.854,15.813-72.198-6.885
c-11.006-11.16-13.06-28.533,4.124-38.84c17.184-10.312,84.609,3.943,84.609,3.943L134.295,147.8L149.159,155.398z"/>
</g>
</pattern>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="url(#duck)"></rect>
</svg>
hope this helps
a more complete tutorial here
Related
How can I bundle many SVG images inside just one?
It's not bad if I load an HTML page img, svg { background-color: #eee; margin: 20px; } <div> <img src="circle.svg"/> <img src="square.svg"/> </div> with just a pair of SVG images circle.svg <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300" width="400" height="300"> <circle cx="200" cy="150" r="100" stroke="red" fill="blue" stroke-width="10" /> </svg> square.svg <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300" width="400" height="300"> <rect x="100" y="50" width="200" height="200" stroke="green" fill="gray" stroke-width="10" /> </svg> but with over a hundred SVG images, the server gets excessively hit by requests. One solution is to serve the static files from a dedicated server, but this only dodges the problem. The number of requests remains high. How can I bundle many SVG images inside just one?
You could use a SVG sprite generator to create one big file with all images aligned in it. SVG sprite generator will also generate a CSS file in which each individual SVG will be represented with a specific class. In you HTML you just have to call each image by its class name. A basic sprite.css could be : .svg { background-image: url(sprite.svg) no-repeat; } .circle { background-position: top left; height:300px; width: 400px; } .square{ background-position: top right; height:200px; width: 200px; } And then in your html file you could just call: <div> <div class="circle"></div> <div class="square"></div> </div>
It sounds like you need an SVG sprite. I use this trick all the time. It's great. Just make your svg blocks symbol elements and nest them inside an svg like this: <svg id="svg-sprite" xmlns="http://www.w3.org/2000/svg"> <symbol id="svg-circle" viewBox="0 0 400 300" width="400" height="300"> <circle cx="200" cy="150" r="100" stroke="red" fill="blue" stroke-width="10" /> </symbol> <symbol id="svg-square" viewBox="0 0 400 300" width="400" height="300"> <rect x="100" y="50" width="200" height="200" stroke="green" fill="gray" stroke-width="10" /> </symbol> </svg> Note that you don't want the xlmns attribute on the individual symbol elements, just the root svg. And the root svg doesn't need a viewBox attribute, since that is encoded in the child symbol elements. Then you call the symbols elsewhere in the HTML like this via the <use> tag: <svg> <use xlink:href="#svg-circle"></use> </svg> Lastly, you need to hide the sprite in CSS: #svg-sprite { display: none; } Here's a Fiddle to demonstrate. Good luck!
The following is a combination of gael's and maqam7's answers, with a bug fix and some details. First, we combine the two SVGs into one. (We write our own script, use an editor's macros, use one of the web sites that do it, or do it by hand.) sprite.svg <svg id="mysprite" xmlns="http://www.w3.org/2000/svg"> <symbol id="circle" viewBox="0 0 400 300" width="400" height="300"> <circle cx="200" cy="150" r="100" stroke="red" fill="blue" stroke-width="10" /> </symbol> <symbol id="square" viewBox="0 0 400 300" width="400" height="300"> <rect x="100" y="50" width="200" height="200" stroke="green" fill="gray" stroke-width="10" /> </symbol> </svg> When we want a circle or a square, we use the xlink:href attribute (deprecated but continue to use it), which will invoke a sub-sprite. <div class="container"> <svg> <use xlink:href="sprite.svg#circle"></use> </svg> <svg> <use xlink:href="sprite.svg#square"></use> </svg> </div> There is no need to include the sprite in the body <img src="sprite.svg"/> as the sprite is referenced within each svg element. Hence there is no need to hide the global sprite. #svg-sprite { display: none; } Only the sub-parts appear. One caveat: Chrome loads an img and svg directly, but will refuse to load use/xlink:href unless you run a local server. Remaining issue(s) I'm not sure this is optimal. It may be that two requests continue to be sent. It's just that the cache will catch the second as identical. No harm is done. Still, loading once via a hidden svg may be a better approach, if someone can fill in the details.
Fill responsive svg with background image with preserving ratio
I try to draw a svg in my HTML Code to have a specific path/object with an background image. The object should be a little bit responsive (using bootstrap), but filled with the image and the image should preseve its ratio. <svg width="100%" height="370px" viewBox="0 0 1148.942 598.47" preserveAspectRatio="none" > <defs> <pattern id="img1" patternUnits="userSpaceOnUse" width="1153" height="680"> <image xlink:href="images/headerBackground.png" x="0" y="0" width="1153" height="680" /> </pattern> </defs> <path fill="url(#img1)" d="M1145.237,3.395H3.379v592c0,0,247.108-160.416,1141-99L1145.237,3.395z"/> </svg> You can see it here in the live demo: https://liveweave.com/N5nib6 https://jsfiddle.net/zyyvd86g/ Maybe anybody can help? I hope the problem is clear enough.
You can use max-width:100% for the svg element and div element wrap on this svg. You can get the responsive image div { width: 80%; height: auto; margin: 0 auto; } svg { max-width: 100%; height: auto; } <div> <svg width="100%" height="370px" viewBox="0 0 1148.942 598.47" preserveAspectRatio="none" > <defs> <pattern id="img1" patternUnits="userSpaceOnUse" width="1153" height="680"> <image xlink:href="images/headerBackground.png" x="0" y="0" width="1153" height="680" /> </pattern> </defs> <path fill="url(#img1)" d="M1145.237,3.395H3.379v592c0,0,247.108-160.416,1141-99L1145.237,3.395z"/> </svg> </div>
IMO opinion, the simple solution to your problem is to use a different preserveAspectRatio on your SVG. Using preserveAspectRatio="none" is going to stretch your SVG and cause problems. I'm assuming you want to keep the shape of the "swoop" on the bottom of your path. Correct? If that is the case, you might prefer to use preserveAspectRatio="xMidYMax slice" instead. This scales the SVG up to fill the full width of the SVG viewport, whilst keeping the aspect ratio the same, and keeping the bottom of the SVG viewBox on screen. <svg width="100%" height="370px" viewBox="0 0 1148.942 598.47" preserveAspectRatio="xMidYMax slice"> <defs> <pattern id="img1" patternUnits="userSpaceOnUse" width="1153" height="680"> <image xlink:href="http://lorempixel.com/1153/680/" x="0" y="0" width="1153" height="680" /> </pattern> </defs> <path fill="url(#img1)" d="M1145.237,3.395H3.379v592c0,0,247.108-160.416,1141-99L1145.237,3.395z"/> </svg>
SVG mask stroke color
I really hope someone here can help me out, since i'm stuck for 3 days straight now. I have a header image with half a circle cut out by using a SVG mask, this half circle needs to have a colored stroke but since it's a mask it won't let me do this. I have tried and searched everything, and came upon this codepen snippet which is using the SVG use tag: https://codepen.io/rewfergu/pen/oJCif However, i can not get this to work at all. Here is my SVG code including the white transparent stroke (as far as i got): <div id="myCarousel" class="carousel carousel-fade slide myCarousel-slide" style="height:auto; max-height:499px; overflow:hidden"> <div class="carousel-inner" role="listbox"> <div id="slide2" class="item active" data-navpos="" data-navposarrow="" data-center="1" data-maxheight="499" data-id="2" style="height:499px;"><img id="slideimg2" class="logofull img-responsive" src="http://placehold.it/1800x499.jpg"></div> </div> </div> <svg width="100%" height="100%"> <defs> <style type="text/css"><![CDATA[ circle { stroke: #942994; stroke-width: 5; } ]]></style> <mask id="mask" x="0" y="0" width="100%" height="100%"> <rect x="0" y="0" width="100%" height="100%" fill="#fff"/> <circle id="c1" cx="50%" cy="105%" r="180" fill="#000"/> </mask> </defs> <rect x="0" y="0" width="100" height="50" mask="url(#mask)" fill-opacity="0.7"/> </svg> And my CSS, applied on my header image (the carousel is 100% width and around 500px high): #myCarousel .item { border-bottom: 5px solid #942994; width: 100%; height: 100%; overflow-x: hidden; overflow-y: hidden; mask: url(#mask); } Unfortunately i can not use PNG's, because the header images need to be easily changable. Update: Created a new fiddle with my exact setup: https://jsfiddle.net/oqfdfart/2/ Also some strange behaviour: In Chrome, Edge and IE the half circle does not appear at all in the headerimage. Update: I found the answer, following my latest fiddle i've separated both SVG's like so: <svg width="100%" height="100%"> <defs> <style type="text/css"><![CDATA[ #inner { stroke: #942994; stroke-width: 5; fill-opacity: 0; z-index: 9999; } ]]></style> <mask id="mask" x="0" y="0" width="100%" height="100%"> <rect x="0" y="0" width="100%" height="100%" fill="#fff"/> <circle id="c1" cx="50%" cy="105%" r="180" fill="#000"/> </mask> </defs> <rect x="0" y="0" width="100" height="50" mask="url(#mask)" fill-opacity="0.7"/> </svg> <svg id="innercircle" width="100%" height="100%" x="0" y="0"> <circle id="inner" x="0" y="0" cx="50%" cy="105%" r="181" fill="#fff" /> </svg> And added the following CSS: #headeroverlay { width: 100%; position: absolute; top:0; background: rgba(255,255,255,0); height: 499px; z-index: -1; } #innercircle { position: absolute; top: 0; left: 0; } First i had a very dark overlay on top of my headerimage, but this was fixed by giving #headeroverlay the z-index -1. Maybe this solution is not so pretty since i had to define a fixed height for my headersection, but at least for this project that's no problem. If someone has a better solution i'm very curious :) Also i'm still stuck with Chrome, Edge and IE not rendering my SVG's at all.
Masks only affect the translucency of the element it is applied to. If you want to outline the hole with a colour, then you'll need to create an element the same shape as the hole, then draw it on top of the masked element.
svg mask rect has no dimension in firefox
I animate on hover the opacity of a masked SVG to put a semi transparent layer over an image. It works all fine except with Firefox, where the mask is not showing and the image goes all white. The mask is applied to the image through CSS <svg id="svg-fade" class="visible-sm-block img-circle" width="200" height="200"> <defs> <mask id="mask2" width="200" height="200" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox"> <rect x="0" y="0" width="200" height="200" style="stroke:none; fill: #bbbbbb"></rect> <rect x="95" y="50" width="10" height="100" style="stroke:none; fill: #000000"></rect> <rect x="50" y="95" width="100" height="10" style="stroke:none; fill: #000000"></rect> </mask> </defs> <rect class="target" width="200" height="200" style="stroke:none; fill: rgba(255,255,255,1)"></rect> </svg> The live code can be viewed here. Is there an attribute missing or why is the mask not showing up in Firefox? Your help is much appreciated!
For any future reference: I found that the id of the mask has to be unique throughout the whole document even when the mask is defined in the very same SVG and you can't use a class instead either.
Cutting out a rectangular area of a photo using an svg mask in html5
My goal is to cut out a rectangular area of a photo using an svg mask in html5. I have attempted to implement this using the code below and in this fiddle, to no avail. Can anyone tell me what I'm doing wrong? html: <body> <svg id="svg-rect" width="50px" height="50px"> <defs> <mask id="masking" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox"> <rect width="100%" height="100%" /> </mask> </defs> </svg> <!--<svg id="svg-rect" width="50px" height="50px"> <rect width="100%" height="100%" /> </svg>--> <img src="https://scontent-a.xx.fbcdn.net/hphotos-prn1/t1.0-9/p235x165/75938_10152243783285987_398136218_n.jpg"/> </body> css: img { mask: url(#masking); position:absolute; top:0px; left:0px; } #svg-rect{ position:absolute; top:50px; left:60px; z-index:2; }
Applying SVG effects to HTML only works in Firefox. You have to use -webkit-mask in Chrome/Safari and that's been deprecated. Next, you have to fill your rectangle with a color for the mask to take effect. And there is a bug in firefox, where you have to specify the x/y offset for a rect in a mask in decimal form, %'s won't work. Change your rect definition to: <rect x=".2" y=".2" width=".25" height=".25" fill="white" /> And you'll see a mask effect (in Firefox only) or... to invert the mask, use an empty fill and a solid stroke <rect x="0" y="0" width="1" height="1" stroke="white" stroke-width=".4" /> The best way to do this for maximum compatibility, however, is to use inline SVG all the way, and just do your image content in SVG using the SVG image tag.
Elaborating on Michaels' last point, here's how you would do it in a pure SVG way. <svg width="235" height="314" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <mask id="masking"> <rect width="100%" height="100%" fill="white" /> <rect x="60px" y="50px" width="50px" height="50px" fill="black" /> </mask> </defs> <image width="235" height="314" mask="url(#masking)" xlink:href="https://scontent-a.xx.fbcdn.net/hphotos-prn1/t1.0-9/p235x165/75938_10152243783285987_398136218_n.jpg" /> </svg> Fiddle here