【问题标题】:How to make 3-corner-rounded triangle in CSS如何在 CSS 中制作三角圆角三角形
【发布时间】:2013-01-04 23:34:21
【问题描述】:

我想在不使用 Javascript 的情况下实现这样的自定义颜色形状:

目前,我正在将“框架”的图像覆盖在橙色矩形 div 上,但这很 hacky。 我想我可以使用动态生成的画布元素,但这不仅需要 JS,还需要 HTML5 画布支持。有什么想法吗?

【问题讨论】:

  • +1 有趣的挑战!是的,你可以只使用 CSS 来做到这一点。我会做一个演示:)

标签: css css-shapes


【解决方案1】:

使用某种图像。这就是图像的用途。如果您需要缩放,SVG is a good choice,否则,只需使用 png 作为背景,或者如果它是内容的一部分,则使用 <img> 元素。

如果您绝对必须将它放在 CSS 文件中,您可以尝试data: urls(IE7 及以下版本不支持)。

【讨论】:

  • 虽然<span class="triangle"></span> 可能比<path d="M 24 4 L 43 37 L 5 37 z" /> 更容易记住:)
  • @jinglesthula, <img src="triangle.svg" alt="triangle"> 一点也不难记,而且具有实际可访问性的优势。
【解决方案2】:

dabblet demo

.triangle, .triangle:before, .triangle:after { width: 4em; height: 4em; }
.triangle {
	overflow: hidden;
	position: relative;
	margin: 7em auto 0;
	border-radius: 20%;
	transform: translateY(50%) rotate(30deg) skewY(30deg) scaleX(.866);
	cursor: pointer;
	pointer-events: none;
} 
.triangle:before, .triangle:after {
	position: absolute;
	background: orange;
	pointer-events: auto;
	content: '';
}
.triangle:before {
	border-radius: 20% 20% 20% 53%;
	transform: scaleX(1.155) skewY(-30deg) rotate(-30deg) translateY(-42.3%) 
			skewX(30deg) scaleY(.866) translateX(-24%);
}
.triangle:after {
	border-radius: 20% 20% 53% 20%;
	transform: scaleX(1.155) skewY(-30deg) rotate(-30deg) translateY(-42.3%) 
			skewX(-30deg) scaleY(.866) translateX(24%);
}

/** extra styles to show how it works **/

.triangle:hover { overflow: visible; }
.triangle:hover:before, .triangle:hover:after { background: none; }
.triangle:hover, .triangle:hover:before, .triangle:hover:after {
	border: dashed 1px;
}
<div class='triangle'></div>

这个想法非常简单:您首先对您的 .triangle 元素(具有 overflow: hidden; - 您可以删除它以查看会发生什么;)应用一系列变换以获得菱形。

然后,您将相同的变换应用到 :before:after 伪元素,再加上一些使它们也变成菱形。

最后,你有三个相交的菱形,橙色的形状是它们的交点。悬停三角形以查看相交的形状;)

它可以很好地扩展,您只需更改.triangle 元素的widthheight

对于 Firefox、Chrome 和 Safari,只有带有圆角的橙色三角形对悬停敏感(感谢 .triangle 元素上的 pointer-events: none; 和伪元素上的 pointer-events: auto;)。否则,这可以通过将.triangle 包装在具有相同widthheight(以及相同的border-radius)和overflow: hidden; 的元素中来实现。


注意事项

  • 您也可以使用 CSS 渐变来实现。但是,unlike 2D transforms,CSS 渐变 won't work in IE9
  • 我希望我不必取消从其父级继承倾斜的伪元素的倾斜,只是在旋转后再次倾斜它们,但它似乎不起作用。

【讨论】:

  • 很棒的答案——非常聪明!
  • 唯一的问题是,在非常大的尺寸和/或某些屏幕上,两个底角都有小瑕疵;毫无疑问,近似半径的结果
  • 我们想念你,@Ana!这是一个很好的解决方案
  • @Ana +1 太棒了!但是......你如何计算缩放倾斜和旋转的值?你有博客解释这个吗?
【解决方案3】:

Ana 的回答启发我尝试另一种方法,这种方法远非完美,但至少是对称的。这是实际尺寸和放大的预览。它只是一个用剪裁圆/边框半径包裹的边框黑客三角形:

