Svg shadow gets cut only when transforming parent with same dimensions - html

I have an svg which takes its parent width, but when I scale or rotate the parent the svg's drop shadow gets cut. The left one is fine, but when the parent is the same width and height of the svg (right one) it behaves different. I have overflow visible and filterUnits="userSpaceOnUse" http://jsfiddle.net/xrsknjfv/
scale.addEventListener("mousedown", function(){
this.parentElement.classList.toggle("scale");
})
svg{
fill: yellow;
overflow: visible;
width: 100%;
}
body > div{
position: absolute;
left: 50px;
top: 50px;
}
div > div{
display: inline-block;
width: 150px;
transition: 5s all;
}
div > div:nth-of-type(1){
padding: 15px;
}
div.scale > div{
transform: scale(0);
}
<div>
<button id="scale">
scale
</button>
<div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 409.96 254.59">
<defs>
<filter filterUnits="userSpaceOnUse" id="f1">
<feDropShadow filterUnits="userSpaceOnUse" dx="1.5" dy="0.8" stdDeviation="1"></feDropShadow>
</filter>
<filter filterUnits="userSpaceOnUse" id="f2">
<feDropShadow filterUnits="userSpaceOnUse" dx="-2" dy="1.8" stdDeviation="1"></feDropShadow>
</filter>
<filter filterUnits="userSpaceOnUse" id="f3">
<feDropShadow flood-opacity="0.1" stdDeviation="10" dy="-4" dx="-2" filterUnits="userSpaceOnUse"></feDropShadow>
</filter>
</defs>
<g style="filter: url(#f2);">
<g style="filter: url(#f3);">
<path d="M167.1,52.17S209.77-28.24,301.66,10.6c0,0,59.62,23.52,56.34,96.81,0,0,55.45,16.41,51.79,79.86,0,0-.3,61.95-67.65,67.28H220.75q-72.56,0-145.12,0C29.57,254.66-2.8,215,.19,170.31c0,0,7.74-70,81.58-68.37C81.77,101.94,101.46,42.87,167.1,52.17Z" style="filter: url(#f1);"></path>
</g>
</g>
</svg>
</div>
<div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 409.96 254.59">
<defs>
<filter filterUnits="userSpaceOnUse" id="f1">
<feDropShadow filterUnits="userSpaceOnUse" dx="1.5" dy="0.8" stdDeviation="1"></feDropShadow>
</filter>
<filter filterUnits="userSpaceOnUse" id="f2">
<feDropShadow filterUnits="userSpaceOnUse" dx="-2" dy="1.8" stdDeviation="1"></feDropShadow>
</filter>
<filter filterUnits="userSpaceOnUse" id="f3">
<feDropShadow flood-opacity="0.1" stdDeviation="10" dy="-4" dx="-2" filterUnits="userSpaceOnUse"></feDropShadow>
</filter>
</defs>
<g style="filter: url(#f2);">
<g style="filter: url(#f3);">
<path d="M167.1,52.17S209.77-28.24,301.66,10.6c0,0,59.62,23.52,56.34,96.81,0,0,55.45,16.41,51.79,79.86,0,0-.3,61.95-67.65,67.28H220.75q-72.56,0-145.12,0C29.57,254.66-2.8,215,.19,170.31c0,0,7.74-70,81.58-68.37C81.77,101.94,101.46,42.87,167.1,52.17Z" style="filter: url(#f1);"></path>
</g>
</g>
</svg>
</div>
</div>

Overflow shadows aren't retained during transform transitions - so you need to add margin/padding to your box to make sure they're ok.
Incidentally, you can make your SVG a lot terser
You don't need to re-declare filters within each inline SVG fragment
You only need to declare your filterUnits in the filter element itself (not each primitive)
You can use self-closing tags for feDropshadow ("/>")
You can get rid of the style and just declare a filter attribute directly.
<div>
<button id="scale">
scale
</button>
<div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 409.96 254.59">
<defs>
<filter id="f1" >
<feDropShadow dx="1.5" dy="0.8" stdDeviation="1"/>
</filter>
<filter id="f2">
<feDropShadow dx="-2" dy="1.8" stdDeviation="1"/>
</filter>
<filter id="f3" >
<feDropShadow stdDeviation="10" dy="-4" dx="-2"/>
</filter>
</defs>
<g filter="url(#f2)">
<g filter=" url(#f3)">
<path d="M167.1,52.17S209.77-28.24,301.66,10.6c0,0,59.62,23.52,56.34,96.81,0,0,55.45,16.41,51.79,79.86,0,0-.3,61.95-67.65,67.28H220.75q-72.56,0-145.12,0C29.57,254.66-2.8,215,.19,170.31c0,0,7.74-70,81.58-68.37C81.77,101.94,101.46,42.87,167.1,52.17Z" filter= "url(#f1)"></path>
</g>
</g>
</svg>
</div>
<div>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 409.96 254.59">
<g filter= "url(#f2)">
<g filter= "url(#f3)">
<path d="M167.1,52.17S209.77-28.24,301.66,10.6c0,0,59.62,23.52,56.34,96.81,0,0,55.45,16.41,51.79,79.86,0,0-.3,61.95-67.65,67.28H220.75q-72.56,0-145.12,0C29.57,254.66-2.8,215,.19,170.31c0,0,7.74-70,81.58-68.37C81.77,101.94,101.46,42.87,167.1,52.17Z" filter= "url(#f1)"></path>
</g>
</g>
</svg>
</div>
</div>

