深入解析CSS

作者基思·J.格兰特分类计算机-计算机综合
推荐值86.8 %来源微信读书
笔记数量91评论数量

第一部分 基础回顾

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

1.1 层叠

  • 下面来分析层叠的规则。当声明冲突时,层叠会依据三种条件解决冲突。(1) 样式表的来源:样式是从哪里来的,包括你的样式和浏览器默认样式等。(2) 选择器优先级:哪些选择器比另一些选择器更重要。(3) 源码顺序:样式在样式表里的声明顺序。
  • 标记了!important的声明会被当作更高优先级的来源,因此总体的优先级按照由高到低排列如下所示:(1) 作者的!important(2) 作者(3) 用户代理
  • ID选择器的优先级比拥有任意多个类的选择器都高。同理,类选择器的优先级比标签选择器(也称类型选择器)更高。
  • 你可能知道,处理层叠时有两条通用的经验法则。因为它们很有用,所以提一下。(1) 在选择器中不要使用ID。就算只用一个ID,也会大幅提升优先级。当需要覆盖这个选择器时,通常找不到另一个有意义的ID,于是就会复制原来的选择器,然后加上另一个类,让它区别于想要覆盖的选择器。(2) 不要使用!important。它比ID更难覆盖,一旦用了它,想要覆盖原先的声明,就需要再加上一个!important,而且依然要处理优先级的问题。

第2章 相对单位

2.2 em和rem

  • 在CSS中,1em等于当前元素的字号,其准确值取决于作用的元素。
  • 这里设置内边距的值为1em。浏览器将其乘以字号,最终渲染为16px。这一点很重要:浏览器会根据相对单位的值计算出绝对值,称作计算值(computed value)。
  • 当设置padding、height、width、border-radius等属性时,使用em会很方便。这是因为当元素继承了不同的字号,或者用户改变了字体设置时,这些属性会跟着元素均匀地缩放。
  • 这就是em的好处。可以定义一个元素的大小,然后只需要改变字号就能整体缩放元素。
  • 了解这些非常有用。对大多数浏览器来说,默认的字号为16px。准确地说,medium关键字的值是16px。
  • 当用em来指定多重嵌套的元素的字号时,就会产生意外的结果。为了算出每个元素的准确值,就需要知道继承的字号,如果这个值是在父元素上用em定义的,就需要知道父元素的继承值,以此类推,就会沿着DOM树一直往上查找。
  • 列表多级嵌套并且给每一级使用em定义字号时,就会发生文字缩小的现象。
  • em用在内边距、外边距以及元素大小上很好,但是用在字号上就会很复杂。值得庆幸的是,我们有更好的选择:rem。
  • rem是root em的缩写。rem不是相对于当前元素,而是相对于根元素的单位。不管在文档的什么位置使用rem,1.2rem都会有相同的计算值:1.2乘以根元素的字号。

2.3 停止像素思维

  • 更进一步地说,我们甚至可以根据屏幕尺寸,用媒体查询改变根元素的字号。这样就能够基于不同用户的屏幕尺寸,渲染出不同大小的面板(如图2-8所示)。
  • 通过给页面根元素设置不同字号,我们响应式地重新定义了整个网页的em和rem。也就是说,即使不直接修改面板的样式,它也是响应式的。

第3章 盒模型

