Oblique or twisted border shape

独自空忆成欢 提交于 2019-11-28 10:37:59

Most easiest and neat solution would be to use svg to create the border.

#container {
  position: relative;
  width: 200px;
  height: 30px;
}
#content {
  text-transform: uppercase;
  position: absolute;
  width: 200px;
  height: 30px;
  top: 0;
  text-align: center;
  line-height: 30px;
}
<div id="container">
  <svg width="200" height="30" viewBox="-1 -2 201 33">
    <path d="M0,0 h200 l-15,15 l15,15 h-200 l15,-15z" stroke="black" stroke-width="2" fill="none" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>

You could even spice it up with some curves using quadratic curves.

#container {
  position: relative;
  width: 200px;
  height: 30px;
  margin-bottom: 30px;
}
#content {
  text-transform: uppercase;
  position: absolute;
  width: 200px;
  height: 30px;
  top: 0;
  text-align: center;
  line-height: 30px;
}
<div id="container">
  <svg width="200" height="30" viewBox="-1 -1 201 33">
    <path d="M0,0 h200 q-20,15 0,30 h-200 q20,-15 0,-30" stroke="black" stroke-linejoin="round" stroke-width="2" fill="none" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>

<div id="container">
  <svg width="200" height="30" viewBox="-1 -1 201 33">
    <path d="M0,0 h200 q0,10 -15,15 q10,0 15,15 h-200 q0,-10 15,-15 q-10,0 -15,-15" stroke="black" stroke-linejoin="round" stroke-width="2" fill="none" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>

<div id="container">
  <svg width="200" height="30" viewBox="-1 -1 201 33">
    <path d="M0,0 h200 q-10,0 -15,12.5 l15,2.5 l-15,2.5 q0,10 15,13 h-200 q10,0 15,-12.5 l-15,-2.5 l15,-2.5 q0,-10 -15,-12.5" stroke="black" stroke-linejoin="round" stroke-width="2" fill="none" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>

You could easily add a drop shadow effect.

#container {
  position: relative;
  width: 200px;
  height: 30px;
  margin-bottom: 30px;
}
#content {
  text-transform: uppercase;
  position: absolute;
  width: 200px;
  height: 30px;
  top: 0;
  text-align: center;
  line-height: 30px;
}
<div id="container">
  <svg width="205" height="35" viewBox="-1 -1 205 38">
    <filter id="f">
      <feGaussianBlur stdDeviation="1.5" />
    </filter>
    <path filter="url(#f)" d="M0,0 h200 l-15,15 l15,15 h-200 l15,-15z" stroke="black" stroke-linejoin="round" stroke-width="2" transform="translate(0,3)" fill="black" />
    <path id="shape" d="M0,0 h200 l-15,15 l15,15 h-200 l15,-15z" stroke="black" stroke-linejoin="round" stroke-width="2" fill="white" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>

<div id="container">
  <svg width="205" height="35" viewBox="-1 -1 205 38">
    <path filter="url(#f)" d="M0,0 h200 q0,10 -15,15 q10,0 15,15 h-200 q0,-10 15,-15 q-10,0 -15,-15" stroke="black" stroke-linejoin="round" stroke-width="2" transform="translate(0,3)" fill="black" />
    <path d="M0,0 h200 q0,10 -15,15 q10,0 15,15 h-200 q0,-10 15,-15 q-10,0 -15,-15" stroke="black" stroke-linejoin="round" stroke-width="2" fill="white" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>

<div id="container">
  <svg width="205" height="35" viewBox="-1 -1 205 38">
    <path filter="url(#f)" d="M0,0 h200 q-10,0 -15,12.5 l15,2.5 l-15,2.5 q0,10 15,13 h-200 q10,0 15,-12.5 l-15,-2.5 l15,-2.5 q0,-10 -15,-12.5" stroke="black" stroke-linejoin="round" stroke-width="2" transform="translate(0,3)" fill="black" />
    <path d="M0,0 h200 q-10,0 -15,12.5 l15,2.5 l-15,2.5 q0,10 15,13 h-200 q10,0 15,-12.5 l-15,-2.5 l15,-2.5 q0,-10 -15,-12.5" stroke="black" stroke-linejoin="round" stroke-width="2" fill="white" />
  </svg>
  <div id="content">lorem ipsum</div>
</div>

Alternatively you could always use :after and :before :pseudo-elements.

The width and height of the :after and :before :pseudo-elements were calculated using some basic trigonometry.

The opposite side is the width and height of the :after and :before :pseudo-elements. The one on the left is given top and right borders and the one on the right is given top and left borders. Then, the one on the left has been rotated 45deg and the one on the right has been rotated -45deg.

