《深入解析css》读书笔记

351 阅读35分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

写在前面

周末这两天看完了一本书《深入解析css》, 看完了这本书之后,感觉我对css有了更深一步的理解,于是便写下了这篇读书笔记。篇幅过长。这本书一共分为四个部分:基础,精通布局,css在大型项目中的应用和高级话题。其中前面三个部分我们在项目中经常会用到,值得我们思考和学习,而且这部分的内容我在前端知识路线中也整理过相关的知识体系,感兴趣的同学也可以去看看。第四部分是高级话题,这部分的内容主要是介绍了背景,阴影,渐变,过渡,变换,动画,网络字体以及一些我们在写前端页面的时候如何从UI设计的角度去写css样式,提高页面的美感和用户体验。下面详解介绍一下每一章核心的知识点.

第一部分 基础回顾

第一章 层叠、优先级和继承

1.1 控制选择器的优先级

样式的层叠我们可以从三个方面来考虑优先级:来源,选择器类型,代码顺序。

  • 来源: 浏览器默认的样式表称为代理样式表,我们自己开发写的样式表叫做用户样式表,用户样式表可以覆盖代理样式表。
  • 选择器类型:!important > id选择器 > 类选择器 > 标签选择器
  • 代码顺序: 如果前面两种的层叠一样,后面的代码优先级比前面的代码优先级高。

1.2 不要混淆层叠和继承

  • 层叠指的是有多种方式给统一元素添加样式,这些样式会层叠,根据层叠顺序决定元素的样式。
  • 继承:元素的某个属性没有层叠值,那么它就会继承某个祖先元素的值。元素只要有属性,那么它一定有层叠值。

1.3 某些属性会被继承

并不是所有的属性都能被继承,一般元素的文本相关的属性可以被继承,对于列表元素而言,她的列表属性也能被继承,对于表格元素而言,它的边框相关的属性可以被继承。

这也可以解释我们在开发的时候一般不需要给文本元素一层一层地设置字体和颜色,因为它可以继承祖先元素的样式。

1.4 不要混淆initial和auto值

在写元素的样式时,我们除了可以设置具体的值之外,还有两个特殊的值可以设置:initial和inherit

  • initial: 初始值,恢复到该元素的默认值。
  • inherit: 继承祖先元素的当前属性的属性值。
  • auto:initial和inherit是一般元素属性都具有的属性值,但是auto只有特定属性才具有,比如:width, height, overflow.而且它表示的是按情况自动设置为特定的值

1.5 简写属性要注意顺序,避免踩坑

在简写属性的时候我们一定要注意简写的顺序,一般可以分成两种:

  1. 上下左右:padding,margin等,省去会取对应方向的值
  2. 水平垂直:background-position, box-shadow, text-shadow等
第二章 相对单位

2.1 使用相对单位

对于响应式布局来说,相对单位可以实现在不同大小的屏幕中根据窗口的比例地缩放。从而实现响应式布局。

2.2 建议使用rem作为单位

rem的大小是相对于根元素的字体大小,也就是说1rem=html的font-size。这种方式也经常使用在移动端适配上,随着各大浏览器对vw的兼容性越来越好了,现在主要使用vw来设置尺寸大小。

2.3 不用媒体查询也能让整个网页响应式缩放

其实这一点和上面是一个意思,有了相对单位之后,我们不需要设置媒体查询去适配不同的屏幕元素的样式,而且相对单位比我们使用媒体查询更能精准地让网页响应式缩放。

2.4 使用无单位的值设置行高

有些属性允许无单位的值, 支持这种值的属性包括line-height、z-index、font-weight。一个无单位的值0只能用于长度值和百分比。行高line-height的属性值设置成无单位的值是相对当前文本的font-size来决定的,这样的话可以控制不同屏幕大小字体大小不一样,行高也不一样,从而实现响应式布局。

2.5 熟悉自定义属性

第三章 盒模型

3.1 建议全局设置border-box, 以便得到预期的元素大小

由于设计稿给我们的样式宽度都是针对整个盒子而言的,而浏览器默认的我们的宽度是给内容盒子设置的,如果这时候我们再给元素设置边框和外边距的时候,整个盒子的宽度就会比设计稿的大,因此我们需要给元素设置box-sizing: border-box。但其实在开发中我们并不需要给所有的盒子都设置这个属性,因为我们一般采用的都是无宽度布局或者flex布局,不会给所有元素的宽度设置具体的值,如果针对最外层的容器盒子需要设置宽度的话就可以使用这个属性。

