SVG - Top pixels were not visible - css

Using SVG as a source of my <img> and it is a clock having a circle and hour minute hands.
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg">
<g class="sprite" id="ico-watch" transform="scale(0.03125 0.03125)">
<path d="M512 960c-282.317 0-512-229.683-512-512s229.683-512 512-512 512 229.683 512 512-229.683 512-512 512zM512-23.040c-259.727 0-471.040 211.292-471.040 471.040 0 259.727 211.313 471.040 471.040 471.040 259.748 0 471.040-211.313 471.040-471.040 0-259.748-211.292-471.040-471.040-471.040zM790.733 748.298c8.274-7.68 8.765-20.644 1.085-28.938l-225.587-243.057c4.444-8.499 7.209-18.043 7.209-28.303 0-15.79-6.124-30.065-15.933-40.94l84.808-156.344c5.407-9.933 1.7-22.364-8.233-27.75-3.092-1.679-6.431-2.478-9.748-2.478-7.27 0-14.316 3.871-18.022 10.711l-84.808 156.324c-3.113-0.492-6.246-0.963-9.503-0.963-33.935 0-61.44 27.505-61.44 61.44s27.505 61.44 61.44 61.44c8.663 0 16.896-1.843 24.371-5.079l225.403 242.852c7.7 8.335 20.623 8.786 28.959 1.085z" fill="#000000" stroke-width="1" />
</g>
</svg>
Demo: jsFiddle
Issue: The top pixel(s) is not visible, the circle is incomplete. Adding padding-top:10px; dynamically works, but not when added to the SVG file itself.

Using translate(0, 60) works, you just need to reposition your svg in the viewbox.
Since your SVG was a big blank space with a small clock, I've used width="32" height="32" on the <svg> element to size the viewport
<?xml version="1.0"?>
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg">
<g class="sprite" id="ico-watch" transform="scale(0.03125 0.03125) translate(0, 60)">
<path d="M512 960c-282.317 0-512-229.683-512-512s229.683-512 512-512 512 229.683 512 512-229.683 512-512 512zM512-23.040c-259.727 0-471.040 211.292-471.040 471.040 0 259.727 211.313 471.040 471.040 471.040 259.748 0 471.040-211.313 471.040-471.040 0-259.748-211.292-471.040-471.040-471.040zM790.733 748.298c8.274-7.68 8.765-20.644 1.085-28.938l-225.587-243.057c4.444-8.499 7.209-18.043 7.209-28.303 0-15.79-6.124-30.065-15.933-40.94l84.808-156.344c5.407-9.933 1.7-22.364-8.233-27.75-3.092-1.679-6.431-2.478-9.748-2.478-7.27 0-14.316 3.871-18.022 10.711l-84.808 156.324c-3.113-0.492-6.246-0.963-9.503-0.963-33.935 0-61.44 27.505-61.44 61.44s27.505 61.44 61.44 61.44c8.663 0 16.896-1.843 24.371-5.079l225.403 242.852c7.7 8.335 20.623 8.786 28.959 1.085z" fill="#000000" stroke-width="1" />
</g>
</svg>

