Skip to content

CSS 常用属性与CSS 选择器(Day6 3/4) ​

本页对应 Day06_CSS,共 5 段视频,约 55 分钟。

学习目标 ​

  • 能够使用 cursor 属性设置 default、pointer、move、none 等鼠标光标样式,并使用 url(...) 加回退值实现自定义光标。
  • 能够使用 list-style-type、list-style-position、list-style-image 及 list-style 复合属性设置列表项标记,并判断样式对 ul、ol、li 及其他元素是否生效。
  • 能够使用 table-layout、border-spacing、border-collapse、caption-side、empty-cells 等表格专用属性完成列宽固定、单元格边框合并等表格样式设置。
  • 能够编写后代元素选择器(空格),选中指定元素内部所有符合条件的后代元素,并准确判断匹配结果。
  • 能够编写子元素选择器(>),仅选中指定元素的直接子元素,并与后代选择器对比区分匹配范围;能够混合使用两种选择器并判断最终匹配结果。

知识点 ​

说明:本节笔记未提供可嵌入的图片文件,转写稿中提到的光标图、列表项小火箭/火焰图均以代码中的图片路径说明保留。

鼠标光标样式:cursor ​

为什么需要:普通元素悬停时仍是箭头,但链接会变小手,文字会变文本光标。开发者需要用 cursor 主动告诉用户“这里可点”“这里可拖动”“这里别点”。

怎么想:先判断元素默认行为,再决定是否覆盖。常见值只需记 pointer(小手)和 move(移动图标);none 可隐藏光标,但属于特殊效果;自定义光标要用图片 URL,并补一个备用值。

怎么做:

css
.box {
  width: 600px;
  height: 250px;
  background: #eee;
}
.box:hover {
  cursor: pointer;
}
.custom {
  /* 自定义图片后必须再跟一个常见值作为备用 */
  cursor: url("./a23.png"), pointer;
}
a {
  cursor: pointer;
}

易错点:只写 cursor: url("./a23.png"); 可能无效。转写稿中调试时,检查元素发现属性值无效,原因是 URL 后缺少逗号备用值。写成 url(...), pointer 才生效。另外 none 会让光标“失踪”,商业项目少用。

列表样式:list-style 系列 ​

为什么需要:ul/ol 自带小黑点或数字,但实际网页常要去掉默认图标,再用背景图、伪元素或自定义图片做更统一的列表标记。列表样式还决定标记在 li 里面还是外面。

怎么想:先明确选择器选到的是 ul/ol 还是 li。list-style-type 管图标类型,list-style-position 管位置,list-style-image 管自定义图片,list-style 是复合属性。实际开发第一步常写 list-style: none; 去掉默认标记。

怎么做:

css
.news {
  list-style-type: none;      /* 最常用:去掉默认图标 */
}
.news li {
  list-style-type: square;    /* disc/circle/square/decimal/lower-alpha/upper-roman 等 */
  list-style-position: inside;/* 默认 outside,在 li 外面 */
}
.news li.custom {
  list-style-image: url("./fire.png");
}
.news li {
  list-style: url("./rocket.png") inside;
}

易错点:列表样式只对 ul、ol、li 这类列表标签有效,给 p 设置 list-style-type: disc 不会出现小黑点。复合属性 list-style 会覆盖前面分开写的子属性;图片不能乱用大图,否则列表标记会撑得很大。inside 会让标记进入 li 内容区,outside 在外部。

表格样式:table 专用属性 ​

为什么需要:旧表格常用 cellspacing、cellpadding 等 HTML 属性控制样式,学了 CSS 后应改用 CSS。表格列宽还会受内容影响,数据一长列就变宽,需要固定列宽。

怎么想:先给 table 设宽度,再给 td, th 设边框和内边距。列宽用 table-layout: fixed 固定;单元格间距用 border-spacing;相邻边框合并用 border-collapse: collapse;标题位置用 caption-side;空单元格显隐用 empty-cells。