3.1 元素宽度的问题

  • 在一些网站设计中,某些容器的背景色可能是透明的。在这种情况下,可以先暂时给容器设置一个背景色,等实现了容器的大小和位置后再去掉背景色。
  • 因为IE有一个bug,它会默认将<main>元素渲染成行内元素,而不是块级元素,所以代码中我们用声明display: block来纠正。
  • 虽然将两列宽度设置为70%和30%,但它们总共占据的宽度超过了可用空间的100%,这是因为盒模型的默认行为(如图3-4所示)。当给一个元素设置宽或高的时候,指定的是内容的宽或高,所有内边距、边框、外边距都是追加到该宽度上的。
  • 最笨的方法是减少其中一列(比如侧边栏)的宽度。在我的屏幕上,侧边栏改为宽26%,两列能够并排放下,但是这种方式不可靠。26%是一个魔术数值(magic number)。它不是一个理想的值,而是通过改样式试出来的值
  • 替代魔术数值的一个方法是让浏览器帮忙计算。在本例中,因为加了内边距,两列的宽度总和超出了3em,所以可以使用calc()函数减去这个值,得到刚好100%的总和。比如设置侧边栏宽度为calc(30% -3em)就能刚好并排放下两列,但是还有更好的解决办法。
  • box-sizing的默认值为content-box,这意味任何指定的宽或高都只会设置内容盒子的大小。将box-sizing设置为border-box后,height和width属性会设置内容、内边距以及边框的大小总和,这刚好符合示例的要求
  • 使用box-sizing: border-box后,两个元素加起来正好等于100%宽度。现在因为它们70%和30%的宽度包含内边距,所以一行放得下两
  • 从现在开始,本书的每个示例都假设你的样式表开头修改为了border-box。
  • 看着有点奇怪的做法。不知道多少项目是按照比规则实现的
    从现在开始,本书的每个示例都假设你的样式表开头修改为了border-box。
  • 百分比是相对于父元素的完整宽度的
  • [插图]

3.2 元素高度的问题

  • 但是通常最好避免给元素指定明确的高度。普通文档流是为限定的宽度和无限的高度设计的。内容会填满视口的宽度,然后在必要的时候折行。因此,容器的高度由内容天然地决定,而不是容器自己决定。
  • 当明确设置一个元素的高度时,内容可能会溢出容器。当内容在限定区域放不下,渲染到父元素外面时,就会发生这种现象
  • 通常情况下,我倾向于使用auto而不是scroll,因为在大多数情况下,我不希望滚动条一直出现
  • 要想让百分比高度生效,必须给父元素明确定义一个高度。人们使用百分比高度是想让一个容器填满屏幕。不过更好的方式是用视口的相对单位vh,第2章已经介绍过。100vh等于视口的高度。
  • 不像block的元素,默认情况下,显示为table的元素宽度不会扩展到100%,因此需要明确指定宽度❶。以上代码已经差不多实现了需求,但是缺少间隔。这是因为外边距❷并不会作用于table-cell元素,所以要修改代码,让间隔生效。
  • 奇怪的规则,为什么外边距不能生效在table cell
    不像block的元素,默认情况下,显示为table的元素宽度不会扩展到100%,因此需要明确指定宽度❶。以上代码已经差不多实现了需求,但是缺少间隔。这是因为外边距❷并不会作用于table-cell元素,所以要修改代码,让间隔生效。
  • Flexbox不需要一个额外的div包裹元素,它默认会产生等高的元素。此外也不需要使用负外边距。
  • 给容器设置display: flex,它就变成了一个弹性容器(flex container),子元素默认等高。你可以给子元素设置宽度和外边距,尽管加起来可能超过100%, Flexbox也能妥善处理。
  • 除非别无选择,否则不要明确设置元素的高度。先寻找一个替代方案。设置高度一定会导致更复杂的情况。
  • min-height和max-height。你可以用这两个属性指定最小或最大值,而不是明确定义高度,这样元素就可以在这些界限内自动决定高度。
  • vertical-align声明只会影响行内元素或者table-cell元素。对于行内元素,它控制着该元素跟同一行内其他元素之间的对齐关系

3.3 负外边距

  • 不同于内边距和边框宽度,外边距可以设置为负值。负外边距有一些特殊用途,比如让元素重叠或者拉伸到比容器还宽。

3.4 外边距折叠

  • 折叠外边距的大小等于相邻外边距中的最大值。
  • 是因为弹性子元素的外边距不会折叠,而这一块刚好用了Flexbox布局。

3.5 容器内的元素间距

  • 要给按钮加上通用样式。将其设置为块级元素,以便填满容器的宽度,也能够让每个按钮单独

第二部分 精通布局

第4章 理解浮动

