Render beveled border on SVG rect - svg

Is it possible to render a border of a SVG rect to emulate an outset?
with CSS?
with filters?
NB: It has to be a single scalable simple rect object, so I don't want to build it with paths / composite objects.

It's possible to do this with a filter. You do it by drawing a masking shape in the SVG and doing the stroking in the filter.
<svg width="600px" height="800px" color-interpolation-filters="sRGB">
<filter id="rect-and-stroke" x="0%" y="0%" width="100%" height="100%">
<feFlood flood-color="red" result="red-stroke"/>
<feFlood flood-color="orange" result="orange-stroke"/>
<feFlood x="10" y="10" width="180" height="80" flood-color="yellow" result="yellow-field"/>
<feComposite operator="in" in2="SourceGraphic" in="red-stroke" result="red-partial"/>
<feComposite operator="out" in2="SourceGraphic" in="orange-stroke" result="orange-partial"/>
<feMerge>
<feMergeNode in="red-partial" />
<feMergeNode in="orange-partial" />
<feMergeNode in="yellow-field" />
</feMerge>
</filter>
<path filter="url(#rect-and-stroke)" fill="black" d="M 0 0 L 10 10 180 80 200 100 0 100Z"/>
</svg>

Related

How do I change the following SVG filter so that it will get applied to a text in an HTML element?