Related

SVG light and shadow a 3D feelling

I want to make an svg looks like it's on 3D by adding a small light in the top and left BORDER and a shadow in the bottom and right BORDER
something like this
#div1 {
background: #ddd;
}
#div1, #div2, #div3 {
width: 100px;
height: 100px;
position: relative;
}
#div2 {
box-shadow: inset -2px -2px 10px 1px #000;
position: absolute;
}
#div3 {
box-shadow: inset 2px 2px 14px 1px #fff;
position: absolute;
}
<div id="div1">
<div id="div2"></div>
<div id="div3"></div>
</div>
But I don't know how to do that with svg filter
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="1000">
<defs>
<filter id="filter1" x="0" y="0">
<feSpecularLighting result="specOut"
specularExponent="20" lighting-color="#bbbbbb">
<fePointLight x="-100" y="-100" z="600"/>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="specOut"
operator="arithmetic" k1="0" k2="1" k3="1" k4="0"/>
</filter>
</defs>
<path filter="url(#filter1)" fill="#fff" stroke="#000" d="M20,20 L220,20 L220,220 L20,220 L20,20 "></path>
</svg>
Help please and thanks
Firstly, you are trying to light a pure white rectangle with a dim white light. You aren't going to see anything.
If you make the rectangle darker, you'll start to see some effect.
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="300">
<defs>
<filter id="filter1" x="0" y="0">
<feSpecularLighting result="specOut"
specularExponent="20" lighting-color="#bbbbbb">
<fePointLight x="-100" y="-100" z="600"/>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="specOut"
operator="arithmetic" k1="0" k2="1" k3="1" k4="0"/>
</filter>
</defs>
<path filter="url(#filter1)" fill="#666" stroke="#000" d="M20,20 L220,20 L220,220 L20,220 L20,20 "></path>
</svg>
But in the above example we are only getting gradient of light over our rectangle. How do we make a sort-of bevel edge on the rectangle?
It is important to know that it is not really the RGB channels of an element that determine how the lighting filter components behave. The lighting components treat the alpha component of the colour as a bump map. Varying values of alpha become a topological map that effects the way the pixels are lit.
One way to create varying values of alpha is to use a gaussian blur filter. Here's what that looks like. Note that it is the alpha channel (SourceAlpha) of our shape that we are blurring.
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="300">
<defs>
<filter id="filter2">
<feGaussianBlur in="SourceAlpha" stdDeviation="8" result="blur1"/>
<feBlend in="SourceGraphic" in2="blur1" mode="multiply"/>
</filter>
</defs>
<path filter="url(#filter2)" fill="#666" stroke="#000" d="M20,20 L220,20 L220,220 L20,220 L20,20 "></path>
</svg>
Now if use that blurred alpha channel, we get something close to what you are after.
You can fiddle with the blur, the lighting filter values, and the feComposite values to adjust the effect.
Note that I've also switched to using an feDistantLight here. I think it is more appropriate for this purpose.
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="300">
<defs>
<filter id="filter2">
<feGaussianBlur in="SourceAlpha" stdDeviation="8" result="blur1"/>
<feSpecularLighting result="specOut" in="blur1" specularConstant="1.2" specularExponent="12" lighting-color="#fff">
<feDistantLight azimuth="225" elevation="45"/>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"/>
</filter>
</defs>
<path filter="url(#filter2)" fill="#666" stroke="#000" d="M20,20 L220,20 L220,220 L20,220 L20,20 "></path>
</svg>
Update
To handle the situation where shapes overlap (see comments), then you will need to clip away any parts of the blur that is outside the shape. You can do that with another feComposite operation.
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="300">
<defs>
<filter id="filter2">
<feGaussianBlur in="SourceAlpha" stdDeviation="8" result="blur1"/>
<feSpecularLighting result="specOut" in="blur1" specularConstant="1.2" specularExponent="12" lighting-color="#fff">
<feDistantLight azimuth="225" elevation="45"/>
</feSpecularLighting>
<feComposite in="SourceGraphic" in2="specOut" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="result"/>
<feComposite operator="atop" in2="SourceGraphic"/>
</filter>
</defs>
<path filter="url(#filter2)" fill="#666" stroke="#000" d="M20,20 L220,20 L220,220 L20,220 L20,20 "></path>
<path filter="url(#filter2)" fill="#666" stroke="#000" d="M40,40 L200,40 L200,110 L40,110 L40,40 "></path>
<path filter="url(#filter2)" fill="#666" stroke="#000" d="M40,120 L200,120 L200,200 L40,200 L40,120 "></path>
</svg>

