斜切角

2018-02-24 15:42 更新

原文出處:http://www.w3cplus.com/css3/css-secrets/cutout-corners.html

問(wèn)題

斜切角在Web設(shè)計(jì)和印刷中是相當(dāng)受歡迎的樣式。它通常是在一個(gè)或多個(gè)元素的角落切一個(gè)45°的角(也就是所謂的斜切角)。特別是最近,扁平化設(shè)計(jì)的勢(shì)頭壓過(guò)了擬真設(shè)計(jì),也使這種效果更加流行。當(dāng)斜切角只存在元素的一側(cè),并且每個(gè)都占據(jù)元素的50%高度的時(shí)候,一個(gè)箭頭的形狀產(chǎn)生了,這在按鈕和面包屑導(dǎo)航中非常受歡迎。

斜切角

圖注:帶斜切角的按鈕,創(chuàng)建了箭頭形狀強(qiáng)調(diào)其意義

但是,要用CSS來(lái)創(chuàng)建這個(gè)效果并不是那么容易,這不是一行代碼就可以搞定的效果。這導(dǎo)致很多作者傾向于直接使用背景圖像完成,而不是結(jié)合三角形來(lái)完成斜切角(當(dāng)背景是純色),也不會(huì)去使用一個(gè)或多個(gè)角落已經(jīng)被切的圖像來(lái)作為整個(gè)背景。

斜切角

圖注:應(yīng)用了斜切角的網(wǎng)站示例(半透明的“Find & Book”盒子的左下角)

這種方法顯然是不靈活的,而且難以維護(hù),還增加了延遲,因?yàn)樵黾恿薍TTP請(qǐng)求和網(wǎng)站的總文件大小。有沒(méi)有什么更好的方法呢?

解決方案

第一個(gè)解決方案是萬(wàn)能的CSS漸變。我們假設(shè)我們暫時(shí)只完成一個(gè)斜切角——右下角那個(gè)。其訣竅在于漸變可以接受一個(gè)角度值作為參數(shù)(如45deg),色標(biāo)位置是絕對(duì)長(zhǎng)度,這兩個(gè)都不會(huì)因?yàn)樵睾捅尘俺叽绲母淖兪艿接绊憽?/p>

綜上所述,我們只需要一個(gè)線性漸變就ok了。它需要一個(gè)透明的色標(biāo)作為斜切角,還有另一個(gè)相同位置的帶有我們想要作為背景顏色的色標(biāo)。CSS代碼如下(如一個(gè)15px大小的切角):

background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0);

很簡(jiǎn)單,對(duì)不對(duì)?你可以看到結(jié)果。

斜切角

圖注:右下角斜切的元素,通過(guò)一個(gè)簡(jiǎn)單的CSS漸變完成

從技術(shù)上說(shuō),我們甚至不需要第一條聲明。我們只是把它作為一個(gè)降級(jí)引入:當(dāng)CSS漸變不被支持時(shí),也就是第二條聲明失效的時(shí)候。所以我們還是需要一個(gè)純色背景。

為方便調(diào)試,我們使用不同的顏色(#58a#655)。在應(yīng)用中,兩個(gè)漸變應(yīng)該是相同的顏色。

現(xiàn)在,假設(shè)我們需要兩個(gè)斜切角,左右下角分別一個(gè)。只用一個(gè)漸變是沒(méi)辦法搞定的,所以兩個(gè)漸變上場(chǎng)。我們首先想到的可能是:

background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0),
            linear-gradient(45deg, transparent 15px, #655 0);

但是,如下圖所示,這是不ok的。

斜切角

圖注:給底部?jī)蓚€(gè)角都應(yīng)用斜切角效果的失敗嘗試

默認(rèn)情況下,兩個(gè)漸變被應(yīng)用于同一個(gè)元素,它們會(huì)相愛相殺(彼此掩蓋)。我們需要把它們變小,通過(guò)使用background-size來(lái)讓每個(gè)漸變都只應(yīng)用于元素的一半:

background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0) right,
            linear-gradient(45deg, transparent 15px, #655 0) left;
background-size: 50% 100%;

你可以在下圖中看到結(jié)果。

斜切角

圖注:只一條background-size是不夠噠~

即使應(yīng)用了background-size,這倆漸變還是會(huì)把對(duì)方蓋住。因?yàn)槲覀兺税?code>background-repeat關(guān)掉了,所以我們的背景就都重復(fù)了兩次。因此,我們的背景還是在相愛相殺——這次是因?yàn)楸尘爸貜?fù)。新修改的代碼如下:

background: #58a;
background: linear-gradient(-45deg, transparent 15px, #58a 0) right,
            linear-gradient(45deg, transparent 15px, #655 0) left;
background-size: 50% 100%;
background-repeat: no-repeat;

你可以在下圖中看到結(jié)果。

斜切角

圖注:我們的左下和右下斜切角終于ok了

它終!于!通過(guò)驗(yàn)證了!現(xiàn)在,你應(yīng)該知道要如何把這個(gè)效果應(yīng)用到其它四個(gè)角了吧。一共需要四個(gè)漸變,代碼如下:

background: #58a;
background: linear-gradient(135deg, transparent 15px, #58a 0) top left,
            linear-gradient(-135deg, transparent 15px, #655 0) top right,
            linear-gradient(-45deg, transparent 15px, #58a 0) bottom right,
            linear-gradient(45deg, transparent 15px, #655 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;

你可以在下圖中看到結(jié)果。

斜切角

圖注:使用四個(gè)漸變,給四個(gè)角都應(yīng)用了效果

前面的代碼有個(gè)問(wèn)題是,它不是特別可維護(hù)的。要改變背景顏色還有四個(gè)角的大小,需要五次編輯。加入預(yù)處理器mixin有助于減少重復(fù)。這是SCSS代碼:

@mixin beveled-corners($bg, $tl:0, $tr:$tl, $br:$tl, $bl:$tr) {
    background: $bg;
    background: linear-gradient(135deg, transparent $tl, $bg 0) top left,
                linear-gradient(225deg, transparent $tr, $bg 0) top right,
                linear-gradient(-45deg, transparent $br, $bg 0) bottom right,
                linear-gradient(45deg, transparent $bl, $bg 0) bottom left;
    background-size: 50% 50%;
    background-repeat: no-repeat;
}

然后,在需要的時(shí)候,它可以像這樣被使用,使用2-5個(gè)參數(shù):

@include beveled-corners(#58a, 15px, 5px);

在這個(gè)示例中,我們將會(huì)得到在左上角和右下角得到15px斜切角,在左下角和右上角得到5px斜切角,和border-radius的原理相似。這是因?yàn)槲覀優(yōu)镾CSS的mixin的參數(shù)提供了默認(rèn)值,還有,這些默認(rèn)值也可以引用其它的參數(shù)。

曲線切口角

有很多漸變的方法可以用來(lái)創(chuàng)建曲線切口角,大家常常把這個(gè)效果稱之為“內(nèi)圓角”,因?yàn)樗雌饋?lái)就是圓角的反相版本。和斜切角唯一的不同是它使用了徑向漸變,而不是線性漸變:

斜切角

g2geogeske.com上使用曲線切口角的非常棒的例子;設(shè)計(jì)師已經(jīng)把它們變成核心設(shè)計(jì)元素,因?yàn)樗鼈兇嬖谟趯?dǎo)航、內(nèi)容、甚至頁(yè)腳中。

background: #58a;
background: radial-gradient(circle at top left,
            transparent 15px, #58a 0) top left,
            radial-gradient(circle at top right,
            transparent 15px, #58a 0) top right,
            radial-gradient(circle at bottom right,
            transparent 15px, #58a 0) bottom right,
            radial-gradient(circle at bottom left,
            transparent 15px, #58a 0) bottom left;
background-size: 50% 50%;
background-repeat: no-repeat;

你可以在下圖中看到結(jié)果。

斜切角

圖注:使用徑向漸變完成的曲線切口角

和前面的技術(shù)一樣,切口角的大小可以通過(guò)色標(biāo)的位置進(jìn)行控制,使用mixin可以讓代碼更易于維護(hù)。

內(nèi)聯(lián)SVG、border-image的解決方案

雖然基于漸變的解決方案是可行的,但是它有幾個(gè)問(wèn)題:

  • 代碼非常長(zhǎng),而且重復(fù)。在通常情況下,我們希望在四個(gè)角都有相同尺寸的切口角,這樣我們就需要重復(fù)四次編輯。相似的,要修改背景顏色我們也需要四次編輯,五個(gè)計(jì)算降級(jí)。
  • 在不同尺寸的切口角之間設(shè)置動(dòng)畫是完全不可能的(依賴于瀏覽器)。

幸好,根據(jù)我們的需求,還有幾個(gè)我們可以采用的方法。一個(gè)是在內(nèi)聯(lián)SVG中使用border-image生成圓角。根據(jù)border-image的工作原理,你可以想象一下我們的SVG會(huì)如何嗎?

因?yàn)槌叽绮⒉恢匾?code>border-image可以縮放,而且SVG縮放是完美的,不需要擔(dān)心尺寸——這就是矢量圖的好處!),單位可以是1,或者更直接的,直接是數(shù)字。拐角長(zhǎng)度可以是長(zhǎng)度1,直邊長(zhǎng)度也為1。結(jié)果(縮放)如下圖所示。

斜切角

圖注:基于SVG的border-image,及其切片

代碼如下:

border: 15px solid transparent;
border-image: 1 url('data:image/svg+xml,\<svg xmlns="http://www.w3.org/2000/svg" width="3" height="3" fill="%2358a">\<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2"/>\</svg>');

注意我們使用了大小為1的切片。這不是1像素的意思,它指的是SVG文件的坐標(biāo)系(因此缺省單位)。如果我們指定了它的百分比,我們需要的就是1/3圖像的近似值,如33.34%。近似值是有風(fēng)險(xiǎn)的,因此不是所有的瀏覽器都使用相同的精確度。但是,通過(guò)使用SVG文件的坐標(biāo)系統(tǒng)的單位,我們就不需要糾結(jié)精確值的問(wèn)題了。

斜切角

圖注:給border-image屬性應(yīng)用SVG

結(jié)果如上圖所示。我們的切口角有了,但是沒(méi)有背景。你可以通過(guò)兩個(gè)方法解決:指定一個(gè)背景,或者給我們的border-image聲明添加一個(gè)關(guān)鍵字fill,這樣它就不會(huì)丟棄中間的切片。這里,我們選擇指定一個(gè)背景,因?yàn)檫@樣也可以作為一個(gè)降級(jí)。

另外,我們的切口角比前面創(chuàng)建的切口角要小,有點(diǎn)奇怪。我們明明指定了一個(gè)15px的邊框?qū)挾?!這是漸變?cè)斐傻模?code>15px沿著漸變方向的,而方向垂直于梯度。同時(shí)邊框的寬度不是對(duì)角線測(cè)量的,而是水平/垂直方向的。所以你找到原因了嗎?對(duì),我們要再次使用勾股定理,我們?cè)谇懊嬉仓v過(guò)。