怎么做:

css
table {
  width: 800px;
  table-layout: fixed;          /* 列宽固定,平均分配 */
  border-spacing: 10px;         /* 单元格间距 */
  border-collapse: collapse;    /* 合并相邻单元格边框 */
  caption-side: bottom;         /* 标题在表格下方,默认 top */
  empty-cells: hide;            /* 隐藏无内容单元格,默认 show */
}
td, th {
  border: 1px solid #999;
  padding: 10px;
}
caption {
  font-size: 24px;
  font-weight: 800;
}

易错点:table-layout、border-spacing、border-collapse、caption-side、empty-cells 这些表格专用属性只对 table 生效,设给 td/th 不好使。设了 border-collapse: collapse 后,border-spacing 无效,因为相邻单元格已共用一条边框。empty-cells: hide 在合并边框时也不容易看出效果,需先取消合并边框观察。

后代元素选择器 ​

为什么需要:页面结构常有“列表套列表”,如果直接写 li 会选中所有层级的 li。后代选择器可以限定“某个祖先里面的所有后代”,让选择更精确。

怎么想:从左往右读,先找选择器一,再在它的后代中找选择器二。后代不限层级,子级、孙级都算。类名、标签名可组合,也可写多层。

怎么做:

css
.news li {
  border: 1px solid red;
}
.news ol li {
  border: 1px solid red;
}

易错点:.news li 会选中 .news 里所有层级的 li,不只是直接子级。写多层时不要漏空格;空格表示“后代”,不是普通装饰。

子元素选择器 ​

为什么需要:有时只想选直接子级,不想选孙级。比如 .news > li 只控制外层列表项,嵌套列表项不受影响。

怎么想:把后代选择器中的空格换成 >。> 两边常加空格只为可读,语法上不是必须。它只匹配直接子元素。

怎么做:

css
.news > li {
  border: 1px solid red;
}
.news > li > ol {
  border: 1px solid red;
}

易错点:.news > li 选不到孙级 li;.news ol 能选到后代中的 ol,但 .news > ol 选不到,因为 ol 不是 .news 的直接子元素。后代选择器与子元素选择器可混搭,如 .news ul > li,但读的时候要逐层分析。

小结 ​

本节核心是“专用属性要设对元素”:cursor 记 pointer、move,自定义光标加备用值;列表样式只对列表标签有效,常先用 list-style: none 清默认标记;表格五个专用属性只设给 table,合并边框后 border-spacing 失效;选择器里空格是后代,> 是直接子元素。

鼠标光标样式:cursor ​

为什么需要:鼠标悬停在元素上时,默认箭头、文字光标、超链接小手并不总够用;通过 cursor 可以提示“可点击”“可移动”“等待”等交互状态。
怎么想:先记住最常用的两个值:pointer 表示小手,move 表示移动图标;特殊效果如 none、wait、text 了解即可。自定义光标要用图片 URL,并给出回退值。
怎么做:

css
.book {
  width: 600px;
  height: 250px;
  background: #eee;
  cursor: pointer; /* 小手,最常用 */
}
.pic {
  cursor: move; /* 移动图标,常见于商品放大镜 */
}
a {
  cursor: url("./rocket.cur"), pointer;
}

转写稿中调试自定义光标时,只写 cursor: url(...) 会被浏览器判为无效,需要写成 url(...), pointer,表示图片不可用时回退为小手。
易错点:cursor 不是 csor;只写 URL 容易无效;图片路径要正确;none 会让光标“失踪”,属于恶搞;商业项目通常只用 pointer、move 等常见值。

列表样式:list-style 系列 ​

为什么需要:ul/ol/li 的语义是列表,但默认小黑点、数字不一定是设计需要的;CSS 可以在保留语义的同时改图标、改位置、换图片。
怎么想:实际开发常先 list-style: none; 去掉默认图标,再用背景图或伪元素自行装饰;需要保留系统符号时再用 list-style-type。
怎么做:

css
.news {
  list-style: none; /* 最常用:去掉默认图标 */
}
.news li {
  width: 560px;
  padding: 20px;
  margin-bottom: 10px;
  background: #f5f5f5;
}
.music {
  list-style: decimal inside;
}
.news {
  list-style: url("./fire.png") inside;
}

转写稿中用给 li 设宽度、内边距、背景的方式观察范围,从而看清 outside 在 li 外面、inside 在 li 里面。
易错点:列表样式只对 ul/ol/li 有效,给 p 设置无效;ul/ol 自带约 40px 左内边距,缩进结构来自它;list-style 复合属性会覆盖子属性;自定义图片不能过大,否则列表项会被撑坏;outside/inside 受 li 范围影响。

表格样式:用 CSS 替代表格旧属性 ​

为什么需要:以前用 table 的 cellspacing 等 HTML 属性做样式,结构和表现混在一起;学 CSS 后应把样式交给 CSS。
怎么想:通用属性如宽高、内边距可给 table/td/th;表格专用属性如 table-layout、border-spacing、border-collapse、caption-side、empty-cells 只对 table 生效。
怎么做:

css
table {
  width: 800px;
  table-layout: fixed;
  border-collapse: collapse; /* 合并相邻单元格边框 */
}
td, th {
  border: 1px solid #999;
  padding: 10px;
}
caption {
  font-size: 24px;
  font-weight: 800;
}

转写稿调试:table-layout: fixed; 后列宽平均分配,长地址自动换行,避免列宽被内容撑得忽宽忽窄;border-spacing: 10px; 可设单元格间距,但设置 border-collapse: collapse; 后间距无效。
易错点:表格专用属性设置给 td/th 不好使,只能设给 table;border-collapse 合并的是单元格边框,不是合并单元格;合并边框后 border-spacing 无效;empty-cells: hide 在合并边框下不易看出效果;caption-side: bottom 虽可用但很少用。

后代元素选择器:空格 ​

为什么需要:页面结构常有嵌套,只想选“某个容器里的所有某类元素”,需要比单个类名更精确。
怎么想:从左往右读:先找选择器一,再从它的所有后代中找选择器二;后代不限直接子级,层级可多层。
怎么做:

css
.news li {
  border: 1px solid red;
}
.news ol .item {
  border: 1px solid red;
}

转写稿中 .news li 会选中 .news 里所有 li,包括嵌套列表中的 li;.news ol .item 可三层混搭。
易错点:空格不能省;选的是所有后代,不是只有子元素;ID 语法上可参与但一般少与组合选择器混用;全局选择器权重低,少参与复杂组合。

子元素选择器:> ​

为什么需要:只想选直接子级,避免把深层后代也选进来。
怎么想:A > B 表示先找 A,再只从 A 的直接子元素中找 B。
怎么做:

css
.news > li {
  border: 1px solid red;
}
ul > li {
  border: 1px solid red;
}
.news > li > ol {
  border: 1px solid red;
}
.news ul > li {
  border: 1px solid red; /* 可与后代选择器混搭 */
}

转写稿对比:.news li 会选中所有后代 li;改成 .news > li 后,嵌套在 ol 里的 li 选不中,因为它不是 .news 的直接子元素。> 两边空格只为好看,不是后代选择器的空格含义。
易错点:> 只认直接子元素;.news > ol 选不到深层 ol;不要把它和后代选择器混为一谈;多层组合可以,但要从左到右逐层验证。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

代码示例 ​

示例一:鼠标光标样式(cursor) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>鼠标光标样式</title>
<style>
  .book {
    width: 600px;
    height: 250px;
    background: #eee;
    cursor: pointer;          /* 最常用:小手 */
  }
  .book p {
    width: 560px;             /* 560 + 左右内边距 20*2 = 600 */
    margin: 20px;
    padding: 0 20px;
    background: #ccc;
  }
  /* 超链接默认就是 pointer,这里故意改成“移动”图标 */
  .book a {
    cursor: move;             /* 第二个常用值:移动十字 */
  }
  .none   { cursor: none; }   /* 光标消失,恶搞用 */
  .text   { cursor: text; }   /* 文本竖线光标 */
  .custom {
    /* 自定义光标:url(图片路径), 兜底关键字 —— 兜底值不能省 */
    cursor: url(./images/a23.cur), pointer;
  }