3.2 避免明确设置元素的高度,以免出现溢出问题

这个想法和不给元素设置明确的宽度的思维是一样的,对于内容不确定的元素,不设置宽度和高度,通过设置内边距,以及内容的尺寸来实现元素的宽度和高度自适应,防止溢出问题。

3.3 使用现代布局方式(比如flex布局)来实现列等高或者垂直居中的布局

随着现在各大浏览器对一些现代布局方式的适配性越来越好了,以前的那种浮动定位来设置布局的方式慢慢地被替代了,对于现在的我们来说,更推荐使用现代布局方式,比如flex布局。

3.4 防止外边距折叠

在写布局的时候经常会发生外边距折叠的问题,这点我在前端学习路线里面已经讲到,为了避免这种情况的发生,我们采用的是创建一个BFC的方式,使其和其他盒子完全隔离开,这样就不会产生外边距折叠的问题了。

3.5 使用猫头鹰选择器全局设置堆叠元素之间的外边距

如果在堆叠元素之间同时设置上下外边距是会发生外边距重叠,对于这种方式我们一般有以下几种方式解决:

  • 给每个堆叠元素创建一个BFC,但是这种方式不推荐,如果堆叠元素太多的话,需要创建很多个
  • 不同时给堆叠元素设置上下边距,一般设置其中一个就行,这种方式需要单独处理第一个元素或者最后一个元素的样式
  • 使用猫头鹰选择器
    body * + * {
      margin-top: 1.5em;
    }
    

第二部分 精通布局

第四章 理解浮动

4.1 浮动的设计初衷是让文字围绕一个元素排列

浮动最开始设计出来就是为了实现报纸上的那种图文混排的布局,但是在以前成为了页面布局的最好的方式,随着现代布局技术在浏览器上的各种适配越来越来越好了,我们应该避免用浮动去实现页面布局。

4.2 使用清除浮动来包含浮动元素

我们之前已经了解到浮动是会脱离文档流的,因此给元素设置了浮动之后是会影响到后面的元素在文档流中的位置,因此对于浮动元素,我们需要清除浮动,常见的清除浮动的方式特别多,推荐使用的是下面这种方式:

.clearfix::before, .clearfix::after {
  content: '';
  display: table;
}
.clearfix::after {
  clear: both;
}
.clearfix {
  *zoom: 1;
}

4.3 BFC的作用

块级格式化上下文(BFC)的作用就是将当前盒子和其他盒子单独隔离出来,互不影响。它还可以解决外边距折叠,父容器高度塌陷的问题

4.4 使用双容器模式让页面内容居中

这种实现页面内容居中的方式现在已经比较少了,更多的是使用flex布局来实现内容的居中。

4.5 使用媒体对象模式将描述文字定位到图片旁边

使用文字可以实现图文混排的方式,要想实现文字定位到图片旁边可以在浮动的基础上给文字内容的盒子创建一个新的BFC,使其和图片盒子单独分开,这样就可以设置外边距了。 当然除了这个方式之外,还可以使用flex布局的方式实现将描述文字定位到图片旁边。

4.6 使用网络系统实现更丰富的网页布局

现代布局方式中的flex布局是一维布局,如果要想实现更丰富的二维布局,可以使用网格系统。网格系统可以同时设置行和列上的属性。通过列数设置元素的高度的百分比,还可以设置元素之间的间隔。

第五章 flexbox

5.1 使用flex布局实现灵活易操作的页面布局

比起以前传统的布局方式,flex布局提供了很多简单好用的属性,可以帮助我们实现更加灵活易操作的页面布局。

5.2 Autoprefixer简化flexbox对旧版浏览器的支持

flexbox布局现在已经能适配大多数浏览器了,在这之前很多老版浏览器不支持的时候,通常需要带上浏览器的前缀,就像这种:display: -webkit-flex; display: flex;由于页面中使用到这种flex布局的地方会很多,如果这样手动去添加的话会很麻烦,因此提供了一种Autoprefixer插件,帮助我们自动添加浏览器前缀。

5.3 使用flex指定任何弹性子元素大小的组合