斜切角

圖注:指定border-width15px,得到結(jié)果為15 / 根號(hào)(2) ≈ 10.606601718的拐角尺寸,這也是為什么我們的拐角看起來(lái)小很多

上圖有助于我們理解??偠灾?,為了得到相同的尺寸,我們使用的邊框應(yīng)該是我們用漸變方法的尺寸的根號(hào)(2)倍。這里,應(yīng)該是15 * 根號(hào)(2) ≈ 21.213203436像素,也就是約等于20px,除非我們真的需要對(duì)角線盡可能地接近于15px

border: 20px solid transparent;
border-image: 1 url('data:image/svg+xml,\<svg xmlns="http://www.w3.org/2000/svg" width="3" height="3" fill="%2358a">\<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2"/>\</svg>');
background: #58a;

斜切角

圖注:我們的切口角哪去了?!

但是,上圖的效果并不是我們期待的效果。我們辛辛苦苦創(chuàng)建的切口角躲到哪里去了?年輕人,不要擔(dān)心!切口角還在那里。如果你把背景設(shè)置成其它的顏色,如#655,你就會(huì)知道是怎么回事了。

斜切角

圖注:把我們的background換成其它顏色,就可以發(fā)現(xiàn)神秘消失的切口角了

上圖所示,我們的切口角消失的原因是我們指定的背景把它們擋住了。我們需要做的是使用background-clip來(lái)阻止背景擴(kuò)展到覆蓋了我們的邊框:

border: 20px solid transparent;
border-image: 1 url('data:image/svg+xml,\<svg xmlns="http://www.w3.org/2000/svg"\ width="3" height="3" fill="%2358a">\<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2"/>\</svg>');
background: #58a;
background-clip: padding-box;

這個(gè)問(wèn)題已經(jīng)解決,我們現(xiàn)在的盒子如下圖所示。

斜切角

