文章出處

前言

 說起box-shadow那第一個想法當然就是用來實現陰影,其實它還能用于實現其他好玩的效果的,本篇就打算說說box-shadow的那些事。

二話不說看效果

3D小球

<style type="text/css">
.ball{
  background: rgba(100,100,100,0.2);
  width: 100px;
  height: 100px;
  padding: 10px;
  border-radius: 50%;
  box-shadow: -14px 8px 100px #333 inset, 
              0 0 2px #888,
          3px -1px 4px #444;
}
</style>
<div class="ball"></div>

紙張陰影(來自@張鑫旭老師)

<style type="text/css">
.curved_box {
    display: inline-block;
    *display: inline;
    width: 200px;
    height: 248px;
    margin: 20px;
    background-color: #fff;
    border: 1px solid #eee;
    -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 60px rgba(0, 0, 0, 0.06) inset;
    -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset; 
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset;
    position: relative;
    *zoom: 1;
}

.curved_box:before {
    -webkit-transform: skew(-15deg) rotate(-6deg);
    -moz-transform: skew(-15deg) rotate(-6deg);
    transform: skew(-15deg) rotate(-6deg);
    left: 15px;
}
.curved_box:after {
    -webkit-transform: skew(15deg) rotate(6deg);
    -moz-transform: skew(15deg) rotate(6deg);
    transform: skew(15deg) rotate(6deg);
    right: 15px;
}

.curved_box:before, .curved_box:after {
    width: 70%;
    height: 55%;
    content: ' ';
    
    -webkit-box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
    -moz-box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3); 
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
    
    position: absolute;
    bottom: 10px;
    z-index: -1;    
}
</style>
<div class="curved_box"></div>

細讀屬性

 看到上面這么絢麗的效果,是不是迫不及待想弄清box-shadow呢?下面我們來一步步解密它吧!

概述屬性語法

box-shadow: none | <shadow>[,<shadow>]*
默認值為none
<shadow>:inset? && <length>{2,4} && <color>?
shadow pattern,默認為outset,即采用outer box-shadow。通過設置為inset時,則采用inner box-shadow。
horizontal offset,陰影距離原位置的水平位移,正數表示向右移動,負數表示向左移動。
vertical offset,陰影距離原位置的垂直位移,正數表示向下移動,負數表示向上移動。
blur radius,默認值為0,陰影模糊度半徑。
spread distance,默認值為0,擴展或縮小陰影的作用面積。
<color>,陰影顏色,默認與color屬性一致。

注意:我們可以同時設置多個陰影,而陰影的z-index值從左向右遞減。

outer box-shadow 和 inner box-shadow怎么玩?

 默認情況下采用的是outer box-shadow,當在box-shadow中添加inset關鍵詞后,則采用inner box-shadow了,但到底它倆的效果是如何的呢?

<style type="text/css">
.box{
  float: left;

  background: #888;
  width: 100px;
  height: 100px;
  margin-right: 20px;
}
.outer-box-shadow{
  box-shadow: 10px 10px #F00;
}
.inner-box-shadow{
  box-shadow: 10px 10px #F00 inset;
}
</style>
<div class="box outer-box-shadow"></div>
<div class="box inner-box-shadow"></div>
</div>

outer-box-shadow
特點:陰影落在元素的border box之外。
實現原理:

  1. 創建一個與元素border box尺寸一致的陰影盒子;
  2. 將陰影盒子定位到于元素border box重合,并位于元素之下;
  3. 根據horizontal offsetvertical offset來相對原位置作移動;
  4. 根據spread distance縮放陰影盒子的尺寸(會影響盒子的位移);
  5. 根據blur radius對陰影盒子作加工;
  6. 最后將陰影盒子與元素border box重合部分剪切掉。

    <style type="text/css">
    .box{
      background: #888;
      width: 100px;
      height: 100px;
    }
    .outer-box-shadow{
      box-shadow: 90px 10px #F00;
    }
    </style>
    <div class="box outer-box-shadow"></div>
    </div>

    模擬一下:

    <style type="text/css">
    .box{
      position: relative;
    }
    .box-shadow{
      position: absolute;
      z-index: -1;
      background: #F00;
      width: 100px;
      height: 100px;
      left: 20px;
      top: 20px;
    }
    .box-content{
      background: #888;
      width: 100px;
      height: 100px;
    }
    </style>
    <div class="box">
      <div class="box-shadow"></div>
      <div class="box-content"></div>
    </div>

