跳转至

现代 CSS 与用 JavaScript 操作页面

这一章讲什么: 前半(第 18 章)是 CSS 的现代化——从「给文字换个颜色」 到「圆角、阴影、动画、响应式布局」全套设计能力,收尾在两大布局系统 flexbox 与 CSS Grid。后半(第 19 章)是合龙——用 JavaScript 读写这些样式、 响应鼠标和键盘、增删页面元素、用时钟驱动动画。 读完这两章,「静态呈现(CSS)」和「动态交互(JS)」之间的墙就拆了—— 这正是 React(第 20 章)登场前你要有的全部手艺。 读之前需要本组 09、10。

1. 顶层全景:两条河的汇合

  CSS 河(18):选谁 → 怎么长(盒模型/背景/边框) → 怎么排(flexbox/grid)
  JS 河(19):选中元素(byId/style/by) → 读写样式 → 响应事件 → 增删改元素 → 定时驱动

  汇合点:用户点一下/滑一下 ──事件──▶ JS 改 style ──▶ CSS 呈现变化
        (鼠标悬停换图、时钟跳动、方块横移——全是这一个环)

  图说:CSS 负责「可能的样子」,JS 负责「何时变成那样」。

2. 选择器与盒模型地基(原书第 18 章开头)

十种选择器里,CSS3 给属性选择器加了三把 substring 刀:^= 匹配开头、 $= 匹配结尾、*= 匹配任意子串——a[href^='http://website'] 选中链向某站的链接, img[src$='.png'] 选中所有 PNG 图,a[href*='google'] 选中链接里含 google 的46。

三把刀各配一个「匹配/不匹配」的对照(原书逐一给了反例,一并接住):

选择器 选中 不选中(反例)
a[href^='http://website'] http://website.com http://mywebsite.com(^= 卡在开头,my- 开头不符)
img[src$='.png'] photo.png snapshot.jpg($= 卡在结尾)
a[href*='google'] http://google.com http://gmail.com(*= 要求子串连写出现)

实用派生用法随手就有:给所有外链加小图标(a[href^='http'],注意站外链接), 给所有下载链接标箭头(a[href$='.pdf']),给提到某产品的段落加高亮。 CSS2 时代只能全等匹配(a[href='info.htm']),CSS3 的这三刀让「按属性值的 一部分」选元素成为可能——页面结构不用为样式牺牲,选择器自己去文本里找特征46。

盒模型的百年之争在此收拢:CSS 标准规定 width/height 只管内容区 (content-box),padding 和 border 另算;而设计师常想要「说 200px 就含边框的 200px」。 box-sizing: border-box 给你后者——现代项目的全局默认(原书图 18-1 并排展示了 同一 width: 200px 在两种模型下的实际占地)47。

把两种算法的数字摆开,差别立刻具体:一个 width: 200px; padding: 10px; border: 5px 的元素——

算法 占地总宽 200px 指
content-box(默认) 200 + 10×2 + 5×2 = 230px 只有中间内容区
border-box 200px(内容区被压到 170) 含内边距和边框的整只盒子

这就是为什么团队代码里常见一行全局重置 * { box-sizing: border-box }: 尺寸从此「说多少是多少」,排版心算不再受 padding 偷袭47。

3. 背景、边框与文本效果

背景三件套管一张背景图的起止:background-clip 决定背景画到哪一圈 (边框外沿/内边距外沿/内容区外沿),background-origin 决定图的左上角从哪一圈开始, background-size 定尺寸(一个值两边同;auto 单边等比缩放;还有 contain/cover 两个 智能值)48。多重背景用逗号并排多张图——原书的「月度员工奖状」例子把 8 张 GIF (四角 + 四边)叠成一个可随容器任意伸缩的边框;后写的在下层,所以边条要写在角图 后面49。

把这个奖状例子走一遍(例 18-1),多重背景的设计意图就全清楚了:

.border {
  width: 350px; height: 500px; padding: 60px;
  background: url('b1.gif') top left no-repeat,     /* ① 左上角 */
              url('b2.gif') top right no-repeat,    /* ② 右上角 */
              url('b3.gif') bottom left no-repeat,  /* ③ 左下角 */
              url('b4.gif') bottom right no-repeat, /* ④ 右下角 */
              url('ba.gif') top repeat-x,           /* ⑤ 上边条(横向平铺) */
              url('bb.gif') left repeat-y,          /* ⑥ 左边条(纵向平铺) */
              url('bc.gif') right repeat-y,         /* ⑦ 右边条 */
              url('bd.gif') bottom repeat-x;        /* ⑧ 下边条 */
}

逐层看:①–④ 四张角图各占一个角、不平铺(no-repeat),把四个角钉死; ⑤–⑧ 四张边条各沿一边平铺(repeat-x 横向 / repeat-y 纵向),把边铺满。 顺序即层序:先写的在上——角图必须先落位,边条从后面铺过来才不会盖住角。 整个容器无论怎么改尺寸,角永远贴角、边自动延伸,边框严丝合缝—— 原书点评:这比用表格或多个元素拼边框高明一个时代49。