I have tried removing the
<!-- DILATED TEXT -->
<text font-size="85px" dx="125" dy="130" font-weight="700" filter="url(#outline)">upgrade yourself</text>
<feMergeNode in="SourceGraphic" /> and in="SourceAlpha" parts in the code, so that it would apply to the element to which is referenced via CSS, but it just wipes the text out, and it doesn't produce the outline that it's supposed to.
How do I apply the OUTLINE section to the HTML element?
All SVG text effect tutorials imply that the text is inside the SVG element, but I need to apply this text stroke via the SVG filter to text in an HTML element.
<svg width="900" height="200" viewBox="100 0 900 200">
<filter id="outline">
<feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="4"></feMorphology>
<feFlood flood-color="#32DFEC" flood-opacity="1" result="PINK"></feFlood>
<feComposite in="PINK" in2="DILATED" operator="in" result="OUTLINE"></feComposite>
<feMerge>
<feMergeNode in="OUTLINE" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- DILATED TEXT -->
<text font-size="85px" dx="125" dy="130" font-weight="700" filter="url(#outline)">upgrade yourself</text>
</svg>
You just apply the filter to the HTML text in the same way...
p {
font-size: 85px;
font-weight: 700;
filter: url(#outline);
}
<svg width="0" height="0">
<filter id="outline">
<feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="4"></feMorphology>
<feFlood flood-color="#32DFEC" flood-opacity="1" result="PINK"></feFlood>
<feComposite in="PINK" in2="DILATED" operator="in" result="OUTLINE"></feComposite>
<feMerge>
<feMergeNode in="OUTLINE" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</svg>
<p>upgrade yourself</p>

SVG text edges change color when scaling

I've created an SVG filter and applied it to some text. When I scale the text smaller by resizing the browser window, some of the edges of the text have a colored line down one side.
<svg
class="tstx" viewBox="0 0 160 160"
height="160" width="160"
style="width: 100%; height: 100%">
<defs>
<filter id="innershadow" x0="-50%" y0="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/>
<feOffset dy="3" dx="3"/>
<feComposite in2="SourceAlpha" operator="arithmetic"
k2="-1" k3="1" result="shadowDiff"/>
<feFlood flood-color="grey" flood-opacity="1"/>
<feComposite in2="shadowDiff" operator="in"/>
<feComposite in2="SourceGraphic" operator="over"/>
</filter>
</defs>
<g
font-family="Verdana" font-size="80" font-weight="bold"
stroke="none" fill="#fff" filter="url(#innershadow)">
<text x="10" y="70">A</text>
<text x="80" y="70">B</text>
</g>
</svg>
How can I fix this?
Codepen Example
Move the middle margin right to scale text.
EDIT: It looks like I may have fixed the problem - I just don't know why it worked or if it will cause problems later on. I removed the following:
<feComposite in2="SourceGraphic" operator="over"/>
And the lines disappeared. Is anyone able to explain why?

Matching SVG fill pattern with repeated background image on containing element?

I am trying to create some ornate page dividers using SVGs with a fill pattern using the same image as the containing element's background image but I am having difficulty getting the SVG pattern to match the repeated background image of the containing element. I found a few similar questions on StackOverflow which mentioned using preserveAspectRatio but none of the solutions I've found are creating the desired effect.
Here's what my SVG code looks like:
<svg id="Layer_1" class="divider" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 150" >
<defs>
<pattern id="imgpattern" patternUnits="userSpaceOnUse" width="576" height="576" preserveAspectRatio="xMinYMin slice">
<image width="576" height="576" xlink:href="http://s12.postimg.org/730a258rx/pattern2.jpg"/>
</pattern>
<filter id="dropshadow" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="0" dy="2" result="offsetblur"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<path d="M-394.09,367.9V295.34l1400,0v70s-3.39.9-4.92,1.38c-56.68,17.79-114.85,25.72-174.22,26.17-36.9.27-73.6-2.7-110.25-6.28q-67.4-6.59-134.7-14.08c-49.65-5.51-99.28-8.74-149-1.64-35.12,5-68.54,15.05-99.24,33.08-6,3.53-12.09,7-18.13,10.48-8.94,5.18-17.93,5.51-27,.36-3.47-2-7.14-3.6-10.51-5.71-48.22-30.22-101-43.79-157.83-41.84-29.13,1-58.27,2.45-87.3,4.94-40.49,3.48-80.88,8.18-121.32,12.27-24.37,2.46-48.71,5.26-73.14,7a714.52,714.52,0,0,1-96.42.34,605.73,605.73,0,0,1-96.81-13.9C-368.07,374.88-394.09,367.9-394.09,367.9Z" transform="translate(394.09 -295.32)" stroke="none" fill="url(#imgpattern)" filter="url(#dropshadow)" />
</svg>
And here's a JSFiddle which recreates my issue. Notice how the background pattern of the SVG appears more stretched and because of that does not completely match the repeated background image of the container.
One option is just to move the pattern fill into the filter like so - although there is a small problem that your texture has a one pixel black border, so the tiling isn't perfect.
<filter id="dropshadowandfill" height="130%" >
<feImage x="0" y="0" width="575" height="575" xlink:href="http://s12.postimg.org/730a258rx/pattern2.jpg"></feImage>
<feTile/>
<feComposite operator="in" in2="SourceGraphic" result="filledOriginal"/>
<feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
<feOffset dx="0" dy="2" result="offsetblur"/>
<feMerge>
<feMergeNode/>
<feMergeNode in="filledOriginal"/>
</feMerge>
</filter>
</defs>
<path d="M-394.09,367.9V295.34l1400,0v70s-3.39.9-4.92,1.38c-56.68,17.79-114.85,25.72-174.22,26.17-36.9.27-73.6-2.7-110.25-6.28q-67.4-6.59-134.7-14.08c-49.65-5.51-99.28-8.74-149-1.64-35.12,5-68.54,15.05-99.24,33.08-6,3.53-12.09,7-18.13,10.48-8.94,5.18-17.93,5.51-27,.36-3.47-2-7.14-3.6-10.51-5.71-48.22-30.22-101-43.79-157.83-41.84-29.13,1-58.27,2.45-87.3,4.94-40.49,3.48-80.88,8.18-121.32,12.27-24.37,2.46-48.71,5.26-73.14,7a714.52,714.52,0,0,1-96.42.34,605.73,605.73,0,0,1-96.81-13.9C-368.07,374.88-394.09,367.9-394.09,367.9Z" transform="translate(394.09 -295.32)" stroke="none" filter="url(#dropshadowandfill)" />

Rectangle with looming border

I want to create rectangle with smoothed border. Important part that size of it's solid part should be certain. To clarify I'll give an example:
I can achieve desired effect with Gaussian filter:
<svg id="svg-root" width="800" height="600"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="test-body-content">
<defs>
<filter id="blur" filterUnits="userSpaceOnUse">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
<feMerge>
<feMergeNode in="blur" />
</feMerge>
</filter>
</defs>
<rect x="50" y="50" width="200" height="100" fill="black" filter="url(#blur)"/>
</g>
</svg>
Result:
But it doesn't meet requirements because it is not fully solid within given dimensions (width="200" height="100"):
Also I thought about applying gradient perpendicular to stroke, but SVG doesn't support such thing.
As #ABFORCE wrote you can provide the width and height you want via the filter element.
For example:
<filter id="blur" filterUnits="objectBoundingBox"
x="0" y="0" width="100%" height="100%">
...
</filter>
Note that this means that above filter will be clipped to the boundingbox of the filtered element.
If you want the original shape in the filter output you could add another feMergeNode like this:
<svg id="svg-root" width="800" height="600"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="test-body-content">
<defs>
<filter id="blur" filterUnits="userSpaceOnUse">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<rect x="50" y="50" width="200" height="100" fill="black" filter="url(#blur)"/>
</g>
</svg>
Live example.

Why does a filter break the half-pixel trick for crisp 1px strokes?

I'm using the "offset everything by half a pixel" trick discussed in the second answer to this question to get a crisp 1px stroke on a shape.
(There are rounded edges involved, so the shape-rendering: crispEdges solution isn't viable here -- it makes the curved parts of strokes look terrible.)
How come adding a filter (I'm using a gaussian blur + offset filter to implement a drop shadow) breaks the half-pixel offset hack?
You can play with the jsfiddle.
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="f1" x="-20%" y="-20%" width="160%" height="160%">
<feOffset result="offOut" in="SourceAlpha" dx="10" dy="10" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="2" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
</defs>
<g transform="translate(5.5,5.5)">
<!-- This one has a blurry stroke -->
<rect width="50" height="50" rx="5" ry="5" stroke="black" stroke-width="1" fill="steelblue" filter="url(#f1)" />
<!-- This one has a crisp stroke -->
<rect x="150" width="50" height="50" rx="5" ry="5" stroke="black" stroke-width="1" fill="steelblue" />
</g>
</svg>
Apparently I can't post inline images as a new user, but you can this is an image of how the svg looks for me.
If you don't like the blurry edges, you can always experiment with adding an feComponentTransfer with feFuncA to manually manipulate the edge blur. Aka:
<filter id="fee" x="-20%" y="-20%" width="160%" height="160%">
<feComponentTransfer>
<feFuncA type="table" tableValues="0 0 1" />
</feComponentTransfer>
</filter>

Resources