CSS三角形是如何工作的?

2023

CSS Tricks - Shapes of CSS网站上有许多不同的CSS形状,我特别困惑于一个三角形:

CSS Triangle

#triangle-up {
  width: 0;
  height: 0;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  border-bottom: 100px solid red;
}
<div id="triangle-up"></div>

它是如何运作以及为什么有效?


64
你可以:http://jsfiddle.net/wbZet/ - mskfisher
61
那个不在的正方形怎么办?http://jsfiddle.net/minitech/sZgaa/ - Ry-
1
@mskfisher 你等边三角形底部边框的大小不应该是 ceil(sqrt(3) * 60) 吗?再多几个像素! - Niloct
1
@Niloct:我快速地用大致的数字估算了一下。你说得对,更精确的等边测量应该是(边长:58,底边:100)或(边长:60,底边:104)。 - mskfisher
1
这是一个适用于各种方向和大小的优秀CSS三角形生成器:http://apps.eky.hk/css-triangle-generator/ - Allan Stepps
显示剩余4条评论
23个回答

2378

CSS三角形:五幕悲剧

正如alex所说的,相等宽度的边框以45度角相接:

边框以45度角相接,中间是内容

当您没有上边框时,它看起来像这样:

没有上边框

然后,您将其宽度设置为0...

没有宽度

...和高度0...

也没有高度

...最后,您将两个侧边框设置为透明:

透明的侧边框

这就形成了一个三角形。


11
@Jauzsika,您可以使用:before:after伪类将这些三角形添加到页面中,而无需添加其他元素。 - zzzzBov
120
动画效果演示:http://jsfiddle.net/pimvdb/mA4Cu/104/。这是为了那些像我一样需要更多视觉证明的人而准备的…… - pimvdb
通过不同的 left-borderright-border,可以制作出非等腰三角形。当许多三角形组合在一起时... http://jsfiddle.net/zRNgz/ - JiminP
4
2018年,有没有比使用这种hack方法更好的CSS制作三角形的方式? - Scribblemacher
2
@Scribblemacher 内联SVG可以做到。 - GKFX
显示剩余3条评论

560

边框使用一个倾斜的边缘相交(45度角等宽边框,但改变边框宽度可以扭曲角度)。

边框示例

div {
  width: 60px;
  border-width: 30px;
  border-color: red blue green yellow;
  border-style: solid;
}
<div></div>

看一下jsFiddle

通过隐藏某些边框,可以获得三角形效果(如上图所示,通过使不同部分有不同的颜色)。transparent经常用作边缘颜色来实现三角形形状。


540

从一个基本的正方形和边框开始。每个边框都会被赋予不同的颜色,这样我们就可以区分它们:

.triangle {
    border-color: yellow blue red green;
    border-style: solid;
    border-width: 200px 200px 200px 200px;
    height: 0px;
    width: 0px;
}
<div class="triangle"></div>

这将为您提供此内容:

带有四个边框的正方形

但是我们不需要顶部边框,所以将其宽度设置为0px。现在,我们的200px下边界将使我们的三角形高度为200像素。

.triangle {
    border-color: yellow blue red green;
    border-style: solid;
    border-width: 0px 200px 200px 200px;
    height: 0px;
    width: 0px;
}
<div class="triangle"></div>

最后我们会得到这个

四周有边框的正方形底部

接着,为了隐藏两个侧三角形,将边框颜色设置为透明。由于顶部边框被删除了,所以我们也可以将边框顶部颜色设置为透明。

.triangle {
    border-color: transparent transparent red transparent;
    border-style: solid;
    border-width: 0px 200px 200px 200px;
    height: 0px;
    width: 0px;
}
<div class="triangle"></div>

最终我们得到了这个

三角形底部边框


22
酷,但这不是同一种方法吗? :-) - Stanislav Shabalin
6
还有另一种绘图方法......结果证明这种方法是相同的 :) 不过讲解得很好。 - TheTechGuy
17
对于使用带有严重伪影的JPEG图片,评分为-1。但是对于创建一个很好的示例以展示何时不要使用JPEG图片,并且可以在将来进行引用,评分为+1。 ;) - Henrik Heimbuerger
4
为什么这里不使用GIF呢? - prusswan
4
抱歉 @hheimbuerger,我通过修复图片搞砸了你的示例。 以后你将不得不链接到此答案的第2个版本修订 - Rory O'Kane
显示剩余2条评论

306

另一种方法:使用CSS3三角形和transform rotate

使用这种技术制作三角形形状非常容易。如果您喜欢看一个解释这种技术的动画,请看这里:

gif动画:如何使用transform rotate制作三角形

否则,以下是制作等腰直角三角形的详细解释,分为4个步骤(这不是一部悲剧)。

  • 注1:对于非等腰三角形和花哨的东西,您可以查看第4步
  • 注2:在以下代码段中,供应商前缀未包含在内。它们包含在codepen demo
  • 注3:以下说明的HTML始终是:<div class="tr"></div>

步骤1:制作一个div

很容易,只需确保width = 1.41 x height。您可以使用任何技术(请见此处),包括使用百分比和padding-bottom来维护宽高比并制作响应式三角形。在下面的图像中,div具有金黄色边框。

在该div中,插入一个伪元素,并将其设为父元素的100%宽度和高度。伪元素在以下图像中具有蓝色背景。

使用transform roate制作CSS三角形第一步

此时,我们有以下CSS

.tr {
    width: 30%;
    padding-bottom: 21.27%; /* = width / 1.41 */
    position: relative;
}

.tr: before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: #0079C6;
}

步骤 2:让我们旋转

首先,最重要的是定义旋转的基准点默认的基准点位于伪元素中心,而我们需要它在左下角。通过在伪元素中添加以下CSS

transform-origin:0 100%; 或者 transform-origin: left bottom;

现在我们可以使用transform : rotate(45deg);将伪元素顺时针旋转45度。

使用CSS3创建三角形第2步

此时,我们有了这个CSS

.tr {
    width: 30%;
    padding-bottom: 21.27%; /* = width / 1.41 */
    position: relative;
}

.tr:before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: #0079C6;
    transform-origin: 0 100%;        
    transform: rotate(45deg);
}

第三步:隐藏

为了隐藏赘余的伪元素部分(即溢出黄色边框的内容),你只需要在容器上设置overflow:hidden;。去掉黄色边框后,你就得到了一个三角形!:

演示

CSS三角形

CSS:

.tr {
    width: 30%;
    padding-bottom: 21.27%; /* = width / 1.41 */
    position: relative;
    overflow: hidden;
}

.tr:before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #0079C6;
    transform-origin: 0 100%;
    transform: rotate(45deg);
}

步骤4:更深入地了解...

演示所示,您可以自定义三角形:

  1. 通过使用skewX()使它们变得更薄或更平。
  2. 通过调整变换原点和旋转方向来使它们指向左侧、右侧或其他任何方向。
  3. 使用3D变换属性进行一些反射
  4. 为三角形添加边框
  5. 在三角形内放置图像
  6. 更多...发挥CSS3的威力吧!

为什么要使用这种技术?

  1. 三角形很容易响应式设计。
  2. 您可以制作带有边框的三角形
  3. 您可以保持三角形的边界。这意味着您只能在光标位于三角形内部时触发悬停状态或单击事件。这在某些情况下非常方便,例如此处,每个三角形都不能覆盖其相邻的三角形,因此每个三角形都有自己的悬停状态。
  4. 您可以制作一些炫酷的效果,如反射
  5. 它将帮助您理解2D和3D变换属性。

为什么不使用这种技术?

  1. 主要缺点是浏览器兼容性,2D变换属性由IE9+支持,因此如果您计划支持IE8,则无法使用此技术。有关更多信息,请参见CanIuse。对于某些使用3D变换的炫酷效果,例如反射,浏览器支持为IE10+(有关更多信息,请参见CanIuse)。
  2. 如果您不需要响应式设计且简单的三角形就可以满足您的需求,则应该选择此处解释的边界技术:浏览器兼容性更好,而且由于这里的惊人帖子,更易于理解。

19
值得一提的是,1.41是√2的近似值,也是您创建的三角形的斜边长度,这就是为什么您需要(至少)该宽度的原因。 - KRyan
我本想保持答案简洁,但你说得对,应该提到 @KRyan。 - web-tiki
实际上,在尝试使用此功能时,提及如何推导出与 skewX 一起使用的不同宽度将会很有用。 - KRyan
2
当您需要三角形的1像素实线边框时,此方法效果更佳。 - Roman Losev
这是为了在三角形周围创建边框的情况而言,当我想要创建这个AnnotationBox注释框时,我被边框的方式所困扰。 - vanduc1102
现在似乎应该将其作为被接受的答案,因为没有人再关心IE了。 - matronator

194

这里是我为演示创建的JSFiddle中的动画

下面还可以查看代码片段。

这是从屏幕录制中制作的动画GIF。

Triangle的动画GIF

