CSS3 box-shadow介紹

我對任何美的東西都會本能地生出一種愛,在CSS的世界里,凡和色彩漸變等沾邊的屬性都是我的菜。因此box-shadow這個屬性怎能放過。本篇就詳細介紹一下box-shadow盒子陰影。

按例先看一下基本參數:

none:是默認值,表示沒陰影。設為none后下面參數都將變得無意義。

inset:內陰影。該參數可選,不設的話默認是外陰影。

x-offset / y-offset:必須的參數。水平和垂直陰影的偏移量。正值表示往x軸y軸正方向偏移(即往右往下)。負值反過來往x軸y軸反方向偏移(即往左往上)。

blur-radius:陰影模糊半徑。該參數可選,值為0表示不模糊,值越大,陰影的邊緣就越模糊。值不能為負數。

spread-radius:陰影擴展半徑。該參數可選,正值表示陰影擴展,負值表示陰影縮小。

color:陰影顏色。該參數可選,不設就取瀏覽器的默認色。因為各瀏覽器的默認色不同,推薦還是設一下,設一下又不會懷孕...

完整的語法box-shadow: [inset x-offset y-offset blur-radius spread-radius color]+ 熟悉正則表達式的能看懂后面+號表示可以設多個陰影。

理論是枯燥的,實際來試試。先來個最簡單的,只設必選參數x-offset / y-offset和非必須但推薦設一下的color

.box-shadow {
    width: 150px;
    height: 50px;
    border-radius: 10px;
    border: 1px solid #b9b9b9;
    box-shadow: 5px 10px red;
}
<div class="box-shadow"></div>

效果一目了然。當x-offset / y-offset是正值時,陰影向x軸y軸正方向偏移。即相右偏移5px,向下偏移10px。同理x-offset / y-offset為負值時,陰影向x軸y軸負方向偏移。例如box-shadow: -5px -10px red;

x-offset / y-offset一正一負呢?看看就知道了。左圖box-shadow: -5px 10px red;右圖box-shadow: 5px -10px red;
上面都是兩邊陰影,要單邊陰影呢?將x-offset / y-offset其中一個設為0即可,請自行腦補一下圖片。

加上blur-radius模糊半徑試試:左圖box-shadow: 5px 10px 10px red;中圖box-shadow: 5px 10px 20px red;右圖box-shadow: 5px 10px 50px red;

很明顯看出增加了blur-radius模糊半徑后,原本的實體陰影其實往外擴展了,尤其是右圖模糊半徑設成50px后擴展的更為明顯,邊框的4條邊都有了陰影效果。你可以試試模糊半徑改成100px,500px,你會感覺生無可戀…

那為何陰影會外擴呢?那就必須解釋一下瀏覽器實現陰影的原理,當瀏覽器讀取到上面box-shadow: 5px 10px 10px red;這行CSS代碼后,會分如下4步來實現陰影效果:

上圖從左至右依次是瀏覽器的4步動作。首先根據指定的color克隆一個和原始元素同樣尺寸的元素。然后根據指定的x-offset / y-offset將克隆出來的元素進行偏移。

第三步根據指定的blur-radius模糊半徑10px,依據高斯算法進行模糊處理。本質上是在陰影邊緣將陰影色和純透明色之間的顏色過渡,長度近似于blur-radius模糊半徑的兩倍,即20px左右。這就是導致陰影外擴的原因。

最后,瀏覽器在克隆元素上,將交集部分剪切掉,剩余部分拼接到原始元素邊上,就實現了最終的效果。注意這和我們看上去的有的不同,看上去像是兩個元素疊加在了一次,導致下層的克隆元素部分被遮蓋了。其實不是的。這意味著即使你將原始元素的背景色設成半透明,也不會看到底層的克隆元素,因為原始元素的下面根本沒有任何東西。

如果你想限制模糊半徑的范圍,如單邊模糊時,你就需要加上spread-radius陰影擴展半徑。左圖box-shadow: 0 10px 20px red;。雖然只設了y軸偏移,但由于陰影外擴導致3邊都出現了陰影。右圖box-shadow: 0 10px 20px -10px red;。通過spread-radius負值讓陰影縮小,-10px會把陰影的左右寬度和上下高度均縮小10px,即寬度和高度均縮小20px。

spread-radius的負值和blur-radius的值相等時,陰影會消失。

如果blur-radius為0(表示不模糊陰影),只有spread-radius時,效果相當于border。例如下圖box-shadow: 0 0 0 5px red;。當然這并不是真正的border,盒子模型計算時寬高不會被計算在內,因此文字hello和陰影重疊了,如果是真的border是不會重疊的。

陰影默認都是外陰影,你可以設inset將陰影指定為內陰影。例如左圖box-shadow: inset 0 0 20px red;右圖box-shadow: inset 0 0 20px 10px red;

但當給圖片加上內陰影會發現毫無作用,例如左圖:

/* 左圖 */
.div1 {
    display: inline-block; 
    box-shadow: inset 0 0 10px 5px blue;
}
<div class="div1">
    <imgsrc="head.png" />
</div>

左圖div容器雖然已經設了內陰影,但完全沒有效果。其實內陰影已經有了,只不過被圖片給遮住了而已。要實現右圖效果,你可以:

方案一:將子元素img層級降低,所以先將其設成relative再設z-index為-1

.div1 {
    display: inline-block; 
    box-shadow: inset 0 0 10px 5px blue;
}
.img1 {
    position: relative;
    z-index: -1;
}
<div class="div1">
    ![](head.png)
</div>

方案二:將子元素img改成父元素div的background-img,所以先給div定寬高,再設background-image。關于background屬性你可以點擊這里

.div1 {
    width:150px;
    height: 150px;
    display: inline-block; 
    box-shadow: inset 0 0 10px 5px blue;
    background-image: url("head.png");
}
<div class="div1"></div>    //里面不再需要img子元素啦

方案一利用了CSS的層級關系,你可以理解為大層級關系

方案二其實是利用了box-shadow的層級關系,你可以理解為小層級關系。box-shadow的層級關系看W3C的原圖:

width: 100px; height: 100px;
border: 12px solid blue; background-color: orange;
border-top-left-radius: 60px 90px;
border-bottom-right-radius: 60px 90px;
box-shadow: 64px 64px 12px 40px rgba(0,0,0,0.4),
            12px 12px 0px 8px rgba(0,0,0,0.4) inset;

圖中看出box-shadow的層級關系從高到低依次是border > 內陰影 > background-image > background-color > 外陰影。方案二就是利用了內陰影 > background-image這一特性。

像background一樣,你還可以指定多層陰影,用逗號隔開。實現方式就是兩個0偏移量和0模糊值加上正值的擴張半徑。這也是實現多重邊框的常見手段。彩虹走一個~


.box-shadow {
    width: 150px;
    height: 50px;
    border:2px solid red;
    box-shadow: 0 0 0 2px orange,
                0 0 0 4px yellow,
                0 0 0 6px green,
                0 0 0 8px #66CCCC,
                0 0 0 10px blue,
                0 0 0 12px #996699;
}
<div class="box-shadow"></div>

多層陰影的一個很常見的例子就是實現兩側陰影:


box-shadow: 6px 0 5px -5px red,
            -6px 0 5px -5px red;

上面介紹的不論是單邊還是多邊陰影,不論是單層還是多層陰影,都是均勻的陰影。下面來介紹一下單邊不均勻的陰影是如何實現的。

其實單邊不均勻的陰影不是僅靠box-shadow屬性就能實現的,還需要配合圖層覆蓋和部分動畫(如旋轉)。如下圖,下邊的陰影是不均勻的,左下和右下的陰影明顯比中間更突出:


分幾步來講解如何實現的:


step0是普通的div,沒什么好多講的,源代碼如下:
body {
    background: #eee;
}
.box {
    width:200px;
    height:100px;
    background:#FFF;
    margin:10px;
    line-height:100px; 
    text-align:center;
    position: relative;  /*為下面absolute定位做準備*/
}
<div class="box">step 0</div>

從step1開始實現不均勻的陰影效果。先給div加上::before::after兩個偽元素,內容為空,我們只要偽元素的軀殼,并不真想讓偽元素顯示出來。(偽元素里的紅色border純粹是為了看起來更清晰,最后會刪掉的。)

.effect::before, .effect::after {
    content: "";
    border:1px solid red;
    width: 50%;
}
<div class="box effect">step 1</div>

再看step2,為兩個偽元素增加absolute定位。通過lefttopabsolute元素定位,通過bottom拉伸absolute元素。(關于absolute定位可以參照這里

.effect::before, .effect::after {
    content: "";
    border:1px solid red;
    width: 50%;
    position: absolute;
    left: 10px;
    top: 80%;
    bottom: 15px;
}

step2中定位后::before::after兩個偽元素完全重合在了一起,因此在step3中為::after指定right位置將它倆分開:

.effect::after {
    right: 10px;
    left: auto;
}

step3中兩個偽元素一左一右分開后,在step4中讓它倆稍微旋轉一點角度,并加上本篇介紹的陰影:

.effect::before, .effect::after {
    content: "";
    border:1px solid red;
    width: 50%;
    position: absolute;
    left: 10px;
    top: 80%;
    bottom: 15px;
    transform: rotate(-5deg);    /*旋轉*/
    box-shadow: 0 15px 10px #777; /*陰影*/
}
.effect::after {
    transform: rotate(5deg);   /*旋轉*/
    right: 10px;
    left: auto;
}

到step4其實已經能明白不均勻陰影的實現原理了,最后一步設置z-index:-1;將偽元素隱藏掉(為演示效果而加的紅色邊框直接刪掉)。最終代碼:

.effect::before, .effect::after {
    content: "";
    width: 50%;
    position: absolute;
    left: 10px;
    top: 80%;
    bottom: 15px;
    transform: rotate(-5deg);
    box-shadow: 0 15px 10px #777;
    z-index: -1;
}
.effect::after {
    transform: rotate(5deg);
    right: 10px;
    left: auto;
}

總結

box-shadow屬性本身參數不算多(相對其他屬性),但要用好不容易。我承認憑腦子想就能寫出效果并不容易,所以網上有一堆可視化頁面可自動生成box-shadow效果,例如可以到css3gen上去試試。但能明白每個參數的意義,改動起來會容易點。權威請參考W3CMDN

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容