如何在SVG中制作插入阴影

时间:2013-12-26 02:50:37

标签: css3 svg svg-filters

我需要制作一个带有插入阴影的方框,就像CSS3插入阴影一样。到目前为止我发现的是一个带有feGaussianBlur的过滤器,但问题是它还在盒子外面添加了一个阴影,这是我不想要的。这是我到目前为止的代码:

<svg>
    <defs>
        <filter id="drop-shadow">
            <feGaussianBlur in="SourceAlpha" result="blur" stdDeviation="5" />
            <feGaussianBlur in="SourceAlpha" result="blur2" stdDeviation="10" />
            <feGaussianBlur in="SourceAlpha" result="blur3" stdDeviation="15" />
            <feMerge>
                <feMergeNode in="blur" mode="normal"/>
                <feMergeNode in="blur2" mode="normal"/>
                <feMergeNode in="blur3" mode="normal"/>
                <feMergeNode in="SourceGraphic" mode="normal"/>
            </feMerge>
        </filter>
    </defs>
    <rect x="10" y="10" width="100" height="100"
    stroke="black" stroke-width="4" fill="transparent" filter="url(#drop-shadow)"/>
</svg>

我已经制作了一个demo,它也会将此代码与所需的CSS制作结果进行比较。滤镜不仅适用于矩形,也适用于梯形和更复杂的多边形。

我已经尝试过使用radialGradient,但由于这会使渐变呈圆形,因此也不好。

2 个答案:

答案 0 :(得分:9)

如果你有一个实心填充,你可以添加

<feComposite operator="in" in2="SourceGraphic"/> 

到过滤器的末尾,它会将模糊剪切为SourceGraphic的形状。由于你的形状是透明的,你将不得不做更多的工作。我建议在原始图形上使用半透明填充,以便获得合成的正确选择,并使用feFuncA将填充归零以进行最终操作。事实证明这非常复杂。但这是一个适用于任何实心笔画形状的解决方案

<filter id="inset-shadow" >
            <!-- dial up the opacity on the shape fill to "1" to select the full shape-->
            <feComponentTransfer in="SourceAlpha" result="inset-selection">
                <feFuncA type="discrete" tableValues="0 1 1 1 1 1"/>
            </feComponentTransfer>

            <!-- dial down the opacity on the shape fill to "0" to get rid of it -->
            <feComponentTransfer in="SourceGraphic" result="original-no-fill">
                <feFuncA type="discrete" tableValues="0 0 1"/>
            </feComponentTransfer>

            <!-- since you can't use the built in SourceAlpha generate your own -->
            <feColorMatrix type="matrix" in="original-no-fill" result="new-source-alpha" values="0 0 0 0 0
                      0 0 0 0 0
                      0 0 0 0 0
                      0 0 0 1 0"
/>            

            <feGaussianBlur in="new-source-alpha" result="blur" stdDeviation="5" />
            <feGaussianBlur in="new-source-alpha" result="blur2" stdDeviation="10" />
            <feGaussianBlur in="new-source-alpha" result="blur3" stdDeviation="15" />
            <feMerge result="blur">
                <feMergeNode in="blur" mode="normal"/>
                <feMergeNode in="blur2" mode="normal"/>
                <feMergeNode in="blur3" mode="normal"/>
            </feMerge>
            <!-- select the portion of the blur that overlaps with your shape -->
            <feComposite operator="in" in="inset-selection" in2="blur" result="inset-blur"/>
             <!-- composite the blur on top of the original with the fill removed -->
            <feComposite operator="over" in="original-no-fill" in2="inset-blur"/>            
        </filter>

这是我的小提琴:http://jsfiddle.net/kkPM4/

答案 1 :(得分:5)

主要基于experiment that I found,这是我提出的:

<defs><filter id="inset-shadow">
    <feOffset dx="10" dy="10"/>                                                         <!-- Shadow Offset -->
    <feGaussianBlur stdDeviation="10"  result="offset-blur"/>                           <!-- Shadow Blur -->
    <feComposite operator="out" in="SourceGraphic" in2="offset-blur" result="inverse"/> <!-- Invert the drop shadow to create an inner shadow -->
    <feFlood flood-color="black" flood-opacity="1" result="color"/>                     <!-- Color & Opacity -->
    <feComposite operator="in" in="color" in2="inverse" result="shadow"/>               <!-- Clip color inside shadow -->
    <feComponentTransfer in="shadow" result="shadow">                                   <!-- Shadow Opacity -->
        <feFuncA type="linear" slope=".75"/>
    </feComponentTransfer>
    <!--<feComposite operator="over" in="shadow" in2="SourceGraphic"/>-->                       <!-- Put shadow over original object -->
</filter></defs>

<rect width="100" height="100" fill="yellow" filter="url(#inset-shadow)"/>

如果您希望看到填充,请取消注释上一个<feComposite>。不幸的是,fill="transparent"不会为过滤器提供alpha工作,并且不会产生阴影。