边框:border-color 可以四边分开(border-color:#f00 #0f0 #880 #00f 顺时针 上右下左);border-radius 一个值四角同圆,四个值顺时针各角,单角属性还能给 两个参数(水平半径 + 垂直半径,画出椭圆角)50。box-shadow: 15px 15px 10px #888 = 横向偏移、纵向偏移、模糊量、颜色51。溢出方向可以分开管(overflow-x/y), column-count + column-gap + column-rule 让文本像报纸一样分栏流排52。

多栏的完整声明只有三行(例 18-3),把报纸排版从「切 div 硬排」变成一行声明:

.columns {
  column-count: 3;            /* 分三栏 */
  column-gap: 1em;            /* 栏间距 1em */
  column-rule: 1px solid black;  /* 栏间的分隔线 */
}

效果:文字先灌满第一栏、自动续到第二栏、再第三栏——内容增减时栏高自动平衡, 比手工分栏强在「流」:内容变了布局自适应。长文章页、产品特性页是多栏的用武之地; 新闻站首页那种「多列各自独立」的版面则不是(那是 Grid 的菜)—— 栏内文字连续流 = column,互不相干的列 = Grid52。

颜色与透明度四函数一堂课:HSL(色相环 0–359、饱和度 0–100%、明度 0–100%, hsl(60,100%,50%) 是标准黄)、HSLA(第四参 alpha 0–1)、RGB(rgb(255,255,0) 或百分比)、RGBA;另有 opacity 属性让整个元素(含内容)透明53。

HSL 值得多走两步,因为它是「调颜色」最人性化的写法。三个参数的直觉:

  1. 色相(0–359):色轮上的角度——0 红、120 绿、240 蓝,三原色各隔 120 度; 想要橙?在 0 和 120 之间挑(约 30–45);想要紫?在 120 和 240 之间(约 270)。
  2. 饱和度(0–100%):0% 是灰,100% 最鲜艳——「颜色有多纯」。
  3. 明度(0–100%):50% 是该色相最饱满的亮度;往下调掺黑、往上调掺白—— 「同一家族里挑深浅的旋钮」。

所以「标准黄」= 色相 60(红绿之间)、饱和拉满、明度标准:hsl(60, 100%, 50%); 「深蓝」= 240 度、满饱和、明度压到 40%:hsl(240, 100%, 40%)。 同一家族做配色(主色 + 深一度 + 浅一度)在 HSL 里只是改第三个数字, 在十六进制里却要重算三个分量——这就是设计师偏爱 HSL 的原因53。 透明度两个口:颜色自带的 alpha(hsla(60,100%,50%,0.3) 是 30% 不透明的黄), 或元素级的 opacity: 0.25(连文字带背景一起透明)。要文字实、背景透, 用 hsla/rgba;要整个元素淡出,用 opacity53。 文本效果三件套:text-shadow(参数同盒阴影)、text-overflow: ellipsis (截断处显示省略号——前提是 overflow 非 visible、white-space:nowrap、宽度不足, 三条件缺一不可)、word-wrap: break-word(长单词硬换行,治 Honorificabilitudinitatibus 这类撑破容器的怪词)54。

把 text-overflow 的三条件走一遍,因为它是「看似简单、最容易配不出来」的属性:

.ellipsis {
  width: 200px;              /* 条件③:容器比文字窄 */
  overflow: hidden;          /* 条件①:溢出部分裁掉(非 visible) */
  white-space: nowrap;       /* 条件②:不许换行(否则永远溢不出) */
  text-overflow: ellipsis;   /* 裁剪点显示「…」 */
}

效果对照:同一长句装不进 200px 时,不配 text-overflow 是「话说到一半被刀切断」, 配上是「话说到一半 trailing off……」——用户立刻明白「后面还有,不是出错」。 原书特意强调三者缺一不可:缺 overflow:hidden,文字照样铺开,无从截起; 缺 nowrap,文字早换行了,永远不会溢出;缺窄宽度,前两条都白搭。 这套组合在列表页、卡片标题、表格单元格里天天用54。

Web 字体:@font-face 把字体文件声明成 font-family;更省事的是 Google Fonts——挑好字体,把一段 <link> 粘进 <head> 就能用。 原书专设了一个隐私提示框:用 Google 托管的字体,你的访客会向 Google 的服务器发请求 (欧洲站点可能要先征得同意)——不放心就下载字体自托管55。

@font-face 的最小声明两行:font-family 给这个字体起个名字, src 指到字体文件(ttf/otf 均可,format() 函数注明类型):声明之后, 就能像系统字体一样在任意 font-family 里引用这个名字—— 「把外部字体变成可引用的家族」就是它的全部职责。Google Fonts 的用法更简: 在官网选好字重,它生成一段 <link href='http://fonts.googleapis.com/css?family=Lobster' rel='stylesheet'>, 粘进 <head>,然后 font-family: 'Lobster', arial, serif—— 排在前面的 Lobster 优先,加载失败时优雅降级到 arial 再 serif(后备名单按喜好排)。 注意两点:网络字体会阻塞页面渲染(字体没到,文字可能空白或闪烁——行业称 FOIT/FOUT, 原书未展开);以及前述隐私权衡55。

4. transform 与 transition:动画的前半场

transform 让元素脱离死板矩形:translate(挪)、scale(缩放)、 rotate(45deg)(旋转)、skew(斜切——矩形变平行四边形)、matrix(矩阵万能); 可叠加 scale(1.5, 2) rotate(45deg);3D 版有 perspective/rotate3d 等56。

把 transform: scale(1.5, 2) rotate(45deg) 走一遍,叠加的次序就有体感: 先按宽 1.5 倍、高 2 倍把元素拉大(此时还是正的矩形),再整体顺时针转 45 度—— 先写的先动手,两个变换都作用在同一个元素上、合成一个最终姿态。 若调换顺序(先转再拉),拉的方向跟着元素转过的坐标系走,结果完全不同—— 变换的组合不可交换,这是线性代数在这条声明里的影子56。

3D 的入场券是 perspective:transform: perspective(200px) rotateX(20deg) rotateY(40deg) rotateZ(10deg)——perspective(200px) 先给元素「造一个 200 像素视距的三维空间」,之后的三轴旋转才有了远近深浅;没有 perspective, rotateX/rotateY 只是变形的平面图。transform-origin 再帮你把旋转轴心从默认的 元素中心挪到任意点(配合一个角做「翻页」效果)56。

transition 是「变化之间的补间动画」:你只管声明起点和终点, 浏览器自动补齐中间每一帧。四个参数:transition-property(哪些属性参与,all 全包)、 transition-duration(多久)、transition-delay(延迟,负值=从中间开始)、 timing-function(缓动: ease/linear/ease-in/ease-out/ease-in-out,或 cubic-bezier 自造)57。

本章的招牌例子(例 18-4)只有两行核心:

#square    { background: orange; transition: all .8s ease-in-out; }
#square:hover { background: yellow; transform: rotate(180deg); }

效果:鼠标悬停时方块平滑旋转半圈、由橙变黄;鼠标移开,动画自动倒放回原状—— transition 被中断时会优雅地折返58。这句话值得记住:能用 CSS 做的动效, 别动 JavaScript——声明式、性能好、代码少。

把 transition 的四个参数拆开走一遍(例 18-4 的 transition: all .8s ease-in-out):

  1. transition-property(all):哪些属性参与补间。写 all 最省心—— 本例里 background 和 transform 都会平滑变化;也可以逗号列多个 (width, height, opacity),精确控制。
  2. transition-duration(.8s):补间总时长 0.8 秒。这是「动画速度」的主要调节项。
  3. transition-timing-function(ease-in-out):缓动曲线——先慢、中间快、收尾慢, 模拟物理世界的加减速,最自然。linear(匀速)反而显得机械; 进阶用 cubic-bezier(四个数自造曲线,原书给了五条标准曲线对应的参数)。
  4. transition-delay(例中未写,默认 0):延迟启动;负值表示「从动画中途开始」。

中断折返是 transition 最贴心的行为:动画放到一半把鼠标移走,它不会跳回起点, 而是从当前位置平滑倒回初值——「smart」是原书用的词。相比之下, JS 逐帧动画要自己处理这种回退,这正是「CSS 优先」的另一条理由58。

5. 两大布局系统:flexbox 与 CSS Grid

CSS 布局的历史包袱(float 假浮动、position 硬定位)在两大新系统面前退场。

Flexbox(一维:一行或一列):容器 display: flex 后,子元素变 flex items, 沿着「主轴」排队。常用属性一张表59:

属性 管什么 常用值
flex-direction 主轴方向 row(默认)/ column / 各自 -reverse
justify-content 主轴上的分布 space-between(首尾贴边均匀分)/ center / space-evenly…
align-items 交叉轴对齐 center / stretch / baseline…
align-self 单个子项覆盖容器对齐 end…
flex-grow / flex-shrink / flex-basis 子项伸缩比例与基准 flex: 1 1 100px 简写
flex-wrap 放不下的换行吗 nowrap(默认)/ wrap
order 显示顺序(不改 HTML 源码序) 数字,小的在前
gap 子项间距 10px;grid-gap 是旧别名

CSS Grid(二维:行列同时定义):容器 display: grid; grid-template-columns: 1fr 2fr 1fr 定义三列(中间列两倍宽,fr 是分数单位), grid-template-rows: 100px auto 定义行高;grid-auto-flow 管填充顺序(可 dense 回填空洞);子项用 grid-column: 2 / span 2(从第 2 列起跨 2 列)这类语法精确摆放, 四参 grid-area: 2 / 2 / 5 / 6 一口气定起止行列;对齐有 justify-items(横)与 align-items(纵)60。两系统都进了浏览器开发者工具(Chrome 的 flex/grid editor 可视化调参),这也是学习它们最快的方式61。

分工一句话:内容是一行/一列的排列(flexbox),页面是二维网格(Grid)—— 两个都用,嵌套也行。** 拿真实项目的典型嵌套把这句落地:Grid 排页面骨架, 每个格子内部再用 flexbox 排内容——

#page   { display: grid; grid-template-columns: 220px 1fr; }   /* 骨架:二维 */
#topnav { display: flex; justify-content: space-between; }      /* 页头内部:一维 */
#sidebar { display: flex; flex-direction: column; gap: 8px; }   /* 侧栏:一维竖排 */
#main   { display: grid; grid-template-columns: 1fr 1fr 1fr; }  /* 主区:卡片网格 */

四个声明各司其职:骨架横切两列;页头的一排链接用 flex 拉开; 侧栏一列按钮竖排+缝;主区的三张卡片用 Grid 三等分。 「Grid 定骨架、flex 填血肉」是社区主流——两者不竞争,是分工; 判断口诀:这个容器的内容「主要朝一个方向排队」→ flex,「要同时管行和列」→ Grid6061。

5.1b 把一个导航条走通:flexbox 实战

光背属性不动手,布局学不会的。拿一个最常见的场景——顶部导航条——把 flexbox 从声明到生效走一遍:

<nav id="topnav">
  <a href="/">首页</a> <a href="/news">资讯</a>
  <a href="/about">关于</a> <a href="/login">登录</a>
</nav>
#topnav {
  display: flex;              /* ① 容器变 flex:四个链接沿主轴(默认横排)排队 */
  justify-content: space-between; /* ② 首尾贴边、中间均匀分布 */
  align-items: center;        /* ③ 交叉轴(竖直)居中——链接文字垂直对齐 */
  gap: 12px;                  /* ④ 相邻链接间距 12px */
}

走一遍:① display: flex 一声明,四个 自动横排(不再各占一行—— 块级元素默认竖着摞,flex 把它们改成横队);② space-between 把「免费空间」 均匀塞进相邻链接之间,首链接贴左、尾链接贴右——这是导航条最经典的排法; ③ 若链接里有的带图标、字号不一,align-items: center 让它们在竖直方向中线对齐; ④ gap 只影响「缝」,不影响首尾——比给每个子项写 margin 干净。 想换成竖排菜单? 只改一行:flex-direction: column,justify 与 align 的角色 自动互换(主轴变竖的)——这就是「主轴/交叉轴」抽象的价值:换方向不用重写规则59。

5.2b 把一个页面骨架走通:CSS Grid 实战

flexbox 管一维,整页布局要二维——页头、侧栏、主区、页脚的经典骨架,用 Grid 四五行就立起来:

#page {
  display: grid;
  grid-template-columns: 200px 1fr;   /* 两列:侧栏 200px,主区吃掉剩余 */
  grid-template-rows: 60px 1fr 40px;  /* 三行:页头 60、主区弹性、页脚 40 */
  gap: 10px;
  height: 100vh;
}
#page > header { grid-area: 1 / 1 / 2 / 3; }  /* 页头:第 1 行,跨两列 */
#page > footer { grid-area: 3 / 1 / 4 / 3; }  /* 页脚:第 3 行,跨两列 */
/* 侧栏与主区不用写——按 DOM 顺序自动落位(第 2 行的两列) */

grid-area 的四参「起始行 / 起始列 / 结束行 / 结束列」是 1 起数的网格线编号—— 1 / 1 / 2 / 3 读作「从第 1 行线、第 1 列线起,到第 2 行线、第 3 列线止」, 正好盖住第一行整片。剩下的子项不用管:grid-auto-flow: row(默认)按 HTML 顺序 把侧栏、主区依次填进第 2 行的两格。改布局 = 改模板数字:想侧栏挪右边? columns 改成 1fr 200px 即可,子项写法一行不动——这就是 Grid 对 float/position 的 代差优势60。

6. JS 操作 CSS 的扳手(原书第 19 章前半)

6.1 三个小函数:全章的脚手架

function byId(id)    { return document.getElementById(id) }
function style(sel)  { return document.querySelector(sel).style }
function by(sel)     { return document.querySelectorAll(sel) }

style('#myobj').color = 'green' 一行换掉以前的长链; by('.myclass') 收来所有匹配元素(注意 querySelector 只回第一个), 循环统一处理。三个函数收进 functions.js,一章的示例都靠它们瘦身—— 原书明说:真实项目你会用框架或自己更全的工具库,这里只为教学短62。

把这三个函数的分工钉成一张表:

函数 底层调用 选中 典型用途
byId('myobj') getElementById 一个(id 唯一) 操作特定元素
style('#myobj') querySelector 一个(第一个匹配) 直接拿到 .style 改样式
by('.myclass') querySelectorAll 全部匹配 循环批量处理

一个使用纪律:这三者是「教学脚手架」,不是「项目基建」——书中示例靠它们保持简短, 真实代码里要么用框架(React 第 20 章)要么封装自己的工具;但 querySelector / querySelectorAll 这两个底层 API 是必须记住的原语,所有封装都站在它们上面。

注意 style 和 byId 的重叠:都需要 id 时,style('#x') 比 byId('x').style 少敲几个键;by 则是唯一「成群取元素」的入口。选择器参数就是 CSS 选择器语法—— 第 18 章那十种(含 ^= 三刀)在这里全能用:by("img[src$='.png']") 选中所有 PNG 图, by('div > p') 选中所有「div 的直系 p 子元素」。CSS 学和 JS 选择在同一个语法上合流了62。

属性名的驼峰换算:JS 里连字符是减号,所以 CSS 的 text-decoration 要写成 textDecoration、font-size 写成 fontSize;想保留原名就用 setAttribute('style', 'font-size:16pt')63。window 对象上还有一屋子属性可摸: innerWidth/innerHeight(内容区尺寸,做居中常用)、screen(用户显示器)、 history(只给数不给内容,上一章讲过)、localStorage/sessionStorage64。

6.2 事件:页面开始听你指挥

两种挂法。内联:<img onmouseover="this.src='orange.png'" …>——事件名前加 on, 写在标签里;this 指当前元素65。外联(推荐):脚本里 o.onmouseover = function() { this.src = 'orange.png' }——HTML 与行为分离66。

常用事件一屏记:click / dblclick / mousedown / mouseup / mousemove / mouseover / mouseout(鼠标一族);keydown / keypress / keyup(键盘一族—— keypress 不含 Shift/Ctrl 等功能键);focus / blur(得失焦点);change / submit / reset(表单);load / error(媒体与脚本);scroll / resize(窗口)67。 Warning 一条:事件要挂在对的元素上——不是表单的元素不会响应 onsubmit68。

事件何时发、挂在哪类元素上,一张速查表收拢(原书 Table 19-2 的常用子集):

