【问题标题】:How to make this arrow in CSS only?如何仅在 CSS 中制作此箭头?
【发布时间】:2015-02-22 12:58:30
【问题描述】:

我正在构建一个类似向导的订购流程,其中包含以下菜单:

活动页面为绿色(在本例中为模型)。

如何仅使用 CSS 制作这个箭头?:

目前我正在通过使用多个 div 和图像来实现我的目标:

<div class="menuItem">
    <div></div> <!-- The left image -->
    <div>Varianten</div>
    <div></div> <!-- The right image -->
</div>

左图:

右图:

我找到了一个 SO 答案,其中部分内容是: Arrow Box with CSS,但是我遇到了左侧缩进的问题。

如果您对如何执行此操作有更好的想法,请告诉我!

【问题讨论】:

标签: html css css-shapes


【解决方案1】:

这是一个使用 CSS3 特性的替代方法。使用这种方法的一个优点(也是添加单独答案的主要原因之一)是箭头之间的空间可以是透明的。

基本上实现如下:

  1. 每个步骤/项目都有一个div,它包含需要显示的文本。假设这个divheightx(在这个例子中是50px)。
  2. 创建了两个伪元素(:before:after),它们的 width 与父级相同,divheight 是父级的一半(x/2)。 :before 元素没有border-bottom,而:after 元素没有border-top 以避免在形状中间出现一条线(平行于x 轴)。
  3. 然后将这两个伪元素skew 转换为相反的方向,并以它们直接位于彼此下方的方式定位,从而最终形成所需的形状。
  4. 伪元素被分配一个负数z-index,以将它们推到父div(以及它的文本)后面。
  5. first-childlast-child 元素稍作修改(left 位置,border 的伪元素,backgroundborder 的父级div)以实现直边。
  6. 我们可以为活动元素添加一个active 类,也可以将hover 效果添加到如下示例中的形状。

.steps {
  height: 50px;
  width: 150px;
  text-align: center;
  line-height: 50px;
  position: relative;
  margin: 10px 0px 10px 20px;
  display: inline-block;
}
.steps:before,
.steps:after {
  content: '';
  position: absolute;
  left: 0px;
  width: 150px;
  height: 25px;
  z-index: -1;
}
.steps:before {
  top: -2px;
  border-top: 2px solid blue;
  border-right: 2px solid blue;
  border-left: 2px solid blue;
  background: lightblue;
  -moz-transform: skew(30deg);
  -webkit-transform: skew(30deg);
  transform: skew(30deg);
}
.steps:after {
  bottom: -2px;
  border-left: 2px solid blue;
  border-right: 2px solid blue;
  border-bottom: 2px solid blue;
  background: lightblue;
  -moz-transform: skew(-30deg);
  -webkit-transform: skew(-30deg);
  transform: skew(-30deg);
}
.steps:last-child {
  background: lightblue;
  border-right: 2px solid blue;
  border-top: 2px solid blue;
  border-bottom: 2px solid blue;
  margin-left: 38px;
}
.steps:first-child {
  background: lightblue;
  border-left: 2px solid blue;
  border-top: 2px solid blue;
  border-bottom: 2px solid blue;
  margin-right: 18px;
}
.steps:first-child:before,
.steps:first-child:after {
  left: 18px;
}
.steps:last-child:before,
.steps:last-child:after {
  left: -18px;
}
/* Hover Styles */

.steps:first-child:hover,
.steps:last-child:hover,
.steps:hover:before,
.steps:hover:after {
  background: lightgreen;
}
.steps:first-child:hover {
  border-left: 2px solid green;
}
.steps:last-child:hover {
  border-right: 2px solid green;
}
.steps:hover:before {
  border-top: 2px solid green;
  border-right: 2px solid green;
  border-left: 2px solid green;
}
.steps:hover:after {
  border-left: 2px solid green;
  border-right: 2px solid green;
  border-bottom: 2px solid green;
}
.steps:first-child:hover,
.steps:last-child:hover {
  border-top: 2px solid green;
  border-bottom: 2px solid green;
}

/* Active Styles */