</style>
</head>
<body>
  <div class="book">
    <p>普通段落:鼠标放到文字上是文本光标,放到 p 的空白处还是箭头。</p>
    <a href="#">超链接:这里被我改成了 move 图标</a>
  </div>

  <div class="book none">cursor: none,鼠标放上来就“失踪”了</div>
  <div class="book text">cursor: text</div>
  <div class="book custom">自定义光标(图片不存在时退回 pointer)</div>
</body>
</html>

关键行与易错点

  • cursor 是继承属性,写在 .book 上,整块区域(包括 p)都变成小手;a 单独覆盖成 move 才生效。
  • 默认 cursor: default 就是“该什么样就什么样”,一般元素不用写。
  • 自定义光标语法必须是 cursor: url(路径), 关键字;——只写 url(...) 浏览器会判定“属性值无效”,检查元素里能看到删除线。
  • 兜底关键字写什么都行(pointer、move 等),意思是“图片加载不出来时用它”。
  • 实战只记两个值:pointer(小手)、move(移动),自定义光标属奇技淫巧。

示例二:列表样式(list-style) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>列表样式</title>
<style>
  /* 1. 列表项图标类型 */
  .news {
    list-style-type: square;   /* 实心圆 disc(默认) / 空心圆 circle / 方块 square / 数字 / 字母 / 罗马数字 */
  }

  /* 2. 列表项图标位置:默认 outside(在 li 外面),inside 在 li 里面 */
  li {
    width: 300px;
    padding: 10px;
    margin-bottom: 10px;
    background: #f5f5f5;
    list-style-position: inside;
  }

  /* 3. 复合属性:一句话搞定类型 + 位置 + 自定义图片 */
  .music {
    list-style: none;                       /* 最常用:先去掉自带图标 */
  }
  .music li {
    list-style: url(./images/fire.png) outside;  /* 自定义图片当列表图标 */
  }

  /* 4. 只给某几个 li 单独设置 */
  .music .active {
    list-style: url(./images/fire.png) inside;
  }
</style>
</head>
<body>
  <ul class="news">
    <li>新闻一</li>
    <li>新闻二</li>
    <li>新闻三</li>
  </ul>

  <hr>

  <ol class="music">
    <li>音乐排行榜 1</li>
    <li class="active">音乐排行榜 2</li>
    <li>音乐排行榜 3</li>
  </ol>
</body>
</html>

关键行与易错点

  • 用 ul 还是 ol 取决于语义,不是看前面是小圆点还是数字——图标完全可以被 CSS 改掉(ul 也能显示数字)。
  • list-style-type: none 是最常用的值:实际项目里 99% 的列表都会先去掉自带图标,再自己用背景图等方式做“点”。
  • list-style-position 只有两个值:outside(默认,图标在 li 外面)、inside(图标进入 li 内部)。想看出区别,必须先给 li 设宽度、内边距、背景色,否则看不到 li 的范围。
  • list-style 复合属性一写,前面单独写的 list-style-type 等子属性全部失效;多个值用空格分隔,无顺序、无数量要求。
  • list-style-image 的图片尺寸不能乱选,图太大图标会撑爆;且它同样受 list-style-position 影响。
  • 列表样式只能设置给 ul / ol / li,给 p、div 设置一概无效。