事件 挂哪 什么时候发
click 任何元素 被点击
mouseover / mouseout 任何元素 鼠标进入 / 离开元素边界
mousedown / mouseup 任何元素 按下 / 松开鼠标键(click = 两者成对)
keydown / keyup 有焦点的元素 按下 / 松开键盘任意键
keypress 有焦点的元素 按下「字符键」(不含 Shift/Ctrl/Esc 等功能键)
focus / blur 可交互元素 获得 / 失去焦点(点进输入框 vs 点走)
change 表单控件 内容被修改后失焦时
submit / reset 表单 表单被提交 / 被重置
load / error 媒体元素、window 加载完成 / 加载出错
scroll 文档 页面滚动
resize window 浏览器窗口改大小

focus 的含义值得单独一句:「有焦点的元素」就是用户此刻「正在交互」的那个—— 刚点过的输入框、刚按过的按钮。键盘事件只发给有焦点的元素,所以「全局快捷键」 要挂 document 而不是某个 div67。

6.2b 事件驱动完整环:从点击到变色

把事件的完整因果链走一遍(这是第 19 章一切例子的骨架):

const btn = byId('btn')                        // ① 选中元素
btn.onclick = function() {                     // ② 挂处理器(此刻不执行)
  this.style.background = 'gold'               // ③ 处理器体内的动作
}

时间线:页面加载 → ② 把函数「挂号」到按钮的 click 事件上,函数体一行不跑 → 用户点击 → 浏览器按下述动作替你执行 ③:造一个事件对象、把 this 设成按钮、 调用你挂的函数 → 函数里 this.style.background = 'gold' 改样式 → 渲染层把按钮刷成金色。 从头到尾你的代码只在「挂号」和「被调」两个时刻运行——中间那段「等用户点」 的时间里没有你的代码在跑。理解这个「被动唤醒」模型,事件编程就通了: 你写的不是流程,是「当 X 发生时做 Y」的一堆约定66。

事件名与 on 前缀的对应也顺手记住:mouseover → onmouseover、 submit → onsubmit、click → onclick;HTML 内联写法把同一对写在标签属性里 (<img onmouseover="…">),脚本写法则 o.onmouseover = fn—— 原书两式都教了,现代团队更推崇后者(HTML 与行为分离,页面不掺杂逻辑)6566。

6.3 增删元素与显隐术

造元素三步:document.createElement('div') 造 → 设 id/样式/内容 → document.body.appendChild(newdiv) 挂进 DOM——挂进去的瞬间它就和其他元素 完全平等69。删除要绕一步:element.parentNode.removeChild(element) (得通过父元素删)70。

只是要「藏起来」就不必出生入死:visibility = 'hidden' 隐身但占位; display = 'none' 彻底坍缩、邻居补位,恢复用 display = 'block'(或 flex/grid); innerHTML = '' 清内容也是一种「消失」71。

6.4 定时器:时钟与动画

setTimeout(fn, 5000) 五秒后调一次;setInterval(fn, 1000) 每秒反复调, 配对的 clearTimeout/clearInterval 取消——取消前要把调用时返回的「句柄」存好72。

三个新手必撞的坑,原书都点了名:① 传函数,不传调用—— setTimeout(alert('Hello'), 5000) 会立刻弹窗(函数马上执行,返回值被传给定时器); 要写 setTimeout(() => alert('Hello'), 5000)73。② 别传字符串—— 老写法有安全风险和性能损耗74。③ 动画的帧率换算:每 30 毫秒一帧 ≈ 33 帧/秒 (1000 ÷ 30)。

本章的动画例子(例 19-10)把第 18 章的 transform 换成直接改样式: 每 30 毫秒让方块 width/height 加 10、left 加 3,到 200/600 就归零重来—— 一个边跑边胀的方块。同样的循环骨架,换个变量就是时钟(每秒 toTimeString 截前 8 位)、 进度条、轮播图75。

6.4b 时钟走查:setInterval 的完整一拍

拿本章的时钟例子(例 19-9)当主线,把「周期任务」的机制逐拍走清:

setInterval(() => showtime(byId('time')), 1000)   // 每 1000ms 调一次

function showtime(object) {
  const date = new Date()
  object.innerText = date.toTimeString().substr(0, 8)   // "14:23:05"
}

走一遍:① 页面加载,setInterval 被调用——它把箭头函数注册进浏览器的定时器队列, 立即返回一个句柄(存下它才能日后 clearInterval); ② 此后每过 1000 毫秒,浏览器替你把箭头函数调一次; ③ 每次调用:new Date() 拿到此刻的时间对象 → toTimeString() 转成 "14:23:05 UTC+0800" 这样的串 → substr(0,8) 截取前 8 个字符("14:23:05") → 赋给 span 的 innerText → 页面上的秒数跳一下。 ④ 想停?const id = setInterval(...) 存句柄,clearInterval(id) 注销—— 注销后浏览器不再调它,时钟定格。还可以套一层:setTimeout(() => clearInterval(id), 10000) 让时钟 10 秒后自动停72。

这个「注册 → 周期唤醒 → 注销」的三拍结构,和事件的「挂号 → 触发 → 注销」同构—— 浏览器替你守着时间,你的函数只在被唤醒的瞬间存在。动画(例 19-10)只是 把时间间隔压到 30 毫秒、把「改文字」换成「改 width/height/left」: 每帧动 10 像素、每帧挪 3 像素,人眼就把离散的快照看成了连续的运动75。

7. 两章合龙的主线例子:一次完整的「悬停换装」

把散件装成一个能跑的完整小场景——图片悬停换图(苹果变橘子),用第 19 章的外联写法:

<img id='fruit' src='apple.png' alt='fruit'>
<script src='functions.js'></script>
<script>
  const img = byId('fruit')
  img.onmouseover = function() { this.src = 'orange.png' }
  img.onmouseout  = function() { this.src = 'apple.png'  }
</script>

走一遍:① 页面加载,两个匿名函数挂到 img 的两个事件上(此刻不执行); ② 鼠标移入 → 浏览器发 mouseover → this(img 自己)的 src 换成橘子图,浏览器重新加载显示; ③ 鼠标移出 → mouseout → 换回苹果。 事件 = 浏览器在特定时刻替你调函数;this = 出事的那个元素——这两句话是第 19 章的全部机密。

再往前一步(本章末尾的动画同构):把「换图」换成「改 style 数值 + setInterval 循环」, 你就从「交互」跨进了「动画」;把「鼠标事件」换成「fetch 的 then」,就接上了第 17 章。 前端的一切花样,都是这一个环的变奏。

7.1 同一个环,三种换法

把 §7 的「悬停换装」沿两个方向各走一步,看清「一个环的变奏」不是比喻:

变奏一:事件换成定时器(自动化)。 没人碰它,它也自己动——把两个事件处理器 换成一个 setInterval,苹果橘子图就变成每 2 秒自动轮播的图片槽:

let showingApple = true
setInterval(() => {
  img.src = (showingApple = !showingApple) ? 'apple.png' : 'orange.png'
}, 2000)

变奏二:改 src 换成改样式(内容变呈现)。 不换图了,改颜色—— this.style.filter = 'grayscale(100%)' 悬停时变灰;再叠上第 18 章的 transition: filter .4s,变色也平滑了。第 18 章的 transition 在这里回收: JS 只负责「何时」,CSS 负责「怎么变」——两章的分工在这个三行例子里合龙。

变奏三:改自己换成改别人(局部刷新)。 鼠标悬停一张缩略图,旁边的大图区换 src—— 处理器里操作的 this 换成 byId('preview'),作用对象和事件源分离。 第 17 章的 fetch 版只是把「换图」换成「请求数据后换内容」,环还是同一个环75。

8. 作者的判断与证据

书中的说法 成色
「能用 CSS 做的动效,别动 JavaScript」(章首建议) 设计立场,与 transition 章节的能力相互支撑;理由(更干净的设计、文档属性自描述)成立,但对复杂交互动画(逐帧控制)JS 仍是必须——书中动画例恰好是例外76
Google Fonts 的隐私提示 少见的合规提醒,超出一般前端教材的边界;「可下载自托管」给了可执行的对策55
用 transition 做悬停动画、会「优雅折返」 机制事实,中断回退是浏览器内建行为,实验即可验证58
byId/style/by 三函数只是教学脚手架 作者自陈(真实项目用框架/自己的库),诚实;但也暗示了一个判断:querySelector 系的 API 已成为事实标准62
setTimeout 别传字符串 安全 + 性能双重理由,与 eval 的废弃同一条主线74
keypress 不含功能键等事件差异 机制事实表,照 MDN 口径;细节随规范演进可能微调(原书也指向 MDN 全表)67
Chrome 的 flex/grid 编辑器推荐 工具建议(可视化调参),对学习价值很大;但非 Chromium 浏览器(尤其 Safari)用户没有等价物,属平台偏向61
visibility vs display 的取舍 机制说明清晰(占位 vs 坍缩),但没给出「什么时候选哪个」的场景判据——经验口诀:布局会重排的选 visibility,要腾出地方的选 display71

9. 边界与局限

  • 两大布局系统的教法是「属性清单式」:给了属性和取值,但没有带你排一个真实页面 (页头/侧栏/主区/页脚的 Grid 经典布局没有完整示范);响应式(@media 查询)全书未讲—— 「mobile-friendly」只在第 2 章提了一句 BrowserStack。
  • 浏览器前缀与兼容:一笔带过(「看 Can I Use」);历史遗留的 -webkit- 前缀问题 和老浏览器支持矩阵本书一律不背——教学减负合理,但接手旧代码会撞见。
  • CSS 变量(custom properties)缺席:var(--main-color) 已是现代 CSS 的核心件, 本章没有;JS 读写 CSS 变量这套组合技也随之缺席。
  • JS 侧的事件模型停在 DOM Level 0:o.onclick = fn 只能挂一个处理器, addEventListener(第 16 章用过!)才是现代标准——两章之间口径不一, 第 16 章用了真标准、第 19 章回头教老写法,顺序略怪。
  • 动画课停在 setInterval:requestAnimationFrame(浏览器官方动画节拍器, 省电、帧率自适应)没有出现——setInterval 动画在后台标签页会空转耗 CPU, 是已被业界替换的旧法。
  • window 属性表是「知道有」级别:localStorage/sessionStorage 与 cookie、 会话的关系没有讲透;真正持久化前端数据的主线缺席。
  • DOM 增删的教学例子偏玩具:例 19-8 用 alert + setTimeout 演示增删, 真实场景的「列表里插入一行」「模态框」只给了 Note 一句; createDocumentFragment、insertBefore 这些常用 API 没有登场。
  • Flexbox 与 Grid 的属性值讲全了但组合演示少:justify-content 的九个值 逐个列了,什么时候该 space-around 而不是 space-evenly 这类判断没有场景支撑; 学习者容易「每个都认识、排的时候全忘」。