4.1 浮动的设计初衷

  • 浮动能将一个元素(通常是一张图片)拉到其容器的一侧,这样文档流就能够包围它(如图4-1所示)。这种布局在报纸和杂志中很常见,因此CSS增加了浮动来实现这种效果。[插图]
  • 通常,最简单的方式是先将网页的大块区域布局好,再逐级布局内部的小元素。
  • 使用了max-width而不是width,因此如果视口宽度小于1080px的话,内层容器就能缩小到1080px以下。换句话说,在小视口上,内层容器会填满屏幕,在大视口上,它会扩展到1080px。这种方式能有效避免在小屏幕上出现水平滚动条。

第5章 Flexbox

5.1 Flexbox的原则

  • 元素添加display: flex,该元素变成了一个弹性容器(flex container),它的直接子元素变成了弹性子元素(flex item)。弹性子元素默认是在同一行按照从左到右的顺序并排排列。弹性容器像块元素一样填满可用宽度,但是弹性子元素不一定填满其弹性容器的宽度。
  • 弹性子元素高度相等,该高度由它们的内容决定。
  • 。在标准稳定前,浏览器一般是这样来支持CSS新特性的。比如,旧版Safari浏览器没实现display: flex,而是实现了display:-webkit-flex。
  • 这就是之前发现的行高对span无效类似的原因
    注意这里的链接被设置为块级元素。如果链接还是行内元素,那么它给父元素贡献的高度会根据行高计算,而不是根据内边距和内容,这样不符合预期。
  • 这里给水平方向设置的内边距比垂直方向的要多一点,因为从美学上来讲这样更让人愉悦。
  • Flexbox允许使用margin: auto来填充弹性子元素之间的可用空间
  • 这个可以解决如何设置ul下第一个li元素样式的问题!
    给每个弹性子元素之间加上了外边距,最外侧的两个元素除外。为了实现这一效果,可以采用margin-left属性和一个相邻兄弟组合器,这个方法跟第3章的猫头鹰选择器类似。
  • 同时给最后的按钮加上一个auto的左侧外边距,这样就会让这个外边距填充所有可用空间,如此一来,最后的按钮就会被推到最右侧

5.2 弹性子元素的大小

  • 前面的代码使用外边距给弹性子元素设置了间距。你可以用width和height属性设置它们大小,但是比起margin、width、height这些常见属性,Flexbox提供了更多更强大的选项。我们来看一个更有用的Flexbox属性:flex。
  • flex属性是三个不同大小属性的简写:flex-grow、flex-shrink和flex-basis。在代码清单5-7里,只提供了flex-grow的值,剩下的两个属性是默认值(分别是1和0%),因此flex: 2等价于flex: 210%。通常首选简写属性,但也可以分别声明三个属性。
  • flex-basis定义了元素大小的基准值,即一个初始的“主尺寸”。flex-basis属性可以设置为任意的width值,包括px、em、百分比。它的初始值是auto,此时浏览器会检查元素是否设置了width属性值。如果有,则使用width的值作为flex-basis的值;如果没有,则用元素内容自身的大小。如果flex-basis的值不是auto, width属性会被忽略。
  • 每个弹性子元素的flex-basis值计算出来后,它们(加上子元素之间的外边距)加起来会占据一定的宽度。加起来的宽度不一定正好填满弹性容器的宽度,可能会有留白(如图5-8所示)。多出来的留白(或剩余宽度)会按照flex-grow(增长因子)的值分配给每个弹性子元素,flex-grow的值为非负整数。如果一个弹性子元素的flex-grow值为0,那么它的宽度不会超过flex-basis的值;如果某个弹性子元素的增长因子非0,那么这些元素会增长到所有的剩余空间被分配完,也就意味着弹性子元素会填满容器的宽度
  • 每个子元素的flex-shrink值代表了它是否应该收缩以防止溢出。如果某个子元素为flex-shrink: 0,则不会收缩;如果值大于0,则会收缩至不再溢出。按照flex-shrink值的比例,值越大的元素收缩得越多。

