20

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>
spliter
  • 12,321
  • 4
  • 33
  • 36

1 Answers1

30

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

Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • Worked like a charm, Paul! Thank you very much for the explanation! – spliter Feb 04 '15 at 06:51
  • From what I can tell, this only works if a) you're using a `` element, and b) you're not drawing any diagonal lines beyond a triangle. ``, ``, etc. will not work with the `clipPathUnits="objectBoundingBox"` attribute, and any diagonal lines beyond a triangle will be filled into a square. Bummer. – kmgdev Apr 28 '15 at 02:37
  • 3
    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. – Paul LeBeau Apr 28 '15 at 05:48
  • 4
    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! – Jordi Nebot Sep 02 '16 at 13:54
  • 2
    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. – Paul LeBeau Sep 03 '16 at 03:21
  • The SVG with `defs` should be outside of the `header`... this way is totally confusing and does not hints on reusability. – Roko C. Buljan Mar 29 '17 at 12:26
  • 1
    There's an EXCELLENT script to convert this data here: https://stackoverflow.com/a/29509756/842768 – giovannipds Dec 03 '17 at 08:00
  • Worked fine with Sketch: Just resizing the Object to 1px, Export, Copy Path, add clipPathUnits="objectBoundingBox", Done. – alboth - undkonsorten.com Dec 26 '18 at 14:48
  • 12
    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 - https://yoksel.github.io/relative-clip-path/ – Gavin Kemp Feb 16 '21 at 22:11
  • 3
    @GavinKemp YOU ARE A LIFE SAVER THANK YOU FOR THIS LINK – joshmillgate Mar 12 '21 at 14:11