user2307706
user2307706

Reputation: 471

Is it possible to create an angled corner in CSS?

I am wondering if there is any way to create this shape with pure CSS. To extend this problem further, this shape needs to clip the image inside (think of it as a mask - but the grey border has to be visible).

enter image description here

Or am I better off creating this in canvas/svg?

Upvotes: 44

Views: 78230

Answers (6)

Vikas Ghodke
Vikas Ghodke

Reputation: 6655

You can do this by using pseudo, along with border-width and border-color see the below code to see how it can be done.

.cut {
  position: relative;
  width: 500px;
  height: 200px;
  padding: 20px;
  color: #000;
  background: #ccc;
}

.cut:before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  border-width: 30px 30px 0px 0px;
  border-style: solid;
  border-color: #fff transparent transparent #fff;
}
<div class="cut"></div>

Another Solution using this jQuery script for cross browser support. --> http://jquery.malsup.com/corner/

SEE THE DEMO HERE

HTML

<div class="cut"></div>

CSS

.cut {
    position:relative;
    width:500px;
    height: 200px;
    padding:20px;
    color:#000;
    background:#ccc;
}

JS

$(".cut").corner("bevel tl 50px");

Upvotes: 12

ediblecode
ediblecode

Reputation: 11971

It is possible to do this, but it is a CSS3 solution so won't work on older browsers I don't think.

What I've done is, I've created two divs, one has a border all around, and the other has a border only on the bottom. Using translate I've then rotated that div 45 degrees to mask the corner of the other div, giving the desired effect.

.holder {
  position: relative;
  width: 180px;
  margin: 30px
}

.main {
  width: 160px;
  height: 40px;
  border: 1px solid grey;
  position: absolute;
  left: 0;
  z-index: 1;
}

.corner {
  border-bottom: 1px solid grey;
  width: 30px;
  height: 41px;
  position: absolute;
  top: -25px;
  right: 0;
  z-index: 2;
  background: #fff;
  transform: rotate(45deg);
}
<div class="holder">
  <div class="main"></div>
  <div class="corner"></div>
</div>

See Fiddle

Upvotes: 3

Max Tuzenko
Max Tuzenko

Reputation: 1359

There is official one liner for this: clip-path. You can use this helper web page to generate desired shape. enter image description here

.container{
  display: flex;
}

.shape1{
  height: 200px;
  width: 200px;
  clip-path: polygon(36% 0, 100% 0, 100% 100%, 0 99%, 0 31%);
  background-image: url("https://images.pexels.com/photos/12258844/pexels-photo-12258844.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1");
  background-size:cover;
}
.shape2{
  height: 200px;
  width: 200px;
  clip-path: polygon(20% 0%, 0% 20%, 30% 50%, 0% 80%, 20% 100%, 50% 70%, 80% 100%, 100% 80%, 70% 50%, 100% 20%, 80% 0%, 50% 30%);
  background-image: url("https://images.pexels.com/photos/12258844/pexels-photo-12258844.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1");
  background-size:cover;
}
.shape3{
  height: 200px;
  width: 200px;
  clip-path: polygon(31% 5%, 89% 0, 98% 35%, 63% 52%, 100% 71%, 57% 77%, 16% 100%, 24% 66%, 2% 35%, 51% 22%);
  background-image: url("https://images.pexels.com/photos/12258844/pexels-photo-12258844.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1");
  background-size:cover;
}
        <div class="container">
            <div class="shape1"></div>
            <div class="shape2"></div>
            <div class="shape3"></div>
        </div>

Upvotes: 0

Temani Afif
Temani Afif

Reputation: 272866

I have an online generator from where you can easily get such shape. Select your configuration and you will get the clip-path values

Angled corner CSS only

.box {
  display: inline-grid;
  position: relative;
  /* from the generator */
  clip-path: polygon(0 102.00px,102.00px 0,100% 0,100% 100%,0 100%);
}
.box:before {
  content: "";
  position: absolute;
  inset: 0;
  background: red; /* your border color */
  /* from the generator*/
  clip-path: polygon(0 102.00px,102.00px 0,100% 0,100% 100%,0 100%,0 102.00px,10px  calc(102.00px + 4.14px),10px calc(100% - 10px),calc(100% - 10px) calc(100% - 10px),calc(100% - 10px) 10px,calc(102.00px + 4.14px) 10px,10px calc(102.00px + 4.14px));
}
<div class="box">
<img src="https://picsum.photos/id/1069/400/250">
</div>

Upvotes: 3

