《深入解析CSS》读书笔记
作者基恩·J·格兰特, 排版文字等多有不足,仅供个人回忆知识点使用。
第一部分 基础回顾
层叠、优先级和继承
层叠
继承
特殊值
简写属性
总结
相对单位
相对值的好处
em和rem
拿不准的时候,用rem设置字号,用px设置边框,用em设置其他大部分属性。
em
em:最常见的相对长度单位,适合基于特定的字号进行排版。在CSS中,1em等于当前元素的字号,其准确值取决于作用的元素。
注意:
- 当同时用em指定一个元素的字号和其他属性,浏览器必须先计算字号,然后使用这个计算值去计算其余的属性值。
- 当使用em指定多重嵌套的元素的字号时,如果em!=1,则文字会逐级增大或减小。比如多层嵌套的列表。可以通过以下代码纠正,bu不过更好的方法是使用rem.
ul{
font-size: .8em;
}
ul ul {
font-size: 1em;
}
rem
rem是root em的缩写,是相对于根元素的单位。在使用时,可以首先指定根元素大小:
:root {
font-size: 1em; /* :root也可以写成html(类型选择器),1em是浏览器默认字号 */
}
ul {
font-size: .8rem;
}
停止像素思维
构造响应式面版
媒体查询,即@media规则,可以指定某种屏幕尺寸或者媒体类型(比如,打印机或者屏幕)下的样式。这是响应式设计的关键部分
html {
font-size:0.75em; /* 默认 */
}
@media (min-width:800px) {
:root {
font-size:0.875em; /* 仅作用到宽度800px及其以上,覆盖之前 */
}
}
@media (min-width:1200px){
:root {
font-size:1em; /* 仅作用到宽度1200px及其以上,覆盖之前 */
}
}
缩放单个组件
先有个基础的panel类,再有一个更进一步的.panel.large从而实现单个组件的放缩。代码如下(Vue):
<template>
<div>
<div class="panel">
<h2>Single-origin</h2>
<div class="panel-body">
We have built partnerships with small farms around the world to hand-select beans at the peak of season.
</div>
</div>
<div class="panel large">
<h2>Single-origin</h2>
<div class="panel-body">
We have built partnerships with small farms around the world to hand-select beans at the peak of season.
</div>
</div>
</div>
</template>
<script>
</script>
<style>
html {
font-size:0.75em;
}
@media (min-width:800px) {
:root {
font-size:0.875em;
}
}
@media (min-width:1200px){
:root {
font-size:1em;
}
}
.panel {
font-size: 1rem;
padding:1em;
border-radius: 0.5em;
border:1px solid #999;
}
.panel > h2 {
margin-top:0;
font-size:0.8em;
font-weight: bold;
text-transform: uppercase;
}
.panel.large {
font-size:1.2rem;
}
</style>
视口的相对单位
视口:浏览器窗口里网页可见部分的边框区域。它不包括浏览器的地址栏、工具栏、状态栏。
vh:视口高度的1/100
vw:视口宽度的1/100
vmin:视口宽、高中较小一方1/100(应该在手机上用得比较多?横屏竖屏)
vmax:视口宽、高中较大一方的1/100
可以用于展示一个填满屏幕的大图。
使用vw定义字号
之前使用媒体查询时,是会有一个突变的。而用vw定义字号不会如此。例如使用font-size:2vw。不过直接用,字号常常会变得不合理。有大屏上宽比高大,小屏上宽比高小等原因。
这时用到CSS的calc()函数。
calc()函数内可以对两个及其以上的值进行基本运算。当要结合不同单位的值时,calc()特别实用。它支持的运算包括:加(+)、减(−)、乘(×)、除(÷)。加号和减号两边必须有空白,因此我建议大家养成在每个操作符前后都加上一个空格的习惯,比如calc(1em + 10px)。
代码例下:
:root {
font-size: calc(0.5em + 1vw);
}
无单位的数值和行高
line-height、z-index、font-weight(700=bold,400=normal)支持无单位的值。
line-height 行高比较特殊,通常用无单位的数值。举个例子,但是不太懂运作机制。
<template>
<div class="main">
<p class="about-us">
We have built partnerships with small farms around the world to
hand-select beans at the peak of season. We then carefully roast in
small batches to maximize their potential.
</p>
</div>
</template>
<script>
</script>
<style>
.main {
line-height: 1.2; /* 改成1.2em试试 */
}
.about-us {
font-size: 2em;
}
</style>
自定义属性(即CSS变量)
变量名必须前面有两个连字符(--)用来跟CSS属性区分。下例定义了一个--main-font的变量
:root {
--main-font: Helvetica, Arial, sans-serif;
}
调用函数var()就能使用该变量
:root {
--main-font: Helvetica, Arial, sans-serif;
}
p {
font-family: var(--main-font);
}
也可以提供备用值,在第一个参数没用的时候使用。如var(--secondary-color,blue).
如果var()函数算出来的是一个非法值,对应的属性会设置为其初始值。
如果在一个选择器中改变了变量值,则容器内的变量值会更新,不影响容器外的变量值。
盒模型
元素宽度的问题
在下面的代码中,main列和sidebar列看似一个70%,一个30%,但是没有能够并排显示,其原因如下:

<template>
<div class="body">
<header>
<h1>TeaWithCola Running Club</h1>
</header>
<div class="container"> /* 如果父元素不能包含子元素,则使用overflow:auto 详见https://blog.csdn.net/a495420712/article/details/50974609*/
<main class="main">
<h2>Come join us!</h2>
<p>
This is yi duan hua.
</p>
</main>
<aside class="sidebar">
<div class="widget"></div>
<div class="widget"></div>
</aside>
</div>
</div>
</template>
<script>
</script>
<style>
.body {
background-color:#eee;
font-family: Arial, Helvetica, sans-serif
}
header {
color:#fff;
background-color: #0072b0;
border-radius: .5em;
}
main {
display:block;
}
.main {
float: left; /* 将main列向左浮动 */
width: 70%;
background-color: #fff;
border-radius: .5em;
}
.sidebar {
float: left; /* 将sidebar列向左浮动 */
width: 30%;
padding:1.5em;
background-color: #fff;
border-radius: .5em;
}
</style>
如何解决问题呢?提供以下的方法:
- 减少一列的宽度,但是这是试出来的。
- 使用
calc()函数,在上例中,是由于加了内边距,所以用calc()函数减去其值:calc(30% - 3em). - 调整盒模型。
调整盒模型
CSS中可以使用box-sizing属性调整盒模型的行为。
box-sizing的默认值为content-box,意味着任何指定的宽/高都只设置内容盒子的大小。
设置为border-box后,则会设置内容、内边距、边框的大小总和。这种情况下,内边距不会让一个元素更宽,而是让内部的内容更窄。

可以在选择器内部设置box-sizing: border-box作用于单个元素。
全局设置border-box
将此代码放到样式表开头:
*,
::before,
::after {
box-sizing: border-box;
}
注意:如果在网页中使用了带样式的第三方组件,就可能会因此破坏其中一些组件的布局,尤其是当第三方组件在开发CSS的过程中没有考虑到使用者会修改盒模型时。因为全局设置border-box时使用的通用选择器会选中第三方组件内的每个元素,修改盒模型可能会有问题,所以最终需要写另外的样式将组件内的元素恢复为content-box。
有一种简单点方式:利用继承改一下修改盒模型的方式。如下:
:root {
box-sizing: border-box; /* 根元素设置为border-box*/
}
*,
::before,
::after {
box-sizing:inherit; /* 盒模型通常不会被继承,使用inherit关键字强制继承 */
}
在必要时选中第三方组件的顶级容器,将其恢复为content-box,这样组件内部元素会继承该盒模型。
.third-party-component {
box-sizing: content-box;
}
之后的示例都假设样式表开头修改为了border-box
给列之间加上间隔
- 基于百分比的外边距留白
2.使用calc()从宽度中减去间距
元素高度的问题
通常最好避免给元素指定明确的高度。普通文档流是为限定的宽度和无限的高度设计的。容器的高度由内容天然决定。
(普通文档流:指的是网页元素的默认布局行为。行内元素跟随文字的方向从左到右排列,当到达容器边缘时会换行。块级元素会占据完整的一行,前后都有换行)
控制溢出行为
溢出情况:

用overflow属性可以控制溢出内容的行为,该属性支持以下4个值:
visible(默认值)——所有内容可见,即使溢出容器边缘
hidden——溢出容器内边距边缘的内容被裁剪,无法看见
scroll——容器出现滚动条,用户可以通过滚动查看剩余内容。
auto——只有内容溢出时容器才会出现滚动条。
谨慎使用滚动条,用户体验不好。
水平方向溢出:可以用overflow-x属性单独控制水平方向的溢出,或者用overflow-y控制垂直方向溢出。这些属性支持overflow的所有值,然而同时给x和y指定不同的值,往往会产生难以预料的结果。
百分比高度的备选方案
用百分比指定高度存在问题。百分比参考的是元素容器块的大小,但是容器的高度通常是由子元素的高度决定的。这样会造成死循环,浏览器处理不了,因此它会忽略这个声明。要想让百分比高度生效,必须给父元素明确定义一个高度。
等高列的实现方式:
CSS表格布局:给容器设置display: table,给每一列设置display:table-cell。如果对齐出现问题,可以利用负外边距。代码如下:
<template>
<div class="body1">
<header>
<h1>TeaWithCola Running Club</h1>
</header>
<div class="wrapper">
<div class="container" style="overflow:auto">
<main class="main">
<h2>Come join us!</h2>
<p>
This is yi duan hua.
</p>
</main>
<aside class="sidebar">
<div class="widget"></div>
<div class="widget"></div>
</aside>
</div>
</div>
</div>
</template>
<script>
</script>
<style>
*,
::before,
::after {
box-sizing: border-box;
}
.body1 {
background-color:#f0f0f0;
font-family: Arial, Helvetica, sans-serif
}
header {
color:#fff;
background-color: #0072b0;
border-radius: .5em;
}
.wrapper {
margin-left: -1.5em;
margin-right: -1.5em;
}
.container {
display: table; /* 表格样的容器布局 */
width: 100%; /*默认情况下,显示为table的元素宽度不会扩展到100%,需要明确指定宽度 */
border-spacing: 1.5em 0 /* 单元格之间加上水平的border-spacing,这是会产生对齐问题,我们使用负外边距进行解决 参见wrapper类 */
}
main {
display:block;
}
.main {
display: table-cell; /* 表格单元格一样的列布局*/
width: 70%;
background-color: #fff;
border-radius: .5em;
}
.sidebar {
display: table-cell; /* 表格单元格一样的列布局 */
width: 30%;
padding:1.5em;
margin-left: 1.5em; /*外边距不再生效 */
background-color: #fff;
border-radius: .5em;
}
</style>
Flexbox:给容器设置display: flex,它就变成了一个弹性容器(flex container),子元素默认等高。你可以给子元素设置宽度和外边距,尽管加起来可能超过100%, Flexbox也能妥善处理。以上代码清单渲染出来的样式跟表格布局一样,而且不需要额外包裹元素,CSS也更简单。
<template>
<div class="body1">
<header>
<h1>TeaWithCola Running Club</h1>
</header>
<div class="container" style="overflow:auto">
<main class="main">
<h2>Come join us!</h2>
<p>
This is yi duan hua.
</p>
</main>
<aside class="sidebar">
<div class="widget"></div>
<div class="widget"></div>
</aside>
</div>
</div>
</template>
<script>
</script>
<style>
*,
::before,
::after {
box-sizing: border-box;
}
.body1 {
background-color:#f0f0f0;
font-family: Arial, Helvetica, sans-serif
}
header {
color:#fff;
background-color: #0072b0;
border-radius: .5em;
}
.container {
display: flex;
}
main {
display:block;
}
.main {
/* 无需指定display或float*/
width: 70%;
background-color: #fff;
border-radius: .5em;
}
.sidebar {
width: 30%;
padding:1.5em;
margin-left: 1.5em; /*外边距生效 */
background-color: #fff;
border-radius: .5em;
}
</style>
min-height和max-height
用法就像其名字一样,指定最小高度或最大高度。
垂直居中内容
为什么vertical-align不生效:
vertical-align声明只会影响行内元素或者table-cell元素。对于行内元素,它控制着该元素跟同一行内其他元素之间的对齐关系。比如,可以用它控制一个行内的图片跟相邻的文字对齐。
对于显示为table-cell的元素,vertical-align控制了内容在单元格内的对齐。如果你的页面用了CSS表格布局,那么可以用vertical-align来实现垂直居中。
- CSS中最简单的垂直居中方法是给容器相等的上下内边距,让容器和内容自行决定自己的高度.
- 如果需要指定高度或避免使用内边距:对容器使用display: table-cell和vertical-align: middle。
- 可以用Flexbox
- 如果容器内只有一行文字:设置一个大的行高,让它等于理想的容器高度。这样会让容器高度扩展到能够容纳行高。如果内容不是行内元素,可以设置为inline-block。
- 容器和内容的高度都知道:绝对定位
- 不知道内部元素的高度:用绝对定位结合变形(transform)。
- 参考howtocenterincss网站,根据自己的场景填写几个选项,然后它会相应地生成垂直居中的代码。
负外边距