div {
  position: relative;
  text-transform: uppercase;
  width: 200px;
  height: 30px;
  text-align: center;
  line-height: 27px;
  border-top: 3px solid black;
  border-bottom: 3px solid black;
  box-sizing: border-box;
}
div:after,
div:before {
  position: absolute;
  content: '';
  width: 21.21px;
  height: 21.21px;
  border-top: 3px solid black;
  border-right: 3px solid black;
  transform: rotate(45deg);
  box-sizing: border-box;
  top: 1px;
  left: -9px;
}
div:after {
  border-right: 0;
  border-left: 3px solid black;
  left: 100%;
  margin-left: -10px;
  transform: rotate(-45deg);
}
<div>lorem ipsum</div>

Yes, you can do this purely in CSS by manipulating the :before and :after psuedo elements.

The key advantages are that you can keep your HTML 'as is', and it maintains a strict seperation of concerns between content (html) and styling (CSS).

body {
  text-align: center;
}
div {
  border: 2px solid;
  display: inline-block;
  position: relative;
  padding: 0 40px;
  margin: 20px;
  height: 30px;
  line-height: 30px;
  overflow: hidden;
  border-right: 0;
  border-left: 0;
}
div:after,
div:before {
  border: 2px solid;
  height: 30px;
  width: 30px;
  content: '';
  display: block;
  position: absolute;
  top: -2px;
  transform: rotate(45deg);
}
div:after {
  right: -23px;
}
div:before {
  left: -23px;
}
<div>Lorem Ipsum</div>
Harry

This is a different approach using pure CSS alone to achieve this effect (using the method explained in this answer but reverse rotation of elements).

Basically it involves two pseudo elements that are rotated with a bit of perspective and positioned one below the other to achieve the shape.

This approach works like below:

  1. Two pseudo-elements :before and :after which are roughly about half the size (including borders) of the main .button element. The height of each pseudo-element is 35.5px + 3px border on one side (top/bottom) and 1.5px on the other side (because the two overlap at half distance).
  2. The top half of the shape is achieved using the :before element whereas the bottom half is achieved using the :after element.
  3. Using a rotateX with perspective to achieve the tilted effect and positioning to place the two elements such that they form the expected shape.

Note: There is a bit of extra styling for a sample hover effect which causes the shape to turn into an elongated hexagon. This is not part of the question but is added just for sample (and a bit of fun :)). Also, older versions of Chrome and Safari seems to be giving incorrect output for the hover behavior whereas the latest versions of all browsers are doing fine.

/* General Button Style */

.button {
  position: relative;
  width: 300px;
  height: 80px;
  line-height: 80px;
  text-align: center;
  text-transform: uppercase;
  color: #000;
  margin: 40px auto;
  box-sizing: border-box;
}
.button:before,
.button:after {
  width: 300px;
  left: 0px;
  height: 35.5px;
  z-index: -1;
  border: 4px solid #000;
  border-top-width: 3px;
  border-bottom-width: 3px;
}
.button:before {
  border-bottom: none;
}
.button:after {
  border-top: none;
}
.button:before {
  position: absolute;
  content: '';
  -webkit-transform: perspective(15px) rotateX(-3deg);
  -moz-transform: perspective(15px) rotateX(-3deg);
  transform: perspective(15px) rotateX(-3deg);
}
.button:after {
  position: absolute;
  top: 35.5px;
  content: '';
  -webkit-transform: perspective(15px) rotateX(3deg);
  -moz-transform: perspective(15px) rotateX(3deg);
  transform: perspective(15px) rotateX(3deg);
}
/* Hover Styles */

.button:hover:before,
.button:hover:after {
  background: #000;
}
.button:hover:before {
  top: -3px;
  -webkit-transform: perspective(15px) rotateX(3deg);
  -moz-transform: perspective(15px) rotateX(3deg);
  transform: perspective(15px) rotateX(3deg);
}
.button:hover:after {
  top: 38px;
  -webkit-transform: perspective(15px) rotateX(-3deg);
  -moz-transform: perspective(15px) rotateX(-3deg);
  transform: perspective(15px) rotateX(-3deg);
}
.button:hover {
  color: #fff;
}
<div class="button">Lorem Ipsum</div>

As-is, this would degrade quite well in IE 8 and IE 9 into a square button with borders. However, due to the nullification of one border (border-bottom for :before and border-top for :after) it would leave a white area (resembling a strike-through line) in the middle. This can be overcome by adding a couple of IE < 10 specific styles using conditional comments like in this demo.

<!--[if IE]>
    <style>
        .button:after{
            top: 38px;
        }
        .button:hover:before, .button:hover:after {
            border-bottom: 4px solid black;
        }
    </style>
<![endif]-->

Output Screenshots from IE 9 and IE 8: (both normal and during hover)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!