Matt.C
Matt.C

Reputation: 1322

It's a little difficult keeping the border, but I managed to achieve a close effect using :before and :after elements with a parent container (:before and :after don't work on an img tag)

  1. Add a border to the container

  2. Add a before to block out a corner and offset by -1 to cover the border

  3. Add an after that's slightly offset from the before to create the line inside the cut off

As you can see, the thickness of the 45deg line is a bit of an issue:

.cutCorner {
    position:relative; background-color:blue; 
    border:1px solid silver; display: inline-block;
}

.cutCorner img {
    display:block;
}

.cutCorner:before {
    position:absolute; left:-1px; top:-1px; content:'';
    border-top: 70px solid silver;
    border-right: 70px solid transparent;
}

.cutCorner:after {
    position:absolute; left:-2px; top:-2px; content:'';
    border-top: 70px solid white;
    border-right: 70px solid transparent;
}
<div class="cutCorner">
    <img class="" src="https://www.google.co.uk/logos/doodles/2013/william-john-swainsons-224th-birthday-5655612935372800-hp.jpg" />
</div>

JSFiddle

Upvotes: 38

Harry
Harry

Reputation: 89750

Using CSS:

The exact shape can be achieved using CSS. The idea is to have an element with a border-radius for the top-left corner, skew it along the Y axis and then position it just before the rectangle. Doing these would make it look as though the rectangular element has a triangular cut at the top with one curved edge.

If the inside part of the shape has only a color (solid or transparent) then it can be achieved using only one element. However, if an image needs to be added inside the shape (like mentioned in question), then we need more than one element because we have to reverse the skew effect on the image and this cannot be done without a child element.

.shape,
.shape-image {
  position: relative;
  height: 150px;
  width: 400px;
  border-bottom: 2px solid crimson;
  overflow: hidden;
}
.shape:before,
.shape:after,
.shape-image:after {
  position: absolute;
  content: '';
  top: 0px;
  height: 100%;
  z-index: -1;
}
.shape:before,
.shape-image .before {
  left: 0px;
  top: -2px;
  width: 50px;
  border: 2px solid crimson;
  border-width: 3px 0px 0px 2px;
  border-top-left-radius: 8px;
  transform-origin: right bottom;
  transform: skewY(-45deg);
}
.shape:after,
.shape-image:after {
  left: 52px;
  width: calc(100% - 54px);
  border: 2px solid crimson;
  border-left: none;
}
.shape:after,
.shape:before {
  background: aliceblue;
}
.shape.semi-transparent:after,
.shape.semi-transparent:before {
  background: rgba(150, 150, 150, 0.5);
}
.shape-image .before {
  position: absolute;
  top: 0px;
  height: 100%;
  overflow: hidden;
}
.shape-image .before .img {
  height: 100%;
  width: 100%;
  border-top-left-radius: 8px;
  background: url(http://lorempixel.com/400/150);
  transform-origin: right bottom;
  transform: skewY(45deg);
}
.shape-image:after {
  background: url(http://lorempixel.com/400/150);
  background-position: -50px 0px;
}

/* Just for demo */

body{
  background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
.shape{
  margin: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="shape"></div>
<div class="shape semi-transparent"></div>
<div class="shape-image">
  <div class="before">
    <div class="img"></div>
  </div>
</div>


Using SVG:

Alternately the same can be achieved in a more hassle free way with SVG like in the below snippet.

.vector {
  height: 150px;
  width: 410px;
  padding-left
}
svg {
  height: 100%;
  width: 100%;
}
path {
  stroke: crimson;
  stroke-width: 2;
  fill: none;
}
polygon {
  fill: url(#bg);
}

/* Just for demo */

body {
  background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class='vector'>
  <svg viewBox='0 0 400 150' preserveAspectRatio='none'>
    <defs>
      <path d='M50,2 h 342 v144 h-390 v-90 a6,12 0 0,1 3,-9 z' id='p' />
      <clipPath id='clipper'>
        <use xlink:href='#p' />
      </clipPath>
      <pattern id='bg' width='400' height='150' patternUnits='userSpaceOnUse'>
        <image xlink:href='http://lorempixel.com/400/150' height='150' width='400' />
      </pattern>
    </defs>
    <polygon points='2,2 392,2 392,148 2,148' clip-path='url(#clipper)' />
    <use xlink:href='#p' />
  </svg>
</div>
<h3>Original Image</h3>
<img src='http://lorempixel.com/400/150' />

Screenshot:

enter image description here

Upvotes: 11

Related Questions