inner-box-shadow
特點:陰影落在元素的padding box之內。
實現原理(純個人理解):

  1. 創建一個與元素padding box尺寸一致的陰影盒子;
  2. 將陰影盒子定位到于元素padding box重合,并位于元素之上;
  3. 水平和垂直各畫兩條線,分別跟元素padding edge重合;(共4條分別記為left/top/right/bottom-guideline)
  4. 根據horizontal offsetvertical offset移動left/top/right/bottom-guideline。
  5. 根據spread distance移動4條線。spread distance為正數時,left-guideline向右移動,top-guideline向下移動,right-guideline向左移動和bottom-guidelien向上移動;spread distance為負數時,則相反。
  6. 根據blur radius加工元素各padding edge至其對應的guideline間的區域.
  7. 對陰影盒子進行剪裁
  8. 剪切掉不與元素padding box重疊的部分;
  9. 僅顯示元素各padding edge至其對應的guideline間的區域。

    <style type="text/css">
    .box{
      float: left;
      background: #888;
      width: 100px;
      height: 100px;
      margin-right: 10px;
    }
    .box1{
      box-shadow: 0 0 0 20px red inset;
    }
    .box2{
      box-shadow: 10px 0 0 20px red inset;
    }
    .box3{
      box-shadow: 10px 0 10px 20px red inset;
    }
    .box4{
      box-shadow: 0 0 10px 50px red inset;
    }
    </style>
    <div class="box box1"></div>
    <div class="box box2"></div>
    <div class="box box3"></div>
    <div class="box box4"></div>

    模擬一下:

    <style type="text/css">
    .box-shadow{
      position: relative;
      display: inline-block;
      background: red;
      overflow: hidden;
    }
    .bg{
      position: absolute;
      background: #888;
      left: 30px;
      right: 10px;
      top: 20px;
      bottom: 20px;
    }
    .content{
      position: relative;
      z-index: 1;
      width: 80px;
      height: 80px;
      padding: 20px;
    }
    </style>
    <div class="box-shadow">
      <div class="bg"></div>
      <div class="content"></div>
    </div>

模糊邊框 by blur radius

 W3C spec中沒有規定瀏覽器廠商使用哪種方式實現模糊效果,反正效果與高斯模糊效果差不多就是了。但有一點我們需要注意的,那就是模糊效果會擴大陰影的面積

<style type="text/css">
.outline{
  border: 1px solid red;
  margin: 40px 0;
}
.s{
  background: rgba(255, 100, 100, 0.1);
  width: 100px;
  height: 100px;
}
.s1{
  box-shadow: 110px 0 0 #333;
}
.s2{
  box-shadow: 110px 0 20px #333;
}
.s3{
  box-shadow: 110px 0 40px #333;
}
</style>
<div class="outline">
  <div class="s s1">sample1</div>
</div>
<div class="outline">
  <div class="s s2">sample2</div>
</div>
<div class="outline">
  <div class="s s3">sample3</div>
</div>

sample1是blur radius為0的效果,可以看到陰影尺寸與元素尺寸一模一樣。而sample2是blur radius為20px的效果,可以看到陰影尺寸有所擴展了,而sample3則擴展得更多一些。
 現在我們感性上認知到blur radius值大于0時會擴展陰影尺寸,那么到底擴展多少呢?那我們要先明確模糊發生的起始位置了。

  1. 對于outer-shadow-box而言,模糊發生的起始位置就是陰影盒子的各邊;
  2. 對于inner-shadow-box而言,模糊發生的起始位置就是各guideline。
     然后模糊效果是從發生的位置,對于水平方向的邊或guideline則向垂直方向發散,對于垂直方向的邊或guideline則向水平方向發散,且發散的距離相同。
     發散的距離相同,因此每個方向各發散為blur radius/2的距離。看sample3中陰影尺寸已經與元素盒子重疊了,因為陰影盒子左邊框向左發散了20px了,超過它倆之間10px的水平距離了,而sample2則恰恰鄰近而已。

縮放陰影尺寸 by spread distance

 如果說blur radius是暗地里擴大陰影的尺寸,那么spread distance則是明目張膽地縮放陰影的尺寸了。

<style type="text/css">
.outline{
  border: 1px solid red;
  margin: 40px 0;
}
.s{
  background: rgba(255, 100, 100, 0.1);
  width: 100px;
  height: 100px;
}
.s1{
  box-shadow: 110px 0 0 #333;
}
.s2{
  box-shadow: 110px 0 0 10px #333;
}
.s3{
  box-shadow: 110px 0 0 -10px #333;
}
</style>
<div class="outline">
  <div class="s s1">sample1</div>
</div>
<div class="outline">
  <div class="s s2">sample2</div>
</div>
<div class="outline">
  <div class="s s3">sample3</div>
</div>

 還記得《CSS魔法堂:重拾Border之——解構Border》中提及通過border-top/right/bottom/left-colors實現彩虹邊框嗎?由于兼容性問題和1px對應一種color的緣故,實際應用得很少,但通過outer-box-shadow和spread distance我們就可以得到效果更好,兼容性很高的實現方案了。

<style type="text/css">
.rainbow{
  margin: 50px;
  width: 100px;
  height: 100px;
  box-shadow: 0 0 0 2px rgb(255,0,0),
              0 0 0 5px rgb(255,165,0),
              0 0 0 8px rgb(255,255,0),
              0 0 0 10px rgb(0,255,0),
              0 0 0 12px rgb(0,127,255),
              0 0 0 15px rgb(0,0,255),
              0 0 0 20px rgb(139,0,255);
}
</style>
<div class="rainbow"></div>

