Skip to content

CSS3 新增盒子相关样式(Day12 3/3) ​

本页对应 Day12_CSS3,共 5 段视频,约 1 小时 1 分。

学习目标 ​

  • 能列举 display 的常用值,并通过修改元素 display 值实现块级、行内块、列表项等显示模式切换,解释 list-item 对列表标记的影响。
  • 能使用 box-sizing 在 content-box 与 border-box 间切换,计算并验证元素内容宽高、内边距、边框与总宽高之间的关系。
  • 能使用 box-shadow 设置水平/垂直偏移、模糊值、外延值、颜色、inset 内阴影及逗号分隔的多重阴影,并实现输入框悬停、聚焦时的阴影变化效果。
  • 能区分 opacity 与 rgba 背景透明度的作用范围,设置 0–1 的 opacity 实现元素整体半透明,并验证文字、背景及后代元素一起透明。
  • 能使用 position: sticky 配合 top 等偏移实现导航条滚动吸顶,并说明其与固定定位的差异及粘连触发条件。

知识点 ​

display:让元素可切换显示模式 ​

为什么需要:CSS 的初衷是让结构归 HTML、样式归 CSS,因此需要一套机制让元素能切换显示模式。display 不只是 block、inline-block,它还有很多值,可以让元素表现得像列表项、表格行、单元格等。

怎么想:list-style-type 只能对 display: list-item 的元素生效。p 默认是 display: block,所以给 p 设小圆点无效;把 p 改成 list-item 后,小圆点才出现。转写稿里演示的正是这个推导:不是选择器不行,而是元素的 display 不是 list-item。

怎么做:

css
p.item {
  display: list-item;
  list-style-type: disc;
}

易错点:不要用 p、div 硬仿列表,语义不如 ul/li;表格类 display 值能演示,但实际项目没必要“拿 div 装表格”;flex 等值后续再学,先别混用。

box-sizing:调整宽高设置规则 ​

为什么需要:默认 content-box 下,width/height 只表示内容区,总宽高还要加 padding 和 border。设计稿量出 400×300 时,开发者要反算内容宽高,容易算错。

怎么想:border-box 让 width/height 表示总宽总高,浏览器自动把 padding 和 border 算进去,内容区自动缩小。转写稿调试两个盒子:同样 width:400; height:300; padding:20; border:3px dashed #900;,content-box 总宽高是 446×346,border-box 总宽高是 400×300。

怎么做:

content-box		width和height设置的内容宽高,默认值
border-box		width和height设置的总宽总高,也称为怪异模式

易错点:border-box 常被叫“怪异模式”,这是历史叫法,来自早期 IE 的宽高计算方式,正式规范不这么命名;全局设置后内容区可能变小,要检查内容是否溢出。

盒子阴影 box-shadow ​

为什么需要:阴影能让盒子更有立体感,输入框内阴影也能表达状态。转写稿里鼠标悬停上移并加阴影,就是典型应用。

怎么想:长度值按顺序解析:前两个必写,是 X、Y 偏移;第三个是模糊值;第四个是外延值。颜色可写在长度前或后;inset 表示内阴影;多阴影用逗号分隔。转写稿还调试出:默认阴影颜色跟随 color;偏移不能用百分比;长度必须连续写,颜色和 inset 位置较灵活。

怎么做:

css
box-shadow: x偏移 y偏移 模糊值 外延值 颜色 内阴影;
css
/* 设置阴影的偏移位置 x方向 y方向 */
box-shadow: 10px 5px;

/* 设置阴影的 偏移位置 颜色 */
box-shadow: -5px 10px #ccc;
box-shadow: #099 -5px -10px;

 /* 设置阴影的模糊值 */
box-shadow: 5px 5px 10px;
/* 设置阴影的模糊值 颜色 */
box-shadow: 5px 5px 10px #ccc;
box-shadow: rgba(0,0,0,.3) 5px 5px 10px;
/* 阴影不偏移 靠模糊值向四周扩散 */
box-shadow: 0 0 15px #000;

