【问题标题】:Complex parallelogram button shapes复杂的平行四边形按钮形状
【发布时间】:2016-04-30 14:37:37
【问题描述】:

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

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

【问题讨论】:

    标签: css svg css-shapes


    【解决方案1】:

    正如您自己指出的那样,生成有问题的形状非常容易,下面是关于如何实现它的示例 sn-p。基本思想是使用一个伪元素,将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>

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


    我们可以在下面的 sn-p 中使用clip-path,这样就可以使用伪元素添加边框,但这种方法有以下缺点:

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

    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 可能会进一步调整。上面的 sn-p 只是一个示例,用于说明可以实现的目标。)

    【讨论】:

    • 感谢您的详细解答!我要玩弄你的代码示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    • 2014-11-17
    • 1970-01-01
    • 2010-11-16
    • 1970-01-01
    • 2013-08-10
    相关资源
    最近更新 更多