但是,我們可以只在一個(gè)地方很容易地改變拐角的尺寸:我們只需要修改邊框的寬度。我們甚至可以給它添加動(dòng)畫,因?yàn)?code>border-width是可添加動(dòng)畫的!我們還可以只通過(guò)兩次編輯就改變背景。另外,因?yàn)槲覀兊谋尘艾F(xiàn)在是獨(dú)立于拐角效果的,我們甚至可以給它指定一個(gè)漸變,或其它的紋理,只要它在邊緣處的顏色還是#58a就好。例如,看看下圖,使用了一個(gè)從hsla(0,0%,100%,.2)transparent的徑向漸變。

斜切角

圖注:帶有徑向漸變背景的切口角

只剩下一個(gè)小問(wèn)題了。如果border-image不被支持,降級(jí)不僅沒(méi)有拐角。因?yàn)楸尘安眉?,它看起?lái)還像是盒子邊緣和內(nèi)容之間沒(méi)有任何填充空間。為了解決這個(gè)問(wèn)題,我們可以給我們的邊框添加一個(gè)和背景相同的顏色:

border: 20px solid #58a;
border-image: 1 url('data:image/svg+xml,\<svg xmlns="http://www.w3.org/2000/svg"\ width="3" height="3" fill="%2358a">\<polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2"/>\</svg>');
background: #58a;
background-clip: padding-box;

當(dāng)border-image應(yīng)用的時(shí)候,顏色會(huì)被忽略,這可以提供一個(gè)更優(yōu)雅的降級(jí),看起來(lái)如圖所示。

斜切角

因?yàn)檫@個(gè)缺陷,使得我們想要改變背景顏色的時(shí)候,需要的編輯次數(shù)從2變成了3。

clip-path的解決方案

因?yàn)?code>border-image的解決方案非常緊湊而且相對(duì)DRY,它仍然有其局限性。例如,我們?nèi)匀恍枰幸粋€(gè)純色背景,或一個(gè)在邊緣處帶有純色的背景。如果我們想要一種不同的背景呢,例如紋理、圖案,或一個(gè)線性漸變?

有一個(gè)方法可以使我們不受所有的這些限制,盡管它也有自己的局限性。還記得clip-path屬性嗎?一件非常令人驚嘆的事情是,CSS的clip-path可以結(jié)合百分比(這里指的是元件尺寸)以及絕對(duì)長(zhǎng)度使用,給了我們極大的靈活性。

例如,clip-path裁剪一個(gè)帶20px(水平方向)切角的矩形元素的代碼如下所示:

background: #58a;
clip-path: polygon( 20px 0, calc(100% - 20px) 0, 100% 20px,
                    100% calc(100% - 20px), calc(100% - 20px) 100%,
                    20px 100%, 0 calc(100% - 20px), 0 20px
);

盡管代碼很短,也不意味著它是DRY的,這就是它本身最大的問(wèn)題之一,如果你不使用預(yù)處理器的話。事實(shí)上,這是我們提出的最WET的CSS解決方案,要改變拐角尺寸需要8次編輯!但是,我們只需要在一處位置改變背景。

它的優(yōu)勢(shì)是我們可以使用任何我們想要的背景,甚至是裁剪像圖片這樣的替換元素。如下圖帶有切角的圖像。

斜切角

圖注:通過(guò)clip-path制作的帶有切角的圖片

前面的幾種方法都不能完成。另外,clip-path是可動(dòng)畫的,即使斜切角的大小不同,形狀也不同。我們需要做的只是使用一個(gè)不同的裁剪路徑。

除了WET,它的瀏覽器支持也不夠,它還有個(gè)缺點(diǎn)是:如果沒(méi)有提供足夠的padding,它還會(huì)裁剪文本,因?yàn)樗徊眉粼?,而不區(qū)分都是哪些部分。與此相反,漸變的方法只是讓文本在超出拐角(因?yàn)樗鼈冎皇潜尘埃?,這樣border-image方法只是扮演邊框的角色,來(lái)包裹文本。

將來(lái)的拐角

將來(lái)我們不需要再通過(guò)CSS漸變、裁剪或SVG來(lái)完成這種效果了。一個(gè)新屬性,corner-shape即將加入到CSS Backgrounds & Borders Level 4中,可以幫我們節(jié)省很多精力。它可以和border-radius結(jié)合使用,用于產(chǎn)生不同切口角效果,在border-radius中定義尺寸即可。如,在所有角落指定15px的切口角將會(huì)很簡(jiǎn)單:

border-radius: 15px;
corner-shape: bevel;
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)