示例三:表格样式 + 后代/子元素选择器 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>表格样式与选择器</title>
<style>
  table {
    width: 800px;
    table-layout: fixed;        /* 列宽固定,各列平均分,内容多就换行 */
    border-collapse: collapse;  /* 合并相邻单元格边框,真正 1px */
    /* border-spacing: 10px;    与 collapse 冲突,写了也无效 */
  }
  td, th {
    border: 1px solid #999;
    padding: 10px;
  }
  caption {
    font-size: 24px;
    font-weight: 800;
    caption-side: top;          /* 默认值;改成 bottom 标题跑到表格下方 */
  }
  /* empty-cells: hide;  隐藏没有内容的单元格(需配合 border-collapse: separate 才看得出来) */

  /* 后代选择器:空格。找 .news 里“所有后代”中的 li(含嵌套层) */
  .news li {
    border: 1px solid red;
  }

  /* 子元素选择器:> 。只找 .news 的“直接子元素” li */
  /* .news > li { border: 1px solid red; } */

  /* 混搭:先找 .news 的后代 ul,再找它的直接子元素 li */
  /* .news ul > li { border: 1px solid blue; } */
</style>
</head>
<body>
  <table>
    <caption>用户信息表</caption>
    <thead>
      <tr><th>姓名</th><th>年龄</th><th>电话</th><th>地址</th></tr>
    </thead>
    <tbody>
      <tr>
        <td>张三</td><td>20</td><td>13800000000</td>
        <td>新疆维吾尔自治区伊犁哈萨克自治州某某自治县</td>
      </tr>
      <tr><td>李四</td><td>22</td><td>13900000000</td><td>北京</td></tr>
      <tr><td>王五</td><td>25</td><td>13700000000</td><td></td></tr>
    </tbody>
  </table>

  <ul class="news">
    <li>新闻 1</li>
    <li>新闻 2
      <ol>
        <li>子新闻 2-1</li>
        <li>子新闻 2-2</li>
      </ol>
    </li>
    <li>新闻 3</li>
  </ul>
</body>
</html>

关键行与易错点

  • table-layout: fixed 让列宽不再受内容影响(否则谁的地址长谁的列就宽),默认值是 auto;实际项目数据是后端动态渲染的,固定列宽更稳。
  • border-collapse: collapse 才是“相邻单元格共用一条 1px 边框”;把 border-spacing 设为 0 只是“间距没了”,中间仍是两条边框叠成 2px,看起来更粗。
  • 设了 border-collapse: collapse 后,border-spacing 无论写在前面还是后面都失效——都合并共用边框了,哪还有间距。
  • 边框不能只给 table 设,否则只有最外圈一圈;要给 td, th 设(逗号是“并集选择器”,同时选中两类元素)。
  • table-layout、border-spacing、border-collapse、caption-side、empty-cells 这 5 个属性只能设置在 table 上,给 td/th 设置无效;宽高、内外边距这些是通用属性,谁都行。
  • 后代选择器 .news li 与子元素选择器 .news > li 的区别:前者连嵌套在 ol 里的 li 也会被选中(那些是后代但不是子元素);后者只选 .news 的直接子 li。
  • > 两边的空格只是排版好看,与后代选择器的“空格”含义完全不同,别混;> 不加空格语法也合法。
  • 选择器可以多级串联(.news ul > li 三层、甚至更多),也可与后代选择器混搭,范围越写越精确。

