Responsive clip-path with inline SVG
Asked Answered
C

1

21

On an element with a background (image or solid color don't really matter):

<header id="block-header"></header>

I am trying to apply a clip-path using SVG. To achieve this, I am putting SVG inline into the same element like this:

<header id="block-header">
    …
    <svg width="100%" height="100%" viewBox="0 0 4000 1696" preserveAspectRatio="none">
        <defs>
          <clipPath id="myClip">
            <path d="M0 1568.18V0h4000v1568.18S3206.25 1696 2000 1696C984.37 1696 0 1568.18 0 1568.18z"/>
          </clipPath>
        </defs>
    </svg>
    …
</header>

You can run the code snippet below or check the JSFiddle. You can see original SVG image (in black) put inline, having curviness along the bottom and being responsive. In contrast, the red rectangle shows the same image applied (or, rather, not applied) as a clip-path.

I guess I misunderstand either viewBox or preserveAspectRatio attributes though can not find what is exactly wrong here. Any help would be appreciated.

#block-header {
    background: Red;
    min-height: 100px;
    -webkit-clip-path: url(#myClip);
	clip-path: url(#myClip);
}
<h1>SVG image</h1>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100" viewBox="0 0 4000 1696" preserveAspectRatio="none"><path d="M0 1568.18V0h4000v1568.18S3206.25 1696 2000 1696C984.37 1696 0 1568.18 0 1568.18z"/></svg>

<h1><code>clip-path</code> using the same SVG</h1>
<header id="block-header">
    <svg width="100%" height="100" viewBox="0 0 4000 1696" preserveAspectRatio="none">
        <defs>
          <clipPath id="myClip">
            <path d="M0 1568.18V0h4000v1568.18S3206.25 1696 2000 1696C984.37 1696 0 1568.18 0 1568.18z"/>
          </clipPath>
        </defs>
    </svg>
</header>
Cathepsin answered 4/2, 2015 at 1:5 Comment(0)
B
36

References to SVG clip paths are to the clip path definitions themselves and the dimensions or other attributes of the <svg> are meaningless in this context.

What is happening in your example is that you are applying a 4000 px wide clip path to your header. Which is probably only of the order of 900 px wide. So the curvature isn't visible.

If you want a responsive clip path, you should define it using clipPathUnits="objectBoundingBox".

#block-header {
    background: Red;
    min-height: 100px;
    -webkit-clip-path: url(#myClip);
	clip-path: url(#myClip);
}
<h1>SVG image</h1>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100" viewBox="0 0 1 1" preserveAspectRatio="none"><path d="M0,0 1,0 1,0.9 C 1,0.9, 0.77,1, 0.5,1 0.23,1, 0,0.9,0,0.9z"/></svg>

<h1><code>clip-path</code> using the same SVG</h1>
<header id="block-header">
    <svg width="0" height="0">
        <defs>
          <clipPath id="myClip" clipPathUnits="objectBoundingBox">
            <path d="M0,0 1,0 1,0.9 C 1,0.9, 0.77,1, 0.5,1 0.23,1, 0,0.9,0,0.9z"/>
          </clipPath>
        </defs>
    </svg>
</header>    

Fiddle here

Begrime answered 4/2, 2015 at 1:40 Comment(10)
Worked like a charm, Paul! Thank you very much for the explanation!Cathepsin
From what I can tell, this only works if a) you're using a <path> element, and b) you're not drawing any diagonal lines beyond a triangle. <circle>, <polygon>, etc. will not work with the clipPathUnits="objectBoundingBox" attribute, and any diagonal lines beyond a triangle will be filled into a square. Bummer.Titos
Circle, polygon etc will work just fine. What I suspect you are doing is using values that are too large. When using clipPathUnits="objectBoundingBox" coordinates should be in the range of 0..1. Think of them as percentages of the bounding box. (0,0) is top-left corner of the element, (1,1) is the bottom right corner of the element.Begrime
But, how do you transform d="M0 1568.18V0h4000v1568.18S3206.25 1696 2000 1696C984.37 1696 0 1568.18 0 1568.18z" into d="M0,0 1,0 1,0.9 C 1,0.9, 0.77,1, 0.5,1 0.23,1, 0,0.9,0,0.9z"? Thank you!Reptile
You scale the original clip coordinates by the viewBox. So 1568/1696 ~= 0.9 etc. However, my clip-path is only an approximation of the original one. It's not exact.Begrime
The SVG with defs should be outside of the header... this way is totally confusing and does not hints on reusability.Mireillemireles
There's an EXCELLENT script to convert this data here: https://mcmap.net/q/507548/-how-to-apply-clippath-to-a-div-with-the-clippath-position-being-relative-to-the-div-positionLeyva
Worked fine with Sketch: Just resizing the Object to 1px, Export, Copy Path, add clipPathUnits="objectBoundingBox", Done.Klink
I found this online tool that you enter path coordinates into and it will convert it to the fraction/decimal based system needed for objectBoundingBox - yoksel.github.io/relative-clip-pathDrennan
@GavinKemp YOU ARE A LIFE SAVER THANK YOU FOR THIS LINKConverted

© 2022 - 2024 — McMap. All rights reserved.