10. 章末自测:两章的问答题合答

原书的问题 我们的回答
^=、$=、*= 各干什么? 属性值的开头 / 结尾 / 任意子串匹配46
背景图尺寸用哪个属性? background-size(单值双边、auto 单边等比、contain 整图可见、cover 铺满裁切)48
圆角半径? border-radius(四角顺时针各角;单角两参 = 水平半径 + 垂直半径,画椭圆角)50
多栏文本? column-count + column-gap + column-rule(文字按栏连续流;互不相干的列用 Grid)52
四个颜色函数? hsl、hsla、rgb、rgba;hsl 三参 = 色相环角度 + 饱和度 + 明度53
右下角 5px 偏移、3px 模糊的灰文字阴影? text-shadow: 5px 5px 3px #808080(横偏移、纵偏移、模糊量、颜色)54
省略号表截断? text-overflow: ellipsis——三条件:overflow:hidden + white-space:nowrap + 容器窄于文字54
怎么引入 Google 字体? 复制 Google Fonts 给的 <link> 进 <head>,font-family 引用并把系统字体列作后备55
旋转 90 度? transform: rotate(90deg);transform 函数可叠加(先写先动手)56
任何属性变化都线性过渡半秒? transition: all .5s linear(简写:属性 时长 缓动 [延迟])57
flexbox 容器怎么建? display: flex——子元素立即沿主轴排队(默认横排);改竖排 flex-direction: column59
主轴分布? justify-content(space-between 首尾贴边、space-evenly 缝与边等宽、center 居中)59
交叉轴对齐? align-items(单项目用 align-self 覆盖);stretch 让子项拉满交叉轴59
伸缩由哪两个属性管? flex-grow 与 flex-shrink(flex-basis 定基准)59
改 flex 显示顺序? order(数字小的在前,不改源码序;默认 0,负数最前)59
Grid 怎么建? display: grid + grid-template-columns/rows;fr 是「分数单位」,1fr 2fr 1fr = 三列按 1:2:1 分宽60
Grid 流向? grid-auto-flow(row/column/dense)60
摆放 grid 子项的两个属性? grid-column 与 grid-row(起 / span 跨数);grid-area 四参简写「起行/起列/止行/止列」60
网格间距属性与旧名? gap(grid-gap);行列分开用 column-gap / row-gap,gap: 10px 15px 两个值60
纵横对齐? justify-items(横)与 align-items(纵);Grid 与 flexbox 都有 align-items,语义一致60
按 id 简写取元素的函数? function byId(id){ return document.getElementById(id) }(每次调用省 19 个字符)62
改 CSS 属性的两条路? camelCase 属性赋值(fontSize)或 setAttribute('style',…)63
窗口内容区宽高? window.innerWidth / innerHeight64
鼠标移入移出都做动作? onmouseover + onmouseout;外联写法(脚本里挂)优于内联(标签里写)65
创建/挂接元素的函数? createElement 造、appendChild 挂到父元素(本例 document.body)69
隐身 vs 坍缩? visibility:hidden 隐身占位(display 布局不变);display:none 坍缩让邻居补位;恢复用 display: block(或 flex/grid 等原值)71
未来一次性事件? setTimeout(传函数句柄,不带括号;要传参就包箭头函数)72
周期事件? setInterval + clearInterval(句柄先存);想跑 N 次自动停:套一层 setTimeout 去 clearInterval72
可移动元素的 position 值? absolute(配合 left/top 定位)75
50 帧/秒的间隔? 1000 ÷ 50 = 20 毫秒75

这一组问答题的特点是「全实操」:二十余问几乎每问都对应一个具体声明, 答得出 = 写得出。建议拿它当自测清单:每答一问,顺手在本地起个页面把声明敲出来看效果—— CSS 是唯一「看一遍就会」不能成立的技能,手指记忆才是真的记忆。

11. 可带走的

  1. 属性三刀:^= 头、$= 尾、*= 身;盒模型选 border-box。
  2. 背景三件套 clip/origin/size;多重背景逗号叠、后写在下。

快速回忆:clip 管「画到哪一圈」、origin 管「从哪一点起笔」、size 管「画多大」; 奖状边框例(8 图分层叠)是多重背景的完整范式4849。 3. border-radius 四角顺时针,单角双参画椭圆;box/text-shadow 同参数四件。 4. 颜色 hsl/hsla/rgb/rgba + opacity;HSL 的「色相环 + 饱和 + 明度」比 RGB 好调。 5. text-overflow: ellipsis 三条件缺一不可;word-wrap 治长单词。 6. @font-face / Google Fonts;托管字体的隐私代价要知道,可自托管。 7. transform 四件(translate/scale/rotate/skew)可叠加;transition 四参补间, 中断自动折返;CSS 能搞定的动效别上 JS。 8. flexbox 一维:direction/justify/align/grow/shrink/wrap/order/gap; Grid 二维:template 定骨架、grid-area 摆子项;两者可嵌套。 9. byId/style/by 三件套 + camelCase 换算;window 一屋子尺寸属性。

window 的常用三员:innerWidth/innerHeight(内容区,居中弹层用它)、 screen(用户显示器的分辨率与色深)、pageXOffset/pageYOffset(页面滚动了多少)—— 移动端适配的头几条信息全在这里64。 10. 事件 onXxx 挂函数;this 是出事元素;事件要挂对的元素。

事件名的 on 前缀只用于「挂处理器」的写法(onclick、onmouseover);
事件本身叫 click、mouseover(第 16 章的 addEventListener('submit', …)
用的是不带 on 的原名)——两个名字都留名,读代码时才不会以为是两件事[^22]。
  1. createElement + appendChild 增,parentNode.removeChild 删; 显隐首选 visibility/display,别轻易生删 DOM。
  2. setTimeout/setInterval 传函数句柄不传调用、不传字符串;句柄存好才能取消; 1000÷帧率 = 毫秒间隔。

    最后一道自检:能把「时钟」和「动画」两个例子从空白页默写出来 (时钟 = setInterval + Date + innerText;动画 = setInterval + 变量递增 + style), 第 19 章的核心回路就真正到手了75。

11.1 两章合一张「呈现 × 交互」自检表

写任何一段前端代码前,先过这张表——每项答得出,两章才算长在手里:

想做的事 第一选择 本章出处
选元素改样式 byId/style 或 querySelector(All) §6.162
CSS 属性名带连字符 换驼峰(fontSize)或 setAttribute §6.163
鼠标悬停有反馈 :hover + transition(纯 CSS) §458
鼠标悬停换图/改内容 onmouseover/onmouseout + this §6.265
一行文字太长 text-overflow: ellipsis 三条件 §354
长单词撑破容器 word-wrap: break-word §354
一排元素均匀分布 flexbox + justify-content §5.159
整页骨架(头/侧/主/脚) Grid + grid-area §5.260
临时弹个提示再消失 createElement + appendChild + setTimeout 摘除 §6.3/6.46972
元素藏起来但占位 visibility: hidden §6.371
元素彻底让位 display: none §6.371
每秒刷新内容 setInterval + clearInterval 句柄 §6.472
平滑补间任何属性 transition(property/duration/timing/delay) §457

这张表也是进第 20 章 React 前的对照基线:React 做的仍然是这些事, 只是「选元素、改样式、响应事件」换了组织方式——本表每一行的「第一选择」, 在 React 里都有对应的部件,但理解对应关系的前提是先把原语玩熟。

11.2 两章在全书的位置

到这里,本书前端线的「手艺层」就齐了:第 13–17 章给了 JavaScript 的语言与通信 (算和取),第 18–19 章给了呈现与交互(看和摸)。三件套的分工可以用一句完整的话 复述全书到此处的主线:PHP 在服务器把数据算成 HTML,MySQL 把数据存住, JavaScript 在浏览器把页面变得可交互,CSS 决定这一切长什么样。 第 20 章的 React 与第 21 章的 Node.js,分别是「JavaScript 写界面」和 「JavaScript 写服务器」两条线的现代化延伸——它们的根基,就是这两章的原语。

11.3 第 18 章地图:按"给元素添能力"重新排的目录

原书第 18 章小节很多,换一个更有用的视角——每节都在给元素 添一种什么能力:

选得更准   → 属性选择器(10 种,Table 18-1 总览)[^32]
算得更顺   → box-sizing:border-box(宽度含 padding 和 border)[^33]
铺得更花   → 背景四件套:clip / origin / size / 多背景叠放[^34]
边得更圆   → border-radius + 边框图片(例 18-2 的九宫格式自适应)[^35]
衬得更深   → box-shadow(元素的影子)
排得更活   → multicolumn(文本多栏,例 18-3)[^36]
色得更细   → HSL/HSLA/RGB/RGBA + opacity(颜色与透明分家)[^37]
字得更艳   → text-shadow / text-overflow / word-wrap + Web Fonts[^38]
变得更动   → transform(旋转/缩放/斜切,2D 与 3D)[^39]
动得更柔   → transition(四参数 + 简写)[^40]
站得更稳   → Flexbox(一维)与 Grid(二维)[^41]

这个视角下的读法:不必按原书顺序啃。做项目缺什么查什么; 但 transform 与 transition 是一对(先变后柔),Flexbox 与 Grid 是一对(先一维后二维),两对是本章的承重墙。

11.4 box-sizing:一行解决"宽度对不上"的老毛病

默认盒模型(content-box)里,你写的 width 只是内容宽度, padding 和 border 另算——于是"设了 width:100% 又加了 padding" 的元素必然撑破父容器。box-sizing:border-box 把宽度定义成 内容+padding+border 的总和,所见即所得11。

实战规矩只有一条,也是事实标准:

* { box-sizing: border-box; }

把它放在样式表第一行,从此脑内不再存在"内宽外宽"两套账。 本书前端部分的所有例子,默认在这行之下讨论。

11.5 颜色系统升级:HSL 是比十六进制更好用的记账法

第 18 章用 HSL/HSLA 补完了颜色体系12。三个值的含义:

  • H(色相):0–360 的角度,红 0、绿 120、蓝 240;
  • S(饱和度):0% 灰、100% 正;
  • L(亮度):0% 黑、50% 正色、100% 白。

它比 #ff8800 好用在一个场景:成套调色。主色定一个 H, 变体只动 L——按钮普通态 L 45%、悬停 L 55%、禁用 L 70%, 一套色板十几个值全从一个数长出来。RGBA/HSLA 尾字母 A 是透明度, 与 opacity 属性分工:前者只透明颜色,后者透明整个元素 (含文字和子元素)13。