How to add box-shadow to a svg path circle shape

I have this problem, where I need to add box-shadow to a circle, but it seems it is not possible.
Why does it not work or how could I add circle shadow to the </circle> element in SVG path to have the glow effect with current specifications?
/*
circle {
fill: red; <-- works
box-shadow: 0 0 50px red; <-- does not work
}
*/
<svg width="450" height="450">
<path id="motionPath"
d="M 50 200 L 400 200 "
stroke="black" fill="transparent" />
<circle class="circle" r=5 fill=#45b6fe z-index=55>
<animateMotion dur="8s" repeatCount="indefinite" rotate="auto">
<mpath href="#motionPath" />
</animateMotion>
</circle>
</svg>
To add a box-shadow, you will need to work on feGaussianBlur attribute. Below is the code for you and it generates beautiful box-shadow. You can check the output for the same
Note: To see the shadow properly, I have increased the dimension of circle. You can keep as per your requirement.
<svg width="450" height="450">
<defs>
<filter id="f1" x="-40%" y="-40%" width="180%" height="180%" filterUnits="userSpaceOnUse">
<feGaussianBlur in="SourceAlpha" stdDeviation="8"/>
<feOffset dx="5" dy="5" result="offsetblur"/>
<feOffset dx="-5" dy="-5" result="offsetblur"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<path id="motionPath"
d="M 50 200 L 400 200 "
stroke="black" fill="transparent" />
<circle class="circle" r=10 fill=#45b6fe z-index=55 style="filter: url(#f1);">
<animateMotion dur="8s" repeatCount="indefinite" rotate="auto">
<mpath href="#motionPath" />
</animateMotion>
</circle>
</svg>
UPDATE:
As per your requirement, I have added desired background color to the box shadow.
<svg width="450" height="450">
<defs>
<filter id="f1" x="-40%" y="-30%" width="180%" height="180%" filterUnits="userSpaceOnUse" >
<feColorMatrix result="offsetblur" in="offOut" type="matrix"/>
<feGaussianBlur in="SourceAlpha" stdDeviation="10" />
<feGaussianBlur in="SourceAlpha" stdDeviation="10" result="blur"/>
<feOffset in="blur" dx="5" dy="5" result="offsetBlur" stdDeviation="1.7"/>
<feFlood flood-color="red" flood-opacity="5" result="offsetColor"/>
<feComposite in="offsetColor" in2="offsetBlur" operator="in" result="offsetBlur"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<path id="motionPath"
d="M 50 200 L 400 200 "
stroke="black" fill="transparent" />
<circle class="circle" r=10 fill=white z-index=55 style="filter: url(#f1);">
<animateMotion dur="8s" repeatCount="indefinite" rotate="auto">
<mpath href="#motionPath" />
</animateMotion>
</circle>
</svg>
so I have this in one of my sites and it works fine for me
.booking-view-tariff-circle > img {
border: 2px solid #fff;
border-radius: 50%;
box-shadow: 2px 2px 4px #000;
display: block;
height: 80px;
width: 80px;
margin-left: auto;
margin-right: auto;
object-fit: cover;
position: relative;
left: -45px;
top: -78px;
box-shadow: 0 8px 8px rgba(0,0,0,0.54);

svg shadow does not appear

I am having a problem with setting up shadow for a svg with mask applied to it. This is the code and jsfiddle: http://jsfiddle.net/3kxnmhfL/
.watch-video-svg {
width: 50px;
height: 50px;
}
<div class="watch-video-svg">
<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" height="100%" width="100%" viewBox="0 0 100 100">
<defs>
<filter id="shadow">
<feDropShadow dx="4" dy="8" stdDeviation="4"/>
</filter>
<mask id="cut-off-bottom">
<circle cx="50%" cy="50%" r="50%" fill="white"/>
<polygon points="31,20, 31,77, 80,50" fill="black"/>
<!-- <rect x="0" y="0" width="200" height="200" fill="url(#Gradient)" /> -->
</mask>
</defs>
<circle cx="50%" cy="50%" r="50%" fill="red" mask="url(#cut-off-bottom)" filter="url(#shadow)" />
</svg>
</div>
I'd like the shadow to appear only around svg circle and not containing div.
What could be the reason for shadow not showing up?
SVG filters have a "filter region". The filter region defines the area of pixels that the browser uses to store the result of the filters. The default filter region is the bounds of the element (that the filter is applied to) plus a margin around it to allow for filter elements that have results larger than the original element.
By default, that margin is 10% of the width and height, applied to all four sides. However in your case, a stdDeviation of "4" causes the blur to extend further than that 10% margin allowance. The result is a clipped blur, even though the viewBox has been enlarged enough to cater for the full blur.
To fix, this, you just need to bump up the filter region size. An allowance of 20% seems to work okay:
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
In addition, I've simplified the SVG by getting rid of the unnecessary mask. I also tweaked the viewBox to include the part of the blur that extends to the left.
.watch-video-svg {
width: 500px;
height: 500px;
background: linen;
}
<div class="watch-video-svg">
<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="-5 0 120 120">
<defs>
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="4" dy="8" stdDeviation="4"/>
</filter>
</defs>
<circle cx="50" cy="50" r="50" fill="red" filter=url(#shadow) />
<polygon points="31,20, 31,77, 80,50" fill="white"/>
</svg>
</div>
You need to adjust your mask. Since your element is already a circle you don't need a circle in the mask, a rect to fill all the width/height is enough.
You need to also adjust the viewBox to leave some space for the shadow:
.watch-video-svg {
width: 50px;
height: 50px;
}
<div class="watch-video-svg">
<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="0 0 120 120">
<defs>
<filter id="shadow">
<feDropShadow dx="4" dy="8" stdDeviation="4"/>
</filter>
<mask id="cut-off-bottom">
<rect x="0" y="0" width="100%" height="100%" fill="white"/>
<polygon points="31,20, 31,77, 80,50" fill="black"/>
</mask>
</defs>
<circle cx="50" cy="50" r="50" fill="red" mask="url(#cut-off-bottom)" filter=url(#shadow) />
</svg>
</div>

SVG Bevel effect for all edges

#logo {
position:relative;
left:20px;
top:20px
}
#logo .container {
height:200px;
width:200px;
top:50px;
left:50px
}
#logo .container, #logo .slice {
position:absolute;
}
#logo .slice {
height:100%;
width:100%;
}
<div id="logo">
<div class="container">
<div class="slice" id="one">
<svg height="200" width="200">
<polygon points="0,200 100,100 200,200" style="fill:green" />
</svg>
</div>
<div class="slice" id="two">
<svg height="200" width="200">
<polygon points="0,0 100,100 0,200" style="fill:blue" />
</svg>
</div>
<div class="slice" id="three">
<svg height="200" width="200">
<polygon points="0,0 100,100 200,0" style="fill:red" />
</svg>
</div>
<div class="slice" id="four">
<svg height="200" width="200">
<polygon points="200,0 100,100 200,200" style="fill:yellow" />
</svg>
</div>
</div>
</div>
I couldn't figure out how to make a bevel filter as in this logo. All three edges of each slice must be equally darker like the light source is projected right above each slice. Briefly, I am expecting an end result exactly the same with the logo in the link.
EDIT:
<svg>
<filter id="inset-shadow">
<feComponentTransfer in=SourceAlpha>
<feFuncA type="table" tableValues="1 0" />
</feComponentTransfer>
<feGaussianBlur stdDeviation="5" />
<feOffset in="offsetblur2" dy="10" result="offsetblur" />
<feOffset dy="-10" result="offsetblur2" />
<feFlood flood-color="rgb(20, 0, 0)" result="color" />
<feComposite in2="offsetblur" operator="in" />
<feComposite in2="SourceAlpha" operator="in" />
<feMerge>
<feMergeNode in="SourceGraphic" />
<feMergeNode />
</feMerge>
</filter>
<polygon points="0,0 100,100 200,0" style="fill:red" filter="url(#inset-shadow)" />
</svg>
Something like this maybe but not enough dark?
Here's a bevel effect using a specular lighting filter:
<svg width="800px" height="600px" viewBox="0 0 200 150"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="MyFilter" height="220%">
<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
<feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75"
specularExponent="30" lighting-color="white"
result="specOut">
<fePointLight x="100" y="75" z="200"/>
</feSpecularLighting>
<feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
<feComposite in="SourceGraphic" in2="specOut" operator="arithmetic"
k1="1" k2="1" k3="0" k4="0"/>
</filter>
</defs>
<rect x="1" y="1" width="600" height="800" fill="#888888" stroke="red" />
<g filter="url(#MyFilter)" >
<path fill="#D90000"
d="M60,80 C30,80 30,40 60,40 L140,40 C170,40 170,80 140,80 z" />
</g>
</g>
</svg>
But you can do the same thing more elegantly just using composites and a blur.
<svg width="800px" height="600px" viewBox="0 0 200 150"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="MyFilter" height="220%">
<feFlood flood-color="black"/>
<feComposite operator="out" in2="SourceGraphic"/>
<feGaussianBlur stdDeviation="5"/>
<feComposite operator="atop" in2="SourceGraphic"/>
</filter>
</defs>
<rect x="1" y="1" width="600" height="800" fill="#888888" stroke="red" />
<g filter="url(#MyFilter)" >
<path fill="#D90000"
d="M60,80 C30,80 30,40 60,40 L140,40 C170,40 170,80 140,80 z" />
</g>
</g>
</svg>

