Complex clip-path / SVG background of an element - css

I need to create something like the image below:
Where:
The black background represents a element on the page, header for example
The cyan background represents the overall background underneath the black one
the black background element has to be treated like a single element, because it will have a pattern overlay on top of it, that will have to stay within the borders of the black element, and not show up outside of it
It would be very easy, to just create the black element with some :pseudo-elements, however that pattern on top of it has brought the whole thing to a standstill.
I've been reading about clip-path prop. but I'm not sure I would be able to create a complex clip like this one (or maybe it seems complex to me).
The whole thing will be used on a iOS app, and so far it seems this clip-path property would be compatible with it.
Another thing to mention, the black element will have a fixed height, but has to be 100% width of its parent.
I've figured I'd get away with using svg instead, but as it needs to be a fixed height, it seems like its distorting when its stretched.
UPDATE:
The right side has to stay the same width, I've figured maybe using a two svgs inside a <g> tag and absolute position them, one would be fluid and the other would have a fixed width. However, I'm not sure if a filter would cover both of them, or if the filter can be applied at all to a <g> tag, inside a svg
SVG sample below:
body {
background: cyan;
}
svg {
min-width: 100%;
height: 80px;
}
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 452 170" preserveAspectRatio="none">
<rect x="1" y="14" width="438" height="142" />
<path d="M0 0v170h452V0H0zM448 166H4V4h444V166z" />
<rect y="14" width="438" height="142" />
</svg>
Any tips or pointers are much appreciated!

May be it would be a better solution go with masking ?
#test {
font-size: 100px;
position: relative;
display: inline-block;
margin: 40px;
}
#test:after {
content: "";
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
z-index: -1;
background: repeating-linear-gradient(45deg, lightblue, tomato 100px);
-webkit-mask-image: linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(transparent, transparent);
-webkit-mask-size: 5% 100%, 5% 100%, 100% 5%, 100% 5%, 80% 80%;
-webkit-mask-position: left top, right top, center top, center bottom, center center ;
-webkit-mask-repeat: no-repeat;
}
body {
background-color: lightgreen;
}
<div id="test">Transparent frame</div>
A fixed width approach
replace the dimensions of the width of the borders with a fixed value in pixels. Use calc for the inner rectangle.
body, html {
width: 90%;
position: relative;
}
#test {
font-size: 100px;
position: relative;
display: inline-block;
margin: 40px;
width: 100%;
height: 40%;
}
#test:after {
content: "";
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
z-index: -1;
background: repeating-linear-gradient(45deg, lightblue, tomato 100px);
-webkit-mask-image: linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(red, red),
linear-gradient(transparent, transparent);
-webkit-mask-size: 10px 100%, 10px 100%, 100% 10px, 100% 10px, calc(100% - 40px) calc(100% - 40px);
-webkit-mask-position: left top, right top, center top, center bottom, center center ;
-webkit-mask-repeat: no-repeat;
}
body {
background-color: lightgreen;
}
<div id="test">Transparent frame</div>
An eliptical example
#test {
font-size: 100px;
position: relative;
display: inline-block;
margin: 40px;
border-radius: 50%;
}
#test:after {
content: "";
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
z-index: -1;
border-radius: 50%;
background: repeating-linear-gradient(45deg, lightblue, tomato 100px);
-webkit-mask-image: radial-gradient(ellipse, red 55%, transparent 56%, transparent 65%, red 66%);
}
body {
background: lightgreen;
}
<div id="test">Transparent frame</div>