5.3 弹性方向

  • 因此要将右边栏(column-sidebar)改为弹性容器,并设置flex-direction: column。然后给里面的两个板块设置非0的flex-grow值。
  • 如何实现竖版的圣杯布局
    因此要将右边栏(column-sidebar)改为弹性容器,并设置flex-direction: column。然后给里面的两个板块设置非0的flex-grow值。
  • 内部的弹性盒子的弹性方向为column,因此主轴发生了旋转,现在变成了从上到下(副轴变成了从左到右)。也就是对于弹性子元素而言,flex-basis、flex-grow和flex-shrink现在作用于元素的高度而不是宽度。由于指定了flex: 1,因此在必要的时候子元素的高度会扩展到填满容器。
  • 水平弹性盒子的大部分概念同样适用于垂直的弹性盒子(column或column-reverse),但是有一点不同:在CSS中处理高度的方式与处理宽度的方式在本质上不一样。弹性容器会占据100%的可用宽度,而高度则由自身的内容来决定。即使改变主轴方向,也不会影响这一本质。
  • 如果内容超出可用宽度或高度呢
    水平弹性盒子的大部分概念同样适用于垂直的弹性盒子(column或column-reverse),但是有一点不同:在CSS中处理高度的方式与处理宽度的方式在本质上不一样。弹性容器会占据100%的可用宽度,而高度则由自身的内容来决定。即使改变主轴方向,也不会影响这一本质。
  • 弹性容器的高度由弹性子元素决定,它们会正好填满容器。在垂直的弹性盒子里,子元素的flex-grow和flex-shrink不会起作用,除非有“外力”强行改变弹性容器的高度
  • 难怪在book mark block的实现中感觉左侧最下方的块没法做到底部对齐
    弹性容器的高度由弹性子元素决定,它们会正好填满容器。在垂直的弹性盒子里,子元素的flex-grow和flex-shrink不会起作用,除非有“外力”强行改变弹性容器的高度
  • not()伪类和属性选择器[type=checkbox]以及[type=radio](参见附录A),可以选中除了复选框和单选按钮以外的所有<input>元素
  • 通常情况下,块级元素会自动填满可用宽度,但是<input>比较特殊,其宽度由size属性决定,而它表示不出滚动条的情况下大致能容纳的字符数量。

5.4 对齐、间距等细节

  • flex-wrap属性允许弹性子元素换到新的一行或多行显示。它可以设置为nowrap(初始值)、wrap或者wrap-reverse。启用换行后,子元素不再根据flex-shrink值收缩,任何超过弹性容器的子元素都会换行显示。
  • flex-flow属性是flex-direction和flex-wrap的简写
  • 值space-between将第一个弹性子元素放在主轴开始的地方,最后一个子元素放在主轴结束的地方,剩下的子元素间隔均匀地放在这两者之间的区域。值space-around类似,只不过给第一个子元素的前面和最后一个子元素的后面也加上了相同的间距。
  • justify-content控制子元素在主轴方向的对齐方式,align-items则控制子元素在副轴方向的对齐方式
  • align-items的初始值为stretch,在水平排列的情况下让所有子元素填充容器的高度,在垂直排列的情况下让子元素填充容器的宽度,因此它能实现等高列。
  • 如果开启了换行(用flex-wrap), align-content属性就可以控制弹性容器内沿副轴方向每行之间的间距
  • 该属性控制弹性子元素沿着容器副轴方向的对齐方式。它跟弹性容器的align-items属性效果相同,但是它能单独给弹性子元素设定不同的对齐方式。auto为初始值,会以容器的align-items值为准。其他值会覆盖容器的设置。
  • 给某个子元素单独设置对齐方式。可以解决bookmark中url向下对齐的问题
    该属性控制弹性子元素沿着容器副轴方向的对齐方式。它跟弹性容器的align-items属性效果相同,但是它能单独给弹性子元素设定不同的对齐方式。auto为初始值,会以容器的align-items值为准。其他值会覆盖容器的设置。
  • 初始状态下,所有的弹性子元素的order都为0。指定一个元素的值为−1,它会移动到列表的最前面;指定为1,则会移动到最后
  • 这里用span而不是div来放置文字,因为span默认就是行内元素。如果因为某些原因CSS加载失败,或者浏览器不支持Flexbox,那么$20.00仍然会在一行显示。

