日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > CSS >内容正文

CSS

CSS如何实现内凹角效果 By 大漠

發布時間:2025/3/19 CSS 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CSS如何实现内凹角效果 By 大漠 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

記得@Lea Verou的《CSS Secrets》一書和前幾天@Chris Coyier剛發的帖子都介紹了CSS怎么實現元素斜切口的效果。我也嘗試著借助Vue的能力,把這種效果構建成一個Vue組件。我把這種效果定義為外切口。而今天將要聊的是與其剛好相反的一個效果:CSS如何實現內凹角的效果


上圖展示的效果就是接下來所要聊的內凹角的效果。也就是說,通過下文的介紹,我們可以知道這種效果是如何做的,而且如何在多個元素上實現這樣的內凹角效果。在實現這樣的效果當中,將會遇到些什么棘手的問題,又是怎么繞過這些問題的。

最初的想法:box-shadow

對于box-shadow的屬性,想必大家已經非常了解了,如果你從未接觸過box-shadow屬性,那么強烈建議您花一點時間去了解一下box-shadow相關的知識。這樣能幫助你更好的理解后續的內容。

我先假設你對box-shadow有了一定的了解。就算你不了解,也沒有關系。你也可以繼續后面的內容。假設我們有一個div的元素。給這個元素添加了一個.box的類名:


<div class="box"></div>
我們可以顯式的給這個.box元素設置大小或者通過其自己的內容來決定大小,不管是哪種方式,都并不很重要。這里為了簡單起見,給其設置了max-widthmin-height(也是用來設置其大小的)。另外為了能在瀏覽器中看到效果,其添加了一個outline的效果,讓其看起來有邊框的樣子。或許你會問,為什么不直接使用border呢?這個問題留給大家去思考吧,因為不是這篇文章要探討的內容。



.box {outline: solid 2px;max-width: 15em;min-height: 10em; }
接下來,通過偽元素::before來創建一個正方形,其邊長等于圓角的直徑(或者半徑--r的兩倍),而且對這個偽元素使用絕對定位。另外為了能在瀏覽器中看到效果,給這個偽元素添加了一個box-shadowbackground屬性。這只是用來輔助大家理解的,后續會刪除的。


