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
Jquery-Ui Datepicker CSS Problem
Start Div Scrollbar from Bottom with Pure CSS
CSS Background Image Centered with Stellar Js
Jw Player: Cross-Browser "Display:None" Player Behavior
Cutting a Triangle Out of Div, But Have It Horizontally Centered
CSS Display Property When a Float Is Applied
Shape-Outside of an Image Centered Between Two Text Blocks
Percentage Height in Nested Flex Box
Does a Cache Buster on an Image Url in CSS Cause an Extra Request
Media Query for iPad (Landscape) Applied to Samsung Galaxy Tab 2 (Landscape) as Well
Fluid Navigation Items of Different Widths with Equidistant Spacing
IE8 Renders Font Weights Randomly
How to Use Both Rel="Preload" and Rel="Stylesheet" for the Same Tag
Vertical-Align Not Working with Xhtml 1.0 Transitional Doctype