The SVG it-self is off canvas.
You can fix it by redefining the canvas with a viewBox attribute
svg {
outline: 1px solid blue;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -70 1030 1040" width="200">
<g class="sprite" id="ico-watch">
<path d="M512 960c-282.317 0-512-229.683-512-512s229.683-512 512-512 512 229.683 512 512-229.683 512-512 512zM512-23.040c-259.727 0-471.040 211.292-471.040 471.040 0 259.727 211.313 471.040 471.040 471.040 259.748 0 471.040-211.313 471.040-471.040 0-259.748-211.292-471.040-471.040-471.040zM790.733 748.298c8.274-7.68 8.765-20.644 1.085-28.938l-225.587-243.057c4.444-8.499 7.209-18.043 7.209-28.303 0-15.79-6.124-30.065-15.933-40.94l84.808-156.344c5.407-9.933 1.7-22.364-8.233-27.75-3.092-1.679-6.431-2.478-9.748-2.478-7.27 0-14.316 3.871-18.022 10.711l-84.808 156.324c-3.113-0.492-6.246-0.963-9.503-0.963-33.935 0-61.44 27.505-61.44 61.44s27.505 61.44 61.44 61.44c8.663 0 16.896-1.843 24.371-5.079l225.403 242.852c7.7 8.335 20.623 8.786 28.959 1.085z"
fill="#000000" stroke-width="1" />
</g>
</svg>
But, I think there is a real problem with the SVG it-self. The circle isn't even a circle!
You could simplify it a lot, and get rid of your off-canvas problem, by recreating a clean one from scratch.
svg {
outline: 1px solid blue;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="200">
<g class="sprite" id="ico-watch" fill="none" stroke="black" stroke-width="4" stroke-linecap="round">
<circle cx="50" cy="50" r="47"/>
<circle cx="50" cy="50" r="6" fill="black" stroke="none"/>
<path d="M50,50 l13,-22 M50,50 l25,25"/>
</g>
</svg>

Related

Manipulation of SVG icon's dimensions

I have the following SVG file
<svg width="523" height="524" style='background-color: teal;' xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-ec2d25d9" viewBox="0 0 60 30">
<g stroke="#000" fill="#fff">
<path d="M0 0h60v60H0z" fill="#FFF"/>
<path d="M0 0l30 37.1v-18l30 37.2" fill="none"/>
</g>
<g>
<path fill="none" d="M-1-1h583v403H-1z"/>
</g>
</symbol>
<path d="M85 84 127 84 127 126 85 126 "/>
<use href="#icon-ec2d25d9" x="85" y="84" width="22" height="36" fill="none" stroke="black" class="icon 4"/>
</svg>
(https://jsfiddle.net/L5xz73j4/) and I would like to modify the dimensions of the small icon inside the black rectangle to match the width and height of the rectangle. I'm generating these kinds of SVG's on the fly so I cannot start playing with the width and height attributes by hand. My question is that can I use the path element of the black rectangle to achieve this or what's the appropriate way?
I've changed the viewBox of the symbol to viewBox="0 0 60 60" acording to the size of the group inside. Now the symbol is square. In order to make the use fill the black square I've changed the width and the height of the use to width="42" height="42" i.e, the size of the black square.
I hope this is what you are asking
<svg width="523" height="524" style='background-color: teal;' xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-ec2d25d9" viewBox="0 0 60 60">
<g stroke="#000" fill="#fff">
<path d="M0 0h60v60H0z"/>
<path d="M0 0l30 37.1v-18l30 37.2" fill="none"/>
</g>
<!--<g><path fill="none" d="M-1-1h583v403H-1z"/></g>-->
</symbol>
<path d="M85 84 127 84 127 126 85 126 " />
<use href="#icon-ec2d25d9" x="85" y="84" width="42" height="42" fill="none" stroke="black" class="icon 4"/>
</svg>

Add shadow on a svg <path>

I'm trying to put a modern shadow on a particular part of a svg.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 162 63.25">
<g style="isolation:isolate">
<g>
<g>
<path d="M149.376,39.75l-49,23.5v-47Z" fill="#811818"/>
<path d="M149.376,39.75H6.688L30.279,22.274,6.624,4.75H149.376Z" fill="#b51c1c"/>
</g>
</g>
</g>
</svg>
I tried using the filter but the edge are visible and it's too blury:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 162 63.25">
<g style="isolation:isolate">
<g>
<g>
<filter id="dropshadow" x="-2" y="-2" width="200" height="200">
<feGaussianBlur stdDeviation="1"/>
</filter>
<path d="M149.376,39.75l-49,23.5v-47Z" fill="#811818"/>
<path style="stroke: rgba(0,0,0,0.19); stroke-width: 0.2; filter: url('#dropshadow');" d="M149.376,39.75H6.688L30.279,22.274,6.624,4.75H149.376Z" fill="#b51c1c"/>
</g>
</g>
</g>
</svg>
I'm expecting to use some modern css shadow like (https://codepen.io/sdthornton/pen/wBZdXq) and don't crop the original svg. I also expect to use less shadow on the top of it
I believe this is what you want, you can just change the values in the filter to fit your needs.
in plain simple words, not to completact thing:
feOffset: x, y to move the blur shadow effect back and forth.
filter: height to move it up and down
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 169 67.25">
<g style="isolation:isolate">
<g>
<g>
<defs>
<filter id="dropshadow" height="122%">
<feGaussianBlur in="SourceAlpha" stdDeviation="1" />
<feOffset in="blur" dx="0.7" dy="0.7" result="offsetBlur"/>
<feOffset dx="1" dy="1" result="offsetblur" />
<feFlood flood-color="#3D4574" flood-opacity="0.3" result="offsetColor"/>
<feComposite in="offsetColor" in2="offsetBlur" operator="in" result="offsetBlur"/>
</filter>
</defs>
<use xlink:href="#path1" filter="url(#dropshadow)"></use>
<path id="path1" d="M149.376,39.75l-49,23.5v-47Z" fill="#811818"/>
<use xlink:href="#path2" filter="url(#dropshadow)"></use>
<path id="path2" style="stroke: rgba(0,0,0,0.19); stroke-width: 0.2;" d="M149.376,39.75H6.688L30.279,22.274,6.624,4.75H149.376Z" fill="#b51c1c"/>
</g>
</g>
</g>
</svg>
Instead of using custom svg filter you can achieve easily the expected result using the standard CSS drop-shadow filter
ie: filter: drop-shadow(0 0 2px rgba(0,0,0,.5));
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 162 63.25">
<g style="isolation:isolate">
<path d="M149.376,39.75l-49,23.5v-47Z" fill="#811818"/>
<path style="stroke: rgba(0,0,0,0.19); stroke-width: 0.2; filter: drop-shadow(0 0 2px rgba(0,0,0,.5));" d="M149.376,39.75H6.688L30.279,22.274,6.624,4.75H149.376Z" fill="#b51c1c"/>
</g>
</svg>

How to invert alpha channel of svg

I have an SVG image like this. I would like to invert it, such that everything that is black becomes transparent, and everything that is transparent becomes black. So the result would be a black square with a transparent, square shaped 'hole' in the middle. How can I achieve this?
Code for the svg:
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 99.999997 99.999997"
height="100"
width="100">
<g
transform="translate(0,-952.36223)"
>
<path
d="M 50.000001,954.80939 65.450848,986.11624 100,991.13652 74.999998,1015.5055 80.901699,1049.915 50,1033.6691 19.098298,1049.915 25.000001,1015.5055 -1.2134336e-6,991.13652 34.549151,986.11624 Z"
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:22.67716599;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>
Use the path as a mask like below:
body {
background:pink;
}
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 99.999997 99.999997">
<defs>
<mask id="hole">
<rect width="100%" height="100%" fill="white"/>
<path transform="translate(0,-952.36223)"
d="M 50.000001,954.80939 65.450848,986.11624 100,991.13652 74.999998,1015.5055 80.901699,1049.915 50,1033.6691 19.098298,1049.915 25.000001,1015.5055 -1.2134336e-6,991.13652 34.549151,986.11624 Z"
fill="black" />
</mask>
</defs>
<rect fill="black" width="100%" height="100%" mask="url(#hole)" />
</svg>
The original answer showed an approach using the feFuncA primitive - GetSelf pointed out below that it wasn't working due to browser bugs).
Another approach that works is to invert the alpha channel using a feColorMatrix filter. Updated code below. Note this still won't work on fully transparent colored shapes in Chrome since it seems to discard any color channel values for shapes with opacity below 0.005.
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 99.999997 99.999997"
height="100"
width="100">
<defs>
<filter id="invert-alpha">
<feColorMatrix type="matrix" values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 -1 1"/>
</filter>
</defs>
<g
transform="translate(0,-952.36223)" filter="url(#invert-alpha)"
>
<path
d="M 50.000001,954.80939 65.450848,986.11624 100,991.13652 74.999998,1015.5055 80.901699,1049.915 50,1033.6691 19.098298,1049.915 25.000001,1015.5055 -1.2134336e-6,991.13652 34.549151,986.11624 Z"
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:22.67716599;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

SVG circle take all the height preserving aspectratio on any div size

The idea is to draw a circle in SVG that takes the whole height on the parent div whatever the size of the parent div. The width should be somehow ignored.
I've been working a bit with aspect ratio of SVG but this does not really work on all scenarios :
<div style='width:400px;height:100px'>
<svg width="100%" height="100%" viewbox="0 0 200 100" preserveAspectRatio="xMinYMin slice">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">Example SVG text 1</text>
</svg>
</div>
With the div width defined with 200px it's working.
Fiddle: https://jsfiddle.net/91sp2j0x/11/
Specifying a value of 50 for the r attribute will allow the nested svg element to maintain a 100% height of its containing (parent) element.
Code Snippet Demonstration:
.resize-demonstration {
resize: auto;
border: 1px solid gray;
box-sizing: border-box;
overflow:hidden;
}
.container-model {
border-right: 1px dashed gray;
}
<p>Resize the element below <u>vertically</u> or <u>horzontally</u> to demonstrate the intended behaviour</p>
<p><em>Note:</em> the <code>svg</code> has been wrapped in an containing element for <em>user-friendly resizing</em> (interaction with the resizing icon in the bottom-right corner), this is <strong>only for the sake of demonstration</strong> and should not be considered required.</p>
<div class="resize-demonstration" style="height: 100px">
<div style='width:50px;height:100%;overflow:hidden;' class="container-model">
<svg height="100%" viewbox="0 0 200 100" preserveAspectRatio="xMinYMin meet">
<circle cx="50" cy="50" r="50" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">100px width : Nothing is visible</text>
</svg>
</div>
</div>
Updated JSFiddle
Is this what you would like to happen? I set the height of the div for each of the divs to different heights, and set the divs to display: inline-block so that the width is not 100%, as divs usually are by default, since they are block elements. That way the height of the SVG will be the height of the div.
<div style='height:200px;display:inine-block;overflow:hidden'>
<svg height="100%" viewbox="0 0 200 100" preserveAspectRatio="xMinYMin meet">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">200px h</text>
</svg>
</div>
<div style='height:500px;display:inine-block;overflow:hidden'>
<svg height="100%" viewbox="0 0 200 100" preserveAspectRatio="xMinYMin meet">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">500px h</text>
</svg>
</div>
<div style='height:300px;display:inine-block;overflow:hidden'>
<svg height="100%" viewbox="0 0 200 100" preserveAspectRatio="xMinYMin meet" >
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">300px h</text>
</svg>
</div>
https://jsfiddle.net/suefeng/v14e7b81/2/
with preserveAspectRatio="none" and svg{width:100%} will give 100% adjusted height.
svg{
width: 100%;
}
<div style='width:200px;height:100px;overflow:hidden'>
<svg height="100%" viewbox="0 0 200 100" preserveAspectRatio="none">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">200px w: cut text</text>
</svg>
</div>
<div style='width:500px;height:100px;overflow:hidden'>
<svg height="100%" viewbox="0 0 200 100" preserveAspectRatio="none">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">500px w: full visible text</text>
</svg>
</div>
<div style='width:50px;height:100px;overflow:hidden'>
<svg height="100%" viewbox="0 0 200 100" preserveAspectRatio="none" >
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">100px width : Nothing is visible</text>
</svg>
</div>
If i understood right, u want to have the circle with the radius of the height...
I did that successfully like so (if i understood what u asked correctly):
<div style='width:800px;height:120px;'>
<svg viewbox="0 -10 200 140" preserveAspectRatio="xMinYMin slice"> /* just remove the height and the width from the svg, it will take the parameters from the div... */
<circle cx="18%" cy="18%" r="18%" stroke="black" stroke-width="0" fill="red" />
<text x="100" y="50">Example SVG text 1</text>
</svg>
</div>

Fill SVG path with colour but on hover fade-in pattern

I am trying to add an SVG image (in this case a flag of Belgium) as the fill of an SVG path (actually an ellipse). On hover, the ellipse's fill has to transition into red. In other words, the fill SVG has to 'fade out'. I tried it in a way I'd do it with CSS, but neither the SVG pattern nor the transition seem to work. I tried on Chrome and Firefox.
svg ellipse {
fill: url(#img1);
transition: fill 400ms;
}
svg:hover ellipse {
fill: red;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" version="1.1" height="480" width="640" viewBox="0 0 640 480">
<defs>
<pattern x="0" y="0" id="img1" height="480" width="640" viewBox="0 0 640 480">
<g fill-rule="evenodd" stroke-width="1pt">
<path d="M0 0h213.335v479.997H0z" />
<path fill="#ffd90c" d="M213.335 0H426.67v479.997H213.335z" />
<path fill="#f31830" d="M426.67 0h213.335v479.997H426.67z" />
</g>
</pattern>
</defs>
<rect fill="none" stroke="blue" x="1" y="1" width="640" height="480"/>
<ellipse stroke="black" stroke-width="5" cx="400" cy="200" rx="350" ry="150" />
</svg>
You can't transition fill like that because the two fills are not something that can be interpolated smoothly between.
What you need to do is have two versions of the ellipse, one on top of the other. Then either fade in or out the top one.
.visible-on-hover {
transition: opacity 400ms;
opacity: 0;
}
.visible-on-hover:hover {
opacity: 1;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" version="1.1" height="480" width="640" viewBox="0 0 640 480">
<defs>
<pattern x="0" y="0" id="img1" height="1" width="1"
viewBox="0 0 640 480" preserveAspectRatio="xMidYMid slice">
<g fill-rule="evenodd" stroke-width="1pt">
<path d="M0 0h213.335v479.997H0z" />
<path fill="#ffd90c" d="M213.335 0H426.67v479.997H213.335z" />
<path fill="#f31830" d="M426.67 0h213.335v479.997H426.67z" />
</g>
</pattern>
</defs>
<rect fill="none" stroke="blue" x="1" y="1" width="640" height="480"/>
<ellipse stroke="black" stroke-width="5" cx="400" cy="200" rx="350" ry="150" fill="url(#img1)"/>
<ellipse stroke="black" stroke-width="5" cx="400" cy="200" rx="350" ry="150" fill="red" class="visible-on-hover"/>
</svg>

Resources