:root {--r: 2em; }.box {position: relative;&::before {content: '';position: absolute;padding: var(--r);box-shadow: 0 0 7px #b53;background: #95a;} }

特別聲明:本文的實例代碼都來自于@ANA TUDOR的《Scooped Corners in 2018》一文。不同的是我把文章中的Sass變量換成了CSS自定義變量。后續內容如無特別說明,都將類似的做了修改。

這個時候看到的效果如下:


效果如你所期望的一樣。接下來對偽元素::beforeborder-radius值設置為50%,讓它成為一個圓形,并且給它設置一個margin的負值,值等于它的半徑--r。偽元素的中心點和它的父容器.box的左上角(0,0)重合。為了讓溢出的.box的偽元素能隱藏起來,需要在.box中添加一個overflow:hidden


:root {--r: 2em; }.box {position: relative;overflow: hidden;&::before {content: '';position: absolute;padding: var(--r);box-shadow: 0 0 7px #b53;background: #95a;margin: calc(var(--r) * (-1));border-radius: 50%;} }
現在的結果是這樣的:


但這樣的效果仍然不是我們想要的。為了達到我們想要的效果,我們需要使用box-shadow的第四個參數值:陰影擴展半徑。如果你想了解box-shadow添加第四個參數值的效果,可以看下面這個Demo:


你可能已經猜到我們下一步要做什么了。把backgroundbox-shadow前三個值(xy軸的偏移值以及模糊半徑)設置為0,并給box-shadow的擴展半徑設置為一個較大的值。


box-shadow: 0 0 0 300px;
下面的這個示例演示了box-shadow的擴展半徑如何讓陰影效果覆蓋容器更多的面積。


這里用到的一個技巧是讓box-shadow有足夠大的擴展半徑,這樣讓偽元素的陰影能覆蓋其容器更多的面積。這是非常有意思的一點,給.box設置box-shadow以及給其偽元素添加一個半透明的陰影效果。


.box {overflow: hidden;position: relative;margin: .25em auto;min-width: 15em;max-width: 15em;min-height: 10em;border-radius: 1em;&:before {position: absolute;margin: calc(var(--r) * -1);padding: var(--r);border-radius: 50%;box-shadow: 0 0 0 300px rgba(#95a, .75);content: ''} }

其實這是很關鍵的一步,如果你不仔細看,你或許會認為,那個凹角的效果是box-shadow實現的。或許你和我一樣會納悶,box-shadow是如何實現透明凹角的效果。事實并非如此,透明凹角部分是偽元素::beforebackground-colortransparent,而整個紫色部分是由::beforebox-shadow實現的(就是陰影擴散半徑有足夠大的值,能鋪滿.box的容器大小)。我錄一個視頻給大家看看,或許能比文字更好的說明一切原理:


是不是一圖勝過千言萬語呀。

上面看到的效果,不難發現,凹角的大小是固定的。好在我們這里使用了CSS的自定義屬性。因為使用CSS自定義屬性之后,可以很容易的通過JavaScript來修改這個屬性。這樣一來,就可以很好的控制凹角的大小。比如:


:root { --r: 50px } .box {padding: var(--r);&:before {margin: calc(-1*var(--r));padding: inherit;} }

這是實現凹角效果的關鍵樣式。具體的不多說了,能只要仔細閱讀上面的內容,你就能明白為什么。

值得一提的是,我們前面看到的效果都是.box中沒有任何內容。也就是說.box里有內容的時候,我們是需要在樣式上做一定的調整的。為什么這么說呢?先來看一個效果:


要解決這個問題,很簡單,咱們只需要在.box的偽元素::before上添加z-index屬性,并且給其設置值為-1。

另外通過.setProperty()來修改--r的值。這需要一些JavaScript代碼來支持:

// 獲取id為r的input元素 和 output元素 const _R = document.getElementById('r'), _O = _R.nextElementSibling.querySelector('output'); // 設置一個變量v let v;// 創建一個update函數,更新--r的值 function update() {if(v !== +_R.value) {document.body.style.setProperty(`--r`, `${_O.value = v = +_R.value}px`)} };update();_R.addEventListener('change', update, false); _R.addEventListener('input', update, false);最終效果如下:



現在離我們想要的效果越來越近了。我們已經知道如何通過box-shadow給單個.box設置單個凹角的效果。那么如果我們想要給一個元素添加四個凹角效果,怎么實現呢?想想,如果你想得出來,可以立馬動手試試,就算你想不出來,也并不要緊,后面我們會介紹怎么給.box盒子的每個角添加凹角的效果。

那么到這一步,咱們先暫停一下。上面我們看到的是CSS的自定義屬性和JavaScript來實現想要的凹角效果。那么咱們先暫停一步,來看看怎么通過Vue來實現上面示例的效果。


有關于Vue的代碼這里就不展示了。詳細的可以查看上面Demo的代碼,其實你還可以添加其他的參數,比如除了給scooped-corners組件傳凹角半徑值之外,還可以傳border-radius和background-color之類。感興趣的可以嘗試一下,并且歡迎在下面的評論中分享您的成果。

就用這種技術

接下來,咱們再深入一點,看看怎么運用這種技術來實現文章開頭展示的效果。這里有一點不一樣,偽元素的中心點與盒子不致,但他們都有一個共同點,偽元素的中心點,在每個盒子的頂點處。

使用的HTML結構非常簡單,這里使用了4個<article>元素(相當于前面所講的.box元素),在<article>元素中包含了一些文本內容:


<article><h3>Yogi Bear</h3><section><p>Smaaaarter than the average bear!</p><a href="#">go</a></section> </article> ...
<body>包含了四個<article>元素,還有一個<header>元素,整個布局效果采用的是Flexbox。從文章開頭的效果上來看,<header>寬度非常寬,然后每行有一個個或兩個<article>元素。具體每行展示一個還是兩個,這取決于瀏覽器視窗的寬度。


如果我們每一行只有一個<article>時,那么元素上就不會有凹角的效果,這個時候需要把凹角的半徑設置為0。否則我們就要設置一個非零的半徑,也就是說--r的值不為0。


:root {--minW: 15rem; /* 每個article元素的最小寬度 */--m: 1rem; /* 每個article元素的margin值 */--r: 0px; /* 每個article元素上凹角的半徑 */ }article {margin: var(--m);min-width: var(--minW);width: 21em; }@media (min-width: 2*($min-w + 2*$m)) {html { --r: 4rem; }article { width: 40%; } }

特別注意,CSS自定義屬性不能用于媒體查詢的條件中,但可以用于媒體查詢的區塊內。

現在我們考慮一下,每行有兩個<article>元素(當然,每個元素都有一個內凹角,因為這個才是我們感興趣的東東)。

第一個元素中,凹角的圓形在它的父元素的最右邊邊,也就是left:100%。為了將凹角圓中心點x坐標移到其父元素的右邊緣,我們就需要減去圓的半徑--r,那么left的值就變成了calc(100% - var(--r))。但我們不想讓它出現在右邊,而是希望它在<article>元素向右移--m。這樣我們就可以算出我們最終想要的一個值:


left: calc(100% - var(--r) + var(--m));



對于最后一個,其水平方向的偏移量和第二個具有相同的值,垂直方向的偏移量和第三個具有相同的值。


所以四個元素對應的lefttop的偏移量如下:


article:nth-of-type(1) { /* 1st */left: calc(100% - var(--r) + var(--m));top: calc(100% - var(--r) + var(--m)); }article:nth-of-type(2) { /* 2nd */left: calc( 0% - var(--r) - var(--m));top: calc(100% - var(--r) + var(--m)); }article:nth-of-type(3) { /* 3rd */left: calc(100% - var(--r) + var(--m));top: calc( 0% - var(--r) - var(--m)); }article:nth-of-type(4) { /* 4th */left: calc( 0% - var(--r) - var(--m));top: calc( 0% - var(--r) - var(--m)); }

這意味著凹角圓的中心位置取決于<article>元素之間的間距(這個間距是我們設置的margin: var(--m)的兩倍),凹角的半徑是--r。在一對水平和垂直的乘數因子分別是--i和--j,而且他們的最初的值都是-1。

對于第一行的兩個<article>元素(第一行是一個2 x 2的網格),我們需要改變垂直方向的乘數因子--j為1,這樣就可以讓凹角的圓心在y軸上低于父容器底部邊緣;而對于奇數的<article>(第一列),需要改變水平方向的乘數因子--i為1,這樣就可以讓凹角的圓心在x軸上位于父容器的右側邊緣。

/* multipliers initially set to -1 */ html { --i: -1; --j: -1 } h3, section {&:before {/* set generic offsets */top: calc((1 + var(--j)) * 50% - var(--r) + var(--j) * var(--m));left: calc((1 + var(--i)) * 50% - var(--r) + var(--i) * var(--m));} }@media (min-width: 2*($min-w + 2*$m)) {article {/* change vertical multiplier for first two (on 1st row of 2x2 grid) */&:nth-of-type(-n + 2) { --j: 1 }/* change horizontal multiplier for odd ones (on 1st column) */&:nth-of-type(odd) { --i: 1 }} }注意,第一行的的兩個凹角位置位于<article>中的<section>元素上,所以這兩個元素的凹角使用的是<section>的偽元素::before;另第二行的兩個凹角位置位于<article>中的<h3>元素上,因此這兩個凹角用的是<h3>的偽元素::before。前兩個元素的<h3>元素的::before的半徑--r設置為0,后兩個元素中<section>的::before的--r設置為0。
@media (min-width: 2*($min-w + 2*$m)) {article {&:nth-of-type(-n + 2) h3, &:nth-of-type(n + 3) section { &:before { --r: 0 ; } }} }
以類似的方式,我們為<article>元素的子元素添加不同的樣式:
h3, section { --p: .5rem;padding: $p; }@media (min-width: 2*($min-w + 2*$m)) {article {&:nth-of-type(-n + 2) section, &:nth-of-type(n + 3) h3 {padding-right: calc(.5*(1 + var(--i))*(var(--r) - var(--m)) + var(--p));padding-left: calc(.5*(1 - var(--i))*(var(--r) - var(--m)) + var(--p));}} }
最終效果如下:


特別聲明:今天使用CSS自定義屬性,在媒體查詢的條件中使用自定義屬性踩了一個坑。那是因為我想在代碼中統一使用CSS自定義屬性來替代Sass這樣處理器的變量。一直以為在CSS的媒體查詢的條件中使用CSS自定義屬性是OK的,結果實測代碼的時候才發現不支持。最后查找了一下原因:

The?var()?function can be used in place of any part of a value in any property on an element. The?var()?function can not be used as property names, selectors, or anything else besides property values. (Doing so usually produces invalid syntax, or else a value whose meaning has no connection to the variable.) —— From the?spec

值得慶達的是,你可以使用PostCSS插件postcss-media-variables來做處理。感興趣的可以自己試試。說實話,再一次感嘆PostCSS的神奇之處和無所不能。

潛在的問題

上面的示例看上去完美,方法簡單而又能跪瀏覽器兼容。或許你已經發現了,上例是在一個特定情況下想的結果,但很多時候我們總不是這么的幸運。哪一天需求一變,是不是還能如此輕易而又完美的實現呢?

首先,我們需要用一個偽元素來做這個凹角,當你只需要一個(比如上面看到的示例)或者兩個的時候,都不是問題,但有的時候元素的四個角都需要這樣的凹角時,那么我們就需要引入一個額外的元素。另外當你的偽元素被其他功能(比如Icon)占用時,你也不得不為此效果添加一個額外的標簽元素。蛋疼了吧!

其次上面示例中的background是一個純色,但我們不可能總是在使用純色背景的場景中。如果我們想要一個半透明的或者漸變的背景,或者在一張背景圖片之下,那么凹角將會成為我們的一個痛點,甚至會說,這個沒法實現。

因此,我們需要探索其他更可靠的方案,并且也能讓它得到眾多瀏覽器的支持。

靈活性和良好的瀏覽器支持?是SVG?

想到SVG并不奇怪,但是如果我們想要靈活一點,瀏覽器兼容性全面一點,SVG可以說是一個最好的解決方案。在.box容器中包含了一個<svg>元素,而且放置在內容的前面。SVG中包含了一個<circle>元素,在這個元素上設置了r屬性。


<div class='box'><svg><circle r='50'/></svg>TEXT CONTENT OF BOX GOES HERE </div>
svg相對于.box元素做相對定位,將將其大小設置為能完全覆蓋父容器:
.box { position: relative; }svg {position: absolute;width: 100%;height: 100%; }
到目前為止,沒有什么有趣的東西,所以給<circle>添加一個id屬性,并且使用SVG的<use>元素來復制多個id相同的<circle>


<circle id='c' r='50'/> <use xlink:href='#c' x='100%'/> <use xlink:href='#c' y='100%'/> <use xlink:href='#c' x='100%' y='100%'/>
看到這里,是不是會覺得比使用::before偽元素要來得簡便,而且也非常方便,就算你要移去一個或多個凹角(示例效果的紫色部分),你只需要少使用幾個<use>去克隆就行了。



從上例效果中可以看到,.box的四個角落都圓圈在那了,但這并不是我們想要的凹角,對吧!不要納悶了,我們的做法是對的。請接著往下看。接下來要做的就是把這些圓圈放到一個<mask>中,給這個<mask>設置一個white的填充色(fill屬性來搞定)。同時在其里面使用<rect>元素設置一個和SVG元素一樣大小的矩形,主要用來覆蓋整個SVG。然后我們在另一個再次使用<use>來調用這個已創建好的<mask>



<mask id='m' fill='#fff'><rect id='r' width='100%' height='100%'/><circle id='c' r='50' fill='#000'/><use xlink:href='#c' x='100%'/><use xlink:href='#c' y='100%'/><use xlink:href='#c' x='100%' y='100%'/> </mask> <use xlink:href='#r' fill='#f90' mask='url(#m)'/>
最終效果如下:



同樣的,我錄制了一個動圖來演示效果中的每一個元素:

特別注意:如果.box中有內容,建議放置在svg元素之后。當然也可以放置在其前面,如果放置在前面,svg在做定位時,需要顯式的設置top、right、bottom和left之類的值。至于為什么,這里不做過多的闡述,感興趣的同學可以自己去深究其中的為什么。

如果.box有文本,需要把.box的padding的值和圓角的半徑設置相同,同樣的,如果使用了CSS自定義屬性,可以使用JavaScript來控制它。最好把圓的半徑和.box的padding使用同一個CSS自定義屬性--r。這樣會更好的控制一點:


我喜歡的就是CSS

或許你會說,我不懂SVG,我就是想使用CSS來實現。其實很高興你能這樣的深究與思考。事實上我們的確可以使用CSS來實現這樣的效果。

遺憾的是,使用CSS的方案目前為止并不是所有瀏覽器都能支持,但使用CSS讓我們把事情變得更簡化,而且在不遠的將來,它們肯定是能得到眾多瀏覽器支持的。

在HTML元素上使用CSS的mask

這里我們移除SVG所有的東西,然后使用CSS,可以在.box元素上設置一個background(可以是一個純色、半透明、漸變、圖像或者多背景,甚至是你任何你想要的CSS)和mask屬性。


.box {/* any kind of background we wish */mask: url(#m); }

使用CSS設置圓半徑

這意味著,需要把<circle>中的r屬性刪除,然后在CSS中給其設置半徑的大小,這里設置的半徑大小與.box容器的padding值一樣:


.box { padding: var(--r); }[id='c'] { r: var(--r); }

這樣一來,如果我們改變半么--r的值,凹角的大小和.box的padding也會隨著更新。

注意,在CSS中給SVG元素設置幾何屬性只在Blink瀏覽器中有效!

結合前兩種方法

雖然這很酷,但遺憾的是目前在任何瀏覽器中都看不到效果。但值得慶幸的是我們可以做得更好!

使用漸變來做朦層

Note that CSS masking on HTML elements doesn't work at all in Edge at this point, though it's?listed as "In Development"?and a flag for it (that doesn't do anything for now)?has already shown up?in?about:flags.

由于我們需要完全拋棄SVG,所以我們需要使用CSS的漸變為mask做些事情。這里將使用CSS徑向漸變來畫圓,下面就是CSS繪制的一個半徑為--r的圓,并且這個圓位于.box的左上角。


.box {background: radial-gradient(circle at 0 0, #000 var(--r, 50px), transparent 0); }

如果您對CSS的漸變不太了解,建議您花點時間閱讀這幾篇文章:《再說CSS3漸變:線性漸變》、《再說CSS3漸變:徑向漸變》、《為什么要使用repeating-linear-gradient》、《?你真的理解CSS的linear-gradient?》。

這個時候你可以看到像上面這樣的一個效果:

接下來在mask使用相同的漸變:


.box {/* same as before *//* any CSS background we wish */mask: radial-gradient(circle at 0 0, #000 var(--r, 50px), transparent 0); }

注意,Webkit瀏覽器仍然需要給mask屬性添加-webkit-前綴。如果你不知道mask怎么使用,建議你花點時間閱讀《如何在CSS中使用遮罩》一文。因為后面很多內容都會涉及到這個屬性,這樣能幫助更好的理解后續的內容。

給.box每個角落都添加漸變繪制的圓:

$grad-list: radial-gradient(circle at 0 0 , #000 var(--r, 50px), transparent 0), radial-gradient(circle at 100% 0 , #000 var(--r, 50px), transparent 0), radial-gradient(circle at 0 100%, #000 var(--r, 50px), transparent 0), radial-gradient(circle at 100% 100%, #000 var(--r, 50px), transparent 0); .box {/* same as before *//* any CSS background we wish */mask: $grad-list }看到上面的代碼是不是感覺要崩潰了,有太多重復的代碼要寫,其實我們使用一個CSS自定義屬性--stop-list可以讓我們把事情簡化不少:


$grad-list: radial-gradient(circle at 0 0 , var(--stop-list)), radial-gradient(circle at 100% 0 , var(--stop-list)), radial-gradient(circle at 0 100%, var(--stop-list)), radial-gradient(circle at 100% 100%, var(--stop-list));.box {/* same as before *//* any CSS background we wish */--stop-list: #000 var(--r, 50px), transparent 0;mask: $grad-list; }
上面這樣做還不是很好,可以借助CSS處理器的循環特性來做,會更好一些:


$grad-list: ();@for $i from 0 to 4 {$grad-list: $grad-list, radial-gradient(circle at ($i%2)*100% floor($i/2)*100%, var(--stop-list)); }.box {/* same as before *//* any CSS background we wish */--stop-list: #000 var(--r, 50px), transparent 0;mask: $grad-list; }

就代碼而言,這樣寫已經很完美了。因為我們不需要多次編寫,并且以后在任何地方使用都不需要做任何更改。但到目前為止的結果并不是我們想要的:

從上面的示例中可以看出,我們除了凹角部分之外的東西都剪切掉了,這正好和我們想要的東西相反。要得到我們想要的效果,咱們只需要做一件事情,把漸變反過來。讓凹角的圓變成透明,剩余的部分全部是黑色

--stop-list: transparent var(--r, 50px), #000 0;

需要注意的是,如果我們只使用一個漸變的時候,那么上面的代碼就幫我們解決了問題:

但是,當我們把所有的四個圓圈(甚至兩個)都堆起來的時候,就會得到一個黑色的矩形,這個矩形的大小相當于我們的mask的大小,這意味著沒有任何東西會被掩蓋掉。

因此,我們需要把每個漸變的大小限制在盒子的四分之處(width的50%和height的50%),從而得到25%的面積:

這個意思就是,我們需要設置mask-size的值為50% 50%,同時mask-repeat的值為no-repeat以及每個mask-image自身的位置。

$grad-list: ();@for $i from 0 to 4 {$x: ($i%2)*100%;$y: floor($i/2)*100%;$grad-list: $grad-list radial-gradient(circle at $x $y, var(--stop-list)) /* mask image */$x $y; /* mask position */ }.box {/* same as before *//* any CSS background we wish */--stop-list: transparent var(--r, 50px), #000 0;mask: $grad-list;mask-size: 50% 50%;mask-repeat: no-repeat; }

但這里有一個大問題,一般情況下,我們的四分之一計算的每個部分會經過四舍五入,那么這四個部分重新組合在一起的時候,width和height都有可能產生間距。如下圖所示:

好吧,我們不能用linear-gradient()來做這個線條或者說把mask-size的尺寸增加到51%。比如下面的這個示例,增加了mask-size的尺寸來處理四個漸變區載之間的間距。

但是,難道沒有更優雅的方式來處理這個間距?不是的,可以使用mask-composite屬性來幫我們處理。當我們返回全部漸變的全尺寸時,可以把mask-composite的值設置為intersect。

$grad-list: ();@for $i from 0 to 4 {$grad-list: $grad-list, radial-gradient(circle at ($i%2)*100% floor($i/2)*100%, var(--stop-list)); }.box {/* same as before *//* any CSS background we wish */--stop-list: transparent var(--r, 50px), #000 0;mask: $grad-list;mask-composite: exclude; }

這非常酷,因為它是純CSS的解決方案,沒有使用任何SVG代碼,但不幸的是,目前得能看到效果的也僅限于Firefox53+。

corner-shape

大約在五年前,@Lea Verou提出了一個想法,甚至還為它創建了一個預覽頁面。遺憾的是,它不僅沒有被任何瀏覽器實現,而且在此期規范還沒有得到很大的提高。對于未來,它仍然是值得期待的,因為它提供了很多靈活性,而且代碼非常少。比如說,實現我們前面所說的效果,只需要以下幾行代碼:

padding: var(--r); corner-shape: scoop; border-radius: var(--r);

就是一個非常簡單的CSS。是不是值得期待,但最終還是要看瀏覽器什么時候會對其支持。

CSS Houdini

CSS Houdini慢慢的開始進入大家的世界當中,試問一下,我們使用CSS Houdini是不是可以更方便的實現這個內凹角的效果呢?比如像下面這樣的一個效果,它就是使用CSS Houdini實現的:

咱們不仿嘗試一下使用Paint Worklet或者CSS Paint API來實現呢?請開動你的大腦,動手擼一擼。希望您能把你的成果在下面的評論中與大家一起分享?如果你感興趣,也可以在下面的評論中留言,我們后續可以專門花一點時間來看看CSS Houdini可以實現內凹角的效果,甚至是前面所講的斜外切口的效果。

構建一個內凹角的Vue組件

記得在《使用Vue制作切口盒子組件》一文中,咱們就嘗試使用Vue構建了一個斜外切口的Vue組件c-noth:

那么我們來看看怎么使用Vue來構建一個內凹角的組件,具體代碼如下:

特別聲明,如果您的瀏覽器沒有看到任何效果,請使用Firefox 53+瀏覽器查閱。具體原因,前面文章已經介紹過來了。

為了照顧其他同學查看最終的效果,我錄了一個屏:

這就是最終的效果。由于我自己是Vue的初學者,現在有一個病,看到什么東西都想用Vue來寫,而且想封裝成一個組件。如果寫得不好,或者有更好的方案,歡迎大家指點,并且希望能看到您的分享的成果。如果你和我一樣,也是Vue的一個初學者,可以和我一起來學習Vue。整理了一些有關于Vue的學習筆記,希望大家能喜歡,更希望能幫助到初學者,同時也希望不會誤人子弟。

總結

文章開頭拋出了怎么實現內凹角的一個效果。首先從CSS的box-shadow著手,使用CSS的box-shadow可以輕易的實現內凹角的效果,但這個方案有一定的局限性,比如要多個內凹角時,需要通過增加元素標簽來實現,特別是在面對漸變,或者有背景圖像和半透明的情景之下,這個方案基本上無法來滿足我們的需求。

接著探索了SVG的方案,通過SVG的mask和use之類的一些獨有的特性,可能靈活的幫助我們實現想要的效果,而且能做到box-shadow無法做到的事情。特別是通過CSS自定義屬性來修改SVG的屬性,讓事情變得更具靈活性,只不過部分瀏覽器還不支持CSS來修改SVG的屬性,這算是其中的一個坑吧。不過我們還是可以規避掉的。

雖然SVG能實現想要的效果,但對于一位CSS執著者而言,總是希望不借助其他的外力,通過純CSS來實現這個效果,事實上也是可以的,使用CSS的徑向漸變和mask相關的知識,可以實現我們想要的效果。遺憾的是,目前眾多瀏覽器對mask還是有所保留,未能全面支持。比如文中提到的,很多mask相關的特性,僅能在Firefox 53+上看到。包括咱們寫的示例,有些僅能在Firefox上看到。

隨著CSS Houdini技術越來越成熟,我在試想,是否可以通過CSS Houdini來實現。正如@Lea Verou五年前提出的corner-shape屬性。我想是可以的,后面可以嘗試動手寫寫。當然,CSS Houdini雖然還沒有得到所有瀏覽器支持,但這并不防礙我們去嘗試著寫各種效果。有興趣的一起動手寫寫,看看這個想法是否能成真。

最后為了能練習Vue相關的知識,嘗試使用Vue封裝了一個簡單的凹角組件。寫得比較拙逼,希望能得到大神的指點。

最后的最后,需要特別感謝@ANA TUDOR寫了這么優秀的教程。我在原作者的基礎上做過一些調整,如果你覺得這里整理和不好,可以查閱原文。

大漠

常用昵稱“大漠”,W3CPlus創始人,目前就職于手淘。對HTML5、CSS3和Sass等前端腳本語言有非常深入的認識和豐富的實踐經驗,尤其專注對CSS3的研究,是國內最早研究和使用CSS3技術的一批人。CSS3、Sass和Drupal中國布道者。2014年出版《圖解CSS3:核心技術與案例實戰》。



原文發布時間為:2018年04月23日
原文作者:掘金

本文來源:?掘金?如需轉載請聯系原作者




總結

以上是生活随笔為你收集整理的CSS如何实现内凹角效果 By 大漠的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。