flex属性是可以设置基础大小的,也就是可以设置任何弹性元素的大小,然后它有一个flex-grow和flex-shrink属性,这两个属性可以实现当父容器存在多余空间或者空间不足的情况下弹性元素可以自适应。

5.4 使用嵌套的弹性盒子来组成复杂的布局,以及填满自适应大小的盒子的宽度

上面的情况已经介绍了为什么flex布局可以填满自适应大小的盒子的宽度,想要了解关于弹性布局更多的知识,可以参考我的另一篇文章:flex布局详解

5.5 flexbox自动地创建等高的列

在flex布局出现之前,每列的内容长短是不一样的,要实现等高的列是很复杂的。有了flex布局之后,只需要给父容器盒子设置display: flex;每个弹性元素设置flex属性值就行,那么有几列都是等高的。

5.6 使用align-items和align-self让一个弹性子元素在弹性容器中垂直居中

align-items是设置所有的弹性元素在容器交叉轴上的对齐方式,如果想设置成垂直居中就是align-items:center;也就是说align-items这个属性是设置在容器上的,align-self与align-self不同,它是设置在弹性元素上的,设置的是当前弹性元素自身在容器交叉轴上的对齐方式,如果是垂直居中,那么就是align-self: center;

第六章 网格布局

6.1 网格布局特别适合做网页整体布局

网格布局即使display: grid;这种布局方式是二维的,因此从网页整体布局而言,它特别适合,但是现在grid布局的浏览器兼容性不是很好,因此在做布局的时候我们使用的比较多的还是flex布局。

6.2 网格可以与flexbox配合实现完整的布局系统

可以用auto-fill / auto-fit以及隐式网格,对大量或者数量未知的网格元素进行布局。这样的话它们可以正好互补,flex布局支持用flex-wrap换行,但是没法让上一行元素跟下一行元素对齐。相反,网格是二维的,旨在解决一个轨道的元素跟另一个轨道的元素对齐的问题。这样的话它们就能完美实现列对齐了。

6.3 网格布局的语法

网格布局里面有几个很重要的概念:

  • 网格线:网格线构成了网格的框架。一条网格线可以水平或垂直,也可以位于一行或一列的任意一侧。如果指定了grid-gap的话,它就位于网格线上。
  • 网格轨道:一个网格轨道是两条相邻网格线之间的空间。网格有水平轨道(行)和垂直轨道(列)。
  • 网格单元:网格上的单个空间,水平和垂直的网格轨道交叉重叠的部分。
  • 网格区域:网格上的单个空间,水平和垂直的网格轨道交叉重叠的部分。 具体语法参考mdn,这里我就不一一介绍了

6.4 可以用auto-fill / auto-fit以及隐式网格,对大量或者数量未知的网格元素进行布局。

当处理大量的网格元素时,挨个指定元素的位置未免太不方便。当元素是从数据库获取时,元素的个数可能是未知的。在这些情况下,以一种宽松的方式定义网格可能更合理,剩下的交给布局算法来放置网格元素。这时需要用到隐式网格(implicit grid)。使用grid-template-*属性定义网格轨道时,创建的是显式网格(explicit grid),但是有些网格元素仍然可以放在显式轨道外面,此时会自动创建隐式轨道以扩展网格,从而包含这些元素。 隐式网格轨道默认大小为auto,也就是它们会扩展到能容纳网格元素内容。可以给网格容器设置grid-auto-columns和grid-auto-rows,为隐式网格轨道指定一个大小(比如,grid-auto-columns: 1fr)。 这种布局方式也能实现流式布局,照片墙。

6.5 可以使用特性查询实现渐进增强

由于现在并不是所有的浏览器都支持网格布局,但这并不影响我们使用它,我们可以使用特性查询的方式实现渐进增强。

@supports (display: grid) {
  ...
}

如果浏览器支持网格布局,那么就会执行大括号里面的代码。

第七章 定位和层叠上下文

7.1 模态框使用固定定位。

因为模态框是要覆盖掉整个视口的,它由两部分组成:遮罩层和内容层。对于遮罩层而言,需要完全覆盖视口,和视口的宽高相同,因此这部分需要设置成固定定位。而里面的内容区也是需要设置成固定定位的,但是内容区里面需要使用定位的元素需要设置成绝对定位,因为它是针对内容区的定位而不是视口。