5.5 值得注意的地方

  • 一旦你熟悉了它,你可能想要在页面的每个地方都开始使用,不过你应该依靠正常的文档流,只在必要的时候才使用Flexbox。这么说并不是让你不用它,而是希望你不要拿着锤子满世界找钉子。
  • 有道理。必要的时候才使用flex
    一旦你熟悉了它,你可能想要在页面的每个地方都开始使用,不过你应该依靠正常的文档流,只在必要的时候才使用Flexbox。这么说并不是让你不用它,而是希望你不要拿着锤子满世界找钉子。

第6章 网格布局

6.1 网页布局开启新纪元

  • 接下来是新属性:grid-template-columns和grid-template-rows。这两个属性定义了网格每行每列的大小。本例使用了一种新单位fr,代表每一列(或每一行)的分数单位(fraction unit)。这个单位跟Flexbox中flex-grow因子的表现一样。grid-template-columns:1fr 1fr 1fr表示三列等宽。

6.2 网格剖析

  • 并用grid-template-columns和grid-template-rows定义了网格轨道。因为列的分数单位分别是2fr和1fr,所以第一列的宽度是第二列的两倍。定义行的时候用到了一个新方法:repeat()函数。它在声明多个网格轨道的时候提供了简写方式。
  • 用repeat()符号还可以定义不同的重复模式,比如repeat(3, 2fr 1fr)会重复三遍这个模式,从而定义六个网格轨道,重复的结果是2fr 1fr 2fr 1fr 2fr 1fr。
  • 为何要使用网格线作为数字的标记值,而不是格子本身?
    如果想要一个网格元素在垂直方向上跨越1号网格线到3号网格线,就需要给元素设置grid-column: 1 / 3
  • 说明这些属性实际上是简写属性:grid-column是grid-column-start和grid-column-end的简写;grid-row是grid-row-start和grid-row-end的简写。中间的斜线只在简写属性里用于区分两个值,斜线前后的空格不作要求。
  • 代码里使用之前介绍的grid-column写法,让网格元素占满网格的宽度。其实还可以用一个特别的关键字span来指定grid-row和grid-column的值(这里用在了grid-row上)。这个关键字告诉浏览器元素需要占据一个网格轨道。因为这里没有指出具体是哪一行,所以会根据网格元素的布局算法(placement algorithm)自动将其放到合适的位置。
  • 两种布局方式有以下两个重要区别。❑ Flexbox本质上是一维的,而网格是二维的。❑ Flexbox是以内容为切入点由内向外工作的,而网格是以布局为切入点从外向内工作的。
  • 因为Flexbox是一维的,所以它很适合用在相似的元素组成的行(或列)上。它支持用flex-wrap换行,但是没法让上一行元素跟下一行元素对齐。相反,网格是二维的,旨在解决一个轨道的元素跟另一个轨道的元素对齐的问题。它们的区别如图6-8所示。
  • 它们的第二个区别在于,Flexbox以内容为切入点由内向外工作,而网格以布局为切入点由外向内工作。Flexbox让你在一行或一列中安排一系列元素,但是它们的大小不需要明确指定,每个元素占据的大小根据自身的内容决定。而在网格中,首先要描述布局,然后将元素放在布局结构中去。虽然每个网格元素的内容都能影响其网格轨道的大小,但是这同时也会影响整个轨道的大小,进而影响这个轨道里的其他网格元素的大小。
  • 可以理解为flex的子元素位置是不需要指定的,也不确定具体的位置。而grid的子元素必须要指定其位于grid中的位置(gird-column、grid-row),而且位置是相关清晰的(虽然大小也会受内容以及其他网格元素影响)
    它们的第二个区别在于,Flexbox以内容为切入点由内向外工作,而网格以布局为切入点由外向内工作。Flexbox让你在一行或一列中安排一系列元素,但是它们的大小不需要明确指定,每个元素占据的大小根据自身的内容决定。而在网格中,首先要描述布局,然后将元素放在布局结构中去。虽然每个网格元素的内容都能影响其网格轨道的大小,但是这同时也会影响整个轨道的大小,进而影响这个轨道里的其他网格元素的大小。