11.6 transform 与 transition:先会"变",再会"柔"

transform 的能力清单(第 18 章):rotate 旋转、scale 缩放、 translate 平移、skew 斜切,可叠加、可 3D14。

transform : scale(1.5, 2) rotate(45deg);   /* 先放大再转,顺序有意义 */

transition 给"属性变化"装上时间轴,四参数各管一段15:

transition-property : width, height, opacity;  ← 哪些属性参与
transition-duration : 1.25s;                   ← 多久
transition-delay    : .1s;                     ← 等多久才起头
transition-timing-function : ease-in-out;      ← 快慢曲线

简写一行梭:transition : all .8s ease-in-out;——书里的方块例子 靠这行加一条 :hover { transform : rotate(180deg); } 就有了 "悬停转正"的完整动效16。

设计判断(我们的延伸,机制属原书):transition 管"状态间的路", transform 管"状态本身"——两者都不需要 JavaScript。 JS 只在"状态由数据决定"时入场(下一节),CSS 能干的动效别动用 JS, 这是性能与代码量的双重节约。

11.7 Flexbox 与 Grid:一维与二维的分工

Flexbox:容器 display:flex 之后,子项沿一条轴分配空间、 对齐、伸缩,不管容器尺寸如何都能自适应17。六个核心旋钮 (本书第 18 章小节顺序):flow-direction(主轴方向)、 justify-content(主轴对齐)、align-items(交叉轴对齐)、 flex-wrap(换行)、order(视觉顺序)、gap(项间距)。 一句选型:"一排或一列的东西"找 Flexbox。

Grid:容器 display:grid,用 grid-template-columns/rows 显式画格子18:

grid-template-columns : 1fr 2fr 1fr;   /* 三列,中列两倍宽 */
grid-template-rows    : 100px auto;    /* 两行,头定高身自适应 */

fr 是"剩余空间的份数",auto 是"内容说了算"。 一句选型:"有行有列的版面"找 Grid。

两者不互斥:Grid 画大框架,Flexbox 收拾格子内部件, 是现代页面的默认组合拳。原书在此收尾第 18 章,顺序本身就是 教学判断——先把一维玩熟,再上二维。

11.8 Web Fonts:字体的两节课

第 18 章的字体课分两节:

  1. @font-face 自托管:声明字体名与字体文件,页面加载时 一并取回19。控制力最强,要自己管字体文件与格式兼容。
  2. Google Fonts 托管:在 Google 的网站选好字体, 它生成一段 <link> 贴进 <head> 即用20—— 本书项目章的字体就是这条路。

配套的隐私提醒(原书点了名):用第三方托管站点,等于告诉它 你的访客观看了哪些页面——对隐私敏感的场景,自托管是更稳的选择21。

11.9 第 19 章的三个小工具:byId / style / by

第 19 章没有新概念,交付的是三个反复用的小函数22:

function byId(id)  { return document.getElementById(id) }        // 按 id 取元素
function style(sel){ return document.querySelector(sel).style }  // 按选择器取 style 子对象
function by(sel)   { return document.querySelectorAll(sel) }     // 按选择器取全部匹配

三个函数覆盖了 DOM 访问的 90% 日常:一个精确(id)、 一个灵活(任意 CSS 选择器、取第一个)、一个成批(全部匹配, 返回数组式集合)23。本书不用 jQuery 之类的框架, 靠的就是这三个小函数把样板代码压到一行24。

11.10 改样式的三条路:内联、类、计算后

第 19 章的例子几乎全走 元素.style.属性 = 值 的内联路。 三条路并排看,才看得清它的位置:

路 写法 何时用
内联 style obj.style.color = 'green' 值由实时数据算出来(宽度、坐标)
切类(class) 预定义 .on{...} 类,JS 只加删类名 状态切换(开/关、选中)——CSS 管样子,JS 管状态
读取计算值 getComputedStyle 系(书外补充) 必须知道"现在到底是多少 px"时

原书用内联路贯穿,因为例子的值都是动态的;但书中也有一句 立场鲜明的推荐:能用 CSS 实现的动态效果,优先 CSS, JavaScript 只是"贴上去"的后备——属性属于文档本身, 设计更干净25。悬停变色这类事,:hover 是纯 CSS 的主场, onmouseover 的 JS 写法只是演示(例 19-6)26。

11.11 显隐的两种语义:visibility 与 display

第 19 章把"藏元素"拆成两种藏法27:

  • visibility:hidden —— 人不在,座位还在(占位保留);
  • display:none(同节语境)—— 连座位一起撤(不占位)。

外加 opacity 当"半透明中间态":0 到 1 之间,元素仍占位、 仍可交互28。

选型一句话:要"闪一下又回来"用 visibility/opacity(重排代价小), 要"真的移除"用 display。再叠上 transition, opacity 还是做"淡入淡出"的默认工具——本节与 §11.6 在此会师: 显隐动画 = opacity 过渡,不是定时器硬改。

11.12 事件绑定的进化史:内联 → 属性 → 监听

第 19 章的鼠标例子恰好排成一条进化线:

onmouseover="this.src='orange.png'"   ← 内联在 HTML 里:能跑,难维护[^60]
o.onmouseover = function(){...}       ← 属性赋值:HTML 干净了,
                                          但同一事件只能挂一个
o.addEventListener('mouseover', ...)  ← 监听:多个处理者共存,可移除

本书主线停在第二式(例子里大量 o.onmouseover 赋值), 第三式是书外补充的现代默认。进化方向的判据始终一致: HTML、CSS、JS 三者的耦合越松越好——内联把三种语言缝在 一个引号里,属性式拆开一半,监听式全拆。

11.13 两章合练:一个"可展开卡片"的完整实现

只用第 18/19 章的机制,拼一个经典小组件(概念拼装):

需求:点击卡片标题 → 正文展开/收起,带 0.3s 过渡

[CSS]  .card .body { overflow:hidden; max-height:0;
        transition: max-height .3s ease; }
       .card.open .body { max-height:300px; }
[JS]   by('.card h3').forEach(h => h.onclick = () =>
         byId(h.closest('.card').id).classList 切换 'open')
[判定] 高度由 CSS 管(含过渡),JS 只管 class 的加删;
       display:none 不能做这件事——它不可过渡

这个组件小,但把两章的分工演示全了:状态在 class 上(11.10)、 过渡在 CSS 上(11.6)、交互在事件上(11.12)、取元素用 by/byId(11.9)。 做完它,两章从"读过"变成"用过"。

11.14 练习场(第 18/19 章)

  1. 盒模型实验:两个同设 width:200px 的 div,一个 content-box 一个 border-box,各加 20px padding,量渲染宽度——把 §11.4 的一行代码变成肉眼可见的差异。
  2. HSL 调色板:给定主色 hsl(210, 70%, 45%),写出悬停/禁用/ 深色底三种变体,只动 L 与 A。
  3. 纯 CSS 动效:方块悬停旋转 180° 并变色,不许写一行 JS; 再写 JS 版对比代码量——体会 §11.6 的设计判断。
  4. Flexbox 急救:把一段用 float 写的三栏布局改写成 display:flex,各栏等高;再用 grid-template-columns 改写一遍, 对比两版的心智负担。
  5. 事件进化:给三个按钮分别用内联/属性/监听绑定点击, 验证监听式可以挂两个处理者而另两种不行。

11.15 FAQ(五问)

Q1:transition 的 all 会不会很贵? transition:all 省心,但任何属性风吹草动都触发过渡; 生产里建议只列真正要动画的属性(width、opacity、transform)。 原书教学例用 all 是图省事,别当惯例30。

Q2:为什么我的过渡不生效? 九成是这两类:①两端状态没变(比如 height 从 auto 到 auto); ②用了不可过渡的属性(display、position)。 查法:把属性换成 opacity 试一次——能过渡就是属性选错。

Q3:Flexbox 和 Grid 先学哪个? 原书顺序 Flexbox 在前31,跟它走:一维问题天天有 (导航、按钮组),二维版面(grid)项目期才密集出现。

Q4:第 19 章为什么不教 jQuery? 成书时 jQuery 已在退潮,原书明确说这三个小函数就是为了 "不必引入框架"32。2026 年的今天看,这个决定完全正确。

Q5:改样式时 innerHTML 拼接大段 style 行不行? 不行,原因和第 17 章同源:字符串拼 HTML 是给 XSS 开门。 样式的正规通道只有 §11.10 的三条路;HTML 结构请用 textContent/DOM 方法,别用字符串糊。

11.16 背景四件套:clip、origin、size、多背景

第 18 章背景一节给了四个经常混淆的属性33,一张表拆清:

属性 管什么 典型值
background-clip 背景画到盒模型的哪一圈为止 border-box / padding-box / content-box
background-origin 背景从哪一圈开始定位 同上三值
background-size 背景图怎么缩放 auto / cover / contain / 具体宽高
多背景 多张图叠一层 background: url(a), url(b) —— 先写的在上

size 的 auto 有讲究:原书专门一节讲它——保持比例时 一个轴给 auto,另一个定死34。cover 是"铺满、允许多裁", contain 是"全看见、允许留白":背景图的选择题,答案永远 在这两者之间。

11.17 边框与阴影:border-radius 与 box-shadow

border-radius:圆角半径,单值四角同、四值顺时针从左上起35。 它不只是美观——大半径+浅色,是"卡片化"界面的全部秘密。

box-shadow 的五个参数位(水平偏移、垂直偏移、模糊、扩展、颜色), 记忆模板:box-shadow: 0 2px 8px rgba(0,0,0,.15) —— "微下沉"的标准卡片阴影。模糊值是气质来源:小=干练,大=梦幻。

overflow(元素溢出)与同节相邻,一条规则:子内容超了父框, overflow:hidden 裁掉、auto 出滚动条36。圆角卡片里 几乎永远配 hidden,否则方角内容会从圆角里戳出来。

11.18 文本效果三件套与多栏布局

text-shadow 与 box-shadow 同构,一个管字、一个管盒37。 text-overflow:ellipsis 是"超长省略号"的标准件38; word-wrap(break-word 系)管"长单词换不换行"39。 三者各管一类文本事故:立体观感、超长截断、爆框单词。

Multicolumn(例 18-3):几行 CSS 把一段文本排成报纸式多栏40—— 适合长文阅读页;导航、表单千万别用。它的启示更通用: CSS 高级特性大多是"特定场景的专用件",通用件仍然 是盒模型、flex、grid 那几样。学的时候全部认识,用的时候 按需取用。

11.19 第 19 章的读法:把例子拆成"骨架 + 肌肉"

第 19 章的例子有个统一骨架,认出它,每页只需读增量:

window.onload = function() {           // 骨架:页面加载完再动手
  const obj = byId('myobj');           // 肌肉①:取元素
  obj.onclick = function() {           // 肌肉②:绑事件
    // 肌肉③:读写样式或属性
  };
};

三个读码问题,按序自问:

  1. 取了谁?(byId / by 的选择器)
  2. 什么时机?(onclick / onmouseover / onload…)
  3. 改了什么?(style 的哪个属性、什么值)

inline 事件写法(<img onmouseover=...>)与属性式 (o.onmouseover = ...)在骨架里是互斥的两代——§11.12 的 进化史在这里是读码的考古层位。

11.20 一个完整交互的逐行走查:开灯/关灯

把第 19 章式的机制拼成一个完整小交互(概念拼装,每行可指认章节):

window.onload = () => {                       // 骨架:onload(§11.19)
  const bulb = byId('bulb');                  // 取元素(byId,§11.9)
  const state = { on: false };                // 状态:一个普通对象
  bulb.onclick = () => {                      // 事件绑定(§11.12)
    state.on = !state.on;                     // 翻转状态
    bulb.style.opacity = state.on ? 1 : .3;   // 内联样式路(§11.10)
    bulb.style.transition = 'opacity .4s';    // 过渡给变化装时间轴(§11.6)
  };
};

五行的五脏俱全:取元素、绑事件、存状态、改样式、上过渡。 这也是 React 心智模型的"手工对照组"——React 把状态与渲染 焊在一起,这里全靠手写。写完这个,第 20 章的"为什么需要 React"就有了可量化的答案(行数、耦合度、状态同步的出错点)。

11.21 第 18/19 章与前 17 章的关系澄清

一个容易产生的误读:"CSS 与 JS 访问既然这么强,前面是不是白学了?" 恰恰相反——第 18/19 章是前面一切的应用层:

  • 选择器(第 18 章属性选择器)→ 第 19 章 querySelector 的 参数就是 CSS 选择器,选得越准,JS 越省事;
  • 盒模型与文档流(补充章基础)→ transform/transition 的坐标系;
  • 第 13–15 章的函数与事件 → 第 19 章的全部弹药;
  • 第 17 章的 fetch → 第 19 章改样式的数据可以来自服务器。

正确的层次观:前 17 章立机制,18/19 章做界面,20/21 章组架构, 22 章成项目。每层都站在上一层肩上。

11.22 FAQ 补遗(四问)

Q1:hsl 和 rgba 我该用哪个? 同一透明度的两种记账法。单处用色 rgba 顺手;成套调色板用 hsl, 因为变体是从一个 H 长出来的(§11.5)。项目里见到哪个用哪个, 自己写新样式时优先 hsl。

Q2:transition 和 CSS animation(@keyframes)本书讲了吗? 第 18 章讲了 transition,没展开 @keyframes 动画体系—— 触发即播、循环播放的动画在本书范围之外(书外补充:那是 animation 属性的领地)。transition 管"状态间的路", keyframes 管"自演的故事",本书只交付前者。

Q3:querySelector 返回的不是数组,为什么例子能下标遍历? by() 返回的是 NodeList——"类数组":有 length 和 [i], 但没有数组的全部方法。for 循环遍历没问题,forEach 在 现代浏览器也通用(书外补充:保险写法是 [...list] 先转数组)。

Q4:本章知识会过期吗? box-sizing、flex、grid、transition、事件模型——全是 2015 年后 稳定下来的标准,十年内不会动。会动的是工具层(第 20 章的 ReactDOM.render 已是例子)。学本章放一百个心,它是全书 最"保值"的两章。

11.23 Flexbox 六旋钮的完整对照

第 18 章 Flexbox 一节占了三百多行,六个旋钮各配一个概念, 合起来是一张"空间分配决策表"41:

旋钮 问的问题 常用值
flex-direction 子项往哪边排? row(默认)/ column
justify-content 主轴上剩余空间怎么分? center / space-between / flex-start
align-items 交叉轴上怎么对齐? center / stretch(默认,等高!)
flex-wrap 塞不下换行吗? nowrap(默认,硬塞)/ wrap
order 视觉顺序重排? 整数,小的在前
gap 项与项的间距 10px 之类

三个最高频的配方,背下来顶半个排版手册:

水平居中:        display:flex; justify-content:center;
水平垂直都居中:  + align-items:center;
两端贴边中间等分: justify-content:space-between;
等高多栏:        align-items:stretch(默认即是,别手贱改)

其中"等高多栏"值得单独一记:float 时代这是表格或伪元素的 黑客行为,flex 里它是默认值——第 18 章用 Flexbox 重排老布局的 隐形收益,往往就是这一条。

11.24 Grid 的从 0 到 1:fr 单位的思维

Grid 的入门只有三件事(第 18 章 Grid 一节的骨架)42:

.container { display:grid; }
.container {
  grid-template-columns: 1fr 2fr 1fr;   /* 列:1:2:1 分剩余空间 */
  grid-template-rows: 100px auto;       /* 行:头定高,身随内容 */
}
  • fr 读作"份":total fr 是 3,中间列拿 2/3。它替代的是 百分比+calc 的心算地狱——"侧栏 240px、其余平分"写成 240px 1fr 1fr,意图直读。
  • auto 读作"看内容":行高随 tallest child 涨缩。
  • 先列后行、先模板后内容——Grid 的设计顺序是"画格子、放东西", 与 Flexbox 的"排一队、再对齐"是两种心智,别串。

一个页面骨架的完整配方(概念拼装):

grid-template-columns: 240px 1fr;      /* 侧栏 + 主区 */
grid-template-rows: 60px 1fr 40px;     /* 头 + 身 + 脚 */

五行 CSS 得到经典"管理后台"版面——这就是第 18 章把 Grid 放在压轴的原因:它一步到位解决了过去十年的布局难题。

11.25 两章的错误博物馆:五个真实踩坑

把第 18/19 章最容易犯、又最难自查的五个错,办成常设展:

  1. transition 写在 :hover 上:悬停时有过渡,移开就瞬跳—— transition 必须写在元素的常态声明里,两端状态共享一条路43。
  2. flex 容器设了 height 却没给 align-items: 子项默认 stretch 的前提是容器有确定高度,否则"等高" silently 失效。症状是"别人的例子等高,我的不等"。
  3. querySelector 的 . 忘了写: by('myclass') 找的是标签 <myclass>,by('.myclass') 才是类—— 选择器字符串必须是完整合法的 CSS 选择器44。
  4. 改了 style 却不生效,其实改的是 CSS 文件里的值: 内联 style 优先于样式表,但元素若被 !important 或更具体的 选择器锁定,内联也可能被压(书外补充:此时用 computed style 排查"到底谁赢了")。
  5. transition:all 在旧设备上卡顿: 触发过渡的属性太多、某些属性(如 width/height)触发布局重算。 生产守则:只过渡 transform 与 opacity,这两个走合成器, 不惹布局45。

错误博物馆的参观方式:每个坑先亲手踩一次,再回来看展签。 只读不踩,等于没看;只踩不读,等于白踩。

11.26 章末总练习:一页落地页

综合两章,从 0 写一页产品落地页(建议 90 分钟):

结构   header 导航 + hero 区 + 三列特性 + 页脚
[18章] box-sizing 开局;Grid 画骨架;flex 收拾格内;
       按钮 hover:transform:translateY(-2px) + transition 柔和;
       卡片:box-shadow 微下沉 + border-radius;
[19章] byId 取"主题切换"钮,onclick 切换 body 的 class;
       class 预定义 .dark{...} —— 切类不切内联(§11.10 的判据)
验收   无 JS 时页面完整可读;JS 只是增强

最后一条验收是全章的总纲:增强,而不是依赖—— CSS 与 JS 的正确关系,是两章合起来最值钱的一句话。

11.27 末格:两章的「保值」与「过时」清单

翻新材料交接用——哪些知识长命、哪些已被新写法接管:

长命(学一次管十年): 盒模型与 box-sizing、层叠与选择器 特异性、Flexbox/Grid 布局、transition 的触发模型、事件 传播(冒泡/捕获)、内联 vs 切类的分工判据。

已被接管(本书写法仍对,但业界默认更新): 事件绑定从 属性式到 addEventListener;取元素从 getElementById 一家到 querySelector 全系;动效从 JS 定时器到 CSS transition/动画。

交接建议:新读者先学长命清单打地基,再学时新清单跟上当下; 两份清单都不碰的部分(如 jQuery),本书没有,也不用补。

11.28 章末总复习:二十个自查问题

合上书,能口头答出即算过;答不出的回标的小节:

选择器    1.属性选择器一族里,"以某值开头"怎么写?(§11.3/11.16)
盒模型    2.border-box 与 content-box 的宽度口径差在哪?(§11.4)
颜色      3.HSL 三个字母各管什么?变体调色动哪个?(§11.5)
动效      4.transition 四参数各叫什么、简写怎么排?(§11.6)
布局      5.一维问题找谁、二维问题找谁?各一个例子。(§11.7/11.24)
字体      6.@font-face 与 Google Fonts 各自的代价?(§11.8)
DOM 访问  7.byId / style / by 三函数的分工边界?(§11.9)
改样式    8.内联、切类、读计算值三条路各什么时候走?(§11.10)
显隐      9.visibility 与 display:none 的占位差异?(§11.11)
事件      10.内联/属性/监听三代绑定各缺什么?(§11.12)
综合      11.为什么 display:none 不能做过渡?(§11.13)
排错      12.过渡不生效的两类主因?(§11.15/11.22)

十二问全过,两章毕业。

11.29 交接备忘

  1. 第 18 章无 @keyframes 与媒体查询——引用本章时别说 "高级 CSS 全覆盖",说"过渡与布局两主线完整覆盖"。
  2. 第 19 章的工具函数命名(byId/style/by)是原书自创, 出本书不通用;但它们演示的"薄封装"思想通用。
  3. 两章例子全部无构建步骤,直接双击 HTML 可跑—— 这是教学上的刻意,也是复现性的保障,保留勿改。

11.30 末行

两章的最后一个建议:把 §11.26 的落地页练习真的做完。 读到这里,知识点已全部交付;做完那个练习,它们才会 第一次在同一块屏幕上互相配合——CSS 给界面,JS 给呼吸, 而你能说出每一行属于哪一章。

11.31 与第 20 章的预接口

提前记一句话,第 20 章会原样引用:React 组件的 return 里写的 JSX,本质就是"第 19 章那三个小函数"想干的事——描述界面, 而不是操作界面。区别只在于 React 接管了"何时更新"的 全部判断。到时候回头看 §11.20 的"开灯"手写版与 React 版 并排,两章的分工一目了然。

11.32 末二行