SVG disappears if filter is applied

I've been playing around with SVGs in websites, and I've been trying to get filters to work, but I can't seem to get it right.
The problem is that the svg disappears completely once I apply a defined filter. I've tried to apply the filter inline, just to see if it worked, like this:
<symbol id="circle" viewBox="0 0 400 209.603" filter="url('#blur-filter')">
...
</symbol>
but with no success.
Ultimately, my goal is that I would be able to apply the filters via CSS, but I can't seem to get it to work, and this is the first time I've really played around with SVGs, so I don't know if I'm making some obvious mistake.
Code:
.svg-circle:hover {
filter: url("#blur-filter");
}
.svg-grey {
fill: #333;
}
<svg xmlns="http://www.w3.org/2000/svg" style="display:none">
<defs>
<filter id="blur-filter">
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
</filter>
<symbol id="circle" viewBox="0 0 400 209.603">
<circle cx="100" cy="100" r="100" />
</symbol>
</defs>
</svg>
<svg>
<use xlink:href="#circle" class="svg-circle svg-grey"/>
</svg>
I want the filter to be applied when I hover over the element. My other question is how I can incorporate this with CSS transitions, so that the blur gets applied gradually, like other css3 transitions.
I also want the filters to be global, so they can be reused across multiple svg images whenever I want, so define once, and reuse.
I've also created a Codepen to demonstrate my problem.
Remove your style="display:none" and add width:0 to your first svg
.svg-circle:hover {
filter: url("#blur-filter");
}
.svg-grey {
fill: #333;
}
svg:first-of-type {
width:0
}
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="blur-filter">
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
</filter>
<symbol id="circle" viewBox="0 0 400 209.603">
<circle cx="100" cy="100" r="100" />
</symbol>
</defs>
</svg>
<svg>
<use xlink:href="#circle" class="svg-circle svg-grey"/>
</svg>
Remove the display: none; on the definitions SVG and give it 0 dimensions. This should do it. Somehow the filter may be inheriting that display: none.
.svg-circle:hover {
filter: url("#blur-filter");
}
.svg-grey {
fill: #333;
}
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<defs>
<filter id="blur-filter">
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
</filter>
<symbol id="circle" viewBox="0 0 400 209.603">
<circle cx="100" cy="100" r="100" />
</symbol>
</defs>
</svg>
<svg>
<use xlink:href="#circle" class="svg-circle svg-grey"/>
</svg>
As for the transition, I don't think you can do that by using referenced filters.
html, body {
margin: 0;
padding: 0;
}
.svg-circle:hover {
filter: url("#blur-filter");
}
.svg-grey {
fill: #333;
}
<svg width="0" height="0">
<defs>
<filter id="blur-filter">
<feGaussianBlur in="SourceGraphic" stdDeviation="2" />
</filter>
<symbol id="circle" viewBox="0 0 400 209.603">
<circle cx="100" cy="100" r="100" />
</symbol>
</defs>
</svg><svg width="400" height="210">
<use xlink:href="#circle" class="svg-circle svg-grey"/>
</svg>