复杂的平行四边形按钮形状

Complex parallelogram button shapes

我想知道是否可以在 CSS3 中制作像这样的复杂按钮?我不知道从哪里开始。我可以很容易地做出类似梯形的形状,但添加边框似乎是不可能的。我错过了什么吗?

(PS: 图片来自 Deus Ex Human Revolution)

正如您自己指出的那样,生成有问题的给定形状非常简单,下面是有关如何实现它的示例片段。基本思想是使用伪元素,向其添加 background 然后倾斜它。父级上的 overflow: hidden 会切掉不需要的形状部分,从而最终生成形状。

ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  list-style-position: inside;
}
li {
  position: relative;
  height: 40px;
  width: 300px;
  margin: 10px;
  padding-right: 30px;
  line-height: 40px;
  text-align: right;
  text-transform: uppercase;
  border-radius: 8px;
  color: crimson;
  overflow: hidden;
}
li:after {
  position: absolute;
  content: '';
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  background: rgba(0, 0, 0, 0.5);
  transform: skew(45deg);
  z-index: -1;
}

/* just for demo */

body {
  background: url(http://lorempixel.com/800/500/abstract/2);
}
*, *:after, *:before {
  box-sizing: border-box;
}
<ul>
  <li>Menu Text 1</li>
  <li>Menu Text 2</li>
  <li>Menu Text 3</li>
</ul>

但是,向使用此方法创建的形状添加边框非常困难,而且形状与其边框之间需要有透明区域这一事实几乎不可能实现。


我们可以像下面的代码片段一样使用 clip-path,它可以使用伪元素添加边框,但这种方法有以下缺点:

  • Firefox 和 IE(所有版本)不支持 clip-path 的纯 CSS 版本。
  • 即使是基于 clip-path 的内联 SVG 也仅在 Chrome 和 Firefox 中受支持。
  • 虽然可以修改 clip-path 以在背景和边框之间生成透明区域,但这会使它变得极其复杂并且几乎无法维护。
  • 分配透明或半透明的背景颜色会导致问题,因为后面有另一个元素,所以颜色会像下面的代码片段一样混合。

ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  list-style-position: inside;
}
li {
  position: relative;
  height: 40px;
  width: 300px;
  margin: 10px;
  padding-right: 30px;
  line-height: 40px;
  text-align: right;
  text-transform: uppercase;
  border-radius: 8px;
  background: crimson;
  color: crimson;
  -webkit-clip-path: polygon(0% 0%, 0% 50%, 10% 100%, 100% 100%, 100% 50%, 90% 0%);
  clip-path: polygon(0% 0%, 0% 50%, 10% 100%, 100% 100%, 100% 50%, 90% 0%);
}
li:after {
  position: absolute;
  content: '';
  height: calc(100% - 4px);
  width: calc(100% - 4px);
  left: 2px;
  top: 2px;
  border-radius: 7px;
  background: rgba(0, 0, 0, 0.5);
  -webkit-clip-path: polygon(0% 0%, 0% calc(50% - 1px), 10% 100%, 100% 100%, 100% calc(50% + 1px), 90% 0%);
  clip-path: polygon(0% 0%, 0% calc(50% - 1px), 10% 100%, 100% 100%, 100% calc(50% + 1px), 90% 0%);
  z-index: -1;
}

/* just for demo */

body {
  background: url(http://lorempixel.com/800/500/abstract/2);
}
*, *:after, *:before {
  box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<ul>
  <li>Menu Text 1</li>
  <li>Menu Text 2</li>
  <li>Menu Text 3</li>
</ul>


综上所述,我建议您使用 SVG 来生成如此复杂的形状。使用 SVG,我们可以使用 path 元素来创建形状的边框和填充。

ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
  list-style-position: inside;
}
li {
  position: relative;
  height: 40px;
  width: 300px;
  margin: 10px;
  padding-right: 30px;
  line-height: 40px;
  text-align: right;
  text-transform: uppercase;
  border-radius: 8px;
  color: crimson;
}
li.active {
  width: 350px;
  height: 50px;
  line-height: 50px;
}
svg #fill {
  fill: rgba(0, 0, 0, 0.5);
}
svg #border {
  stroke: crimson;
  stroke-width: 2;
  fill: transparent;
}
li svg {
  position: absolute;
  top: 0px;
  left: 0px;
  height: 100%;
  width: 100%;
  z-index: -1;
}

/* just for demo */

body {
  background: url(http://lorempixel.com/800/500/abstract/2);
}
*, *:after, *:before {
  box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<svg viewBox='0 0 300 40' height='0' width='0'>
  <defs>
    <g id='shape'>
      <path d='M8,0 A8,8 0 0,0 0,8 L0,20 30,40 292,40 A8,8 0 0,0 300,32 L300,20 270,0z' id='fill' />
    </g>
    <g id='shape-bordered'>
      <path d='M9,1 A8,8 0 0,0 1,9 L1,20 30,39 292,39 A8,8 0 0,0 299,32 L299,20 270,1z' id='border' />
      <path d='M10,4 A7,7 0 0,0 4,6 L4,19 31,36 290,36 A5,5 0 0,0 296,34 L296,21 269,4z' id='fill' />
    </g>
  </defs>
</svg>
<ul>
  <li class='active'>
    <svg viewBox='0 0 300 40' preserveAspectRatio='none'>
      <use xlink:href='#shape-bordered' />
    </svg>Menu Text 1</li>
  <li>
    <svg viewBox='0 0 300 40' preserveAspectRatio='none' vector-effect='non-scaling-stroke'>
      <use xlink:href='#shape' />
    </svg>Menu Text 2</li>
  <li>
    <svg viewBox='0 0 300 40' preserveAspectRatio='none'>
      <use xlink:href='#shape' />
    </svg>Menu Text 3</li>
</ul>

(SVG 可能会进一步调整。上面的片段只是一个示例,用于说明可以实现的目标。)