深入理解CSS

192 阅读11分钟

如果想要深入理解CSS,那么我们首先应了解CSS简要发展史

image.png

基础知识

层叠(Cascading)、优先级

image.png 层叠三大规则(优先程度递减):

  1. 样式表来源
  2. 选择器优先级
  3. 源码位置

样式表来源重要排序(重要程度递增):

  • 用户代理样式(浏览器默认样式)
  • 用户样式表(很少有)
  • 作者样式表(developer写的)
  • 作者样式表中的!important
  • 用户样式表中的!important
  • 用户代理样式表中的!important

选择器有哪些?

  • 基础选择器
    • id选择器
    • 类选择器
    • 标签选择器
    • 通配符选择器
  • 组合器
    • 子组合器(>)--匹配的目标元素是其他元素的直接后代。如:parent>child。
    • 相邻兄弟组合器(+)--匹配的目标元素紧跟在其他元素后面。如:p+h2
    • 通用兄弟组合器(~)--匹配的所有跟随在指定元素之后的兄弟元素,如:li.active~li。
    • 复合选择器 多个基础选择器可以连起来使用,如:h1.page-header。
  • 属性选择器:通过约束属性值,div[data-title="aaa"]
  • 伪类选择器:选中处于某个特定状态或相对于其父级或兄弟元素的位置的元素。如:first-child,:hover
  • 伪元素选择器:匹配在文档中没有直接对应HTML元素的特定部分,或插入内容。如h2:first-letter,div::before
  • 逻辑选择器:较新的选择器 :is() :has() :where() :not()

选择器优先级: 内联>id>class=attribute=pseudo-class>type=pseudo-element

image.png

源码顺序:

  1. 对于@import的样式,根据@import的顺序
  2. 对于link和style标签的样式,根据在document中的顺序决定

由层叠概念引申出的css代码good practice

  • 选择器尽量少用id
  • 尽量不要用!important
  • 自己的样式加载在引用库样式的后面

继承

image.png

css的值和单位

image.png

盒模型

浏览器根据视觉格式化模型(visual formatting model),将所有元素表示为盒子模型,css通过盒模型做layout

  • 控制盒子类型:display:block、inline、inline-block、flex、...
  • 控制盒子大小&计算方式:width,height... box-sizing:content-box、border-box
  • 控制盒中内容流:overflow:auto、scroll、hidden、...
  • 控制定位:position:static、relative、absolute、fixed、sticky
  • 是否可见:visibility:visible、hidden、...

由盒模型的特性能实现哪些展现形式?

image.png

负外边距:padding、border、margin中,只有margin可以设置负值 设置左边或顶部的负外边距,元素就会相应地向左或向上移动,导致元素与它前面的元素重叠 如果设置右边或者底部的负外边距,并不会移动元素,而是将它后面的元素拉过来

image.png

布局

概述

image.png

常规流布局

image.png

image.png

块级格式化上下文(block formatting context)

格式化上下文的布局规范为

"在一个块格式区域中,盒子会从包含块的顶部开始,按序垂直排列。同级盒子间的垂直距离会由“margin”属性决定,相邻两个块级盒子之间的垂直间距会遵循外边距折叠原则被折叠。 在一个块格式区域中,每个盒子的左外边缘会与包含块左边缘重合(如果是从右到左的排版顺序,则盒子的右外边缘与包含块右边重合)。" 块格式化上下文(Block Formatting Context,BFC)是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