This can be achieved by making use of the approach described by Ana in this CSS Tricks article.
Using CSS Clip-path:
All we need to do is use a polygon for clipping like in the below snippet and apply it on the container. Such a path would show the background image in the gap between the outermost box and the middle box, hide or clip the background image between the middle box and the innermost box.
div {
height: 200px;
width: 100%;
background: url(http://lorempixel.com/800/200/abstract/6);
}
#css-pattern {
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0px 0px, 20px 20px, 20px calc(100% - 20px), calc(100% - 20px) calc(100% - 20px), calc(100% - 20px) 20px, 20px 20px, 40px 40px, 40px calc(100% - 40px), calc(100% - 40px) calc(100% - 40px), calc(100% - 40px) 40px, 40px 40px);
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0px 0px, 20px 20px, 20px calc(100% - 20px), calc(100% - 20px) calc(100% - 20px), calc(100% - 20px) 20px, 20px 20px, 40px 40px, 40px calc(100% - 40px), calc(100% - 40px) calc(100% - 40px), calc(100% - 40px) 40px, 40px 40px);
}
/* just for demo */
body {
background: radial-gradient(circle at center, aliceblue, mediumslateblue);
min-height: 100vh;
}
<h3>Pure CSS Clip-path with fixed width gap on all 4 sides</h3>
<div id='css-pattern'></div>
Using SVG Clip-path:
SVG clip-path offers better browser support than the CSS version as it is supported by Firefox too. All we need to do is create a path like in the below snippet and use it for clipping the container.
svg path {
fill: transparent;
stroke: black;
}
/* Just for fun */
path {
animation: draw 5s linear;
stroke-dasharray: 4450;
}
#keyframes draw {
from {
stroke-dashoffset: -4450;
}
to {
stroke-dashoffset: 0;
}
}
<svg width='600px' height='200px'>
<path d='M0,0 600,0 600,200 0,200 0,0 20,20 20,180 580,180 580,20 20,20 40,40 40,160 560,160 560,40 40,40 z' />
</svg>
SVG implementation would have been far easier if the dimensions of your container were static. Since they are not static, fraction values cannot be used as the value would differ based on the actual width of the element (whatever 100% corresponds to). Say for example, a fraction value of 0.2 would mean 40px for a 200px wide element and would mean 80px for a 400px wide element. You can see how this affects the output in the snippet's first sample.
One way to overcome this would be to make use of JavaScript (or any other scripting library that you prefer), get the actual calculated width of the element in pixels and the calculate the coordinate values of the path's d attribute based on it. The second sample in the below snippet uses this method.
Note: Clip-path is not supported by IE but since you are creating an iOS app, I think this should not be a major concern for you.
window.onload = function() {
setPathCoords();
};
window.onresize = function() {
setPathCoords();
};
function setPathCoords() {
var output = [],
borderWidth = '20';
var el = document.getElementById('percentage-pattern'),
path = document.querySelector('#clipper2 > path'),
origPath = 'M0,0 1,0 1,1 0,1 0,0 ';
height = el.clientHeight;
width = el.clientWidth;
for (var x = 1; x < 3; x++) {
point1 = (borderWidth * x) / width + "," + (borderWidth * x) / height;
point2 = (borderWidth * x) / width + "," + (height - (borderWidth * x)) / height;
point3 = (width - (borderWidth * x)) / width + "," + (height - (borderWidth * x)) / height;
point4 = (width - (borderWidth * x)) / width + "," + (borderWidth * x) / height;
output.push(point1);
output.push(point2);
output.push(point3);
output.push(point4);
output.push(point1);
}
document.querySelector('#clipper2 > path').setAttribute('d', origPath + output.join(' ') + 'z');
}
div {
height: 200px;
width: 100%;
background: url(http://lorempixel.com/800/200/abstract/6);
}
#percentage-pattern {
-webkit-clip-path: url(#clipper);
clip-path: url(#clipper);
}
#js-pattern {
-webkit-clip-path: url(#clipper2);
clip-path: url(#clipper2);
}
/* just for demo */
body {
background: radial-gradient(circle at center, aliceblue, mediumslateblue);
min-height: 100vh;
}
<svg width='0' height='0'>
<defs>
<clipPath id='clipper' clipPathUnits='objectBoundingBox'>
<path d='M0,0 1,0 1,1 0,1 0,0 0.1,0.1 0.1,0.9 0.9,0.9 0.9,0.1 0.1,0.1 0.2,0.2 0.2,0.8 0.8,0.8 0.8,0.2 0.2,0.2z' />
</clipPath>
<clipPath id='clipper2' clipPathUnits='objectBoundingBox'>
<path d='M0,0 1,0 1,1 0,1 0,0 ' />
</clipPath>
</defs>
</svg>
<h3>Output with JS</h3>
<div id='js-pattern'></div>
<h3>Pure SVG Clip-path</h3>
<div id='percentage-pattern'></div>

Related

Rounding corners of parallelogram made from clip-path CSS [duplicate]

I want to be able to round out the 3 leftmost corners on this shape that I have created, any idea how that can be done?
div {
position: absolute;
z-index: 1;
width: 423px;
height: 90px;
background-color: #b0102d;
color: white;
right: 0;
margin-top: 10vw;
-webkit-clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
<div></div>
use inset with round property :
inset(0% 45% 0% 45% round 10px)
An SVG filter can round any kind of clip-path. You simply need to apply it to a parent element. Adjust the stdDeviation to control the radius:
.box {
width: 423px;
height: 90px;
background-color: #b0102d;
color: white;
clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
.parent {
filter: url('#goo');
overflow:hidden;
position: fixed;
right:-50px;
z-index: 1;
margin-top: 10vw;
}
<div class="parent">
<div class="box"></div>
</div>
<svg style="visibility: hidden; position: absolute;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9" result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
</defs>
</svg>
Related: https://stackoverflow.com/a/65485455/8620333
I've recently found success experimenting with approaches like this...
SVG
<svg width="0" height="0">
<defs>
<clipPath id="clipped">
<circle cx="var(--myRad)" cy="var(--myRad)" r="var(--myRad)"></circle>
<circle cx="var(--myRad)" cy="calc(var(--myHeight) - var(--myRad))" r="var(--myRad)"></circle>
<circle cx="calc(var(--myWidth) - var(--myRad))" cy="calc(var(--myHeight) - var(--myRad))" r="var(--myRad)"></circle>
<circle cx="calc(var(--myWidth) - var(--myRad))" cy="var(--myRad)" r="var(--myRad)"></circle>
<rect y="var(--myRad)" width="var(--myWidth)" height="calc(var(--myHeight) - (2 * var(--myRad)))"></rect>
<rect x="var(--myRad)" width="calc(var(--myWidth) - (2 * var(--myRad)))" height="var(--myHeight)"></rect>
</clipPath>
</defs>
</svg>
CSS
.clipped {
--myWidth: 100vw;
--myHeight: 10rem;
--myRad: 2rem;
clip-path: url(#clipped);
}
I found this useful as compared to using border-radius with overflow set to hidden, because this approach doesn't create a BFC or break things like sticky position and css perspective effects. Also, this allows you to "inset" the position of the svg paths to clip inside the element with a "corner-radius" if you want.
You can also mess around with the circle to get some different effects.
-webkit-clip-path: circle(60.0% at 50% 10%);
clip-path: circle(50.0% at 50% 50%);
Codepen
Too bad you can't combine the polygon and circle... or maybe you can and I haven't played around with it enough to figure it out. HTH
clip-path: inset(45% 0% 33% 10% round 10px)
I don't have a comment option yes, so I'm writing it as an answer..
you need to write as many points as possible to round the corner. Nothig else...
for, example a few more points to make lower part bit rounder:
-webkit-clip-path: polygon(100% 0%, 100% 100%, 100% 100%, 25% 100%, 5% 70%,1% 60%, 0% 50%, 25% 0%);
oh, yes, or SVG as comment people here.. :)
You could use a child element and do a nested clip-path on that and the child's pseudo element. The parent will do a polygon clip on the shape first, then the pseudo will have an ellipse to round the borders. The clips will have a combined effect.
.parent, .parent div, .parent div:before {
width: 423px;
height: 90px;
position: absolute;
}
.parent {
right: 0;
background-image: linear-gradient(to right, transparent 210px, #b0102d 210px);
margin-top: 15vh;
}
.parent div {
clip-path: polygon(100% 0%, 100% 100%, 25% 100%, 0 50%, 25% 0);
}
.parent div:before {
content: "";
background-color: #b0102d;
clip-path: ellipse(200px 45px at 210px);
}
<div class="parent">
<div></div>
</div>
Here is the demo with some adaptations to illustrate what's going on:
.parent, .parent div, .parent div:before {
width: 423px;
height: 90px;
position: absolute;
}
.parent {
right: 0;
background-image: linear-gradient(to right, transparent 210px, yellow 210px);
margin-top: 15vh;
}
.parent div {
background-color: blue;
clip-path: polygon(90% 0%, 90% 100%, 25% 100%, 0 50%, 25% 0);
}
.parent div:before {
content: "";
background-color: #b0102d;
clip-path: ellipse(200px 45px at 210px);
}
<div class="parent">
<div></div>
</div>
The horizontal size and position of the ellipse can be used to get a different effect on the edges. Note that the background starting postion of the parent needs to be adjusted to the same value as the placement of the ellipse (last value in the clip-path) because it fills up whatever gets clipped off on the right side. This can be visualised by removing background-color: blue from .parent div in the second demo.
Here is an additional Codepen to to try it out.

How to get rounded edges with clip path code? [duplicate]

I want to be able to round out the 3 leftmost corners on this shape that I have created, any idea how that can be done?
div {
position: absolute;
z-index: 1;
width: 423px;
height: 90px;
background-color: #b0102d;
color: white;
right: 0;
margin-top: 10vw;
-webkit-clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
<div></div>
use inset with round property :
inset(0% 45% 0% 45% round 10px)
An SVG filter can round any kind of clip-path. You simply need to apply it to a parent element. Adjust the stdDeviation to control the radius:
.box {
width: 423px;
height: 90px;
background-color: #b0102d;
color: white;
clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
.parent {
filter: url('#goo');
overflow:hidden;
position: fixed;
right:-50px;
z-index: 1;
margin-top: 10vw;
}
<div class="parent">
<div class="box"></div>
</div>
<svg style="visibility: hidden; position: absolute;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9" result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
</defs>
</svg>
Related: https://stackoverflow.com/a/65485455/8620333
I've recently found success experimenting with approaches like this...
SVG
<svg width="0" height="0">
<defs>
<clipPath id="clipped">
<circle cx="var(--myRad)" cy="var(--myRad)" r="var(--myRad)"></circle>
<circle cx="var(--myRad)" cy="calc(var(--myHeight) - var(--myRad))" r="var(--myRad)"></circle>
<circle cx="calc(var(--myWidth) - var(--myRad))" cy="calc(var(--myHeight) - var(--myRad))" r="var(--myRad)"></circle>
<circle cx="calc(var(--myWidth) - var(--myRad))" cy="var(--myRad)" r="var(--myRad)"></circle>
<rect y="var(--myRad)" width="var(--myWidth)" height="calc(var(--myHeight) - (2 * var(--myRad)))"></rect>
<rect x="var(--myRad)" width="calc(var(--myWidth) - (2 * var(--myRad)))" height="var(--myHeight)"></rect>
</clipPath>
</defs>
</svg>
CSS
.clipped {
--myWidth: 100vw;
--myHeight: 10rem;
--myRad: 2rem;
clip-path: url(#clipped);
}
I found this useful as compared to using border-radius with overflow set to hidden, because this approach doesn't create a BFC or break things like sticky position and css perspective effects. Also, this allows you to "inset" the position of the svg paths to clip inside the element with a "corner-radius" if you want.
You can also mess around with the circle to get some different effects.
-webkit-clip-path: circle(60.0% at 50% 10%);
clip-path: circle(50.0% at 50% 50%);
Codepen
Too bad you can't combine the polygon and circle... or maybe you can and I haven't played around with it enough to figure it out. HTH
clip-path: inset(45% 0% 33% 10% round 10px)
I don't have a comment option yes, so I'm writing it as an answer..
you need to write as many points as possible to round the corner. Nothig else...
for, example a few more points to make lower part bit rounder:
-webkit-clip-path: polygon(100% 0%, 100% 100%, 100% 100%, 25% 100%, 5% 70%,1% 60%, 0% 50%, 25% 0%);
oh, yes, or SVG as comment people here.. :)
You could use a child element and do a nested clip-path on that and the child's pseudo element. The parent will do a polygon clip on the shape first, then the pseudo will have an ellipse to round the borders. The clips will have a combined effect.
.parent, .parent div, .parent div:before {
width: 423px;
height: 90px;
position: absolute;
}
.parent {
right: 0;
background-image: linear-gradient(to right, transparent 210px, #b0102d 210px);
margin-top: 15vh;
}
.parent div {
clip-path: polygon(100% 0%, 100% 100%, 25% 100%, 0 50%, 25% 0);
}
.parent div:before {
content: "";
background-color: #b0102d;
clip-path: ellipse(200px 45px at 210px);
}
<div class="parent">
<div></div>
</div>
Here is the demo with some adaptations to illustrate what's going on:
.parent, .parent div, .parent div:before {
width: 423px;
height: 90px;
position: absolute;
}
.parent {
right: 0;
background-image: linear-gradient(to right, transparent 210px, yellow 210px);
margin-top: 15vh;
}
.parent div {
background-color: blue;
clip-path: polygon(90% 0%, 90% 100%, 25% 100%, 0 50%, 25% 0);
}
.parent div:before {
content: "";
background-color: #b0102d;
clip-path: ellipse(200px 45px at 210px);
}
<div class="parent">
<div></div>
</div>
The horizontal size and position of the ellipse can be used to get a different effect on the edges. Note that the background starting postion of the parent needs to be adjusted to the same value as the placement of the ellipse (last value in the clip-path) because it fills up whatever gets clipped off on the right side. This can be visualised by removing background-color: blue from .parent div in the second demo.
Here is an additional Codepen to to try it out.

Adding triangles with CSS that are responsive

I am struggling to create the above design of the green background, two white triangles and blue dots on the point of the triangles.
I have to create two triangles using W3School tutorial but they are not responsive causing issues. I have created the green background in PS with white triangles and blue dots but cannot get the image to sit in the same position across screen sizes.
Any help in creating the above using HTML/CSS would be great.
You can use clip-path on a pseudo element to create the graph-like zig zag and background images on another pseudo element to place the blue dots.
It is important to note that everything has to be done in relative terms, e.g. %s, so that the whole is responsive.
While this is pretty straightforward for the zig zag, adjustments have to be made to the placing of the dots as things are placed relative to their top left corner not relative to their center, which is what we require for the circles.
Also the height of the 'background' (the zigzag plus a little bit below the green to accomodate the circle at the bottom) has to be specified in terms of the width. Eventually CSS aspect-ratio will be useful for this but just at the moment not all browsers support it so this snippet uses the well-known hack of defining an element's height in terms of padding (the units for which are always the width's).
* {
padding: 0;
margin: 0;
}
.graphbg {
background: white;
width: 100vw;
height: 100vh;
position: relative;
margin: 0;
padding: 0;
}
.graphbg::before,
.graphbg::after {
margin: 0;
padding: 0;
box-sizing: border-box;
overflow: hidden;
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 1;
overflow: hidden;
--w: 4;
/* set these so --w/--h is the proportion of width to height you want this background to have */
--h: 1;
/* soon you will be able to use aspect-ratio: 4 / 1 but currently, August 2021, Safari IOS does not support it */
height: 0;
padding-top: calc( var(--h) / var(--w) * 100%);
/* to force the element to have the right height */
}
.graphbg::before {
background: green;
clip-path: polygon(0 0, 98% 0, 50% 95%, 25% 50%, 0 95%);
}
.graphbg::after {
background-image: radial-gradient(circle, blue 0 70%, transparent 70% 100%), radial-gradient(circle, blue 0 70%, transparent 70% 100%), radial-gradient(blue 0 70%, transparent 70% 100%), radial-gradient(blue 0 70%, transparent 70% 100%);
background-repeat: no-repeat;
background-size: 2% 8%;
background-position: -1% 99%, 24.5% 50%, 50% 97%, 99% -4%;
}
<div class="graphbg"></div>

CSS: Slice radial-gradient 50% on bottom for another similar radial-gradient?

If I have this:
https://codepen.io/anon/pen/MveydB
body {
width: 100vh; height: 100vh;
background-image: radial-gradient(circle closest-side, #00bffb, rgba(0, 0, 0, 1));
}
How I can have something like this instead?:
It's impossible to edit HTML in this case too, because it's a theme for Linux.
Cover with a linear gradient
Paint a half transparent, half black linear gradient on top of it.
.bg {
width: 100vh;
height: 100vh;
background: linear-gradient(to bottom, transparent 50%, black 50%),
radial-gradient(circle closest-side, #00bffb, black);
}
body {
margin: 0;
}
<div class="bg"></div>
Or
Cover with a pseudo element
If you want to create a radial gradient with two halves of different color, you can use a pseudo element with half the height of the parent.
.bg {
position: relative;
width: 100vh;
height: 100vh;
background: radial-gradient(circle closest-side, yellow, black);
}
.bg::before {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100vh;
height: 50%;
background: radial-gradient(circle closest-side, #00bffb, black);
background-size: 100% 200%; /** we need to compensate for the 50% height **/
content: '';
}
body {
margin: 0;
}
<div class="bg"></div>
Set the gradient on half of the container with background-size: 100% 50%,
Position the gradient circle so that only its top half is visible with background-image: radial-gradient(circle 50vh at 50% 100%, #00bffb, #0000);
Explanation:
circle 50vh sets the gradient radius to half the size of the container (you need to use a fixed size, thus 50vh, or 200px if your container was 400px tall — % won't work, sadly)
at 50% 100% sets the gradient center in the middle of the bottom edge of the background box.
body {
width: 100vh;
height: 100vh;
background-color: #000;
background-image: radial-gradient(circle 50vh at 50% 100%, #00bffb, #0000);
background-size: 100% 50%;
background-repeat: no-repeat;
}
https://codepen.io/hyvyys/pen/xxKRGwP

How to round out corners when using CSS clip-path

I want to be able to round out the 3 leftmost corners on this shape that I have created, any idea how that can be done?
div {
position: absolute;
z-index: 1;
width: 423px;
height: 90px;
background-color: #b0102d;
color: white;
right: 0;
margin-top: 10vw;
-webkit-clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
<div></div>
use inset with round property :
inset(0% 45% 0% 45% round 10px)
An SVG filter can round any kind of clip-path. You simply need to apply it to a parent element. Adjust the stdDeviation to control the radius:
.box {
width: 423px;
height: 90px;
background-color: #b0102d;
color: white;
clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 25% 100%, 0% 50%, 25% 0%);
}
.parent {
filter: url('#goo');
overflow:hidden;
position: fixed;
right:-50px;
z-index: 1;
margin-top: 10vw;
}
<div class="parent">
<div class="box"></div>
</div>
<svg style="visibility: hidden; position: absolute;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 19 -9" result="goo" />
<feComposite in="SourceGraphic" in2="goo" operator="atop"/>
</filter>
</defs>
</svg>
Related: https://stackoverflow.com/a/65485455/8620333
I've recently found success experimenting with approaches like this...
SVG
<svg width="0" height="0">
<defs>
<clipPath id="clipped">
<circle cx="var(--myRad)" cy="var(--myRad)" r="var(--myRad)"></circle>
<circle cx="var(--myRad)" cy="calc(var(--myHeight) - var(--myRad))" r="var(--myRad)"></circle>
<circle cx="calc(var(--myWidth) - var(--myRad))" cy="calc(var(--myHeight) - var(--myRad))" r="var(--myRad)"></circle>
<circle cx="calc(var(--myWidth) - var(--myRad))" cy="var(--myRad)" r="var(--myRad)"></circle>
<rect y="var(--myRad)" width="var(--myWidth)" height="calc(var(--myHeight) - (2 * var(--myRad)))"></rect>
<rect x="var(--myRad)" width="calc(var(--myWidth) - (2 * var(--myRad)))" height="var(--myHeight)"></rect>
</clipPath>
</defs>
</svg>
CSS
.clipped {
--myWidth: 100vw;
--myHeight: 10rem;
--myRad: 2rem;
clip-path: url(#clipped);
}
I found this useful as compared to using border-radius with overflow set to hidden, because this approach doesn't create a BFC or break things like sticky position and css perspective effects. Also, this allows you to "inset" the position of the svg paths to clip inside the element with a "corner-radius" if you want.
You can also mess around with the circle to get some different effects.
-webkit-clip-path: circle(60.0% at 50% 10%);
clip-path: circle(50.0% at 50% 50%);
Codepen
Too bad you can't combine the polygon and circle... or maybe you can and I haven't played around with it enough to figure it out. HTH
clip-path: inset(45% 0% 33% 10% round 10px)
I don't have a comment option yes, so I'm writing it as an answer..
you need to write as many points as possible to round the corner. Nothig else...
for, example a few more points to make lower part bit rounder:
-webkit-clip-path: polygon(100% 0%, 100% 100%, 100% 100%, 25% 100%, 5% 70%,1% 60%, 0% 50%, 25% 0%);
oh, yes, or SVG as comment people here.. :)
You could use a child element and do a nested clip-path on that and the child's pseudo element. The parent will do a polygon clip on the shape first, then the pseudo will have an ellipse to round the borders. The clips will have a combined effect.
.parent, .parent div, .parent div:before {
width: 423px;
height: 90px;
position: absolute;
}
.parent {
right: 0;
background-image: linear-gradient(to right, transparent 210px, #b0102d 210px);
margin-top: 15vh;
}
.parent div {
clip-path: polygon(100% 0%, 100% 100%, 25% 100%, 0 50%, 25% 0);
}
.parent div:before {
content: "";
background-color: #b0102d;
clip-path: ellipse(200px 45px at 210px);
}
<div class="parent">
<div></div>
</div>
Here is the demo with some adaptations to illustrate what's going on:
.parent, .parent div, .parent div:before {
width: 423px;
height: 90px;
position: absolute;
}
.parent {
right: 0;
background-image: linear-gradient(to right, transparent 210px, yellow 210px);
margin-top: 15vh;
}
.parent div {
background-color: blue;
clip-path: polygon(90% 0%, 90% 100%, 25% 100%, 0 50%, 25% 0);
}
.parent div:before {
content: "";
background-color: #b0102d;
clip-path: ellipse(200px 45px at 210px);
}
<div class="parent">
<div></div>
</div>
The horizontal size and position of the ellipse can be used to get a different effect on the edges. Note that the background starting postion of the parent needs to be adjusted to the same value as the placement of the ellipse (last value in the clip-path) because it fills up whatever gets clipped off on the right side. This can be visualised by removing background-color: blue from .parent div in the second demo.
Here is an additional Codepen to to try it out.

Resources