Oblique or twisted border shape

2019-01-18 17:31发布

I'm interested if it's possible to create wrapped (or maybe better said twisted) border using CSS. Effect I wanted to achieve is in the picture.

enter image description here

3条回答
来,给爷笑一个
2楼-- · 2019-01-18 17:46

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

enter image description here

#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.

enter image description here

#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.

enter image description here

#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.

enter image description here

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>

查看更多
唯我独甜
3楼-- · 2019-01-18 17:55

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>

查看更多
Bombasti
4楼-- · 2019-01-18 18:01

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).

enter image description here

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.

enter image description here

/* 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)

enter image description here

enter image description here

查看更多
登录 后发表回答