以及代码(通过单个font-size属性调整整体大小):

.triangle {
    font-size: .8em;
    position: relative;
    width: 3.8em;
    height: 3.8em;
    text-align: center;
    margin: 10% auto 0;
    overflow: hidden;
    border-radius: 100%;
} 
.triangle:before {
    content: '';
    position: absolute;
    width:0;
    height: 0;
    border: solid 2em transparent;
    border-bottom-color: orange;
    border-bottom-width: 3.2em;
    border-top-width: 0;
    margin: -.3em -2em;
}

在这里玩一下:http://dabblet.com/gist/4590714

【讨论】:

  • 太棒了!因为 :after 可用于感叹号!制作警告图标!
【解决方案4】:

我的最佳尝试:http://dabblet.com/gist/4592062

任何尺寸的像素完美,使用比 Ana 原始解决方案更简单的数学运算,并且在我看来更直观 :)

.triangle {
	position: relative;
	background-color: orange;
	text-align: left;
}
.triangle:before,
.triangle:after {
	content: '';
	position: absolute;
	background-color: inherit;
}
.triangle,
.triangle:before,
.triangle:after {
	width:  10em;
	height: 10em;
	border-top-right-radius: 30%;
}

.triangle {
	transform: rotate(-60deg) skewX(-30deg) scale(1,.866);
}
.triangle:before {
	transform: rotate(-135deg) skewX(-45deg) scale(1.414,.707) translate(0,-50%);
}
.triangle:after {
	transform: rotate(135deg) skewY(-45deg) scale(.707,1.414) translate(50%);
}
<div class="triangle"></div>

【讨论】:

  • 等腰三角形如何,指向左侧?右侧最大。
  • 非常感谢 - 我现在在我的网站上使用它。给未来的读者提个醒:如果你使用 'vmin' 来调整大小,它最终可能会根据生成的 px 值看起来有点歪斜。不知道为什么,因为如果您手动输入相同的 px 值,三角形看起来不错。希望不久的将来的浏览器将使此评论过时!
  • 这么漂亮的解决方案!
  • 这是一个很棒的解决方案!不过,对于某些三角形大小的浏览器,我发现我需要更多位数的 sqrt(2) 和 sqrt(2)/2,才能获得完美的图像。
  • 很好的解决方案,注意rtl页面需要direction:ltr
【解决方案5】:

与 Murray Smiths 最受好评的版本一起玩。将其编写为 Stylus mixin 并修复了一些边距问题并添加了方向选项。 mixin 还将三角形缩放到像素完美的大小。没有很好地测试。小心使用

