RN-《精通CSS》(上)

第一章 基础知识

创建结构化、语义化富HTML

1
2
3
4
5
6
<article class="post">
<header class="post-header">
<h1>How I became a CSS Master</h1>
</header>
<p>Ten-thousand hours</p>
</article>
1
2
3
4
5
6
.post {
/* 样式 */
}
.post-header {
/* 其他样式 */
}

第二章 添加样式

CSS选择符

相邻同辈选择符

1
2
3
4
5
6
<div class="container">
<p>这是第一个段落</p>
<h2>This is h2</h2>
<p>这是第二个段落</p>
<p>这是第三个段落</p>
</div>
1
2
3
4
5
h2 + p {
font-size: 2em;
font-weight: bold;
color: #777;
}

使用相邻同辈选择符,就可以选择位于某个元素后面,并与该元素拥有共同父元素的元素,可以看到只有 这是第二个段落 应用上了 CSS 样式。

一般同辈选择符

1
2
3
4
5
6
<div class="container">
<p>这是第一个段落</p>
<h2>This is h2</h2>
<p>这是第二个段落</p>
<p>这是第三个段落</p>
</div>
1
2
3
4
5
h2 ~ p {
font-size: 2em;
font-weight: bold;
color: #777;
}

使用一般同辈选择符可以选择 h2 元素后面的所有段落,可以看到 这是第二个段落这是第三个段落 都应用上了 CSS 样式。

相邻同辈选择符和一般同辈选择符都不会选择前面的同辈元素,浏览器之所以不支持向前选择同辈元素,主要跟网页渲染性能有关。

通用选择符

1
2
3
4
*{
margin: 0;
padding: 0;
}

简单的应用就像上面这样,只不过现在有很多现成的库可以重设样式并且比上面的简单地把一切都设为0要好一点。

1
2
3
4
5
6
.container > * {
margin: 20px;
font-size: 2em;
font-weight: bold;
color: #777;
}

上面这样组合,可以选择 .container 的元素的所有直接后代。

伪元素

可以使用 ::first-letter 伪元素来选择一段文本的第一个字符。若要选择一段文本的第一行,可以使用 ::first-line

::before::after 这两个伪元素非常适合用来插入小图标及版面装饰符号

伪元素应该使用双冒号语法,与伪类区别开,伪类使用单冒号语法。

伪类

1
<a href="https://www.baidu.com">百度一下</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 未访问过的链接为蓝色 */
a:link {
color: blue;
}
/* 访问过的链接为绿色 */
a:visited {
color: green;
}
/* 链接在鼠标悬停及获取键盘焦点时为红色 */
a:hover,
a:focus {
color: red;
}
/* 活动状态时为紫色 */
a:active {
color: purple;
}

:link:visited 应该排在前面,然后才是与用户交互相关的那些,在触摸屏和键盘等输入方式下不一定真的有悬停状态。因此,不要在重要的交互功能中使用 :hover

结构化伪类

1
2
3
4
5
6
7
8
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
1
2
3
4
/* 奇数行的背景变为黄色 */
li:nth-child(odd) {
background: yellow;
}

nth-child 选择符可以用来交替地为表格行应用样式。

nth-child 的参数可以是 odd 或者 even,还可以是数值,表示目标元素的序数位置

1
2
3
4
/* 第三行背景变黄 */
li:nth-child(3) {
background: yellow;
}

如果参数是数值表达式,如:

1
2
3
4
/* 第一行和第四行变黄。n 首先等于 0 ,然后逐次递增 1。 */
li:nth-child(3n+1) {
background: yellow;
}
1
2
3
4
/* 前三行会变黄 */
li:nth-child(-n+3) {
background: yellow;
}

:nth-last-child 选择符与 :nth-child 类似,只不过是从最后一个元素倒序计算(而不是从第一个元素正序计算)。

:first-child 相当于 :nth-child(1):last-child 对应于 :nth-last-child(1)

层叠

稍微复杂的样式表中都可能存在两条甚至多条规则同时选择一个元素的情况,CSS通过一种叫作层叠(cascade)的机制来处理这种冲突。

层叠机制的重要性级别从高到低如下所示:

  • 标注为 !important 的用户样式;
  • 标注为 !important 的作者样式;
  • 作者样式
  • 用户样式
  • 浏览器的默认样式

在此基础上,规则再按选择符的特殊性排序。特殊性高的选择符会覆盖特殊性低的选择符。如果两条规则的特殊性相等,则后定义的规则优先

!important > 行间样式 > id > class | 属性选择器 > 标签选择器 > 通配符选择器

CSS权重(特殊性)

  • !important Infinity
  • 行间样式 1000
  • id 100
  • class | 属性 | 伪类 10
  • 标签 | 伪元素 1
  • 通配符 0

1000 100 这些不是十进制,是 256 进制

1
<h1 class="title">这是一个h1</h1>
1
2
3
4
5
6
7
8
9
h1 {
color: red;
}
.title {
color: blue;
}
.title {
color: green;
}