transforms = [
         {'border-left-width'   :'30', 'margin-left': '70'},
         {'border-bottom-width' :'80'},
         {'border-right-width'  :'30'},
         {'border-top-width'    :'0', 'margin-top': '70'},
         {'width'               :'0'},
         {'height'              :'0', 'margin-top': '120'},
         {'borderLeftColor'     :'transparent'},
         {'borderRightColor'    :'transparent'}
];


$('#a').click(function() {$('.border').trigger("click");});
(function($) {
    var duration = 1000
    $('.border').click(function() {
    for ( var i=0; i < transforms.length; i++ ) {
        $(this)
         .animate(transforms[i], duration)
    }
    }).end()
}(jQuery))
.border {
    margin: 20px 50px;
    width: 50px;
    height: 50px;
    border-width: 50px;
    border-style: solid;
    border-top-color: green;
    border-right-color: yellow;
    border-bottom-color: red;
    border-left-color: blue;
    cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://code.jquery.com/color/jquery.color-2.1.2.min.js"></script>
Click it!<br>
<div class="border"></div>

随机版本

/**
 * Randomize array element order in-place.
 * Using Durstenfeld shuffle algorithm.
 */
function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}

transforms = [
         {'border-left-width'   :'30', 'margin-left': '70'},
         {'border-bottom-width' :'80'},
         {'border-right-width'  :'30'},
         {'border-top-width'    :'0', 'margin-top': '70'},
         {'width'               :'0'},
         {'height'              :'0'},
         {'borderLeftColor'     :'transparent'},
         {'borderRightColor'    :'transparent'}
];
transforms = shuffleArray(transforms)



$('#a').click(function() {$('.border').trigger("click");});
(function($) {
    var duration = 1000
    $('.border').click(function() {
    for ( var i=0; i < transforms.length; i++ ) {
        $(this)
         .animate(transforms[i], duration)
    }
    }).end()
}(jQuery))
.border {
    margin: 50px;
    width: 50px;
    height: 50px;
    border-width: 50px;
    border-style: solid;
    border-top-color: green;
    border-right-color: yellow;
    border-bottom-color: red;
    border-left-color: blue;
    cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://code.jquery.com/color/jquery.color-2.1.2.min.js"></script>
Click it!<br>
<div class="border"></div>

一次性版本

$('#a').click(function() {$('.border').trigger("click");});
(function($) {
    var duration = 1000
    $('.border').click(function() {
        $(this)
         .animate({'border-top-width': 0            ,
               'border-left-width': 30          ,
               'border-right-width': 30         ,
               'border-bottom-width': 80        ,
               'width': 0                       ,
               'height': 0                      ,
                   'margin-left': 100,
                   'margin-top': 150,
               'borderTopColor': 'transparent',
               'borderRightColor': 'transparent',
               'borderLeftColor':  'transparent'}, duration)
    }).end()
}(jQuery))
.border {
    margin: 50px;
    width: 50px;
    height: 50px;
    border-width: 50px;
    border-style: solid;
    border-top-color: green;
    border-right-color: yellow;
    border-bottom-color: red;
    border-left-color: blue;
    cursor: pointer
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://code.jquery.com/color/jquery.color-2.1.2.min.js"></script>
Click it!<br>
<div class="border"></div>


53

假设我们有以下

<div id="triangle" />

现在逐步编辑CSS,这样你就会清楚地了解周围正在发生什么。

步骤1: JSFiddle链接:

 #triangle {
        background: purple;
        width :150px;
        height:150PX;
        border-left: 50px solid black ;
        border-right: 50px solid black;
        border-bottom: 50px solid black;
        border-top: 50px solid black;
    }

这是一个简单的 div,使用非常简单的 CSS 样式。所以即使是一个外行人也可以理解。div 的尺寸为 150 x 150 像素,边框为 50 像素。图片如下:

图片描述

步骤 2:JSfiddle 链接

#triangle {
    background: purple;
    width :150px;
    height:150PX;
    border-left: 50px solid yellow ;
    border-right: 50px solid green;
    border-bottom: 50px solid red;
    border-top: 50px solid blue;
}
现在我只是改变了四边的边框颜色。图片已附上。

enter image description here

步骤:3 JSFiddle链接:

#triangle {
    background: purple;
    width :0;
    height:0;
    border-left: 50px solid yellow ;
    border-right: 50px solid green;
    border-bottom: 50px solid red;
    border-top: 50px solid blue;
}

现在我只是将div的高度和宽度从150像素改为零。图片如下:

这里输入图片描述

第4步:JSfiddle链接:

#triangle {
    background: purple;
    width :0px;
    height:0px;
    border-left: 50px solid transparent;
    border-right: 50px solid transparent;
    border-bottom: 50px solid red;
    border-top: 50px solid transparent;
}

现在我已经将所有边框设为透明,除了底部边框。下面附有图片。

enter image description here

第5步: JSFiddle链接:

#triangle {
    background: white;
    width :0px;
    height:0px;
    border-left: 50px solid transparent;
    border-right: 50px solid transparent;
    border-bottom: 50px solid red;
    border-top: 50px solid transparent;
}

现在我只是把背景颜色改成了白色。图片已附上。

enter image description here

因此,我们得到了所需的三角形。


6
为什么你在第一步使用下界传送门? - LuizLoyola

39

3
我认为"beaten"在这里不是一个合适的词。解决方案依赖于字体度量,因此精确定位相当可疑,更不用说你无法控制形状。 - user776686
是的,结果并不是非常可控,但通常在您想要为下拉菜单等使用简单图标时,这是最好的解决方案。我会将其放置在::before::aftercontent中。 - jiwopene

34

考虑下面的三角形

.triangle {
    border-bottom:15px solid #000;
    border-left:10px solid transparent;
    border-right:10px solid transparent;
    width:0;
    height:0;
}

这是我们得到的内容:

Small triangle output

为什么是这种形状呢?下面的图解释了它的尺寸,注意底部边框使用了15px,左右各使用了10px。

Large triangle

通过去掉右边框,也很容易制作出一个直角三角形。

Right angle triangle


28
进一步地,基于这个方法,我在我的后退和前进按钮上加入了箭头样式的css(是的,我知道它不是完全跨浏览器兼容的,但仍然很好看)。

.triangle {
  width: 0;
  height: 0;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  border-bottom: 100px solid red;
  margin:20px auto;
}

.triangle-down {
  border-bottom:none;
  border-top: 100px solid red;
}

.triangle-left {
  border-left:none;
  border-right: 100px solid red;
  border-bottom: 50px solid transparent;
  border-top: 50px solid transparent;
}

.triangle-right {
  border-right:none;
  border-left: 100px solid red;
  border-bottom: 50px solid transparent;
  border-top: 50px solid transparent;
}

.triangle-after:after {
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 5px solid red;
  margin:0 5px;
  content:"";
  display:inline-block;
}

.triangle-after-right:after {
  border-right:none;
  border-left: 5px solid blue;
  border-bottom: 5px solid transparent;
  border-top: 5px solid transparent;

}

.triangle-before:before {
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 5px solid blue;
  margin:0 5px;
  content:"";
  display:inline-block;
}

.triangle-before-left:before {
  border-left:none;
  border-right: 5px solid blue;
  border-bottom: 5px solid transparent;
  border-top: 5px solid transparent;

}
<div class="triangle"></div>
<div class="triangle triangle-down"></div>
<div class="triangle triangle-left"></div>
<div class="triangle triangle-right"></div>

<a class="triangle-before triangle-before-left" href="#">Back</a>
<a class="triangle-after triangle-after-right" href="#">Next</a>


1
这怎么不是跨浏览器的?三角形应该能够在IE6上运行。 - chriscauley
4
:before和:after的使用不被100%支持。 - PseudoNinja
2
伪元素不支持IE8及以下版本。 - alex

23

CSS clip-path

这是我认为这个问题中忽略的一个内容; clip-path

clip-path简介

使用clip-path属性进行裁剪,类似于从矩形纸张上切下一个形状(如圆形或五边形)。该属性属于“CSS掩模模块1级规范”。规范指出,“CSS掩模提供了两种部分或完全隐藏视觉元素的方法:掩模和裁剪”。


clip-path将使用元素本身而不是其边框来裁剪您在其参数中指定的形状。它使用超级简单的基于百分比的坐标系,使得编辑它非常容易,并且意味着您可以在几分钟内创建奇怪而神奇的形状。


三角形形状示例

div {
  -webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
  clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
  background: red;
  width: 100px;
  height: 100px;
}
<div></div>


不足之处

目前它有一个主要的不足之处,即它的支持非常有限,只在-webkit-浏览器中得到了广泛覆盖,并且在IE上没有支持,在FireFox上仅有很少的局部支持。


资源

这里提供一些有用的资源和材料,以帮助更好地理解 clip-path ,并开始创建自己的东西。


现在在Firefox中似乎有更好的支持。 - Lazerbeak12345
在2023年,这是一个很好的答案。它比边框技巧更直观,而且更加灵活。看到它在多个几乎相同的讨论边框的答案下面排名如此之低,令人失望! - charcole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接