警告:如果元素被别的元素遮挡,利用负外边距让元素重叠的做法可能导致元素不可点击。
负外边距并不常用,但是在某些场景下很实用,尤其是当创建列布局的时候。不过应当避免频繁使用,不然网页的样式就会失控。
外边距折叠
当顶部和/或底部的外边距相邻时,就会重叠,产生单个外边距。这种现象被称作折叠。
文字折叠
外边距折叠的主要原因与包含文字的块之间的间隔相关。段落(
)默认有1em的上外边距和1em的下外边距。这是用户代理的样式表添加的,但当前后叠放两个段落时,它们的外边距不会相加产生一个2em的间距,而会折叠,只产生1em的间隔。
折叠外边距的大小等于相邻外边距中的最大值。
多个外边距折叠
即使两个元素不是相邻的兄弟节点也会产生外边距折叠。

如果在页面中添加一个空的、无样式的div(没有高度、边框和内边距),它自己的顶部和底部外边距就会折叠。
说明:只有上下外边距会产生折叠,左右外边距不会折叠。
容器外部折叠

通过给
以下方法防止外边距折叠:
- 对容器使用overflow: auto(或者非visible的值),防止内部元素的外边距跟容器外部的外边距折叠。这种方式副作用最小。
- 在两个外边距之间加上边框或者内边距,防止它们折叠。
- 如果容器为浮动元素、内联块、绝对定位或固定定位时,外边距不会在它外面折叠。
- 当使用Flexbox布局时,弹性布局内的元素之间不会发生外边距折叠。网格布局同理。
- 当元素显示为table-cell时不具备外边距属性,因此它们不会折叠。此外还有table-row和大部分其他表格显示类型,但不包括table、table-inline、table-caption。
容器内的元素间距
在之前代码的基础上,做如下更改:
html:
<aside class="sidebar">
<a href="https://www.baidu.com" class="button-link">
go baidu.com
</a>
<a href="https://www.baidu.com" class="button-link">
go baidu.com
</a>
<div class="widget"></div>
</aside>
CSS
.button-link {
display:block; /* 块级元素填满了可用宽度,同时让每个链接单独一行 */
padding: 0.5em;
color: #fff;
background-color: #0090c9;
text-align: center;
text-decoration: none;
text-transform: uppercase;
}
当要加间距的时候,就会出问题。侧边栏的内边距会跟按钮的外边距接触。解决方法:
使用相邻兄弟组合器(+),选中同一个父元素下紧跟在其他button-link后面的button-link元素。
.button-link + .button-link {
margin-top: 1.5em;
}
猫头鹰选择器
迟钝的猫头鹰选择器:* + *
*是通用选择器,+是相邻兄弟组合器。所以会选中页面上有相同父级的非第一个子元素。
浙公网安备 33010602011771号