常见错误 ​

  1. 自定义光标写了不生效,DevTools 里 cursor 值被划删除线并提示"属性值无效" 现象:cursor: url(./img/rocket.png); 刷新后光标毫无变化。 原因:url() 后面必须再跟一个关键字作为回退,单独写图片地址是非法值。 修法:cursor: url(./img/rocket.png), pointer; —— 逗号 + 常用关键字结尾。

  2. 给 p、div 设 list-style-type: none 或 disc 完全没反应 现象:想让段落前出现小圆点,怎么写都不出现。 原因:列表样式是"专用属性",只对 ul / ol / li 生效,其他元素一概无效。 修法:样式写到列表元素上;若确实要给普通元素加符号,用背景图或 ::before 自造。

  3. 给 table 设了 border,结果只有最外圈有框,单元格里空空如也 现象:表格像被"框"住,但格子之间没有线。 原因:table 的边框只作用于表格自身外框,td / th 是独立盒子。 修法:table { border-collapse: collapse; } + td, th { border: 1px solid #ccc; }。

  4. table-layout: fixed 写了但列宽依旧被长内容撑开 现象:地址一列内容变长,整张表跟着变形。 原因:写到了 td 上,或 table 没有确定宽度。 修法:table { width: 800px; table-layout: fixed; },属性只认 table 标签。

  5. 设了 border-collapse: collapse 后 border-spacing 突然失效 现象:间距怎么调都是 0,以为属性写错了。 原因:相邻单元格共用一个边框后,本就不存在"单元格之间的距离"。 修法:二者取其一——要间距就别 collapse(或把间距写成 0 再 collapse);border-spacing 本身也只写在 table 上。

  6. 想只改一级菜单,结果嵌套的二级、三级 li 全被染色 现象:.news li { border: 1px solid red; } 把孙级项也套上了红框。 原因:空格是后代选择器,匹配所有层级的后代。 修法:改用子元素选择器 .news > li;注意 > 两侧的空格只是排版好看,不表示后代关系。

  7. cursor: none 用在整页或按钮上,用户找不到鼠标 现象:演示很酷,实际点不到东西。 原因:none 是把光标彻底隐藏。 修法:正式页面只用 pointer / move;确需隐藏须同时提供视觉反馈(高亮、放大镜框等)。

练习 ​

  1. 购物车列表:ul 去掉自带符号,每一项前面用一张小火箭图片做图标(要求图标尺寸可控、且位于 li 内部使文字整体右移),鼠标悬停整行时变成小手。 考察点:list-style 清空 + 自造图标 + cursor: pointer。

  2. 数据表格:宽度 800px,列宽不随内容变化,单元格 1px 灰色边框且相邻共用一条线,单元格内容留 10px 内边距,标题加粗放大。 考察点:table-layout、border-collapse、padding、caption 样式。

  3. 多级菜单对比实验:写出三层嵌套的 ul > li 结构,先用后代选择器、再用子元素选择器给 li 加边框,截图对比两种写法的命中范围差异,并说明原因。

  4. 混搭选择器:用"后代 + 子元素"混合写法,只给某个 ul 内直接子级的 ol 里的 li 加样式,验证哪些元素被命中。

  5. 改错题:下面三行各有问题,找出并修正—— p { list-style-type: disc; }td { table-layout: fixed; }a { cursor: url(./img/hand.png); }

原视频对照 ​

#视频时长
1鼠标光标样式09:53
2列表样式15:18
3表格样式15:58
4后代元素选择器10:02
5子元素选择器04:40

小结 ​

  1. cursor 日常只需记 pointer(小手)和 move(移动)两个值;自定义图标必须写成"图片地址 + 逗号 + 回退关键字"。
  2. 列表图标一律"先清空、再自造":list-style: none 起手,图标交给背景图或伪元素,尺寸才可控。
  3. 列表样式与表格样式都是专用属性,只对各自的标签生效,写到别的元素上等于白写——这是与宽高、内外边距、背景等通用属性的根本区别。
  4. 表格五属性全部只认 table 标签;其中 border-collapse: collapse 是做出"1px 细线表格"的关键,也是它与 border-spacing: 0 的本质差别。
  5. table-layout: fixed 用于抵御后端动态内容对列宽的干扰,必须写在 table 上并配合确定宽度。
  6. 后代选择器(空格)匹配所有层级,子元素选择器(>)只匹配直接子级;> 两侧的空格纯属排版,与后代含义无关。
  7. 选择器可以多层、可混搭、可用类名或标签名自由组合,越具体命中越精确,但权重也随之上升,所以 ID 一般不参与组合。
  8. 写样式前先问一句"这个属性归谁管"——通用属性随便写,专用属性认准标签,能省掉大半调试时间。