弄清各圖層的z-index


 上圖可以看到沒有陰影時,各圖層的z-index順序。那么陰影呢?

  1. 對于outer-box-shadow,則其z-index高于margin圖層,低于background-color圖層;
  2. 對于inner-box-shadow,則其z-index高于padding圖層,低于content圖層。

陰影的position

 通過horizontal/vertical offset重定位陰影盒子,通過blur radiusspread distance縮放陰影盒子的尺寸,但請注意的是陰影盒子不影響其他盒子的布局,其實陰影盒子就相當于采用absolute定位一樣,不會占據Normal flow的空間,也不會影響其他元素的布局,因此僅修改陰影位置或尺寸時,只會觸發repaint,而不會觸發reflow。

圓角or直角box-shadow傻傻分不清楚?

 陰影不僅默認尺寸與元素盒子一致,默認形狀也一致。也就是元素盒子采用圓角時,陰影的默認形狀也是圓角的。既然說是默認形狀一致,就是說可以不一致咯!那到底如何不一致呢,下面我們一起來看個究竟吧!

<style type="text/css">
.s1{
  background: #0EF;
  width: 100px;
  height: 100px;
  border-radius: 10px;
  box-shadow: 110px 0 0 -10px #333,
        220px 0 0 0 #666,
        360px 0 0 20px #888;
}
</style>
<div class="s1">sample1</div>

當設置spread distance后,border-radius的值也將隨之變化,具體公式為border-radius + spread-distance * (1 + (border-radius / spread-distance - 1)^3)
因此spread distance為正數時,border-radius會變大; 而spread distance為負數時,border-radius會減小,直至為0px為止。

被割裂的box-shadow

 當設置box-shadow的盒子被拆分為多個盒子時,其對應的box-shadow又會如何呢?其實這不僅僅是box-shadow的問題,如border、background-image等均會遇到同樣的問題。CSS3中引入一個新特性box-decoration-break來設置上述情況時的渲染效果。
box-decoration-break: slice | clone
slice是默認值,表示首先按未拆分時的狀態渲染border、background-image等樣式,然后再將其直接拆分為多個盒子;
clone表示首先將其直接拆分為多個盒子,然后再逐個盒子渲染border、background-image等樣式。

<style type="text/css">
.intro{
  font-size: 14px;
  line-height: 1.5;
  text-indent: 1em;
  width: 300px;
}
.intro span{
  border: 1px solid #666;
  border-radius: 5px;
  box-shadow: 5px 3px 3px #AAA;
}
.slice{
  -webkit-box-decoration-break: slice;
}
.clone{
  -webkit-box-decoration-break: clone;
}
</style>
<p class="intro">
<span class="slice">
Hey there, welcome to be here to share something aboute CSS together:) My name is fsjohnhuang, a FE from Midea. Enjoy the evolution of FE, and feel excited in the work I'm doing now.
</span>
</p>
<p class="intro">
<span class="clone">
Hey there, welcome to be here to share something aboute CSS together:) My name is fsjohnhuang, a FE from Midea. Enjoy the evolution of FE, and feel excited in the work I'm doing now.
</span>
</p>

 從上面可以看到,與其說box-decoration-break的屬性值影響box-shadow的效果,還不如說是box-decoration-break的屬性值影響border-radiusborder作用到元素盒子的效果,然后由盒子的效果再間接影響box-shadow的效果。

兼容性

IE和Edge均不支持,FF支持得最好,而Webkit內核的則要加-webkit-前綴。
對于不支持的瀏覽器,其效果如同box-decoration-break:slice

兼容性


IE9都支持box-shadow多讓人可喜可賀的消息啊(因為我工作中只需兼容IE9+就Ok了:))。但IE6~8呢?方案很多啦,上面也有簡單的介紹到。@張鑫旭老師提到在模擬blur radius效果時,采用以下方案

.ieBlock{
    height:100px;
    width:100px;
    background:#000;
    filter:progid:DXImageTransform.Microsoft.Blur(pixelradius=10);
    -ms-filter:"progid:DXImageTransform.Microsoft.Blur(pixelradius=10)"; 
}

要比采用以下方案要好!

.shadow {
    -moz-box-shadow: 3px 3px 4px #000;
    -webkit-box-shadow: 3px 3px 4px #000;
    box-shadow: 3px 3px 4px #000;
    /* For IE 8 */
    -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#000000')";
    /* For IE 5.5 - 7 */
    filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#000000');
}

 另外若想不假思索地用到生產環境中,還是用成熟的CSS庫較好。具體請參考
PIE使IE支持CSS3圓角盒陰影與漸變渲染

總結

 尊重原創,轉載請注明來自:http://www.cnblogs.com/fsjohnhuang/p/5477194.html^_^肥仔John

感謝

the-box-shadow
break-decoration
CSS3 box-shadow實現紙張的曲線投影效果
CSS實現跨瀏覽器兼容性的盒陰影效果
CSS實現跨瀏覽器的box-shadow盒陰影效果(2)
PIE使IE支持CSS3圓角盒陰影與漸變渲染
《圖解CSS3核心技術與案例實戰》 —— 3.5 CSS3盒子陰影屬性


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()