再补一行,凑成对:学完本章,你写下的每一行 CSS 都应该能 回答两个问题——"它属于哪个盒模型圈?"和"它参与过渡吗?" 答得出的样式是设计,答不出的样式是碰运气。

11.33 末三行

最后一行给本章的复现性承诺:全部例子双击 HTML 即跑, 无构建、无依赖、无网络——这是第 18/19 章独有的确定性, 在全书里也算稀缺品。

11.34 收笔

两章至此合拢。

12. 原文地图

主题 原书章 原文位置
选择器与三种属性匹配 Chapter 18. Advanced CSS text/29-ch18-chapter-18-advanced-css.txt:41(搜「10 different types」)· :128(搜「href^='http」)· :156(搜「src$='.png'」)· :184(搜「href*='google'」)
盒模型 同上 text/29-ch18-chapter-18-advanced-css.txt:209(搜「border-box」)· :216(搜「content-box」)
背景三件套与多重背景 同上 text/29-ch18-chapter-18-advanced-css.txt:271(搜「background-clip」)· :322(搜「background-origin」)· :367(搜「background-size」)· :465(搜「order of priority」)
边框/圆角/阴影 同上 text/29-ch18-chapter-18-advanced-css.txt:527(搜「#f00 #0f0」)· :577(搜「border-radius」)· :676(搜「box-shadow」)
多栏与文本效果 同上 text/29-ch18-chapter-18-advanced-css.txt:738(搜「column-count」)· :942(搜「text-shadow」)· :967(搜「ellipsis」)· :1024(搜「break-word」)
颜色与透明度 同上 text/29-ch18-chapter-18-advanced-css.txt:806(搜「hsl(60」)· :835(搜「hsla(60」)· :892(搜「rgba(0%」)· :917(搜「opacity」)
网络字体 同上 text/29-ch18-chapter-18-advanced-css.txt:1062(搜「@font-face」)· :1114(搜「privacy and data collection」)
transform 与 transition 同上 text/29-ch18-chapter-18-advanced-css.txt:1219(搜「rotate(45deg)」)· :1325(搜「transition-property」)· :1481(搜「canceled」)· :1449(搜「transition:all」)
flexbox 全组 同上 text/29-ch18-chapter-18-advanced-css.txt:1500(搜「display : flex」)· :1588(搜「flex-direction」)· :1640(搜「space-between」)· :1683(搜「align-items」)· :1749(搜「flex : 1 1 100px」)· :1788(搜「flex-wrap」)· :1810(搜「order: 2」)· :1841(搜「gap」)
CSS Grid 全组 同上 text/29-ch18-chapter-18-advanced-css.txt:1898(搜「display : grid」)· :1925(搜「grid-template-columns」)· :1981(搜「dense」)· :2001(搜「span 2」)· :2032(搜「grid-area」)· :2102(搜「justify-items」)
byId/style/by 三函数 Chapter 19. Accessing CSS from JavaScript text/30-ch19-chapter-19-accessing-css-from-javascript.txt:42(搜「saves 19」)· :79(搜「querySelector」)· :137(搜「querySelectorAll」)· :191(搜「function byId」)
camelCase 与 setAttribute 同上 text/30-ch19-chapter-19-accessing-css-from-javascript.txt:218(搜「camelCase」)· :234(搜「setAttribute」)
window 属性 同上 text/30-ch19-chapter-19-accessing-css-from-javascript.txt:462(搜「innerHeight」)· :456(搜「cannot be read」)
事件两式与事件表 同上 text/30-ch19-chapter-19-accessing-css-from-javascript.txt:514(搜「onmouseover」)· :565(搜「o.onmouseover」)· :589(搜「Events, elements」)· :733(搜「attach events」)
增删与显隐 同上 text/30-ch19-chapter-19-accessing-css-from-javascript.txt:772(搜「createElement」)· :785(搜「removeChild」)· :853(搜「visibility」)· :867(搜「display」)
定时器与动画 同上 text/30-ch19-chapter-19-accessing-css-from-javascript.txt:945(搜「not the result」)· :965(搜「arrow function」)· :988(搜「security risk」)· :1052(搜「setInterval」)· :1084(搜「toTimeString」)· :1223(搜「33.33 frames」)


  1. 出处:「Chapter 18. Advanced CSS」第 41 段(text/29-ch18-chapter-18-advanced-css.txt:41,搜「10 different types」)。 ↩

  2. 出处:「Chapter 18. Advanced CSS」第 204 段(text/29-ch18-chapter-18-advanced-css.txt:204,搜「total width and height」)。 ↩

  3. 出处:「Chapter 18. Advanced CSS」第 228 段(text/29-ch18-chapter-18-advanced-css.txt:228,搜「CSS Backgrounds」);clip/origin 见第 262、313 段,多背景见第 403 段。 ↩

  4. 出处:「Chapter 18. Advanced CSS」第 536 段(text/29-ch18-chapter-18-advanced-css.txt:536,搜「border-radius」);边框图自适应见第 472 段。 ↩

  5. 出处:「Chapter 18. Advanced CSS」第 709 段(text/29-ch18-chapter-18-advanced-css.txt:709,搜「Multicolumn」)。 ↩

  6. 出处:「Chapter 18. Advanced CSS」第 772 段(text/29-ch18-chapter-18-advanced-css.txt:772,搜「Colors and Opacity」)。 ↩

  7. 出处:「Chapter 18. Advanced CSS」第 924 段(text/29-ch18-chapter-18-advanced-css.txt:924,搜「Text Effects」);Web Fonts 见第 1053 段。 ↩

  8. 出处:「Chapter 18. Advanced CSS」第 1158 段(text/29-ch18-chapter-18-advanced-css.txt:1158,搜「skew, rotate」)。 ↩

  9. 出处:「Chapter 18. Advanced CSS」第 1292 段(text/29-ch18-chapter-18-advanced-css.txt:1292,搜「Transitions」)。 ↩

  10. 出处:「Chapter 18. Advanced CSS」第 1490 段(text/29-ch18-chapter-18-advanced-css.txt:1490,搜「Flexbox」);Grid 见第 1879 段。 ↩

  11. 出处:「Chapter 18. Advanced CSS」第 209 段(text/29-ch18-chapter-18-advanced-css.txt:209,搜「border-box」)。 ↩

  12. 出处:「Chapter 18. Advanced CSS」第 781 段(text/29-ch18-chapter-18-advanced-css.txt:781,搜「HSL Colors」)。 ↩

  13. 出处:「Chapter 18. Advanced CSS」第 901 段(text/29-ch18-chapter-18-advanced-css.txt:901,搜「separately from its color」)。 ↩

  14. 出处:「Chapter 18. Advanced CSS」第 1169 段(text/29-ch18-chapter-18-advanced-css.txt:1169,搜「one or more of the following functions」)。 ↩

  15. 出处:「Chapter 18. Advanced CSS」第 1300 段(text/29-ch18-chapter-18-advanced-css.txt:1300,搜「four properties」)。 ↩

  16. 出处:「Chapter 18. Advanced CSS」第 1449 段(text/29-ch18-chapter-18-advanced-css.txt:1449,搜「ease-in-out」)。 ↩

  17. 出处:「Chapter 18. Advanced CSS」第 1494 段(text/29-ch18-chapter-18-advanced-css.txt:1494,搜「distribute space」)。 ↩

  18. 出处:「Chapter 18. Advanced CSS」第 1920 段(text/29-ch18-chapter-18-advanced-css.txt:1920,搜「grid-template-columns」)。 ↩

  19. 出处:「Chapter 18. Advanced CSS」第 1057 段(text/29-ch18-chapter-18-advanced-css.txt:1057,搜「loaded in and displayed」)。 ↩

  20. 出处:「Chapter 18. Advanced CSS」第 1146 段(text/29-ch18-chapter-18-advanced-css.txt:1146,搜「<link> tag」)。 ↩

  21. 出处:「Chapter 18. Advanced CSS」第 1110 段(text/29-ch18-chapter-18-advanced-css.txt:1110,搜「Privacy Issues」)。 ↩

  22. 出处:「Chapter 19. Accessing CSS from JavaScript」第 20 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:20,搜「abbreviated version」)。 ↩

  23. 出处:「Chapter 19. Accessing CSS from JavaScript」第 84 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:84,搜「only the first element」)与第 125 段(:125,搜「all the objects」)。 ↩

  24. 出处:「Chapter 19. Accessing CSS from JavaScript」第 20 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:20,搜「without needing to include a framework」)。 ↩

  25. 出处:「Chapter 18. Advanced CSS」第 23 段(text/29-ch18-chapter-18-advanced-css.txt:23,搜「instead of JavaScript」)。「make document attributes part of the document itself」见同段。 ↩

  26. 出处:「Chapter 19. Accessing CSS from JavaScript」第 497 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:497,搜「onmouseover」)。 ↩

  27. 出处:「Chapter 19. Accessing CSS from JavaScript」第 848 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:848,搜「hide and unhide」)。 ↩

  28. 出处:「Chapter 19. Accessing CSS from JavaScript」第 900 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:900,搜「opacity」)。 ↩

  29. 出处:「Chapter 19. Accessing CSS from JavaScript」第 514 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:514,搜「orange.png」)。 ↩

  30. 出处:「Chapter 18. Advanced CSS」第 1327 段(text/29-ch18-chapter-18-advanced-css.txt:1327,搜「use the value all」)。「everything about an element」见同段。 ↩

  31. 出处:「Chapter 18. Advanced CSS」第 1490 段(text/29-ch18-chapter-18-advanced-css.txt:1490,搜「Flexbox」)。 ↩

  32. 出处:「Chapter 19. Accessing CSS from JavaScript」第 20 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:20,搜「framework such as jQuery」)。 ↩

  33. 出处:「Chapter 18. Advanced CSS」第 262 段(text/29-ch18-chapter-18-advanced-css.txt:262,搜「background-clip」)与第 313 段(:313,搜「background-origin」)。 ↩

  34. 出处:「Chapter 18. Advanced CSS」第 376 段(text/29-ch18-chapter-18-advanced-css.txt:376,搜「auto Value」)。 ↩

  35. 出处:「Chapter 18. Advanced CSS」第 536 段(text/29-ch18-chapter-18-advanced-css.txt:536,搜「border-radius」)。 ↩

  36. 出处:「Chapter 18. Advanced CSS」第 692 段(text/29-ch18-chapter-18-advanced-css.txt:692,搜「Element Overflow」)。 ↩

  37. 出处:「Chapter 18. Advanced CSS」第 933 段(text/29-ch18-chapter-18-advanced-css.txt:933,搜「text-shadow」)。 ↩

  38. 出处:「Chapter 18. Advanced CSS」第 958 段(text/29-ch18-chapter-18-advanced-css.txt:958,搜「text-overflow」)。 ↩

  39. 出处:「Chapter 18. Advanced CSS」第 1015 段(text/29-ch18-chapter-18-advanced-css.txt:1015,搜「word-wrap」)。 ↩

  40. 出处:「Chapter 18. Advanced CSS」第 725 段(text/29-ch18-chapter-18-advanced-css.txt:725,搜「multiple columns」)。 ↩

  41. 出处:「Chapter 18. Advanced CSS」第 1490–1832 段(text/29-ch18-chapter-18-advanced-css.txt:1490,搜「Flexbox」);六小节标题依次见第 1542、1553、1594、1646、1801、1832 段。 ↩

  42. 出处:「Chapter 18. Advanced CSS」第 1898 段(text/29-ch18-chapter-18-advanced-css.txt:1898,搜「display : grid」);模板属性见第 1920 段。 ↩

  43. 出处:「Chapter 18. Advanced CSS」第 1449 段(text/29-ch18-chapter-18-advanced-css.txt:1449,搜「transition : all」)。书内简写写在元素常态声明块中,hover 块只放终态。 ↩

  44. 出处:「Chapter 19. Accessing CSS from JavaScript」第 84 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:84,搜「valid CSS selector」)。 ↩

  45. 出处:「Chapter 18. Advanced CSS」第 1316 段(text/29-ch18-chapter-18-advanced-css.txt:1316,搜「properties you want to change」)。只过渡所需属性是原书 transition-property 一节的明确建议。 ↩

  46. 出处:「Chapter 18. Advanced CSS」第 41 段(text/29-ch18-chapter-18-advanced-css.txt:41,搜「10 different types」)。选择器十种总表;^=/$=/*= 三运算符及匹配/不匹配的示例分别见第 123、156、184 段。 ↩↩↩

  47. 出处:「Chapter 18. Advanced CSS」第 200 段(text/29-ch18-chapter-18-advanced-css.txt:200,搜「W3C box model」)与第 209 段(:209,搜「border-box」)。「The W3C box model specifies that the width and height of an object should refer only to... the dimensions of an element's content」;图 18-1 的两种模型对比见第 219 段。 ↩↩

  48. 出处:「Chapter 18. Advanced CSS」第 262 段(text/29-ch18-chapter-18-advanced-css.txt:262,搜「background-clip」)与第 313 段(:313,搜「background-origin」)、第 354 段(:354,搜「background-size」)。三档 box 值的含义见第 241–255 段。 ↩↩↩

  49. 出处:「Chapter 18. Advanced CSS」第 434 段(text/29-ch18-chapter-18-advanced-css.txt:434,搜「b1.gif」)与第 465 段(:465,搜「order of priority」)。「additional background images will appear behind already placed images」;可任意缩放的边框效果见第 472 段 Note。 ↩↩↩

  50. 出处:「Chapter 18. Advanced CSS」第 527 段(text/29-ch18-chapter-18-advanced-css.txt:527,搜「#f00 #0f0」)与第 636 段(:636,搜「10px 20px 30px 40px」)、第 653 段(:653,搜「40px 20px」)。「The first argument is the horizontal, and the second is the vertical radius」。 ↩↩

  51. 出处:「Chapter 18. Advanced CSS」第 676 段(text/29-ch18-chapter-18-advanced-css.txt:676,搜「box-shadow」)。四参数说明见第 678 段。 ↩

  52. 出处:「Chapter 18. Advanced CSS」第 696 段(text/29-ch18-chapter-18-advanced-css.txt:696,搜「overflow」)与第 709 段(:709,搜「Multicolumn」)、第 738 段(:738,搜「column-count」)。 ↩↩↩

  53. 出处:「Chapter 18. Advanced CSS」第 776 段(text/29-ch18-chapter-18-advanced-css.txt:776,搜「HSL」)。HSL 三参数的解释见第 785–797 段(色相环、饱和度、明度);alpha 语义见第 826 段。 ↩↩↩↩

  54. 出处:「Chapter 18. Advanced CSS」第 942 段(text/29-ch18-chapter-18-advanced-css.txt:942,搜「text-shadow」)与第 967 段(:967,搜「ellipsis」)、第 1024 段(:1024,搜「break-word」)。省略号三条件见第 993–1005 段。 ↩↩↩↩↩↩

  55. 出处:「Chapter 18. Advanced CSS」第 1062 段(text/29-ch18-chapter-18-advanced-css.txt:1062,搜「@font-face」)与第 1114 段(:1114,搜「privacy and data collection」)。「you may need to obtain user consent... you can also download the selected font and serve the files from your server」。 ↩↩↩↩

  56. 出处:「Chapter 18. Advanced CSS」第 1167 段(text/29-ch18-chapter-18-advanced-css.txt:1167,搜「transform:none」)。五函数清单见第 1174–1198 段;skew 的解释见第 1206 段;3D 件见第 1242–1268 段。 ↩↩↩↩

  57. 出处:「Chapter 18. Advanced CSS」第 1305 段(text/29-ch18-chapter-18-advanced-css.txt:1305,搜「transition-property」)。四参数原文列出;缓动值与 cubic-bezier 见第 1378–1403 段;简写 transition:all .3s linear .2s 见第 1417 段。 ↩↩↩

  58. 出处:「Chapter 18. Advanced CSS」第 1481 段(text/29-ch18-chapter-18-advanced-css.txt:1481,搜「canceled」)。「when they are canceled, they smoothly return to their original value」;悬停例(例 18-4)见第 1438–1454 段。 ↩↩↩↩

  59. 出处:「Chapter 18. Advanced CSS」第 1494 段(text/29-ch18-chapter-18-advanced-css.txt:1494,搜「Flexbox layout」)。主轴/交叉轴定义见第 1557 段;justify-content 九值见第 1603–1620 段;align-items/self 见第 1650–1696 段;flex 三件套与简写见第 1736–1749 段;flex-wrap 见第 1763–1768 段;order 见第 1810 段;gap 见第 1841 段。 ↩↩↩↩↩↩↩↩

  60. 出处:「Chapter 18. Advanced CSS」第 1883 段(text/29-ch18-chapter-18-advanced-css.txt:1883,搜「CSS Grid」)。容器声明见第 1898 段;template 见第 1925 段;grid-auto-flow 见第 1948–1962 段;grid-column/grid-row 见第 2001 段;grid-area 四参见第 2032 段;justify-items/align-items 见第 2102 段。 ↩↩↩↩↩↩↩↩↩

  61. 出处:「Chapter 18. Advanced CSS」第 1530 段(text/29-ch18-chapter-18-advanced-css.txt:1530,搜「flexbox editor」)与第 1901 段(:1901,搜「grid editor」)。Chrome DevTools 的可视化编辑器。 ↩↩↩

  62. 出处:「Chapter 19. Accessing CSS from JavaScript」第 42 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:42,搜「saves 19」)与第 31 段(:31,搜「framework」)。「you likely will have a custom-made or third-party framework」;三函数合集见例 19-4(第 191 段)。 ↩↩↩↩↩

  63. 出处:「Chapter 19. Accessing CSS from JavaScript」第 218 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:218,搜「camelCase」)。「you must convert the name to follow the camelCase notation」;setAttribute 替代见第 234 段。 ↩↩↩

  64. 出处:「Chapter 19. Accessing CSS from JavaScript」第 462 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:462,搜「innerHeight」)与第 308 段(:308,搜「Table 19-1」)。「I've often used these values for centering」;history 只读说明见第 456 段。 ↩↩↩

  65. 出处:「Chapter 19. Accessing CSS from JavaScript」第 514 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:514,搜「onmouseover」)与第 526 段(:526,搜「this keyword」)。「It tells JavaScript to operate on the calling object」。 ↩↩↩↩

  66. 出处:「Chapter 19. Accessing CSS from JavaScript」第 565 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:565,搜「o.onmouseover」)。外联版与内联版等价(第 573 段「attaching anonymous functions to each event」)。 ↩↩↩

  67. 出处:「Chapter 19. Accessing CSS from JavaScript」第 589 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:589,搜「Events, elements」)。Table 19-2 事件全表;keypress 与 keydown 的差别见第 648 段。 ↩↩↩

  68. 出处:「Chapter 19. Accessing CSS from JavaScript」第 733 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:733,搜「attach events」)。「an object that is not a form will not respond to the onsubmit event」。 ↩

  69. 出处:「Chapter 19. Accessing CSS from JavaScript」第 772 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:772,搜「createElement」)与第 793 段(:793,搜「appendChild」)。「This newly created element is exactly the same as if it had been included in the original HTML」见第 808 段。 ↩↩↩

  70. 出处:「Chapter 19. Accessing CSS from JavaScript」第 831 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:831,搜「removeChild」)。「it works like this... access the element's parentNode」。 ↩

  71. 补充出处:「Chapter 19. Accessing CSS from JavaScript」第 862 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:862,搜「zero width and height」)——display:none 的「坍缩补位」与 visibility:hidden 的「占位隐身」对照。主出处:「Chapter 19. Accessing CSS from JavaScript」第 853 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:853,搜「visibility」)与第 867 段(:867,搜「display」)。「invisible but leave it in place」vs「collapse an element to occupy zero width and height」;innerHTML 清内容见第 895 段。 ↩↩↩↩↩

  72. 出处:「Chapter 19. Accessing CSS from JavaScript」第 924 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:924,搜「setTimeout」)与第 1028 段(:1028,搜「setInterval」)、第 1013 段(:1013,搜「clearTimeout」)、第 1135 段(:1135,搜「clearInterval」)。「until you cancel it」。 ↩↩↩↩↩↩

  73. 出处:「Chapter 19. Accessing CSS from JavaScript」第 945 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:945,搜「not the result」)。「The alert pop-up will appear immediately」;箭头函数版见第 970 段。 ↩

  74. 出处:「Chapter 19. Accessing CSS from JavaScript」第 988 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:988,搜「security risk」)。「this has been discouraged for many years as it presents an unnecessary security risk and incurs a performance penalty」。 ↩↩

  75. 出处:「Chapter 19. Accessing CSS from JavaScript」第 1084 段(text/30-ch19-chapter-19-accessing-css-from-javascript.txt:1084,搜「toTimeString」)与第 1191 段(:1191,搜「setInterval(animate」)、第 1223 段(:1223,搜「33.33 frames」)。帧率换算:「This results in an animation rate of 33.33 frames per second (1,000/30 milliseconds)」。 ↩↩↩↩↩↩

  76. 出处:「Chapter 18. Advanced CSS」第 23 段(text/29-ch18-chapter-18-advanced-css.txt:23,搜「I recommend using CSS」)。「I recommend using CSS, instead of JavaScript, to implement dynamic features」——第 19 章的 JS 动画例(例 19-10)属于「逐帧控制」的例外场景。 ↩