Search code examples
svgclip-path

Create responsive SVG clip path / Making SVG <path> responsive


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!


Solution

  • 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.sstatic.net/zubYX.png" alt="" class="clipped-img">