6.3 替代语法

  • 有时候记录所有网格线的编号实在太麻烦了,尤其是在处理很多网格轨道时。为了能简单点,可以给网格线命名,并在布局时使用网格线的名称而不是编号。
  • -start和-end后缀作为关键字,定义了两者之间的区域。如果给元素设置grid-column: left,它就会跨越从left-start到left-end的区域。
  • grid-template-areas属性使用了一种ASCII art的语法,可以直接在CSS中画一个可视化的网格形象。该声明给出了一系列加引号字符串,每一个字符串代表网格的一行,字符串内用空格区分每一列。
  • 网格布局共设计了三种语法:编号的网格线、命名的网格线、命名的网格区域。

6.4 显式和隐式网格

  • 它使用grid-auto-rows为所有的隐式网格行指定一个1fr的大小,每一行拥有相同的高度。该
  • 有时候我们不想给一个网格轨道设置固定尺寸,但是又希望限制它的最小值和最大值。这时候需要用到minmax()函数。它指定两个值:最小尺寸和最大尺寸。浏览器会确保网格轨道的大小介于这两者之间。(如果最大尺寸小于最小尺寸,最大尺寸就会被忽略。)通过指定minmax(200px, 1fr),浏览器确保了所有的轨道至少宽200px。
  • repeat()函数里的auto-fill关键字是一个特殊值。设置了之后,只要网格放得下,浏览器就会尽可能多地生成轨道,并且不会跟指定大小(minmax()值)的限制产生冲突。
  • 在图6-13中,视口能容纳四个200px宽的列,因此一行有四个网格轨道。如果屏幕变宽,就能放下更多轨道。如果屏幕变窄,产生的轨道数也会变少。
  • 可以用在taglist。比通过md,sm之类的更合适
    在图6-13中,视口能容纳四个200px宽的列,因此一行有四个网格轨道。如果屏幕变宽,就能放下更多轨道。如果屏幕变窄,产生的轨道数也会变少。
  • 访问Grid by Example网站的文章auto-fill vs.auto-fit可以看到两者区别的示例。
  • 要注意的是,紧凑的auto-flow方式会导致元素出现的顺序跟HTML里不一致。当使用键盘(Tab键)或者使用以源码顺序而非以显示顺序为准的屏幕阅读器来浏览网页时,用户可能会感到困惑。
  • 认情况下,每个网格元素都会扩展并填满整个网格区域,但是子元素不会,因此网格区域出现了多余的高度。一个简单的解决办法是用Flexbox。在代码清单6-11里,设置每个<figure>为弹性容器,方向为column,元素会从上到下垂直排列。然后给图片标签加上flex-grow,强制拉伸图片填充空白区域。
  • 但是拉伸图片并不可取,因为这会改变图片的宽高比,导致图片变形。好在CSS为控制这一行为提供了一个特殊属性object-fit。默认情况下,一个<img>的object-fit属性值为fill,也就是说整个图片会缩放,以填满<img>元素。你也可以设置其他值改变默认行为。
  • 比如,object-fit属性的值还可以是cover和contain(如图6-17所示)。这些值告诉浏览器,在渲染盒子里改变图片的大小,但是不要让图片变形。
  • Notion bookmark原来是指定了cover
    比如,object-fit属性的值还可以是cover和contain(如图6-17所示)。这些值告诉浏览器,在渲染盒子里改变图片的大小,但是不要让图片变形。
  • ,请查看css-tricks网站的文章A Quick Overiew of object-fit and object-position。

阅读明细

维度指标
累积阅读天数22天
最长连续阅读天数4天
单日阅读最久43分 (2024/03/15)
阅读笔记条数104条
日期阅读时长
2023/12/0324分
2023/12/0417分
2024/01/252分
2024/02/222分
2024/02/2813分
2024/02/2922分
2024/03/011分
2024/03/0517分
2024/03/0612分
2024/03/0716分
2024/03/0834分
2024/03/1016分
2024/03/1118分
2024/03/1230分
2024/03/1431分
2024/03/1543分
2024/03/1939分
2024/03/217分
2024/03/2225分
2024/04/0120分
2024/04/0233分
2024/04/122分
See all book notesSee all book notes