前言

 说起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 offset和vertical 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 offset和vertical 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. 对阴影盒子进行剪裁
    1. 剪切掉不与元素padding box重叠的部分;
    2. 仅显示元素各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 radius或spread 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-radius和border作用到元素盒子的效果,然后由盒子的效果再间接影响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盒子阴影属性

CSS魔法堂:Box-Shadow没那么简单啦:)的更多相关文章

  1. CSS魔法堂:小结一下Box Model与Positioning Scheme

    前言  对于Box Model和Positioning Scheme中3种定位模式的细节,已经通过以下几篇文章记录了我对其的理解和思考.  <CSS魔法堂:重新认识Box Model.IFC.B ...

  2. CSS魔法堂:说说Float那个被埋没的志向

    前言  定位系统中第一难理解就是Normal flow,而第二就非Float莫属了,而Float难理解的原因有俩,1. 一开头我们就用错了:2. 它跟Normal flow靠得太近了.本文尝试理清Fl ...

  3. CSS魔法堂:更丰富的前端动效by CSS Animation

    前言  在<CSS魔法堂:Transition就这么好玩>中我们了解到对于简单的补间动画,我们可以通过transition实现.那到底多简单的动画适合用transtion来实现呢?答案就是 ...

  4. CSS魔法堂:"那不是bug,是你不懂我!" by inline-block

    前言  每当来个需要既要水平排版又要设置固定高宽时,我就会想起display:inline-block,还有为了支持IE5.5/6/7的hack*display:inline;*zoom:1;.然后发 ...

  5. CSS魔法堂:Absolute Positioning就这个样

    前言 当我们以position:absolute之名让元素脱离Normal flow的控制后,以为通过left和top属性值即可让元素得以无限的自由时,却发现还有各种神秘的力量左右着它的来去,于是我们 ...

  6. CSS魔法堂:深入理解line-height和vertical-align

    前言 一直听说line-height是指两行文本的基线间的距离,然后又说行高等于行距,最近还听说有个叫行间距的家伙,@张鑫旭还说line-height和vertical-align基情四射,贵圈真乱啊 ...

  7. CSS魔法堂:不得不说的Containing Block

    前言  <CSS魔法堂:重新认识Box Model.IFC.BFC和Collapsing margins>中提到在没有floated兄弟盒子时,line box的左右边框会与所属的cont ...

  8. CSS魔法堂:hasLayout原来是这样!

    前言 过去一直听说旧版本IE下很多诡异bug均由一个神秘角色引起的,那就是hasLayout.趁着最近突然发神经打算好好学习CSS,顺便解答多年来的疑惑. hasLayout到底是何方神圣? hasL ...

  9. CSS魔法堂:display:none与visibility:hidden的恩怨情仇

    前言  还记得面试时被问起"请说说display:none和visibility:hidden的区别"吗?是不是回答完display:none不占用原来的位置,而visibilit ...

随机推荐

  1. <2048>调查报告心得与体会

    老师这次给我们布置了一个任务,就是让我们写一份属于自己的调查报告,针对这个任务,我们小组的六个人通过积极的讨论,提出了一些关于我们产品的问题,当然这些问题并不是很全面,因为我们是从自己的角度出发,无法 ...

  2. ASP.NET Core 使用 Redis 和 Protobuf 进行 Session 缓存

    前言 上篇博文介绍了怎么样在 asp.net core 中使用中间件,以及如何自定义中间件.项目中刚好也用到了Redis,所以本篇就介绍下怎么样在 asp.net core 中使用 Redis 进行资 ...

  3. 拥抱.NET Core,学习.NET Core的基础知识补遗

    前言 .NET Core的新特性之一就是跨平台,但由于对之前框架的兼容导致编写一个.NET Core类库变得相当复杂,主要体现为相当多的框架目标和支持平台,今天我们就对.NET Core的跨平台特性进 ...

  4. 基于 Jenkins 快速搭建持续集成环境

      什么是持续集成 随着软件开发复杂度的不断提高,团队开发成员间如何更好地协同工作以确保软件开发的质量已经慢慢成为开发过程中不可回避的问题.尤其是近些年来,敏捷(Agile) 在软件工程领域越来越红火 ...

  5. MySQL 游标

    概述 本章节介绍使用游标来批量进行表操作,包括批量添加索引.批量添加字段等.如果对存储过程.变量定义.预处理还不是很熟悉先阅读我前面写过的关于这三个概念的文章,只有先了解了这三个概念才能更好的理解这篇 ...

  6. android内部培训视频_第二节 布局基础

    第二节:布局入门 一.线性布局 需要掌握的属性: 1.orientation:排列方式 vertical:垂直 Horizontal:水平 2.weight:水平布局的权重 3.gravity:子控件 ...

  7. Azure PowerShell (4) 使用PowerShell管理多个订阅

    <Windows Azure Platform 系列文章目录> 笔者手上有两个Azure账户. - Azure Global (windowsazure.com)账户.有两个订阅. - 世 ...

  8. 【VC++技术杂谈002】打印技术之获取及设置系统默认打印机

    本文主要介绍如何获取以及设置系统的默认打印机. 1.获取系统中的所有打印机 获取系统中的所有打印机可以使用EnumPrinters()函数,该函数可以枚举全部的本地.网络打印机信息.其函数原型为: B ...

  9. kindeditor 去掉网络图片上传功能

    kindeditor是一款开源的富文本编辑器,其内容设置均为可配置,使用比较灵活. 去掉网络图片的页面:allowImageRemote: false, 修改上传的图片的name:filePostNa ...

  10. Atitit learn by need 需要的时候学与预先学习知识图谱路线图

    Atitit learn by need 需要的时候学与预先学习知识图谱路线图 1. 体系化是什么 架构 知识图谱路线图思维导图的重要性11.1. 体系就是架构21.2. 只见树木不见森林21.3. ...