Santhosh Kumar Santhosh Kumar - 6 months ago 31
CSS Question

Drawing shapes in css responsively

I have a div with slight curve at the top. I tried and achieved using border. But my concern is its not responsive. How to make it responsive. Any idea?. Here is the code which i tried have a look at this.

<div>

</div>
div{
position:relative;
width:100%;
float:left;
background:green;
height:80px;
overflow:hidden
}
div:before{
position: absolute;
content: '';
left: 0;
right: 50%;
border: 298px solid transparent;
top: 0;
border-top: 13px solid #fff;
}


Also refer the fiddle

enter image description here

Answer

Using CSS Gradients + Transforms:

One way to achieve this shape with a responsive cut at the top would be to use two skewed pseudo elements, add the background to the pseudo-elements alone and not the parent element.

Since, the pseudo-elements are half the width of their parent element, the linear-gradient fill that is required on the parent should also be divided into two halves and assigned to the 2 pseudo-elements.

One potential drawback of this approach is that the depth of the cut will increase if height of the parent div increases.

.shape {
  position: relative;
  height: 100px;
  width: 100%;
  overflow: hidden;
}
.shape:after,
.shape:before {
  position: absolute;
  content: '';
  height: 100%;
  width: calc(50% + 1px);
  top: 0;
  backface-visibility: hidden;
}
.shape:before {
  left: 0;
  background-image: linear-gradient(to right, red, gold);
  transform: skewY(2deg);
  transform-origin: left top;
}
.shape:after {
  right: 0;
  background-image: linear-gradient(to right, gold, crimson);
  transform: skewY(-2deg);
  transform-origin: right top;
}
body {
  background-image: radial-gradient(circle at center, sandybrown, chocolate);
  min-height: 100vh;
}
<div class='shape'></div>

Using CSS Clip-path: (poor browser support)

Another approach would be to make use of CSS clip-path. This, in my opinion, would be the perfect option as there needs to be no gradient manipulation (like dividing into half), the depth of the cut will not change even if the height of the div increases etc. But unfortunately it has poor browser support.

.shape {
  height: 100px;
  width: 100%;
  -webkit-clip-path: polygon(0px 0px, 50% 14px, 100% 0%, 100% 100%, 0% 100%);
  background-image: linear-gradient(to right, red, gold, crimson);
}
body {
  background-image: radial-gradient(circle at center, sandybrown, chocolate);
  min-height: 100vh;
}
<div class='shape'></div>

Using SVG Clip-path: (better browser support)

Another approach would be to make use of SVG clip-path. This has better browser support than its CSS counterpart but unfortunately, here the depth of the cut will change as the dimensions change.

.shape {
  height: 100px;
  width: 100%;
  -webkit-clip-path: url(#clipper);
  clip-path: url(#clipper);
  background-image: linear-gradient(to right, red, gold, crimson);
}
body {
  background-image: radial-gradient(circle at center, sandybrown, chocolate);
  min-height: 100vh;
}
<svg width="0" height="0" viewBox="0 0 200 200">
  <defs>
    <clipPath id="clipper" clipPathUnits="objectBoundingBox">
      <path d="M0,0 0.5,0.07 1,0 1,1 0,1z" />
    </clipPath>
  </defs>
</svg>
<div class='shape'></div>

Alternately, we can do the same using a SVG path or polygon element (instead of clip-path) and position it absolutely within the parent container also, but it would have the same limitation as the SVG clip-path (that is, depth of cut will increase if dimensions change because the values are in fractions of parent container's size and not in fixed length).

Comments