h1 中文字最终会变成 green

继承

继承和层叠看起来有点类似,但实际上他们有着本质上的不同。

有些属性,像颜色或字体大小,会被应用它们的元素的后代所继承。比如,我把 body 元素的文本颜色设置为黑色,那么 body 所有后代元素的文本颜色都会继承这个黑色,字号也一样。

body 上设置了一个字号,会发现页面中标题并不会变成同样的字号。可能你觉得这是因为标题不会继承文本大小。实际上,标题大小是浏览器默认样式表中设定的。任何直接应用给元素的样式都会覆盖继承的样式,因为继承的样式没有任何特殊性

继承的属性没有任何特殊性,连0都说不上。这意味着使用特殊性为0的通用选择符设置的样式都可以覆盖继承的样式。

1
2
3
4
5
<h1 class="title">
h1
<em>这是一个em</em>
h1
</h1>
1
2
3
4
5
6
* {
color: black;
}
h1 {
color: red;
}

在上面这段代码中,表面上看 em 会继承 h1 的红色,但通用选择符给所有元素设置的黑色会覆盖它所继承的红色。通用选择符的特殊性为 0,但仍然优先于继承的属性,在这种情况下,最好是给 body 元素设置一个基准色,这样它的所有元素就都会继承这个颜色,而不是被设置成这个颜色。

第三章 可见格式化模型

盒模型

百分比问题

1
2
3
<div class="group">
<article class="block"></article>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
.group {
width: 300px;
height: 200px;
margin: 0 auto;
border: 1px solid black;
}
.block {
width: 100px;
height: 100px;
border: 1px solid red;
margin-left: 5%;
margin-top: 5%;
}

上面的代码中,5% 指的是父元素 .group 宽度的 5%,.group 宽度是在这里是 300px,那么 margin-left 为 15px。注意,CSS规定,上、下方位的内外边距,仍然基于包含块的宽度,来计算,因此 margin-top 也为 15px。原因就是元素的高度常常不会被声明,而且会因内容多少而差距很大,如果要明确设定默认高度,也最好使用 min-height,因为这个属性允许盒子随内容扩展

匿名盒子

1
2
3
4
<section>
some text
<p>Some more text</p>
</section>

此时,some text 就算没有定义为块级元素,也会被当成块级元素,这种情况下,这个盒子被称为匿名块盒子

浮动模型

浮动盒子可以向左或向右移动,直到其外边沿接触包含块的外边沿,或接触另一个浮动盒子的外边沿。浮动盒子也会脱离常规文档流,因此常规流中的其他块级盒子的表现,几乎当浮动盒子根本不存在一样。

1
2
3
4
5
<div class="container">
<div class="first">1234567891231231315135</div>
<div class="second"></div>
<div class="third"></div>
</div>
1
2
3
4
5
6
7
8
9
10
.container > div {
width: 100px;
height: 100px;
border: 1px solid black;
margin-bottom: 20px;
}
.container .first {
width: auto;
float: right;
}

上面的代码可以看出,.first 会脱离文档流并向右移动,直至其右边接触包含块的有边沿。同时,.first 的宽度也会收缩为适应于其中内容的最小宽度,除非通过 widthmin-width/max-width 明确设置其宽度。

修改 .first 为向左浮动:

1
2
3
4
5
6
7
8
9
10
11
12
13
.container > div {
width: 100px;
height: 100px;
border: 1px solid black;
margin-bottom: 20px;
}
.container .first {
width: auto;
float: left;
}
.container .second {
background: green;
}

可以看出 .first 已经不在文档流中,因此不会再占空间,这导致它浮于上方,遮住了 .second

块级格式化上下文

  • display 属性值设置为 inline-blocktable-cell 之类的元素,可以为内容创建类似块级的上下文
  • float 属性值不是 none 的元素
  • 绝对定位的元素
  • overflow 属性值不是 visible 的元素。

最常见的就是overflow:hiddenfloat:left/rightposition:absolute。也就是说,每次看到这些属性的时候,就代表了该元素以及创建了一个BFC了。

学习 BFC (Block Formatting Context)

第四章 网页排版

字形大小

几乎所有的浏览器中 font-size 的默认大小都是 16 像素,我们不修改默认的 font-size ,而是选择使用 em 单位调整特定元素的大小。

对于 font-size 属性,可用百分比替代 em 。133.3% 和 1.333em 没有区别。

最灵活的方式是使用 rem 单位,它始终基于根元素 html 元素的 font-size 缩放。

em 用于计算盒模型大小时,它不是基于继承的 font-size ,而是基于元素自身计算的 font-size。因此,不同级别的标题对应的 font-size 是不一样的。所以下面的代码推荐使用 rem

1
2
3
4
h1,h2,h3,h4,h5,h6 {
margin-top: 1.5rem;
/* 24px = 16px * 1.5 */
}

不推荐使用绝对物理长度,如mm cm in pt