/* 设置外延值 */
box-shadow: 3px 3px 5px 1px #080;

/* 设置内阴影 */
box-shadow: 10px 10px inset;
box-shadow: -10px 10px inset;
box-shadow: inset -10px -10px #000;

/* 多阴影 */
box-shadow: 5px 0 5px #f00,
            0 5px 5px #080,
            -5px 0 5px #088,
            0 -5px 5px #880;

易错点:长度值必须连续,别把颜色插在长度中间;外延值一般少用;多阴影最后用逗号,不是分号;内阴影常用于输入框,但别把阴影调得太清晰。

不透明度 opacity ​

为什么需要:有时要让整个元素半透明,包括背景、文字和子元素。rgba() 只改变某个颜色,不会让文字一起透明。

怎么想:转写稿对比了 background: rgba(0,0,0,.5) 和 opacity:.5:前者文字仍不透明,后者整体半透明。opacity 取 0 到 1,1 完全不透明,0 完全透明。

怎么做:

css
.box {
  opacity: 0.5;
}

易错点:不要把 opacity 和 rgba 背景混为一谈;opacity 会影响后代元素,做遮罩层时要注意。

粘连定位 position: sticky ​

为什么需要:导航条吸顶时,如果直接 position: fixed,它会一直固定;而 sticky 可以在滚动到视口顶部时粘住,滚回去还能恢复。

怎么想:转写稿调试时先给导航设 position: sticky,页面没变化,因为还要告诉它“粘到哪里”,于是加 top: 0,滚动到距视口顶部 0 时粘连。

怎么做:

css
.page-nav {
  position: sticky;
  top: 0;
}

易错点:必须设置 top(或 bottom 等阈值),否则效果不明显;sticky 不是所有场景都适用,兼容性要查;别和 fixed 混淆。

属性选择器应用:按 href 结尾设置背景图 ​

为什么需要:同一类链接可能指向不同文件类型,如果靠手写 class 区分,链接一多就容易漏、容易改错。属性选择器可以直接根据 href 的结尾匹配,让样式跟着链接地址走。

怎么想:作业要求“根据 href 属性值的结尾”设置背景图,结尾匹配用 $=。例如 .pdf 链接给 PDF 图标,.jpg 链接给图片图标;背景图放在右侧,再给链接留出右内边距,避免文字压住图标。

怎么做:

html
<a href="file.pdf">下载 PDF</a>
<a href="file.jpg">查看图片</a>
css
a[href$=".pdf"] {
  background: url("pdf.png") no-repeat right center;
  padding-right: 20px;
}
a[href$=".jpg"] {
  background: url("jpg.png") no-repeat right center;
  padding-right: 20px;
}

易错点:属性值要加引号;$= 表示“以……结尾”,^= 是开头,*= 是包含,别混用;背景图路径要正确;只设背景不设 padding,图标容易和文字重叠;不要写成 href=".pdf" 这种精确匹配。

:target 应用:点击链接切换图片 ​

为什么需要:不写 JavaScript 也能做简单的图片切换。点击链接后 URL 的 hash 变化,:target 正好匹配当前 hash 指向的元素。

怎么想:准备多个图片,每张图有唯一 id;链接的 href="#id" 指向它。默认隐藏所有图片,被 :target 匹配的图片显示。

怎么做:

html
<a href="#pic1">图片一</a>
<a href="#pic2">图片二</a>

<img id="pic1" class="pic" src="1.jpg" alt="图片一">
<img id="pic2" class="pic" src="2.jpg" alt="图片二">
css
.pic {
  display: none;
}
.pic:target {
  display: block;
}

易错点:href 里的 #pic1 要和元素 id="pic1" 完全一致;默认全部隐藏时页面初始可能空白,需要额外处理默认显示;同一时刻通常只有一个 :target 生效;不要把 class 名当成 hash 目标。

:checked:用单选框控制图片切换 ​

为什么需要::target 依赖地址栏 hash,刷新和前进后退会影响状态;:checked 借助表单控件的选中状态,更适合做一组互斥的图片切换,而且仍然不需要 JavaScript。