http://codepen.io/perlundgren/pen/VYGdwX

    triangle(direction = up, color = #333, size = 32px)
        position: relative
        background-color: color
        width:  2*(round(size/3.25))
        height: 2*(round(size/3.25))
        border-top-right-radius: 30%
        &:before,
        &:after
          content: ''
          position: absolute
          background-color: inherit
          width:  2*(round(size/3.25))
          height: 2*(round(size/3.25))
          border-top-right-radius: 30%

        if direction is up
          transform: rotate(-60deg) skewX(-30deg) scale(1,.866)
          margin: (@width/4) (@width/2.5) (@width/1.2) (@width/2.5)

        if direction is down
          transform: rotate(-120deg) skewX(-30deg) scale(1,.866)
          margin: 0 (@width/1.5) (@width/1.5) (@width/6)

        if direction is left
          transform: rotate(-30deg) skewX(-30deg) scale(1,.866)
          margin: (@width/5) 0 (@width) (@width/1.4)

        if direction is right
          transform: rotate(-90deg) skewX(-30deg) scale(1,.866)
          margin: (@width/5) (@width/1.4) (@width) 0

        &:before
          transform: rotate(-135deg) skewX(-45deg) scale(1.414,.707) translate(0,-50%)
        &:after
          transform: rotate(135deg) skewY(-45deg) scale(.707,1.414) translate(50%)

然后将 mixin 添加到您的类中

    .triangle
      &.up
        triangle()
      &.down
        triangle(down)
      &.left
        triangle(left)
      &.right
        triangle(right)

【讨论】:

    【解决方案6】:

    我看到有人要求一个等腰三角形,通过篡改上面接受的答案,我发现了如何操纵它来获得我想要的东西,因为我需要同样的东西。这应该可以帮助任何希望在圆角三角形中发生细微变化的人。

    您会注意到我将宽度、高度和边框右上角的半径分开,然后继续更改边框右上角的半径来塑造角。我唯一更改的另一件事是直接在元素上的 transform 属性。你可以按照你认为合适的方式塑造它,但这些似乎是唯一必要的改变。

    .diff-arrow {
      margin-left:30px;
      position: relative;
      background-color: #20C0F1;
      text-align: left;
      width: 10em;
      height: 10em;
      border-top-right-radius: 20%;
    }
    
    .diff-arrow:before,
    .diff-arrow:after {
      content: '';
      position: absolute;
      background-color: inherit;
      width: 10em;
      height: 10em;
      border-top-right-radius: 15%;
    }
    
    .diff-arrow {
      transform: rotate(-45deg) skewX(0deg) scale(0.5);
    }
    
    .diff-arrow:before {
      transform: rotate(-135deg) skewX(-45deg) scale(1.414, .707) translate(0, -50%);
    }
    
    .diff-arrow:after {
      transform: rotate(135deg) skewY(-45deg) scale(.707, 1.414) translate(50%);
    }
    <div class="diff-arrow"></div>

    【讨论】:

      【解决方案7】:

      -- 简化版--

      在我的例子中,我需要在带有三个圆角的三角形图标旁边加上文本,但是建议的 overflow: hidden; 根本不起作用,因为文本最终被隐藏了。

      最终结果: ...演示:https://jsfiddle.net/allenski/7p4tbznr/

      我可以通过使用clip-path 来实现类似的掩码。注意:在 IE 中不起作用;但是大多数已经停止支持 IE,尤其是在微软这样做之后。在他们的新 Edge 浏览器中运行良好。

      HTML:

      <span class="warning">
          Mandatory
      </span>
      

      CSS:

      .warning {
          position: relative;
          display: inline-block;
          font-weight: bold;
          color: #FF5500;
      }
      .warning:before {
          position: absolute;
          top: 50%;
          right: 12px;
          font-size: 18px;
          font-weight: bold;
          color: #FFFFFF;
          transform: translateY(-36%);
          text-shadow: 0 0 7px #111111;
          z-index: 1;
          content: '!';
      }
      .warning:after {
          display: inline-block;
          margin-left: 3px;
          font-size: 5px;
          border: solid 3em transparent;
          border-top-width: 0;
          border-bottom-width: 5em;
          border-bottom-color: #FF5500;
          clip-path: circle(54% at 50% 69%);
          vertical-align: bottom;
          content: '';
      }
      

      在 CSS 中,三角形是:after 伪元素。

      【讨论】:

      • 我的目标是在一个 HTML 标记中也包含这些元素,因此三角形只能是 :before:after
      【解决方案8】:

      首先我们使用clip-path创建三角形:

      .triangle {
        display: inline-block;
        width: 150px;
        color:orange;
      }
      
      .triangle::before {
        content: "";
        display: block;
        padding-top: 86%;
        background: currentColor;
        clip-path: polygon(50% 0, 100% 100%, 0 100%);
      }
      &lt;div class="triangle"&gt;&lt;/div&gt;

      然后我们应用受 this article 启发的 SVG 过滤器

      .triangle {
        display: inline-block;
        width: 150px;
        color:orange;
        filter: url('#goo');
      }
      
      .triangle::before {
        content: "";
        display: block;
        padding-top: 86%;
        background: currentColor;
        clip-path: polygon(50% 0, 100% 100%, 0 100%);
      }
      <div class="triangle"></div>
      <div class="triangle" style="color:red;width:200px;"></div>
      <div class="triangle" style="color:blue;width:250px;"></div>
      
      
      <svg style="visibility: hidden; position: absolute;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
        <defs>
              <filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />    
                  <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
                  <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
              </filter>
          </defs>
      </svg>

      要控制半径,我们只需调整过滤器的stdDeviation


      考虑到这一点,您可以使其适用于任何类型的三角形,甚至是随机形状:

      .triangle {
        display: inline-block;
        width: 150px;
        color:orange;
        filter: url('#goo');
      }
      
      .triangle::before {
        content: "";
        display: block;
        padding-top: 86%;
        background: currentColor;
        clip-path: polygon(50% 0, 100% 100%, 0 100%);
      }
      
      .triangle.type2::before {
        padding-top: 70%;
        clip-path: polygon(0 0, 100% 100%, 0 100%);
      }
      
      .triangle.type3::before {
        padding-top: 100%;
        clip-path: polygon(50% 0, 80% 100%, 0 70%);
      }
      
      .triangle.hex::before {
        padding-top: 100%;
        clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
      }
      <div class="triangle"></div>
      <div class="triangle type2" style="color:red;"></div>
      <div class="triangle type3" style="color:blue;"></div>
      <div class="triangle hex" style="color:purple;"></div>
      
      
      
      <svg style="visibility: hidden; position: absolute;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
        <defs>
              <filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />    
                  <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
                  <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
              </filter>
          </defs>
      </svg>

      值得注意的是,我们可以轻松地为形状添加复杂的背景:

      .triangle {
        display: inline-block;
        width: 150px;
        filter: url('#goo');
      }
      
      .triangle::before {
        content: "";
        display: block;
        padding-top: 86%;
        background: var(--b,orange);
        clip-path: polygon(50% 0, 100% 100%, 0 100%);
      }
      
      .triangle.type2::before {
        padding-top: 70%;
        clip-path: polygon(0 0, 100% 100%, 0 100%);
      }
      
      .triangle.type3::before {
        padding-top: 100%;
        clip-path: polygon(50% 0, 80% 100%, 0 70%);
      }
      
      .triangle.hex::before {
        padding-top: 100%;
        clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
      }
      <div class="triangle"></div>
      <div class="triangle type2" style="--b:linear-gradient(red,blue);"></div>
      <div class="triangle type3" style="--b:conic-gradient(green,pink,green);"></div>
      <div class="triangle hex" style="--b:url(https://picsum.photos/id/1067/200/200) center/cover;"></div>
      
      
      
      <svg style="visibility: hidden; position: absolute;" width="0" height="0" xmlns="http://www.w3.org/2000/svg" version="1.1">
        <defs>
              <filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />    
                  <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
                  <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
              </filter>
          </defs>
      </svg>

      【讨论】:

        【解决方案9】:

        从典型的边框三角形开始,然后在三角形中添加 svg 过滤器。

        .c-paper-plane {
            position: relative;
        }
        .scene {
            transform-style: preserve-3d;
            transform: rotate3d(0.2, -1, -0.8, -177deg);
        }
        svg.paper-plane {
            transform: rotateX(0) translateZ(-3px);
            transform-origin: center;
        }
        .paper-tail {
            transform: rotateX(0deg) translate(31px, 10px) translateZ(-5px);
            transform-origin: center;
            fill: grey;
        }
        .paper-tail-div {
            transform: rotateX(269deg) translate(237px, 55px) translateZ(139px);
            fill: grey;
            transform-origin: center;
            position: absolute;
            top: 0;
            width: 0;
            height: 0;
            border-top: 100px solid red;
            border-right: 150px solid transparent;
            filter: url('#goo');
        }
        <div class="c-paper-plane">
          <div class="scene">
            <svg id="paper-plane" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 139.549 79.269">
                        <defs>
                            <filter id="goo"><feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur" />    
                                <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
                                <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
                            </filter>
                        </defs>
                        <g class="plane-group">
                            <path class="paper-wing" d="M47.377,76.654V47.025c0-1.137,0.871-2.084,2.003-2.178l60.357-5.062c0.2-0.01,0.2-0.29,0-0.31l-60.356-5.052
                            c-1.133-0.095-2.004-1.042-2.004-2.179V2.615c0-1.878,1.922-3.142,3.646-2.399l87.37,37.662c1.54,0.664,1.54,2.848,0,3.512
                            l-87.37,37.662C49.299,79.796,47.377,78.531,47.377,76.654z"/>
                        </g>
                    </svg>
            <div class="paper-tail-div"></div>
          </div>
        </div>

        【讨论】:

          最近更新 更多