通常情況下,用 CSS 來實(shí)現(xiàn)一些簡單的圖形會比使用圖片更有優(yōu)勢,譬如:
- CSS 可以隨時調(diào)整圖形的顏色;
- CSS 可以給圖形加復(fù)雜動畫;
- 圖片會消耗額外的網(wǎng)絡(luò)資源;
...
接下來介紹如何用 CSS 精確繪制三角形及其衍生圖形。
盒模型
所有元素都可以被描述為一個個矩形的盒子,盒子由 4 個部分組成:內(nèi)容區(qū)域(content area)、內(nèi)邊距區(qū)域(padding area)、邊框區(qū)域(border area)、外邊距區(qū)域(margin area)。

一個邊框?qū)挾炔粸榱愕木匦卧厥沁@樣的:
<style>
.box {
width: 50px;
height: 50px;
border-width: 30px;
border-style: solid;
border-color: #07C160 #FA5151 #409eff #e6a23c;
}
</style>
<div class="box"></div>

如果把 內(nèi)容區(qū)域 的寬高都置為 0
<style>
.box {
/*
...
*/
width: 0;
height: 0;
}
</style>

此時內(nèi)容、內(nèi)外邊距區(qū)域都為空,盒模型相當(dāng)于被等寬的邊框區(qū)域瓜分成四個等腰直角三角形。那么,只需要將其他三個三角形都透明化,我們要的三角形就呼之欲出了。
實(shí)心三角形
<style>
.triangle {
width: 0;
height: 0;
border-width: 0 50px 50px 50px;
border-style: solid;
border-color: transparent transparent #409eff transparent;
}
</style>
<div class="triangle"></div>

PS:假如我們只需要下方的三角形,那么上邊框是沒有起任何作用的,不妨也將其置為 0。
我們可以通過 調(diào)整各邊框的寬度,來控制三角形的形狀。
<style>
.triangle {
width: 0;
height: 0;
border-width: 0 50px 50px 50px;
border-style: solid;
border-color: transparent transparent #409eff transparent;
}
</style>
<div class="triangle"></div>

空心三角形
在實(shí)心三角形的基礎(chǔ)上,把兩個大小不一的三角形疊在一起,就繪制出空心三角形了。
但這里其實(shí)是有講究的,我們通常期望空心三角形的三邊寬度是相等的,那么為了符合要求我們需要如何調(diào)整兩個三角形的位置?偏移量又是多少呢?
這里利用偽元素來繪制第二個三角形:
<style>
.hollow {
position: relative;
width: 0;
height: 0;
border-width: 0 50px 50px 50px;
border-style: solid;
border-color: transparent transparent #409eff transparent;
}
.hollow:before {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
border-width: 40px;
border-style: solid;
border-color: transparent transparent #e6a23c transparent;
}
</style>
<div class="hollow"></div>

對應(yīng)的模型如下圖所示,其中 內(nèi)三角形 的坐標(biāo)軸原點(diǎn)位于 外三角形 的頂點(diǎn)處(位于父元素的內(nèi)容區(qū)域)。我們先挪動內(nèi)三角形使兩者的頂點(diǎn)重合,那么內(nèi)三角形需要左移和上移各像素。

然后調(diào)整內(nèi)三角形在縱坐標(biāo)軸上的位置。我們期望的最終效果是這樣的

是待求的縱坐標(biāo)偏移值
由于內(nèi)外三角形的三邊都是分別平行的,我們可以建立等式
求出
所以縱坐標(biāo)軸上的總偏移量為
假設(shè)內(nèi)外三角形都是等腰直角三角形,則,那么總偏移量
為
將 demo 中的參數(shù),
代入方程式,求得
所以橫坐標(biāo)偏移量為 -40px,縱坐標(biāo)偏移量為 -34px。

箭頭
箭頭的實(shí)現(xiàn)原理和空心三角形如出一轍,只是得順便把外三角形的下邊給覆蓋住,因此這里 把 內(nèi)三角形 的邊框?qū)挾日{(diào)整為與 外三角形 的相等(或者與 外三角形 的邊框?qū)挾认嘟纯桑?/strong>。
我們期望的最終模型是這樣的

我們最終需要關(guān)心的是的值,它代表著箭頭的寬度。假設(shè)我們需要繪制 1px 寬的箭頭
參考對空心三角形縱軸偏移值的計(jì)算,縱軸上的總偏移量為
假設(shè)內(nèi)外三角形都是等腰直角三角形,則,那么總偏移量
為
將 demo 中的參數(shù)代入方程式,求得
所以橫坐標(biāo)偏移量為 -50px,縱坐標(biāo)偏移量為 -49px。
<style>
.arrow {
position: relative;
width: 0;
height: 0;
border-width: 0 50px 50px 50px;
border-style: solid;
border-color: transparent transparent #409eff transparent;
}
.arrow:before {
content: '';
display: block;
position: absolute;
top: -49px;
left: -50px;
border-width: 50px;
border-style: solid;
border-color: transparent transparent #fff transparent;
}
</style>
<div class="arrow"></div>

實(shí)現(xiàn)等腰直角箭頭的另一種方式
等腰直角箭頭 無非就是正方形的兩條鄰邊,我們只需要將另外兩條鄰邊透明化,同時按需求旋轉(zhuǎn)圖形指向就可以了。
這里繼續(xù)利用偽元素實(shí)現(xiàn)。為了優(yōu)化元素的可用性,我們使偽元素的寬高百分比于父元素,建立以下模型

那么,偽元素的寬度和父元素寬度的關(guān)系為
<style>
.arrow {
position: relative;
width: 50px;
height: 50px;
}
.arrow:before {
content: '';
display: block;
position: absolute;
top: 0;
left: 50%;
width: 70%;
height: 70%;
border-width: 1px;
border-style: solid;
border-color: #409eff transparent transparent #409eff;
transform: rotate(45deg);
transform-origin: 0 0;
}
</style>
<div class="arrow"></div>
所有 demo 詳見:https://codepen.io/JunreyCen/pen/LovdaM
