Skip to content

CSS 高级(三) ​

本页对应 CSS 高级,共 8 段视频,约 1 小时 13 分。

学习目标 ​

  • 能使用 vertical-align: middle 实现图片、行内块元素与文字的垂直居中,并解释基线对齐导致图片底部空隙的原因,能用非 baseline 对齐或 display: block 两种方法消除空隙。
  • 能将 transition 写在元素本身,结合 :hover 实现宽、高、颜色等属性的过渡,并说明过渡属性、持续时间、all 的作用以及写在 :hover 中导致鼠标移出无过渡的问题。
  • 能完成学成在线中的过渡效果:侧边栏文字位移、卡片上浮加阴影、输入框聚焦变宽,并正确使用 padding、负 margin-top、:focus 和 transition。
  • 能区分 opacity 与 rgba 背景透明:使用 opacity 实现整个盒子及内容半透明,使用 rgba 实现仅背景半透明而文字不透明,并说明开发中更常用的方案。
  • 能设置常见鼠标样式 default、pointer、text、move、not-allowed,并能为 button 强制设置小手样式;能完成表格边框、border-collapse: collapse、内容居中和 nth-child(2n/odd) 隔行变色。
  • 能按 ul > li > a > img 结构搭建淘宝轮播图外层盒子,设置固定宽高、overflow: hidden、圆角隐藏、图片 display: block 与宽度适配,并说明轮播图通过整体移动 ul 实现滚动的原理。

知识点 ​

垂直对齐方式 ​

垂直对齐示意

为什么需要:图片、span 等行内块元素和文字排在一行时,默认按文字基线对齐,常出现“图片不居中”或图片底部多出一条缝隙。转写稿里用京东布局复现过:图片放在盒子中,底部总有几像素空白,原因就是图片默认与文字基线对齐。

怎么想:文字可理解为有顶线、中线、基线、底线几条参考线。图片默认对齐的是 baseline(基线),不是盒子底线。想垂直居中,就把图片的对齐线改到中线 middle。

怎么做:

vertical-align 属性

html
<style>
  img {
    /* 行内块元素默认和文字基线对齐 */
    vertical-align: middle;
  }
  span {
    display: inline-block;
    vertical-align: middle;
    width: 50px;
    height: 50px;
    background-color: pink;
  }
  div {
    border: 2px solid red;
  }
</style>

<img src="./images/computer.png" alt=""> my name is 刘德华
<span></span> my name is 刘德华
<hr>
<div>
  <img src="./images/1.webp" alt="">
</div>

去除图片底部缝隙的两种方法:

  1. 给图片加 display: block;;
  2. 给图片加 vertical-align: middle; 等,只要不是 baseline 即可。

易错点:vertical-align 主要作用于行内元素、行内块元素;块元素独占一行,不靠它做“文字基线对齐”。写 baseline 等于默认值,缝隙仍会出现。

过渡与 focus ​

为什么需要:hover 直接改宽高、颜色会“嗖”地突变,不自然。transition 让元素在不同状态间平滑过渡。

怎么想:谁做动画,过渡写给谁。转写稿反复强调:“谁做过渡给谁加”,一般写在元素本身,而不是只写在 :hover 里。只写 height 就只过渡高度;写 all 则所有变化属性一起过渡。

怎么做:

css
.box {
  width: 200px;
  height: 200px;
  background-color: pink;
  /* 谁做过渡给谁加 */
  transition: all .3s;
}
.box:hover {
  height: 300px;
  width: 300px;
  background-color: green;
}
input {
  width: 200px;
  height: 30px;
  transition: all .3s;
}
/* 当表单得到光标的时候 */
input:focus {
  width: 300px;
  background-color: pink;
}

易错点:时间单位是秒 s,0.3s 可写 .3s;把 transition 只写进 :hover,鼠标离开时往往没有“回去”的过渡。:focus 是表单获得光标,不是鼠标经过。

透明度 opacity ​

为什么需要:有时要让整个盒子半透明,有时只想背景半透明而文字清楚。二者效果不同。

怎么想:opacity 作用于整个元素,包含背景和内容;rgba() 只让背景色透明,内容不受影响。转写稿对比过:opacity 盒子里文字也半透明,而 rgba 盒子文字仍是白色不透明。

怎么做:

css
.box1 {
  width: 200px;
  height: 200px;
  background-color: pink;
  opacity: 0.2; /* 0 完全透明,1 不透明 */
}
.box2 {
  width: 200px;
  height: 200px;
  background-color: rgba(0, 0, 0, 0.3);
  color: #fff;
}

易错点:opacity 的取值范围是 0–1;开发中更常用 rgba 做“背景半透明、文字不透明”,避免文字看不清。

光标类型 cursor ​

为什么需要:不同元素有不同交互含义:可点击、可选文本、可移动、禁止操作。鼠标指针能提示用户。

cursor 光标类型

怎么做:

css
div:nth-child(1) { cursor: default; }
div:nth-child(2) { cursor: pointer; } /* 小手 */
div:nth-child(3) { cursor: text; }    /* 文本 */
div:nth-child(4) { cursor: move; }    /* 移动 */
div:nth-child(5) { cursor: not-allowed; } /* 禁止 */
button { cursor: pointer; }

禁用鼠标样式

易错点:button 默认常是普通箭头,想提示可点击要手动加 cursor: pointer;。not-allowed 常用于“数量不能再减”等不可操作状态。

表格样式与合并相邻边框 ​

表格合并边框示意

为什么需要:表格默认每个单元格都有自己的边框,相邻边框会形成双线缝隙,不像真正表格。

怎么想:转写稿演示过:只给 table 加边框,只有外框;行列边框属于 tr、td。相邻两个边框要用 border-collapse: collapse; 合并成一条。

怎么做:

css
table {
  width: 700px;
  height: 400px;
  margin: 0 auto;
  text-align: center;
}
table, tr, td {
  border: 1px solid pink;
  /* 合并相邻的两个边框 */
  border-collapse: collapse;
}
tr:nth-child(even) { background-color: #eee; } /* 2n 偶数 */
tr:nth-child(odd)  { background-color: #ddd; } /* 2n+1 奇数 */
html
<table>
  <tr>
    <td>内</td><td>内</td><td>内</td><td>内</td><td>内</td>
  </tr>
</table>

易错点:只写 table 边框不会自动出现单元格内线;不写 border-collapse: collapse; 相邻边框会分开。2n 等价 even,2n+1 等价 odd,隔行变色时注意奇偶顺序。

案例目标与整体结构 ​

轮播图效果

为什么需要:轮播图一次只展示一张图,但图片本身要横向排成一排,后续才能通过移动整体容器实现切换。
怎么想:先看大盒子:.banner 固定宽高并 overflow: hidden,只露出第一张;里面用 ul > li > a > img,让 ul 横向排列。转写稿里反复强调:轮播图不是让每张图片单独乱动,而是“ul 包小 li,li 里再放 a 和图片”,后期让 ul 整体移动。
怎么做:先搭图片区结构。

html
<div class="banner">
    <!-- 图: ul > li -->
    <ul>
      <li><a href="#"><img src="./images/banner1.jpg" alt=""></a></li>
      <li><a href="#"><img src="./images/banner2.jpg" alt=""></a></li>
      <li><a href="#"><img src="./images/banner3.jpg" alt=""></a></li>
    </ul>
</div>
css
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

li {
  list-style: none;
}

.banner {
  position: relative;
  margin: 100px auto;
  width: 564px;
  height: 315px;
  /* background-color: pink; */
  overflow: hidden;
}

/* 图片 */
.banner img {
  width: 564px;
  border-radius: 12px;
  vertical-align: middle;
}

.banner ul {
  display: flex;
}

易错点:.banner 必须 overflow: hidden,否则横向排列的图片会全部露出来;ul 用 display: flex 让 li 在一行;图片宽度要和盒子宽度一致。转写稿还提到图片默认和文字基线对齐,底部容易出现小缝隙,所以这里用 vertical-align: middle 处理。若按转写稿的调试思路,也可以给图片加 display: block 去除底侧缝隙;父盒子加圆角并配合 overflow: hidden 更稳妥。

箭头:父相子绝与垂直居中 ​

为什么需要:用户需要知道可以上一张、下一张;箭头默认不显示,鼠标进入轮播区域再出现,画面更干净。
怎么想:箭头以 .banner 为定位参照,所以 .banner 写 position: relative,箭头写 position: absolute。垂直居中用 top: 50% 加 transform: translateY(-50%)。转写稿讲定位时也强调“父相子绝”,这里正合适。
怎么做:

html
<!-- 箭头 -->
<!-- 上一张 prev -->
<a href="#" class="prev">
  <i class="iconfont icon-zuoce"></i>
</a>
<!-- 下一张 next -->
<a href="#" class="next">
  <i class="iconfont icon-youce"></i>
</a>
css
/* 箭头 */
.banner .prev,
.banner .next {
  /* 隐藏 */
  display: none;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);

  width: 20px;
  height: 30px;
  background-color: rgba(0,0,0, 0.3);

  text-decoration: none;
  color: #fff;
  line-height: 30px;
}

/* 鼠标滑到banner区域,箭头要显示 display:block */
.banner:hover .prev,
.banner:hover .next {
  display: block;
}

.banner .prev {
  left: 0;
  border-radius: 0 15px 15px 0;
}

.banner .next {
  right: 0;
  border-radius: 15px 0 0 15px;
  text-align: center;
}

易错点:箭头默认 display: none,要在 .banner:hover 下改回 display: block;top: 50% 后必须加 translateY(-50%) 才是真正垂直居中;a 要去下划线并设文字颜色;i 使用 iconfont 图标类,实际页面要保证图标字体已引入。转写稿讲圆角时提到按顺时针写四个值,这里左右箭头的圆角方向不同,是为了贴边更像半圆按钮。

圆点:底部居中与当前项标识 ​

为什么需要:圆点告诉用户一共有几张图、当前在第几张。
怎么想:圆点整体在底部水平居中,所以 ol 绝对定位:bottom: 20px; left: 50%; transform: translateX(-50%);内部 li 用 flex 排成一行;当前项加 .active 变橙色。
怎么做:

html
<!-- 圆点 -->
<ol>
  <li></li>
  <li class="active"></li>
  <li></li>
</ol>
css
/* 圆点 */
.banner ol {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  height: 13px;
  background-color: rgba(255,255,255,0.3);

  display: flex;

  border-radius: 10px;
}

.banner ol li {
  margin: 3px;
  width: 8px;
  height: 8px;
  background-color: #fff;
  border-radius: 50%;
  cursor: pointer;
}

/* 橙色的li */
.banner ol .active {
  background-color: #ff5000;
}

易错点:left: 50% 只是把左边缘放到中间,必须再 translateX(-50%) 才水平居中;ol 也要 position: absolute,否则不会贴在轮播图底部;li 要 border-radius: 50% 才是圆点;当前项靠 .active 区分。转写稿中提到的“黑电的”就是 hidden,本节核心仍是 .banner 的 overflow: hidden 和 ul 横向排列;切换逻辑属于后续 JS 部分,本节先把结构和样式搭稳。

课件图示 ​

课件第25页:案例 轮播图 技术点: 1. 定位 2. 字体图标 3. Flex 布局

课件第13页:CSS 精灵 CSS 精灵,也叫CSS Sprites,是一种网页图片应用处理方

课件第14页:CSS 精灵 实现步骤: 1. 创建盒子,盒子尺寸与小图尺寸相同 2. 设置盒子

课件第18页:1. 引入字体样式表(iconfont.css) 2. 标签使用字体图标类名 1

课件第22页:过渡transition 作用:可以为一个元素在不同状态之间切换的时候添加过渡效

代码示例 ​

示例一:vertical-align 垂直对齐(含图片底部缝隙) ​

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    img {
      /* 行内块元素  默认和文字的基线对齐*/
      vertical-align: middle;
    }

    span {
      display: inline-block;
      vertical-align: middle;
      width: 50px;
      height: 50px;
      background-color: pink;
    }

    div {
      /* width: 300px;
      height: 300px; */
      border: 2px solid red;
    }
  </style>
</head>

<body>
  <img src="./images/computer.png" alt=""> my name is 刘德华

  <span></span> my name is 刘德华

  <hr>
  <div>
    <img src="./images/1.webp" alt="">
  </div>

</body>

</html>

关键行与易错点

  • img { vertical-align: middle; }:图片是行内块元素,默认与文字基线(baseline)对齐,改成 middle 才和文字中线对齐;top、bottom 同理,只要不是 baseline 都行。
  • span 必须先 display: inline-block 才和图片一样参与行内对齐,否则宽高不生效;vertical-align: middle 与 display: inline-block 这两个常一起写。
  • 图片底部缝隙:图片默认基线对齐,基线下方还留着文字下沿的空间,所以盒子底部会出现几像素空白。两种解法:① vertical-align 改成 middle 等非 baseline 值;② 给图片 display: block(块元素独占一行,不存在基线对齐问题)。
  • 易错点:vertical-align 只对行内元素、行内块元素有效,给块元素加是无效的;属性写在图片/行内块自身身上,不是写在父盒子上。
  • 代码里的 ./images/xxx.png 是笔记中的图片路径,实际运行请换成自己的图片,否则图片不显示(span 的居中效果仍然可见)。

示例二:transition 过渡 + :focus 表单获得焦点 ​

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .box {
      width: 200px;
      height: 200px;
      background-color: pink;
      /* 谁做过渡给谁加 */
      transition: all .3s;

    }

    .box:hover {
      height: 300px;
      width: 300px;
      background-color: green;
    }

    input {
      width: 200px;
      height: 30px;
      transition: all .3s;
    }

    /* 当表单得到光标的时候 */
    input:focus {
      width: 300px;
      background-color: pink;
    }
  </style>
</head>

<body>
  <div class="box"></div>

  <input type="text">
</body>

</html>

关键行与易错点

  • transition: all .3s;:复合属性,第一个值是过渡的属性(all 表示所有变化的属性都过渡,也可以写 height、width 等具体属性),第二个值是花费时间,单位秒。
  • 最重要的一条:谁做过渡给谁加。 transition 必须写在 .box、input 这些元素本身的样式里,不能写在 :hover、:focus 里。写在 :hover 里,鼠标移入有过渡、移出瞬间弹回,没有“慢慢回去”的效果。
  • input:focus:表单**得到光标(被点击、可以开始输入)**时生效,注意它和 :hover(鼠标经过)是两种不同状态。
  • 易错点:时间必须带单位,.3s 正确,写成 .3 无效;0.3s 的 0 可以省略。另外别把 transition(过渡)和 transform(变形)写混。

示例三:表格样式——合并相邻边框与隔行变色 ​

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    table {
      width: 700px;
      height: 400px;
      margin: 0 auto;
      text-align: center;
    }

    table,
    tr,
    td {
      border: 1px solid pink;
      /* 合并相邻的两个边框 */
      border-collapse: collapse;
    }

    /* 2n 偶数 / even   */
    /* tr:nth-child(2n) {
      background-color: #eee;
    } */
    tr:nth-child(even) {
      background-color: #eee;
    }

    /* 2n+1 奇数   odd */
    tr:nth-child(odd) {
      background-color: #ddd;
    }
  </style>
</head>

<body>
  <table>
    <tr>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
    </tr>
    <tr>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
    </tr>
    <tr>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
    </tr>
    <tr>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
    </tr>
    <tr>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
    </tr>
    <tr>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
      <td>内</td>
    </tr>
  </table>
</body>

</html>

关键行与易错点

  • 边框要写成 table, tr, td 三个一起加:只给 table 加边框,只有外面一个大方框,里面没有横竖线,因为表格的横线竖线是由行和单元格撑出来的。
  • border-collapse: collapse;:合并相邻的两个边框。默认每个单元格都是独立的四方块,相邻边框会变成“双线+缝隙”,collapse 后两条线折叠成一条,才像真正的表格。写表格基本离不开这句。
  • tr:nth-child(even) 等价于 tr:nth-child(2n)(偶数行),tr:nth-child(odd) 等价于 tr:nth-child(2n+1)(奇数行),两种写法都要认识。
  • 易错点:nth-child 的数字是从 1 开始、按所有同级 tr 计数,不是“第几个变色”;另外 text-align: center 写在 table 上可以继承给单元格里的文字实现水平居中。

常见错误 ​

  1. 图片下方多出几像素缝隙 现象:div 包一张图,容器总比图片高一点,出现白边。 原因:img 是行内块元素,默认与文字基线 baseline 对齐,基线下方还要给字母下沉部分留空间。 修法:给 img 加 display: block;或 vertical-align 取 middle / top / bottom 任一非 baseline 值。

  2. 过渡只"去"不"回" 现象:鼠标移入有动画,移出瞬间跳回原状。 原因:transition 写在了 :hover 里,只在悬停态生效。 修法:transition 写在元素本身的选择器上(谁做过渡给谁加)。

  3. 动画只有一半属性生效 现象:宽高都变了,只有高度渐变,宽度"嗖"地跳过去。 原因:transition 属性值只写了 height。 修法:transition: all .3s;,需要分别控制时用逗号分隔多组「属性 时间」。

  4. 遮罩层把文字也变模糊了 现象:给盒子加 opacity: .3 后,里面的文字一起半透明。 原因:opacity 作用于整个元素,含背景与内容。 修法:改用 background: rgba(0,0,0,.3),只让背景透明。

  5. 表格边框出现双线缝隙 现象:table, tr, td 都加 border 后,单元格之间是两条线。 原因:相邻单元格边框各自独立、叠加显示。 修法:在 table 上加 border-collapse: collapse;。

  6. 轮播图圆角处露出直角 现象:盒子给了 border-radius,但图片四角仍是方的、溢出到圆角外。 原因:圆角只作用于父盒子,图片是矩形且溢出。 修法:给父盒子补 overflow: hidden;(图片本身不必加圆角)。

  7. 轮播图多张图片竖着排 / 只显示第一张 现象:li 换行,父盒子里只看到一张图。 原因:li 是块级元素独占一行;或 ul 宽度不足、父级没裁剪。 修法:ul 设 display: flex(或 li 浮动),ul 宽度足以容纳全部 li,父级 .banner 加 overflow: hidden。

  8. :focus 写了没反应 现象:点进输入框宽度不变。 原因:把 :focus 写成 :hover,或拼写/冒号出错。 修法:input:focus { ... },并确认宽度变化有 transition 才平滑。

练习 ​

  1. 图文对齐:一行内放一张 img 和一段文字,让图片与文字垂直居中;再把图片放进带红色边框的 div 中,分别用两种方法消除底部缝隙,并在注释里写出各自原理。

  2. 过渡卡片:.box 尺寸 200×200 粉色,鼠标悬停变 300×300 且背景变绿。要求宽、高、颜色三者同时渐变,时间 0.3s;完成后故意把 transition 挪到 :hover 里观察差异,并说明原因。

  3. 搜索框:input 宽 200、高 30,聚焦时宽度变 300、背景变粉,带过渡与圆角。再用浏览器开发者工具在任意网站找一个"聚焦变宽"的输入框,对照其写法。

  4. 半透明遮罩:body 铺一张背景图,上面放一个 200×200 的遮罩盒,要求背景半透明、文字完全不透明;另建一个用 opacity 实现的版本,对比两者文字清晰度。

  5. 斑马纹表格:6 行 5 列,宽 700、高 400 居中,单元格文字居中,相邻边框合并;奇数行 #ddd、偶数行 #eee,分别用 2n/2n+1 和 even/odd 各写一遍。

  6. 轮播图骨架:搭建 .banner(564×315,居中,overflow: hidden)+ul>li>a>img 三张图,实现图片横向排列、圆角显示;再补左右箭头(默认隐藏、悬停 .banner 显示、垂直居中)与底部三个圆点(第二个为激活态)。

原视频对照 ​

#视频时长
1垂直居中17:18
2过渡06:02
3学成在线效果08:40
4盒子半透明opacity05:41
5鼠标样式09:22
6表格样式07:09
7淘宝开始12:21
8作业布置07:13

小结 ​

  1. vertical-align 只对行内 / 行内块元素生效,块级元素独占一行不存在这个问题——这是图片缝隙类问题的根因。
  2. 消除图片底部缝隙两条路:display: block(跳出对齐规则)或 vertical-align 取非 baseline 值(改对齐线),后者更常用于图文混排。
  3. transition 的记忆口诀是"谁做动画给谁加",写在元素本体而非 :hover,否则只有单向效果。
  4. 过渡值优先写 all .3s,需要精细控制时再拆成逗号分隔的多组;时间单位是秒,0.3s 可写 .3s。
  5. opacity 与 rgba 的分工:整体(含内容)透明用 opacity,仅背景透明用 rgba;实际开发中后者使用频率远高于前者。
  6. cursor 是提示性属性:可点击的 a、button(button 默认不是小手,需手动加 pointer)用 pointer,不可用状态用 not-allowed。
  7. 表格样式的必备一句是 border-collapse: collapse,配合 :nth-child(2n/2n+1) 完成斑马纹,:nth-child(even/odd) 与之等价。
  8. 轮播图布局的本质是"ul 装多个 li 横向排列 + 父级裁剪",后续的滚动切换动的是 ul 整体,所以结构与 overflow: hidden 必须一次搭对。