怎么想:一组同名 radio 天然互斥;用 label 的 for 绑定 input 的 id,点击文字就能选中单选框;图片默认隐藏,再用 :checked ~ 图片 显示对应图片。

怎么做:

html
<div class="gallery">
  <input type="radio" name="pic" id="pic1" checked>
  <input type="radio" name="pic" id="pic2">
  <label for="pic1">图片一</label>
  <label for="pic2">图片二</label>

  <img class="pic pic1" src="1.jpg" alt="图片一">
  <img class="pic pic2" src="2.jpg" alt="图片二">
</div>
css
.gallery input {
  position: absolute;
  opacity: 0;
}
.gallery .pic {
  display: none;
}
#pic1:checked ~ .pic1 {
  display: block;
}
#pic2:checked ~ .pic2 {
  display: block;
}

易错点:label 的 for 必须等于对应 input 的 id;input 要放在图片前面,后面的 ~ 兄弟选择器才能选中图片;同名 radio 才能互斥;别忘了给默认项加 checked;隐藏 input 时不要影响可访问性,可用透明定位而不是简单粗暴删掉。

阴影作业:鼠标悬停加阴影 ​

为什么需要:卡片、按钮、输入框加阴影能增强立体感和悬停反馈。转写稿里调试阴影时,先只写两个长度,阴影会像硬边色块;补上第三个长度“模糊值”后才变得朦胧。颜色可以写在前或后,但几个长度必须连续写,浏览器要按顺序解析偏移、模糊、外延。转写稿中同音出现的“阴养”“外颜值”“内一鸟”,对应的正确术语是阴影、外延值、内阴影。

怎么想:默认给卡片一个浅阴影或不给,:hover 时加大偏移和模糊,并用 rgba() 半透明黑色,让阴影自然。若做输入框,可用 inset 做内阴影;多阴影用逗号分隔。

怎么做:

css
.card {
  width: 300px;
  padding: 20px;
  background: #fff;
}
.card:hover {
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
}

内阴影示例:

css
.input:focus {
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
}

多阴影示例:

css
.box {
  box-shadow:
    5px 0 5px #f00,
    0 5px 5px #080,
    -5px 0 5px #088,
    0 -5px 5px #880;
}

易错点:偏移位置不要用百分比,转写稿调试时百分比会被划掉;box-shadow 最少写两个长度,模糊值、外延值可选,但长度要连续;颜色可前可后;inset 表示内阴影;悬停变化不要太夸张,阴影本身应是朦朦胧胧的。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

代码示例 ​

示例一:box-sizing 调整宽高设置规则 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>调整宽高设置规则</title>
<style>
  * { margin: 0; padding: 0; }

  .box01,
  .box02 {
    width: 400px;            /* 两个盒子写的是同样的宽高 */
    height: 300px;
    padding: 20px;           /* 内边距 */
    border: 3px dashed #900; /* 边框 */
    background-color: #ccc;
    display: inline-block;   /* 让两个盒子排到一行 */
    margin-left: 10px;
    margin-top: 20px;
  }

  .box01 { box-sizing: content-box; } /* 默认值:宽高 = 内容宽高 */
  .box02 { box-sizing: border-box; }  /* 宽高 = 总宽总高(怪异模式) */
</style>
</head>
<body>
  <div class="box01">box01</div>
  <div class="box02">box02</div>
</body>
</html>

关键行与易错点

  • .box01 是默认的 content-box:width:400px 只框住内容区,实际占位 = 400 + 20×2(左右内边距)+ 3×2(左右边框)= 446px;高度 = 300 + 20×2 + 3×2 = 346px。
  • .box02 改成 border-box:width:400px; height:300px 就是总宽总高,内容区被自动压缩成 354×254,不用自己拿设计稿尺寸去减内边距和边框。
  • 易错点:两个盒子写了完全一样的宽高,量出来却一大一小,原因就在这里——先确认 box-sizing 是什么值。
  • 易错点:border-box 被老程序员叫“怪异模式”,是因为早期 IE 就这么算,并非它真的怪;现在绝大多数项目会统一 * { box-sizing: border-box; }。
  • 易错点:border-box 下若内边距 + 边框超过设置的宽高,内容区会被压到很小,不要反过来再手动加宽。