.active:first-child,
.active:last-child,
.active:before, 
.active:after{
  background: bisque;
}
.active:first-child{
  border-left: 2px solid red;
}
.active:last-child{
  border-right: 2px solid red;
}
.active:before{
  border-top: 2px solid red;
  border-right: 2px solid red;
  border-left: 2px solid red;
}
.active:after{
  border-left: 2px solid red;
  border-right: 2px solid red;
  border-bottom: 2px solid red;
}
.active:first-child, .active:last-child{
  border-top: 2px solid red;
  border-bottom: 2px solid red;
}

/* Just for creating a non solid color background */
body{
  height: 200px;
  background: -webkit-radial-gradient(center, ellipse, #400, #100);
  background: -moz-radial-gradient(center, ellipse, #400, #100);
  background: radial-gradient(center, ellipse, #400, #100);
}
<div class='steps-container'>
  <div class='steps'>1. Step 1</div>
  <div class='steps active'>2. Step 2</div>
  <div class='steps'>3. Step 3</div>
</div>

注意:上面sn-p中的hover在悬停在第一个孩子的右端或最后一个孩子的左端时不起作用,因为z-索引问题。如果您需要无缝的hover 功能,那么在.steps 元素内使用span,如下面的sn-p 所示。 (感谢The Pragmatick 指出这一点)。

.steps {
  height: 50px;
  width: 150px;
  text-align: center;
  line-height: 50px;
  position: relative;
  margin: 10px 0px 10px 20px;
  display: inline-block;
}
.steps span {
  position: relative;
  z-index: 2;
}
.steps:before,
.steps:after {
  content: '';
  position: absolute;
  left: 0px;
  width: 150px;
  height: 25px;
}
.steps:before {
  top: -2px;
  border-top: 2px solid blue;
  border-right: 2px solid blue;
  border-left: 2px solid blue;
  background: lightblue;
  -moz-transform: skew(30deg);
  -webkit-transform: skew(30deg);
  transform: skew(30deg);
}
.steps:after {
  bottom: -2px;
  border-left: 2px solid blue;
  border-right: 2px solid blue;
  border-bottom: 2px solid blue;
  background: lightblue;
  -moz-transform: skew(-30deg);
  -webkit-transform: skew(-30deg);
  transform: skew(-30deg);
}
.steps:first-child:before,
.steps:first-child:after {
  border-left: none;
}
.steps:last-child:before,
.steps:last-child:after {
  border-right: none;
}
.steps:last-child {
  background: lightblue;
  border-right: 2px solid blue;
  border-top: 2px solid blue;
  border-bottom: 2px solid blue;
  margin-left: 38px;
}
.steps:first-child {
  background: lightblue;
  border-left: 2px solid blue;
  border-top: 2px solid blue;
  border-bottom: 2px solid blue;
  margin-right: 18px;
}
.steps:first-child:before,
.steps:first-child:after {
  left: 18px;
}
.steps:last-child:before,
.steps:last-child:after {
  left: -18px;
}
/* Hover Styles */

.steps:first-child:hover,
.steps:last-child:hover,
.steps:hover:before,
.steps:hover:after {
  background: lightgreen;
}
.steps:first-child:hover {
  border-left: 2px solid green;
}
.steps:last-child:hover {
  border-right: 2px solid green;
}
.steps:hover:before {
  border-top: 2px solid green;
  border-right: 2px solid green;
  border-left: 2px solid green;
}
.steps:hover:after {
  border-left: 2px solid green;
  border-right: 2px solid green;
  border-bottom: 2px solid green;
}
.steps:first-child:hover,
.steps:last-child:hover {
  border-top: 2px solid green;
  border-bottom: 2px solid green;
}
.steps:first-child:hover:before,
.steps:first-child:hover:after {
  border-left: none;
}
.steps:last-child:hover:before,
.steps:last-child:hover:after {
  border-right: none;
}
/* Active Styles */

.active:first-child,
.active:last-child,
.active:before,
.active:after {
  background: bisque;
}
.active:first-child {
  border-left: 2px solid red;
}
.active:last-child {
  border-right: 2px solid red;
}
.active:before {
  border-top: 2px solid red;
  border-right: 2px solid red;
  border-left: 2px solid red;
}
.active:after {
  border-left: 2px solid red;
  border-right: 2px solid red;
  border-bottom: 2px solid red;
}
.active:first-child,
.active:last-child {
  border-top: 2px solid red;
  border-bottom: 2px solid red;
}
/* Just for creating a non solid color background */

body {
  height: 200px;
  background: -webkit-radial-gradient(center, ellipse, #400, #100);
  background: -moz-radial-gradient(center, ellipse, #400, #100);
  background: radial-gradient(center, ellipse, #400, #100);
}
<div class='steps-container'>
  <div class='steps'>
    <span>1. Step 1</span>
  </div>
  <div class='steps active'>
    <span>2. Step 2</span>
  </div>
  <div class='steps'>
    <span>3. Step 3</span>
  </div>
</div>

屏幕截图:(将鼠标悬停在第二个项目上)


具有透明背景的响应式实施:

有关带有半透明框的进度跟踪栏的响应版本,请访问this pen。每个步骤/项目的宽度以这样的方式分配,即它们的总和始终为可用宽度的 100%,并且每个项目的大小始终与其他项目相同。

JavaScript 用于以下功能:(所有这些功能都是增值的,可以根据需要移除。注意,当移除 JS 时,应将相应的 CSS 属性放入 CSS 文件中。)

  • 根据编号自动调整每个项目的宽度。栏中的项目数
  • 调整窗口大小时自动调整每个项目的宽度
  • 使用滑块增加或减少栏的高度时自动调整项目的外观。

【讨论】:

    【解决方案2】:

    如果您想要标签之间的透明空间,Harry 目前的答案是他们要走的路。

    但如果您想消除悬停问题,您可以尝试以下方法。它使用box-shadow 作为伪元素而不是纯色背景。
    使用 border: _px inset #___ ;

    可以实现相同的效果

    .li {
        height: 50px;
        width: 120px;
        background: #F5FBF1;
        display: inline-block;
        position: relative;
        margin-left: 30px;
        line-height: 50px;
        color: black;
        font-family: sans-serif;
        text-align: center;
    }
    .li:before, .li:after {
        content: '';
        left: -15px;
        position: absolute;
        height: 23px;
        width: 132px;
        border-left: 2px solid black;
        border-right: 2px solid black;
    }
    .li:before {
        border-top: 2px solid black;
        -webkit-transform-origin: 0% 0%;
        -moz-transform-origin: 0% 0%;
        -ms-transform-origin: 0% 0%;
        transform-origin: 0% 0%;
        -webkit-transform: skewX(30deg);
        -moz-transform: skewX(30deg);
        -ms-transform: skewX(30deg);
        transform: skewX(30deg);
        top: 0;
        box-shadow: inset 0 8px 0 8px #F5FBF1, inset -6px 8px 0 8px #F5FBF1;
    }
    .li:after {
        border-bottom: 2px solid black;
        -webkit-transform-origin: 0% 100%;
        -moz-transform-origin: 0% 100%;
        -ms-transform-origin: 0% 100%;
        transform-origin: 0% 100%;
        -webkit-transform: skewX(-30deg);
        -moz-transform: skewX(-30deg);
        -ms-transform: skewX(-30deg);
        transform: skewX(-30deg);
        bottom: 0;
        box-shadow: inset 0 -8px 0 8px #F5FBF1, inset -6px -8px 0 8px #F5FBF1;
    }
    .li:hover {
        background: #C0EBA4;
    }
    .li:hover:before {
        box-shadow: inset 0 8px 0 8px #C0EBA4, inset -6px 8px 0 8px #C0EBA4;
    }
    .li:hover:after {
        box-shadow: inset 0 -8px 0 8px #C0EBA4, inset -6px -8px 0 8px #C0EBA4;
    }
    <div class="li">ONE</div>
    <div class="li">TWO</div>
    <div class="li">THREE</div>
    <div class="li">FOUR</div>
    <div class="li">FIVE</div>

    FIDDLE


    最终版

    您可以将其无缝悬停。它包括第一个和最后一个标签的平边。

    .li {
        height: 50px;
        width: 100px;
        padding-left: 20px;
        background: #F5FBF1;
        display: inline-block;
        position: relative;
        margin-left: 20px;
        line-height: 50px;
        font-family: sans-serif;
        font-size: 15px;
    }
    .li:before, .li:after {
        content: '';
        left: -15px;
        position: absolute;
        height: 23px;
        width: 132px;
        border-left: 2px solid black;
        border-right: 2px solid black;
    }
    .li:before {
        border-top: 2px solid black;
        -webkit-transform-origin: 0% 0%;
        -moz-transform-origin: 0% 0%;
        -ms-transform-origin: 0% 0%;
        transform-origin: 0% 0%;
        -webkit-transform: skewX(30deg);
        -moz-transform: skewX(30deg);
        -ms-transform: skewX(30deg);
        transform: skewX(30deg);
        top: 0;
        box-shadow: inset 0 8px 0 8px #F5FBF1, inset -6px 8px 0 8px #F5FBF1;
    }
    .li:after {
        border-bottom: 2px solid black;
        -webkit-transform-origin: 0% 100%;
        -moz-transform-origin: 0% 100%;
        -ms-transform-origin: 0% 100%;
        transform-origin: 0% 100%;
        -webkit-transform: skewX(-30deg);
        -moz-transform: skewX(-30deg);
        -ms-transform: skewX(-30deg);
        transform: skewX(-30deg);
        bottom: 0;
        box-shadow: inset 0 -8px 0 8px #F5FBF1, inset -6px -8px 0 8px #F5FBF1;
    }
    .li:hover {
        background: #C0EBA4;
    }
    .li:hover:before { box-shadow: inset 0 8px 0 8px #C0EBA4, inset -6px 8px 0 8px #C0EBA4;}
    .li:hover:after { box-shadow: inset 0 -8px 0 8px #C0EBA4, inset -6px -8px 0 8px #C0EBA4;}
    
    /*First and Last styles*/
    .li:first-of-type {
        left: -15px;
        box-shadow: 15px 0 0 0 #F5FBF1;
        border-left: 2px solid black;
    }
    .li:first-of-type:before, .li:first-of-type:after {
        left: -1px;
        width: 135px;
        border-left: 0;
    }
    .li:first-of-type:hover {box-shadow: 15px 0 0 0 #C0EBA4;}
    .li:last-of-type {
        left: 0px;
        width: 115px;
        box-shadow: inset -2px 0 0 0 black, inset 0 -2px 0 0 black, inset 0 2px 0 0 black;
        border: 0;
    }
    .li:last-of-type:before, .li:last-of-type:after {
        left: -15px;
        border-right: 0;
    }
    .li:last-of-type:hover {background: #C0EBA4;}
    <div class="li">Tab one</div>
    <div class="li">Tab two</div>
    <div class="li">Tab three</div>
    <div class="li">Tab four</div>
    <div class="li">Tab five</div>

    FIDDLE (final)

    输出:

    【讨论】:

      【解决方案3】:

      Here's some great arrows for you

      html{
        background-color:red;
        }
      div#page {
          padding-bottom: 40px;
          padding-top: 40px;
          text-align: center;
          z-index: 1;
          position: relative;
      }
      div.diamond, div.ribbon, div.right-arrow, div.left-arrow {
          display: inline-block;
          color: #FFFFFF;
          font-size: 22px;
          line-height: 38px;
          margin: 15px 0;
          position: relative;
          width: 200px;
      }
      div.diamond:before, div.diamond:after, div.ribbon:before, div.ribbon:after, div.right-arrow:before, div.right-arrow:after, div.left-arrow:before, div.left-arrow:after {
          content:"";
          border-style: solid;
          border-width: 0;
          height: 0;
          position: absolute;
          width: 0;
      }
      div.diamond {
          background-color: #CCCCCC;
      }
      div.diamond:after, div.diamond:before {
          border-color: transparent #CCCCCC;
      }
      div.diamond:before {
          left: -19px;
          border-width: 19px 19px 19px 0;
      }
      div.diamond:after {
          right: -19px;
          border-width: 19px 0 19px 19px;
      }
      div.ribbon {
          background-color: #CCCCCC;
      }
      div.ribbon:before, div.ribbon:after {
          top: 6px;
          z-index: -15;
      }
      div.ribbon:before {
          border-color: #B2B2B2 #B2B2B2 #B2B2B2 transparent;
          border-width: 19px;
          left: -25px;
      }
      div.ribbon:after {
          border-color: #B2B2B2 transparent #B2B2B2 #B2B2B2;
          border-width: 19px;
          right: -25px;
      }
      div.right-arrow {
          background-color: #CCCCCC;
      }
      div.right-arrow:after, div.right-arrow:before {
          border-width: 19px 0 19px 19px;
      }
      div.right-arrow:before {
          border-color: #CCCCCC transparent;
          left: -19px;
      }
      div.right-arrow:after {
          border-color: transparent #CCCCCC;
          right: -19px;
      }
      div.left-arrow {
          background-color: #CCCCCC;
      }
      div.left-arrow:after, div.left-arrow:before {
          border-width: 19px 19px 19px 0;
      }
      div.left-arrow:before {
          border-color: transparent #CCCCCC;
          left: -19px;
      }
      div.left-arrow:after {
          border-color: #CCCCCC transparent;
          right: -19px;
      }
      <div id="page">
          <div class="diamond">Diamond</div>
          <br>
          <div class="ribbon">Ribbon</div>
          <br>
          <div class="right-arrow">Right arrow</div>
          <br>
          <div class="left-arrow">Left arrow</div>
      </div>

      SOURCE

      注意

      这个also allows gradient backgrounds/etc


      对于其他形状,我前几天也看到了this codepen

      【讨论】:

      • 感谢您的回答!但我同意 Gaby 的回答,因为它更适用于我的问题。
      • 那是 np。我只是想我会为任何未来的读者分享这些信息,仅此而已。
      【解决方案4】:

      如果箭头之间的空间不需要透明(它是纯色),您可以使用:before:after 创建边缘(没有新元素在 DOM 中)

      基本上,它会创建带有我们想要的边框的旋转正方形并相应地放置它们

      #flowBoxes {
          margin:auto;
          padding:20px;
          min-width:700px;
      
      }
      #flowBoxes div {
          display:inline-block;
          position:relative;
          height:25px;
          line-height:25px;
          padding:0 20px;
          border:1px solid #ccc;
          margin-right:2px;
          background-color:white;
      }
      
      #flowBoxes div.right:after{
          content:'';
          border-top:1px solid #ccc;
          border-right:1px solid #ccc;
          width:18px;
          height:18px;
          position:absolute;
          right:0;
          top:-1px;
          background-color:white;
          z-index:150;
          
          -webkit-transform: translate(10px,4px) rotate(45deg);
             -moz-transform: translate(10px,4px) rotate(45deg);
              -ms-transform: translate(10px,4px) rotate(45deg);
               -o-transform: translate(10px,4px) rotate(20deg); 
                  transform: translate(10px,4px) rotate(45deg);
      }
      
      #flowBoxes div.left:before{
          content:'';
          border-top:1px solid #ccc;
          border-right:1px solid #ccc;
          width:18px;
          height:18px;
          position:absolute;
          left:0;
          top:-1px;
          background-color:white;
          z-index:50;
          
          -webkit-transform: translate(-10px,4px) rotate(45deg);
             -moz-transform: translate(-10px,4px) rotate(45deg);
              -ms-transform: translate(-10px,4px) rotate(45deg);
               -o-transform: translate(-10px,4px) rotate(20deg);
                  transform: translate(-10px,4px) rotate(45deg);
      }
      #flowBoxes .active{
          background-color:green;
          color:white;
      }
      #flowBoxes div.active:after{
          background-color:green;
      }
      <div id="flowBoxes">
              <div class="right">Diersoort / I&amp;R</div>
              <div class="left right active">Model</div>
              <div class="left right">Varianten</div>
              <div class="left right">Bedrukkingen</div>
              <div class="left">Bevestiging</div>
      </div>

      【讨论】:

      • 完美答案。在我的情况下,箭头之间的空间不必是透明的,但我想它可能对其他人有用。是否可以使空间透明?
      • 很挑剔但为什么不使用:nth-child 伪类而不是CSS 类来定位第一个和最后一个元素? + 转换属性的 -o--moz- 前缀不是 realy necessary anymore
      • @web-tiki 如果您将鼠标悬停在浏览器版本上,您会看到许多版本需要前缀。至于nth-child,您是对的,但我希望您设置的内容更加灵活(以及它们是否都在同一个容器下..
      • 以前的版本确实需要前缀! FF 3.5 到 15 需要 -moz- 而 Opera 11.5 需要 -o-
      • 完美的一个,这真的适用于左侧的扁平狭窄我添加了`#flowBoxes div.left{ margin-left:-5px;左边框:透明 0px 无; } ` 并删除了 ` #flowBoxes div.right:after ` 块
      猜你喜欢
      • 2011-10-21
      • 2013-08-29
      • 2015-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-14
      相关资源
      最近更新 更多