How to Make a Svg Clippath with a <Path> Responsive

Responsive clip-path with inline SVG

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>

Create responsive SVG clip path / Making SVG path responsive

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="Sample Image" class="clipped-img">

Complex SVG clip-path responsive

As Robert said, when you specify clipPathUnits="objectBoundingBox", the coordinates in the clip path definition are supposed to be between 0,0 (the top left) and 1,1 (the bottom right).

Your paths are about 700x575, so your path is about 600 to 700 times too big.

The simplest solution is to add a transform attribute to your <clipPath> that scales the coordinates down to the correct range.

<clipPath id="map" clipPathUnits="objectBoundingBox" transform="scale(0.00143, 0.00174)">
  • 1/700 ~= 0.00143
  • 1/575 ~= 0.00174

https://codepen.io/anon/pen/GyvZOM

Responsive clip-path SVG

You can build it using CSS and keep the same size for your circles:

.box {  width:200px;  height:200px;  margin:5px;  background:url(https://i.picsum.photos/id/1074/800/800.jpg) center/cover;  -webkit-mask:    radial-gradient(circle 20px at top    left ,transparent 97%,#fff 100%) top    left,    radial-gradient(circle 20px at top    right,transparent 97%,#fff 100%) top    right,    radial-gradient(circle 20px at bottom left ,transparent 97%,#fff 100%) bottom left,    radial-gradient(circle 20px at bottom right,transparent 97%,#fff 100%) bottom right;  -webkit-mask-size:51% 51%;  -webkit-mask-repeat:no-repeat;  mask:    radial-gradient(circle 20px at top    left ,transparent 97%,#fff 100%) top    left,    radial-gradient(circle 20px at top    right,transparent 97%,#fff 100%) top    right,    radial-gradient(circle 20px at bottom left ,transparent 97%,#fff 100%) bottom left,    radial-gradient(circle 20px at bottom right,transparent 97%,#fff 100%) bottom right;  mask-size:51% 51%;  mask-repeat:no-repeat;}
<div class="box">
</div>
<div class="box" style="width:400px;">
</div>

Animated div with SVG clip-path not responsive?

Part of the problem are your width and max-width definitions.

Essentially you have to ensure your clipped image keeps its aspect ratio.

You might actually use the css aspect-ratio property – but browser support is still not perfect. Thus we take the old-school aspect-ratio hack.

   .imageHero::before {
content: "";
padding-bottom: 100%;
width: 100%;
display: block;
}

.imageHero {
max-width: 65vh;
margin: 0 auto;
clip-path: url('#my-clip-path');
animation: clipRotateAnim 6s linear infinite;
position: relative;
overflow: hidden;
}

/* force aspect ratio 1:1 */
.imageHero::before {
content: "";
padding-bottom: 100%;
width: 100%;
display: block;
}

/* image */
.imageHero::after {
content: "";
position: absolute;
top: -10%;
bottom: -10%;
left: -10%;
right: -10%;
background: var(--i) center;
background-size: cover;
animation: inherit;
animation-direction: reverse;
}

@keyframes clipRotateAnim {
to {
transform: rotate(360deg);
}
}

.imageHero-wrp {
position: relative;
overflow: hidden;
padding: 40px;
background: #eee;
}

.svg-content {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
}
<main>
<div class="imageHero-wrp">
<div class="imageHero" style="--i:url(https://source.unsplash.com/600x600?summer)" width="100%" height="100%">
</div>

<svg class="svg-content" viewBox="0 0 1 1">
<clipPath id="my-clip-path" clipPathUnits="objectBoundingBox">
<path
d="M0.5,0.768 L0.366,1 L0.366,0.732,0.134,0.866 L0.268,0.634 L0,0.634 L0.232,0.5,0,0.366 L0.268,0.366,0.134,0.134 L0.366,0.268 L0.366,0 L0.5,0.232,0.634,0 L0.634,0.268,0.866,0.134 L0.732,0.366 L1,0.366 L0.768,0.5 L1,0.634,0.732,0.634,0.866,0.866 L0.634,0.732 L0.634,1z">
</path>
</clipPath>
</svg>
</div>
</main>

Responsive svg clipPath with background image

As you have already figured out, you need to convert your path coordinates so that they are in the range 0 to 1.

Assuming your clip path is the size of your viewBox (550.6 x 144.52), then you need to scale your X coords by (1/550.6) and your Y coords by (1/144.52).

So try wrapping your paths in a group that has the appropriate scaling transform applied:

<clippath id="clipPath">
<g transform="scale(0.00182 0.00692)">
<path ... />
<path ... />
<path ... />
<path ... />
</g>
</clippath>

Update / correction

I forgot. Groups aren't allowed in clipPaths. You will need to add the transform to each path.

<clippath id="clipPath">
<path ... transform="scale(0.00182 0.00692) "/>
<path ... transform="scale(0.00182 0.00692)" />
<path ... transform="scale(0.00182 0.00692)" />
<path ... transform="scale(0.00182 0.00692)" />
</clippath>

If the path already contains a transform, then make sure you put the scale before the rest of the transform.

<clippath id="clipPath">
<path ... transform="scale(0.00182 0.00692) translate(-12.27 -345.86)"/>
etc
</clippath>


Related Topics



Leave a reply



Submit