我對任何美的東西都會本能地生出一種愛,在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步來實現陰影效果:
第三步根據指定的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">

</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屬性就能實現的,還需要配合圖層覆蓋和部分動畫(如旋轉)。如下圖,下邊的陰影是不均勻的,左下和右下的陰影明顯比中間更突出:
分幾步來講解如何實現的:
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>
absolute
定位。通過left
和top
為absolute
元素定位,通過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上去試試。但能明白每個參數的意義,改動起來會容易點。權威請參考W3C和MDN。