示例二:盒子阴影 box-shadow 全套写法 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>元素阴影</title>
<style>
  body { background: #f5f5f5; }

  .box {
    width: 400px;
    height: 100px;
    padding: 10px;
    margin: 20px 0 0 10px;
    background: #fff;
  }

  /* ① 只写偏移:颜色默认跟随文字颜色 */
  .box01 { box-shadow: 10px 5px; color: #f00; }

  /* ② 偏移 + 模糊 + 颜色 */
  .box02 { box-shadow: 5px 5px 10px #ccc; }

  /* ③ 偏移 + 模糊 + 外延值 + 颜色 */
  .box03 { box-shadow: 3px 3px 5px 1px #080; }

  /* ④ 不偏移,靠模糊值向四周扩散 */
  .box04 { box-shadow: 0 0 15px #000; }

  /* ⑤ 内阴影:inset 关键字写前写后都行 */
  .box05 { box-shadow: inset -10px -10px 10px rgba(0,0,0,.3); }

  /* ⑥ 多阴影:逗号分隔 */
  .box06 {
    box-shadow: 5px 0 5px #f00,
                0 5px 5px #080,
                -5px 0 5px #088,
                0 -5px 5px #880;
  }
</style>
</head>
<body>
  <div class="box box01">box01</div>
  <div class="box box02">box02</div>
  <div class="box box03">box03</div>
  <div class="box box04">box04</div>
  <div class="box box05">box05</div>
  <div class="box box06">box06</div>
</body>
</html>

关键行与易错点

  • 完整语法:box-shadow: x偏移 y偏移 模糊值 外延值 颜色 内阴影;。前两个长度必写(X 方向、Y 方向),正值向右/向下,负值向左/向上;第三、四个长度(模糊值、外延值)可省。
  • 易错点:几个长度必须连续写,浏览器是按顺序解析每个长度的含义的;但颜色可以写在长度前面,也可以写在长度后面,inset 同理,写哪都行。
  • 易错点:不写颜色时默认取 color(文字颜色),所以 .box01 我把文字设成红色,阴影也变红了——不是黑色。
  • 易错点:偏移值不能用百分比(写了会被浏览器划掉),只能用长度。
  • 易错点:外延值和模糊值不一样——模糊相当于“把墨水滴进水里稀释”,外延是整体放大;外延值实际项目里很少用。
  • 易错点:只写 0 0 而不给模糊值,是看不见阴影的,必须配合模糊值才会向四周发散。
  • 多阴影之间只能用逗号分隔,最后一条后面不加逗号;换行只是为了可读性。

示例三:粘连定位 position: sticky + 不透明度 opacity ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>粘连定位 & 不透明度</title>
<style>
  * { margin: 0; padding: 0; }

  body {
    background: #f5f5f5;
    font-family: sans-serif;
  }

  .container { width: 1100px; margin: 0 auto; }

  .page-header { padding: 30px 0; }

  /* ===== 粘连定位 ===== */
  .nav {
    height: 40px;
    line-height: 40px;
    background: #900;
    position: sticky;   /* 粘连定位 */
    top: 0;             /* 距视口顶部 0 时粘住,必须写 */
  }
  .nav a {
    color: #fff;
    text-decoration: none;
    margin: 0 15px;
  }

  /* ===== 不透明度对比 ===== */
  .main { padding: 20px 0; }

  .box {
    width: 400px;
    height: 300px;
    padding: 20px;
    display: inline-block;
    vertical-align: top;
    margin-right: 10px;
    color: #fff;
    font-size: 2em;
  }

  /* 只有背景半透明,文字不透明 */
  .box01 { background: rgba(0, 0, 0, .5); }

  /* 整个元素半透明,文字也跟着透 */
  .box02 { background: #000; opacity: .5; }

  .main img { display: block; width: 100%; margin-top: 20px; }
</style>
</head>
<body>
  <div class="page-header container">
    <h1>小乐的交友网站</h1>
  </div>

  <div class="nav">
    <div class="container">
      <a href="#">首页</a><a href="#">相册</a><a href="#">留言</a>
    </div>
  </div>

  <div class="main container">
    <div class="box box01">box01</div>
    <div class="box box02">box02</div>
    <!-- 换成自己的图片,图片撑开高度才能看到滚动粘住的效果 -->
    <img src="images/01-xiaole.jpg" alt="">
    <img src="images/02-xiaole.jpg" alt="">
  </div>
</body>
</html>

关键行与易错点

  • position: sticky 必须配合 top(或 bottom 等)才生效,只写 sticky 和不写一样;top: 0 表示“滚到距视口顶部 0 的位置就粘住”,写 top: 10px 就是距顶部还有 10px 时就粘住。
  • 易错点:sticky 和 fixed 不是一回事——fixed 一上来就固定不动,sticky 是到达阈值才固定,页面往回滚时还会回到原来的位置。
  • 易错点:sticky 的老版本浏览器需要加私有前缀,移动端兼容性一般(新版 Chrome/Edge/Safari/Firefox 没问题)。
  • opacity 取值 0~1 的小数:1 完全不透明,0 完全透明,数字越大越不透明。
  • 易错点:opacity 是整个元素半透明(背景、文字、背景图、后代元素全都透),所以 .box02 的白字变灰了;而 rgba() 只让背景色半透明,文字依旧清晰。要“背景透、文字不透”,用 rgba 背景;要“整块都透”,用 opacity。

常见错误 ​

1. 阴影写了却不生效,DevTools 里整条声明被划掉

  • 现象:box-shadow: 10px 10px #ccc 5px; 完全没有阴影。
  • 原因:浏览器按位置顺序解析长度值——第 1、2 个是 X/Y 偏移,第 3 个是模糊值,第 4 个是外延值。颜色插在长度中间会打断解析,导致整条声明非法。
  • 修法:颜色只能写在所有长度的最前面或最后面;inset 同理。养成“长度连续书写”的习惯。

2. 换成 border-box 后内容区被压小,以为属性没起作用

  • 现象:宽高设成 400×300,检查元素发现内容区只有 354×254,文字挤在一起。
  • 原因:border-box 下 width/height 表示的是总宽高,padding 和 border 会从内部扣除,内容区自然变小。这是正常行为,不是 bug。
  • 修法:从设计稿量到多大就写多大,不再手工做减法;如果某处确实需要内容区精确等于某个值,那一个元素单独改回 content-box。

3. 给 p / div 设 list-style 加小圆点,没反应

  • 现象:list-style: disc 写在段落上,圆点不出现。
  • 原因:list-style 只对 display: list-item 的元素生效,而 p 的 display 是 block。
  • 修法:真要实现就补 display: list-item;但更该做的是直接用 ul/li——语义正确,样式也省事。这个例子说明的是“display 决定能设什么样式”,不是让你拿 div 假装列表。

4. 想做半透明背景,用了 opacity,结果文字一起变淡

  • 现象:卡片背景半透明了,但里面的标题、按钮也全变灰。
  • 原因:opacity 作用于元素整体,包括所有后代内容和背景,无法只挑背景。
  • 修法:只让背景半透明就用 background: rgba(0,0,0,.5);确实要整块(含子元素)淡化才用 opacity,例如遮罩层、禁用态。

5. position: sticky 写了但滚动时元素直接滚走

  • 现象:加了 position: sticky,页面一滚导航条照样消失。
  • 原因:缺 top(或 bottom/left/right)阈值,没有阈值就不知道该在哪里粘住;另一个常见原因是某个祖先元素有 overflow: hidden/auto,粘性被限制在那个滚动容器里。
  • 修法:必须补 top: 0; 之类的阈值;再逐层检查祖先的 overflow,把它去掉或调整结构。还要确认父容器高度足够,否则没有可粘区间。

6. 多阴影只显示了第一条

  • 现象:写了 4 组阴影,页面上只有一种颜色。
  • 原因:各组之间用了分号,或者漏了逗号,浏览器认为只有一组;也有人用换行当分隔符,换行本身不构成分隔。
  • 修法:组与组之间严格用逗号,换行只为可读性。

7. 用百分比写阴影偏移量

  • 现象:box-shadow: 10% 50% #999; 声明无效。
  • 原因:偏移、模糊、外延只接受长度单位,百分比没有参照基准。
  • 修法:一律用 px/em/rem。遇到“试了没用”的属性,先看 DevTools 是否把声明划掉,比反复改数值快得多。

练习 ​

练习 1:卡片悬停立体效果(对应作业 4) 做 3 张卡片横向排列,卡片白底、圆角。默认有一层很淡的阴影;鼠标悬停时卡片上移 3px,阴影变大变柔和。要求:过渡时长 0.3s,且用 border-box 保证三张卡片宽度严格一致、不因边框或内边距错位。 自检:把鼠标移开,卡片应平滑落回原位,不出现跳动。

练习 2:输入框的三态阴影(视频 3 的完整案例) 一个输入框,默认带内阴影(偏移 1px、模糊 2px、半透明黑);:hover 时模糊值加大、颜色加深;:focus 时去掉外轮廓线(outline: none),改成向外的柔和阴影。 自检:三种状态肉眼可区分,但都不能“清晰到像描边”——阴影一旦边缘锐利就不像阴影了。

练习 3:box-sizing 对照实验 同一份结构写两遍:一遍全局 content-box,一遍全局 border-box。卡片都设置宽 300、内边距 20、边框 1px。 要求:在页面上量出两种模式下的实际占位宽度,写出算式,并回答“如果设计稿标注卡片宽 300,哪种模式可以照抄数值”。

练习 4:四边异色多阴影 给一个元素加上四组阴影,分别只朝上、下、左、右偏移 5px,模糊 5px,四组不同颜色。 自检:四条边的颜色互不串色;把任意一组之间的逗号改成换行后,效果不变。

练习 5:粘性导航 + 半透明遮罩 页面包含页头、导航条、若干张图片。导航条滚动到顶部后粘住(top: 0)。再给其中一张图片加一层半透明黑色遮罩,遮罩上的文字必须保持完全不透明。 自检:导航条在往回滚动时能回到原位;遮罩里的文字不随遮罩变淡——如果不是,说明你用错了 opacity。


原视频对照 ​

#视频时长
1关于显示模式06:54
2调整元素的宽高设置规则07:11
3元素阴影35:36
4设置元素的不透明度04:27
5粘连定位07:33

小结 ​

  1. box-sizing: border-box 应该成为项目默认值(写进 reset 里),它的价值不是“新特性”,而是让设计稿标注的尺寸可以直接照抄,消灭一整套心算流程。
  2. 阴影好不好看,主要取决于模糊值,偏移量只决定方向。只写偏移不写模糊,出来的是一块生硬的色块;只写模糊不写偏移,才会得到向四周扩散的柔和光晕。
  3. 阴影参数的解析依赖书写位置,所以“长度必须连续、颜色放任意一端”是唯一安全的写法,不必记特例,只要守住这一条。
  4. opacity 和 rgba 不是二选一,而是作用范围不同:要整块淡化用 opacity,要单层颜色透明用 rgba。判断标准只有一句——子元素该不该一起变淡。
  5. sticky 本质是“带阈值的相对定位”:不给阈值它就退化成普通元素,祖先有 overflow 它就被关进小容器。它比 JS 监听省事,但有明确前提,不适合当万能方案。
  6. display 之所以能“让任何元素设置任何样式”,是因为可设置的样式取决于 display 的值,而不是标签名——这也是 p 加不上小圆点的真正原因。
  7. 视觉类属性(阴影、透明度)不要靠肉眼估参数:设计师的稿子可以取色、取偏移量,现成页面可以用 DevTools 直接读 box-shadow 的完整值。会读工具,比会背语法更省时间。