下列方式会创建块格式化上下文:

  • 根元素(<html>
  • 浮动元素(float 值不为 none
  • 绝对定位元素(position 值为 absolute 或 fixed
  • 行内块元素(display 值为 inline-block
  • 表格单元格(display 值为 table-cell,HTML 表格单元格默认值)
  • 表格标题(display 值为 table-caption,HTML 表格标题默认值)
  • 匿名表格单元格元素(display 值为 tabletable-row、 table-row-grouptable-header-grouptable-footer-group(分别是 HTML table、tr、tbody、thead、tfoot 的默认值)或 inline-table
  • overflow 值不为 visibleclip 的块元素
  • display 值为 flow-root 的元素
  • contain 值为 layoutcontent 或 paint 的元素
  • 弹性元素(display 值为 flex 或 inline-flex 元素的直接子元素),如果它们本身既不是 flexgrid 也不是 table 容器
  • 网格元素(display 值为 grid 或 inline-grid 元素的直接子元素),如果它们本身既不是 flexgrid 也不是 table 容器
  • 多列容器(column-count 或 column-width (en-US) 值不为 auto,包括column-count 为 1
  • column-span 值为 all 的元素始终会创建一个新的 BFC,即使该元素没有包裹在一个多列容器中 (规范变更Chrome bug)

格式化上下文影响布局,通常,我们会为定位和清除浮动创建新的 BFC,而不是更改布局,因为它将:

外边距塌陷

会产生外边距塌陷的情况:

image.png

  • 两个兄弟元素之间相邻的上下外边距
  • 父子元素之间相邻的上下外边距
  • 内容为空元素自己上下外边距相邻

消除外边距塌陷的方法:

image.png

  • 在两个相邻的上下边距之间增加border、padding或者内联元素,使之不相邻;
  • 在父子元素重叠时,除了上述方法,还可以设置父元素为BFC,使得父子不在同级BFC中

行内格式化上下文

行内格式化上下文是一个网页的渲染结果的一部分。其中,各行内框(inline boxes)一个接一个地排列,其排列顺序根据书写模式(writing-mode)的设置来决定:

  • 对于水平书写模式,各个框从左边开始水平地排列
  • 对于垂直书写模式,各个框从顶部开始水平地排列

在下面给出的例子中,带黑色边框的两个 (<div>) 元素组成了一个块级格式化上下文(block formatting context),其中的每一个单词都参与一个行内格式化上下文中。水平书写模式下的各个框水平地排列,垂直书写模式下的各个框垂直地排列。

各个框组成了一行,而该行位于一个称为“行框(line box)”的矩形区域之中。该行框的大小将足以包含该行中所有的行内框(inline boxes);当行内方向上没有剩余空间时,将会创建新行。因此,一个段落实际上是一系列行框的集合,这些行框在块的方向上排列。

一个行内框(inline box)被分割到多行中时,margins, borders, 以及 padding 的设定均不会在断裂处生效。下例中有一个 (<span>) 元素,它包裹了一系列单词,占据了两行。可以看见在断裂处,<span> 的 border 同样发生了断裂。

Margins, borders, 以及 padding 的设置,在行的方向上是生效的。在下例中,可以看见行内元素 <span> 的 margin,border 以及 padding 是被加上了的。

在块的方向上对齐

行内框(Inline boxes)可使用vertical-align属性,以不同的方式在块的方向上进行对齐(因此在垂直书写模式下,vertical-align 中的“vertical”根本是名不副实——此时行内框将在水平方向上进行对齐)。

在行内方向上对齐

如果行内方向上还有额外空间,那么 text-align 可用于将各行内框(inline boxes)在行框(line box)内对齐。可以试试把 text-align 的值改成 end 。

浮动造成的效果

在行内方向上,各行框(Line Boxes)通常具有相同的尺寸,即在水平书写模式下,它们有同样的宽度;在垂直书写模式下,它们有同样的高度。但是,如果同一个块格式化上下文中存在一个 float,则这个浮动元素将导致包裹了它的各行框变短。

弹性盒子布局

弹性盒子是一种用于按行或按列布局元素的一维布局方法。元素可以膨胀以填充额外的空间,收缩以适应更小的空间。本文将解释所有的基本原理。 长久以来,CSS 布局中唯一可靠且跨浏览器兼容的创建工具只有 floats 和 positioning。这两个工具大部分情况下都很好使,但是在某些方面它们具有一定的局限性,让人难以完成任务。

以下简单的布局需求是难以或不可能用这样的工具(floats 和 positioning)方便且灵活的实现的:

  • 在父内容里面垂直居中一个块内容。
  • 使容器的所有子项占用等量的可用宽度/高度,而不管有多少宽度/高度可用。
  • 使多列布局中的所有列采用相同的高度,即使它们包含的内容量不同。

指定元素的布局为 flexible

首先,我们需要选择将哪些元素将设置为弹性的盒子。我们需要给这些 flexible 元素的父元素 display 设置一个特定值。在本例中,我们想要设置 <article> 元素,因此我们给 <section>(变成了 flex 容器)设置 display:

section {
  display:flex
}

flex 模型说明

当元素表现为 flex 框时,它们沿着两个轴来布局:

在从左到右的语言中,三个 flex 项并排放置在 flex 容器中。主轴——弹性容器布置 flex 方向上的轴——是水平的。主轴的两端是开始端和结束端,分别位于左侧和右侧。交叉轴是垂直的;垂直于主轴。交叉轴的开始端和结束端分别位于顶部和底部。flex 项沿着主轴排列,在这种情况下,宽度称为主轴尺寸,flex 项沿交叉轴排列,在这种情况下,高度称为交叉尺寸。

  • 主轴(main axis)是沿着 flex 元素放置的方向延伸的轴(比如页面上的横向的行、纵向的列)。该轴的开始和结束被称为 main start 和 main end
  • 交叉轴(cross axis)是垂直于 flex 元素放置方向的轴。该轴的开始和结束被称为 cross start 和 cross end
  • 设置了 display: flex 的父元素(在本例中是 <section>)被称之为 flex 容器(flex container)。
  • 在 flex 容器中表现为弹性的盒子的元素被称之为 flex 项flex item

网格布局

CSS 网格布局擅长于将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系(前提是 HTML 生成了这些区域)。 像表格一样,网格布局让我们能够按行或列来对齐元素。然而在布局上,网格比表格更可能做到或更简单。例如,网格容器的子元素可以自己定位,以便它们像 CSS 定位的元素一样,真正的有重叠和层次。 通过设置 CSS 属性 display: grid; 可以定义一个 CSS 网格。接着可以使用 grid-template-rows 和 grid-template-columns 属性定义网格的列属性 (columns) 和行属性 (rows)。

使用这些属性定义的网格被称为 显式网格 (explicit grid)。

如果开发者将内容放置在显式网格之外,或者依赖自动布局的话,网格法 (grid algorithm) 将需要创建额外的 row 或者 column、 tracks 来包含显示网格之外的内容 grid items,为此将在隐式网格 (implicit grid) 中创建额外的轨道 (tracks)。当内容添加到了已定义的 tracks 之外的时候,隐式网格 (implicit grid) 会被自动创建。

下面的例子创建了一个有两行三列的显式网格*。*由于超过显式网格可容纳的六个条目,此网格中的第三行将是一个隐式网格行轨道 (implicit grid row track)

(注:在容器 div 上用 row 和 column 定义的网格总数,等于 行数乘以列数 个。比如一个容器 div 定义了 2 行 * 3 列 = 6 个网格,这 6 个就是显式网格,但是假如里面有 8 个 子 div,多出来那 2 个就叫做隐式网格。)

Grid和Flex布局的使用策略

  • Flex
    1. 一维布局
    2. 基于内容
    3. 浏览器兼容性更好
  • Grid
    1. 二维布局
    2. 基于布局
    3. 2017年后浏览器的版本普遍支持
  • Gird for layout,Flexbox for components
    1. 大面积或整体布局,推荐使用Grid布局
    2. 小面积或组件中,或Grid Item中可以使用Flex做灵活布局

定位Position

为了我们可以在文档流的基础上,让元素移动,做出更多灵活的改变。当position属性的取值非static的时候,可以使用top,right,bottom,left对其进行定位。

image.png

image.png

image.png

image.png

层叠上下文(The Stacking Context)

image.png 文档中的层叠上下文由满足以下任意一个条件的元素形成:

  • 文档根元素(<html>);

  • position 值为 absolute(绝对定位)或 relative(相对定位)且 z-index 值不为 auto 的元素;

  • position 值为 fixed(固定定位)或 sticky(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);

  • flex (flex) 容器的子元素,且 z-index 值不为 auto

  • grid (grid) 容器的子元素,且 z-index 值不为 auto

  • opacity 属性值小于 1 的元素(参见 the specification for opacity);

  • mix-blend-mode 属性值不为 normal 的元素;

  • 以下任意属性值不为 none 的元素:

  • isolation 属性值为 isolate 的元素;

  • will-change 值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素(参考这篇文章);

  • contain 属性值为 layoutpaint 或包含它们其中之一的合成值(比如 contain: strictcontain: content)的元素。

在层叠上下文中,子元素同样也按照上面解释的规则进行层叠。重要的是,其子级层叠上下文的 z-index 值只在父级中才有意义。子级层叠上下文被自动视为父级层叠上下文的一个独立单元。 总结:

  • 层叠上下文可以包含在其他层叠上下文中,并且一起创建一个层叠上下文的层级。
  • 每个层叠上下文都完全独立于它的兄弟元素:当处理层叠时只考虑子元素。
  • 每个层叠上下文都是自包含的:当一个元素的内容发生层叠后,该元素将被作为整体在父级层叠上下文中按顺序进行层叠。