2

I'm trying to create a responsive SVG Clip Path using a <path> SVG element. However, I having trouble getting it to work.

I have gotten it to work using more basic shapes such as <circle>, but not the <path> element. I have also gotten it to work using static dimensions with the <path> element.

I used the instructions here as a reference: https://www.smashingmagazine.com/2015/05/creating-responsive-shapes-with-clip-path/. I also looked at similar questions on StackOverflow and other examples, but they mostly deal with basic shapes and not the path variable.

The SVG shape I'm using is a raindrop shape which was exported from Adobe Illustrator.

Here is my code:

HTML

<svg id="raindropSVG" viewBox="0 0 810 1012">
    <defs>
        <clipPath id="raindropClipPath" clipPathUnits="objectBoundingBox">
            <path d="M0,604.4C0,523.7,30.7,408.8,97.5,320,217,160.9,409.2,0,409.2,0S597.2,167.8,717,331c63,85.7,93,196.4,93,274,0,224.5-181.3,407-405,407S0,829.5,0,604.4Z"/>
        </clipPath>
    </defs>
</svg>

<img src="clipped-image.jpg" alt="" class="clipped-img">

CSS

.clipped-img {
    clip-path: url(#raindropClipPath);
    width: 100%;
    height: auto;
}

#raindropSVG {
    width: 0;
    height: 0;
}

The idea is that changing the width (or height) of the .clipped-img should scale the raindrop shape accordingly.

Using clipPathUnits="objectBoundingBox" is necessary for making the clipPath responsive. However, as soon as I add this the clipped image disappears.

Where I think I'm going wrong

I suspect that the path specified by the path element is not in relative units, however I don't know how to change the units to relative.


Thanks in advance for all responses!

Ron
  • 231
  • 3
  • 10
  • objectBoundingBox units range from 0 to 1. The M0,604.4 is far too large. Imagine you changed units from 3 inches to 3 kilometres, you wouldn't expect that to be the same distance. – Robert Longson Dec 04 '18 at 17:47
  • @RobertLongson Thanks for your reply. How do I change these units to relative units though? When handling basic shapes, this is pretty simple, but how do I accomplish this with a more complex shape like in the example? – Ron Dec 04 '18 at 18:50
  • 1
    There are two ways this can go when the aspect ratio of the image changes: either the aspect ratio of the clip-path adapts to that of the image (distorting the shape), or the clip path retains its aspect ratio, but does not stretch to all borders of the image. Which way do you want this to work? – ccprog Dec 04 '18 at 19:16
  • @ccprog I'll pick the first way, since this is what I expect. Either way would be fine though. – Ron Dec 05 '18 at 13:48

2 Answers2

6

This answer distorts the shape of the clip path so that it always spans the whole image, regardless of its aspect ratio.

With clipPathUnits="objectBoundingBox", only coordinates between 0 and 1 will lie inside the bounding rectangle of your image. You have to scale down the path for that.

Fortunately, the viewBox for your path names its dimensions. Unfortunately, you cannot leave the computation of the scaling to the renderer, but must give a transformation directly: scale(1 / 810, 1 / 1012). See the restrictions for the content elements of a <clipPath>.

Both the SVG 1.1 and the SVG 2 spec name transform as a possible attribute of the <clipPath> itself, but neither define the coordinate system it should be applied in. For the sake of browser compatibility, it is probably better to leave that alone and use the transform on the <path> element, even if I can see that in Firefox there is no difference in the result.

.clipped-img {
    clip-path: url(#raindropClipPath);
    width: 100%;
    height: auto;
}

#raindropSVG {
    width: 0;
    height: 0;

}
<svg id="raindropSVG">
    <defs>
        <clipPath id="raindropClipPath" clipPathUnits="objectBoundingBox">
            <path transform="scale(0.0012345, 0.00098814)" d="M0,604.4C0,523.7,30.7,408.8,97.5,320,217,160.9,409.2,0,409.2,0S597.2,167.8,717,331c63,85.7,93,196.4,93,274,0,224.5-181.3,407-405,407S0,829.5,0,604.4Z"/>
        </clipPath>
    </defs>
</svg>

<img src="https://i.stack.imgur.com/zubYX.png" alt="" class="clipped-img">
ccprog
  • 20,308
  • 4
  • 27
  • 44
  • You yourself have already written about it above that there will be distortions of proportions, but if this suits the author of the question, then your decision is the best – Alexandr_TT Dec 05 '18 at 17:08
  • I'm going with his comment to my question. But you are right, I should spell that out in the answer for posteriority. – ccprog Dec 05 '18 at 17:12
  • Thanks for your answer. I chose this as the accepted answer because it answers my question more completely. @Alexandr_T, your answer was quite instructive also. – Ron Dec 05 '18 at 20:02
3

SVG will always be responsive if only viewBox is specified.

Svg saves image proportions unless the value `preserveAspectRatio ="none" is specified.

Therefore, the path formativeclip-path will also be responsive.

A picture added to the SVG using the <image> tag will also be adaptive and maintain its proportions.

#raindropSVG {
    width: 75%;
    height: 75%;
}

.clipped-img {
clip-path: url(#raindropClipPath);
}
<svg id="raindropSVG" viewBox="0 0 800 800" preserveAspectRatio="xMinYMin meet">
    <defs>
        <clipPath id="raindropClipPath" >
            <path transform="scale(0.75)" d="M0,604.4C0,523.7,30.7,408.8,97.5,320,217,160.9,409.2,0,409.2,0S597.2,167.8,717,331c63,85.7,93,196.4,93,274,0,224.5-181.3,407-405,407S0,829.5,0,604.4Z"/>
        </clipPath>
    </defs>
<image class="clipped-img" xlink:href="https://i.stack.imgur.com/zubYX.png" x="0" y="0" width="800" height="800" />
 
 </svg>
Alexandr_TT
  • 13,635
  • 3
  • 27
  • 54
  • 1
    Thanks for your answer. When the image is a part of the SVG, like in your example, it is responsive. So that's a step in the right direction. However, for my purpose, I need it to work when the image is outside the SVG and the path referenced via a clip path. This is because what I clip may not be an image, it may be a video or other content. So this is why I need the clip path itself to be responsive. – Ron Dec 05 '18 at 15:56
  • @Ron You have a very interesting idea. I'll think about it. But if clipPath in svg works in all modern browsers, then clip-path css is supported by browsers worse – Alexandr_TT Dec 05 '18 at 16:16
  • 1
    Another downside to this approach is that you cannot set `height:auto` but must size the image explicitely. – ccprog Dec 05 '18 at 16:57