CSS 精確繪制三角形

通常情況下,用 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)。

配圖摘自 https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model

一個邊框?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)三角形需要左移和上移各H_{2}像素。

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

A_{1}A_{2}是待求的縱坐標(biāo)偏移值

A_{1}A_{2} = \frac{x}{\sin ∠O}

由于內(nèi)外三角形的三邊都是分別平行的,我們可以建立等式

H_{1} = A_{1}A_{2} + H_{2} + x =\frac {\sin ∠O + 1}{\sin ∠O}x + H_{2}

求出x

x = \frac{\sin ∠O(H_{1} - H_{2})}{\sin ∠O + 1}

所以縱坐標(biāo)軸上的總偏移量S

S = 0 - H_{2} + A_{1}A_{2} = \frac{(H_{1} - H_{2})}{\sin ∠O + 1} - H_{2}

假設(shè)內(nèi)外三角形都是等腰直角三角形,則\sin ∠O = \frac {\sqrt 2}{2},那么總偏移量S

S = \frac{\frac {\sqrt 2}{2} (H_{1} - H_{2})}{\frac {\sqrt 2}{2} + 1} - H_{2} = (2 - \sqrt 2)(H_{1} - H_{2}) - H_{2}

將 demo 中的參數(shù)H_{1} = 50,H_{2} = 40代入方程式,求得

S = (2 - \sqrt 2)\times 10-40 \approx -34

所以橫坐標(biāo)偏移量為 -40px,縱坐標(biāo)偏移量為 -34px。

箭頭

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

我們期望的最終模型是這樣的

我們最終需要關(guān)心的是x的值,它代表著箭頭的寬度。假設(shè)我們需要繪制 1px 寬的箭頭

x = A_{1}A_{2}\sin ∠O = 1

參考對空心三角形縱軸偏移值的計(jì)算,縱軸上的總偏移量S

S = 0 - H_{2} + A_{1}A_{2} = \frac {1}{\sin ∠O} - H_{2}

假設(shè)內(nèi)外三角形都是等腰直角三角形,則\sin ∠O = \frac {\sqrt 2}{2},那么總偏移量S

S = \sqrt 2 - H_{2}

將 demo 中的參數(shù)H_{2} = 40代入方程式,求得

S = \sqrt 2 - 40 \approx -39

所以橫坐標(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)系為

W_{偽} = \frac{\sqrt 2}{2}W \approx 0.7W

<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

Reference

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容