7.2 下拉菜单、工具提示及其他动态交互使用绝对定位。

自己手动实现一个下拉框的时候,需要给下拉框的菜单栏容器设置成绝对定位。

7.3 关于z-index有两个地方要注意:它只对定位元素有效;它会创建一个层叠上下文。

7.4 在一个页面创建多个层叠上下文时一定要当心潜在的陷阱。

当存在多个层叠上下文的时候一定要注意层叠顺序,如果某个元素的z-index的值设置的很大,但是他还是显示在底层,这种情况下很有可能是该元素的父元素的层叠顺序很低。 层叠上下文的顺序:

  • 层叠上下文的根
  • z-index为负的定位元素(及其子元素)
  • 非定位元素
  • z-index为auto的定位元素(及其子元素)
  • z-index为正的定位元素(及其子元素

7.5 使用粘性定位时注意浏览器的兼容性。

粘性定位是几种定位中最后出现的定位方式,并不是所有的浏览器都支持,因此在使用的时候一定要注意浏览器的兼容性。

第八章 响应式设计

8.1 优先实现移动端设计。

响应式布局的三个原则:移动优先,@media媒体查询,流式布局(也称为液体布局)。其中首要的就是移动优先,移动优先指的是优先设置移动端(也就是小屏的布局),然后针对不同屏幕使用渐进增强。

8.2 使用媒体查询,按照视口从小到大的顺序渐进增强网页。

媒体查询允许某些样式只在页面满足特定条件下才会生效,这样可以根据屏幕大小定制样式,针对小屏幕使用一套样式,针对中等屏幕定义一套样式,针对大屏定义一套样式。这种媒体查询并不是指针对不同屏幕设置元素的尺寸的缩放,而是在布局上去做适配,针对尺寸的缩放可以直接使用相对单位vw就行,不需要使用媒体查询。

8.3 使用流式布局适应任意浏览器尺寸。

流式布局也称为视口布局,指的是使用的容器随视口的变化而变化。在流式布局中,主页面容器不会设置明确宽度,也不会给百分比宽度,但可能会设置内边距,或者设置左右外边距为auto, 让其与视口边缘产生留白。主页面容器中的列设置百分比布局,或者使用flex布局。

8.4 使用响应式图片适应移动设备的带宽限制。

在响应式布局中,不仅要让图片适应屏幕,还要考虑移动端用户的带宽限制。图片通常是网页上最大的资源,首先要保证图片充分压缩,还要避免不必要的高分辨率图片,这一点主要取决于视口的大小。 如果是css设置的背景图片就使用媒体查询,如果是img标签就使用img的srcset属性来实现。

8.5 给视口添加meta标签。

视口的meta标签是用来告诉移动设备,你已经特意将网页适配了小屏设备。如果不加这个标签,移动浏览器会假定网页不是响应式的,并且会尝试模拟桌面浏览器,那之前的移动端设计就白做了。

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
第九章 模块化css

9.1 把css拆解成可复用的模块

将样式表的每个组成部分称为模块,每个模块独立负责自己的样式,不影响其他模块的样式。比如导航菜单、对话框、进度条、缩略图、b表格等等都是一个个的模块。可以通过给DOM元素设置一个独一无二的类名来识别模块。每个模块内部含有一系列的子元素,构成一个组件。模块内部可以嵌套其他模块,最终构成整个页面。

9.2 不要书写可能影响其他模块或者改变其他模块外观的样式

每一个模块内的样式都是独立的,但是它们在页面中又是互相牵制的,只要添加模块的类名就可以使用对应的样式了。因此不要写可能会影响其他模块或者其他模块外观的样式。

9.3 使用变体类,提供同一模块的不同版本

对于统一模块,在不同的页面中可能样式上会有一些差异性,也称为定制化差异。这样的话我们可以通过定义一个以模块名称开头的新类名来创建一个修饰符。比如,消息模块的错误提示应该叫做message-error。通过包含模块名称,可以清楚地表明这个类属于消息模块。

9.4 把较大的结构拆解成较小的模块,然后把多个模块组合在一起构建页面

每个模块应该只做一件事,当模块想要完成完成不止一件事的时候,我们应该考虑把它拆分成更小的模块。当页面中需要什么的时候,我们只需要将这些模块添加到页面中即可,就可以组合在一起构建页面。

9.5 在样式表中,把所有用于同一模块的样式放在一起。

在样式表中,我们一般把同一模块的样式放在一起,根据变体类去定制区分模块的不同的样式。一般有以下几种区分方式:

  • 修饰符:根据功能特点的差异定义修饰符,比如message__error
  • 工具类:根据具体的功能定义类名,比如float-left
  • 状态类:根据模块的状态定义类名,比如is-active, is-open

9.6 使用一种命名约定

对于css模块化的方法论很多,其中有很多是关于css命名的,我们可以根据自己的项目情况,统一选择一种命名方式就可以了。

  • OOCSS——面向对象的CSS,由Nicole Sullivan创建。
  • SMACSS——可扩展的、模块化CSS架构,由Jonathan Snook创建。
  • BEM——块(Block)、元素(Element)和修饰符(Modifier),由Yandex公司提出。
  • ITCSS——倒三角形CSS,由Harry Roberts创建。
第十章 模式库

10.1 使用工具来存档和清点模块,比如KSS。

因为模块是可复用的,所以我们直接将模块组装在一起就可以组成我们的页面。这样的话我们需要关注的就是模块清单了,把模块清单整合成一组文档,在大型项目中已经成为通用做法,这组文档被称为模式库或者样式指南,像我们在开发中使用到的elementUI和vant其实都是这样来实现的,要生成一个模式库需要借助工具,本书中介绍的是KSS。具体使用可以查阅KSS官方文档。

10.2 使用模式库来记录HTML标记示例、模块变体和模块的JavaScript。

html标记示例其实就是告诉使用者该模块如何使用的,这部分使用markdown来编写的,使用过前端UI框架的朋友应该对这个很熟悉了。 模块变体我们在前面已经介绍过,是一组修饰符类的列表,每个列表项后面跟着一个连字符和相关描述。我们也可以添加{{modifier_class}}注释到示例标记上,指明修饰符类所属的位置,KSS扫描已定义的修饰符类列表,把每一个都展示到模式库中。 有些模块需要配合JavaScript一起工作,但是我们没必要在模式库里引入一个功能齐全的JavaScript库。大多数情况下,脚本文件就是根据用户操作切换不同的状态类就够了。然后只需要将.js文件添加到kss-config.json的js模块中。

10.3 开发模块时遵循“CSS优先”。

模式库在小项目中可有可无,但是在大型项目中就显得至关重要了。模块化css是编写大规模css的核心,模式库是保证这些模块条理清晰、使用方便的手段。 使用模式库是从传统的CSS开发方式转变而来的一种解决方案。不同于之前的先写HTML页面再写样式,我们实现了模块化的样式,然后使用这些模块拼装成Web页面。我把这种解决方案称为CSS优先(CSS First)开发方式,先写CSS,而不是HTML。这种开发流程是:

  • 页面开发时,先有一个草图或者原型图或者设计稿等
  • 看看模式库。找找现有模块有没有当前页面需要的模块,如果有的话就直接拿过来用,如果没有的话就自己手动实现一个,从主页面布局和容器开始按照自己熟悉的方式开始编写css。
  • 你会发现有时候需要用到一些模式库提供不了的功能,这时候就需要开发一个或者几个新模块,或者现有模块的新变体。暂停正在编写的页面开发,先在模式库中实现这个模块。为新模块书写文档,确保它的外观和行为跟需求一致。
  • 回到页面开发,使用刚写的新样式并且添加新模块到页面上。

10.4 考虑好CSS定义的API,之后不要轻易修改它。

API是为了阐明HTML代码是通过类名和HTML元素连接CSS样式的。当你使用模式库开发的时候,相当于你正在维护一组与CSS交互的API。每个模块会附带一些类名和少量的DOM结构。只要相关的HTML部分遵照这种结构来编写,样式表就会正确地渲染样式。每个模块里都包含一段HTML示例代码,用来描述约定好的CSS和HTML的搭配格式。这段代码展示了HTML和CSS是如何一起工作的。创建模块的时候,API的结构是最重要的部分,因为后面很难再修改。

10.5 使用语义版本为CSS做版本控制。

有时候为了改成想要的效果,我们不得不修改API,这时候就需要使用到版本控制了,我们用一个三位数字的语义版本(semver)来为CSS设置版本号。一旦版本号变了,开发者自然就知道模块内容改变了。 语义版本——Semantic Versioning的简写,一种软件包版本命名格式,使用圆点分隔的三个数字表示(例如1.4.2)。三个数字分别代表主版本号、次版本号和修订号。可以访问Semantic Versioning网站查看更多信息。

10.6 不要盲目地添加整个CSS框架到页面上,只取自己需要的那部分。

从下面这几章开始,就是从设计和用户体验的角度去帮助你在开发页面的时候可以多关注一些点来优化你的页面,从而让你的页面在细节上也会很突出。

第十一章 背景、阴影和混合模式

11.1 使用渐变和阴影为页面增加立体效果

通过使用background-image给页面元素添加渐变,使用box-shadow或者text-shadow给页面元素添加阴影能够让页面看起来更立体好看。 创建渐变的方式是使用background-image: linear-gradient(to right, white, blue);

条纹渐变

linear-gradient(90deg, red 40%, white40%, white 60%, blue 60%);

重复渐变:

repeating-linear-gradient(-45deg, #57b, #57b 10px, #148 10px, #148 20px);

径向渐变:

radial-gradiennt(white, midnightblue);

背景混合模式:

将两张或者多张背景图片混合在一起,达到我们想要的效果:

background-blend-mode: soft-light;

融合混合模式:

将图片和别的元素混合在一起,可以使用下面这种方式

mix-blend-mode: hard-light;

11.2 基本的扁平化设计也可以少量应用阴影和渐变

扁平化设计讲究色彩明快统一、外观简洁明了,这就意味着尽量少使用渐变、阴影和圆角, 并不是说完全不用这些特效,用还是要用的,但要用得巧用得妙。

11.3 带有明确颜色节点的渐变,可以为元素添加条纹效果

如果在同一个位置设置两个颜色节点,那么渐变会直接从一个颜色变换到另一个,而不是平滑过渡。

background-image: linear-gradient(90deg, red 40%, white 40%, white 60%, blue 60%);

11.4 小巧的背景渐变比纯色背景更能提升设计效果

渐变能为页面营造了细微的立体感,从而能够提升设计效果。

11.5 使用混合模式可以为图片着色或者添加纹理效果

大部分情况下,不论是使用真正的图片还是渐变,元素一般只会使用一张背景图片。但某些情况下你可能想要使用两张或者更多的背景图片,这时候就需要用到混合模式了。混合模式有以下几种应用场景:

  • 使用某种颜色或者渐变为图片着色;
  • 为图片添加纹理效果,比如划痕或者老胶片放映时的颗粒感等;
  • 缓和、加深或者减小图片的对比度,使图片上的文字更具可读性;
  • 在图片上覆盖了一条文字横幅,但是还想让图片完整显示。
第十二章 对比、颜色和间距

12.1 选择性地使用对比,来把用户注意力吸引到页面上重要的部分。

使用不同的颜色、间距和大小是建立对比的一些常用方法,这里可能会比较需要一些美学知识,一般设计稿都会明确地有一些样式参数,我们特别注意这些细节即可。

12.2 使用HSL颜色表示法,让颜色处理更简单更易于理解。

表示颜色的方式有很多

  • 直接使用颜色的单词,比如:red,blue
  • 使用十六进制的颜色值,比如: #ffffff
  • 使用rgb()函数
  • 使用hsl()函数 推荐使用hsl颜色表示法。hsl()函数需要3个参数。第一个参数表示色相,是一个0~359的整数值。这代表色相环上的360度,从红色(0)、黄色(60)、绿色(120)、青色(180)、蓝色(240)、洋红色(300)依次过渡,最后回到红色。第二个参数表示饱和度,是一个代表色彩强度的百分数,100%的时候颜色最鲜艳,0%就意味着没有彩色,只是一片灰色。第三个参数表示明度,也是百分数,代表颜色有多亮(或者多暗)。这种表示方法更加适合人类读取的颜色表示法。

12.3 设计师执着于细节时,要相信他们的判断。

在开发的过程中,我们总会在验收的时候总会遇到一个场景:设计:这两个地方的间距不一样。我:???这明明是一样的呀?因此我们也常常说设计的眼睛是像素级的眼睛。我们要相信设计师的专业。

12.4 花些时间来调整间距。

间距是在写页面时非常容易忽视的地方,但其实间距也是最简单的地方,我们重点关注两个地方:

  1. 是否需要使用相对单位:一般建议使用相对单位
  2. 行高如何影响垂直间距

12.5 牢记行高可以影响垂直间距。

行高设置成无单位的值时,是根据字体大小来计算的,行高会影响到垂直间距。行高减去字体大小的值就是文本上下间距的和。

第十三章 排版

13.1 使用字体供应商(比如谷歌字体)的服务可以轻松集成Web字体。

为了让页面看起来更加美观,有特色,有时候需要设置对应的字体,我们可以直接使用字体供应商的字体,直接在页面中引入即可。

13.2 严格限制添加到网页的Web字体数量,来控制页面体积。

虽然字体可以让我们的页面变得有特色,但是不能滥用web字体,因为web字体要比一般字体文件大小要大,需要严格限制web字体的数量,从而控制页面体积。而且引入web字体太多不利于保持页面字体的统一性。

13.3 使用@font-face规则集管理自己的字体。

@font-face规则定义了浏览器字体,以便在页面的CSS中使用。这种方式需要先将字体文件下载下来

13.4 花点时间调整line-height和letter-spacing,使页面段落分明、清晰易读。

line-height和letter-spacing,这两个属性可以控制文本行之间的距离(垂直方向)和字符之间的距离(水平方向),在网页实现的时候多花点儿时间调整它们,可能会使整个网站的效果产生很大的改进。除此之外,还可以让用户在阅读的时候体验更好,增加用户黏性。line-height属性在1.4和1.6之间比较合适。letter-spacing属性设置成0.01em和0.02em都可以。

13.5 使用Font Face Observer或其他JavaScript来协助控制加载行为,防止文本隐藏的问题。

比起系统字体,Web字体很可能会在屏幕上占据不一样的空间。第二次渲染时,页面布局变了,文字突然跳动了。如果这是在第一次渲染之后很快发生,用户可能不会注意到。但是如果字体下载过程中有网络延迟(或者字体文件太大了),可能长达几秒之后才会再次渲染页面。这种情况发生时,有的用户可能会感到厌烦。他们可能已经开始阅读网页内容了,这时页面突然变化,会让他们注意力分散。这就是所谓的FOUT,即无样式文本闪动(Flash of Unstyled Text)。不再渲染回退字体,改成渲染页面上除了文本以外的其他所有元素。确切地说,他们把文本渲染成不可见的,因此文字依然会占据页面的空间。通过这种方式,页面的容器元素得以实现,用户就可以看到页面正在加载。这就导致了一个新的问题,FOIT,即不可见文本闪动(Flash of Invisible Text)。 使用JavaScript可以监控字体加载事件,这样就可以更好地控制FOUT与FOIT的发生过程。还可以使用js库来帮助处理,我喜欢用一款名叫Font Face Observer的库。这个库可以让你等待Web字体加载,然后做出相应的响应。我一般是在字体准备好时,使用JavaScript为元素添加一个fonts-loaded类。然后就可以使用这个类为页面设置不同的样式,用不用Web字体都可以。

13.6 留意以后font-display的支持情况。

font-display属性需要在@font-face规则内部使用,用来指定浏览器应该如何处理Web字体加载。一共有下面几种属性值:

  • auto——默认行为(在大多数浏览器中是FOIT)。
  • swap——显示回退字体,在Web字体准备好之后进行交换(FOUT)。
  • fallback——介于auto和swap之间。文本会保持较短时间(100ms)的隐藏状态,如果这时候Web字体还没有准备好,就显示回退字体。接下来一旦Web字体加载完成,就会显示Web字体。
  • optional——类似于fallback,但是允许浏览器基于网速判断是否显示Web字体。这就意味着在较慢的连接条件下Web字体可能不会显示。
第十四章 过渡

14.1 使用过渡可以使页面中的突变变得平滑。

渡是通过一系列transition-*属性来实现的。如果某个元素设置了过渡,那么当它的属性值发生变化时,并不是直接变成新值,而是使用过渡效果。

14.2 使用加速运动可以吸引用户注意力。

定时函数是过渡中非常重要的一部分。过渡让某个属性从一个值“移动”到另一个值,定时函数用来说明如何移动。是以恒定的速度移动吗?还是开始的时候慢,后面越来越快?有以下几个关键字:

  • linear:以固定速度改变
  • ease-out: 开始时快速变化,结束时比较慢
  • ease-in: 开始时变化慢,然后一直加速,直到过渡完成。
  • cubic-bezier(0.45, 0.05, 0.55, 0.95):这是贝塞尔曲线可以自定义速度变化
  • steps(): 一系列非连续性的瞬时“阶跃”

14.3 通知用户他们的行为已生效,应该使用减速运动。

14.4 只使用CSS无法满足需求时,可以使用JavaScript更改类配合过渡来实现。

第十五章 变换

15.1 在二维和三维空间中使用变换来缩放、旋转、平移和倾斜元素。

  • 旋转(Rotate)——元素绕着一个轴心转动一定角度。
  • 平移(Translate)——元素向上、下、左、右各个方向移动(有点类似于相对定位)。
  • 缩放(Scale)——缩小或放大元素。
  • 倾斜(Skew)——使元素变形,顶边滑向一个方向,底边滑向相反的方向。

15.2 如果想要优化过渡和动画性能,变换就必不可少。

因为有些过渡和动画性能可以直接使用变换来处理,因为变换的性能要好的多。如果我们要实现过渡或动画,无论什么类型,包括定位或大小操作,都应该尽可能考虑使用变换。

15.3 理解渲染路径是如何工作的,创建动画的时候一定要牢记。

浏览器计算好了页面上哪些样式应用于哪些元素上之后,需要把这些样式转化成屏幕上的像素,这个过程叫作渲染(rending)。渲染可以分为三个阶段:布局、绘制和合成

  • 布局:浏览器需要计算每个元素将在屏幕上占多大空间。因为文档流的工作方式,所以一个元素的大小和位置可以影响页面上无数其他元素的大小和位置。任何时候改变一个元素的宽度或高度,或者调整位置属性(比如top或者left),元素的布局都会重新计算。如果使用JavaScript在DOM中插入或者移除元素,也会重新计算布局。一旦布局发生改变,浏览器就必须重排(reflow)页面,重新计算所有其他被移动或者缩放的元素的布局。
  • 绘制:就是填充像素:描绘文本,着色图片、边框和阴影。这不会真正显示在屏幕上,而是在内存中绘制。如果改变某个元素的背景颜色,就必须重新绘制它。但因为更改背景颜色不会影响到页面上任何元素的位置和大小,所以这种变化不需要重新计算布局,也就是我们通常说的重绘。
  • 合成:在合成(composite)阶段,浏览器收集所有绘制完成的图层,并把它们提取为最终显示在屏幕上的图像。合成过程需要按照特定顺序进行,以确保图层出现重叠时,正确的图层显示在其他图层之上。

15.4 使用自定义定时函数曲线为过渡添加弹跳特效。

自定义的cubic-bezier()函数会产生一个弹跳特效。

第十六章 动画

16.1 使用关键帧动画定义动画中的关键点。

CSS中的动画包括两部分:用来定义动画的@keyframes规则和为元素添加动画的animation属性。其实@keyframes规则是给动画设置关键帧的,每个关键帧发生于动画过程中的哪些时刻。

16.2 使用前向和后向填充模式使动画的开始或结束无缝衔接。

这种实现是使用animation-fill-mode属性来设置的。这个属性有以下几种属性值:

  • none:也是初始值。动画执行前或执行后动画样式都不会应用到元素上。
  • backwards:在动画执行之前,浏览器就会取出动画中第一帧的值,并把它们应用在元素上。
  • forwards:动画播放完成后仍然应用最后一帧的值,并把它们应用在元素上。
  • both:同时向前向后填充

16.3 在恰当的时间使用JavaScript触发动画。

动画很多时候是为了给用户传达一种含义,这时候是和交互绑定在一起的,这时候就需要使用JavaScript来触发动画了。

16.4 为Web页面添加动画,无须华丽炫酷,只需针对用户交互传达正确的含义。

人们对动画有个普遍误解,即它们只是用来让页面变得有趣,没有什么实际用处。有时候确实是这样的(就像上一个例子),但不总是这样。有些非常好的动画不是最后才加上的,而是融入到了开发过程中。它们向用户传达页面上某些事物的特殊含义。因此不一定要华丽炫酷。