如果想要深入理解CSS,那么我们首先应了解CSS简要发展史
基础知识
层叠(Cascading)、优先级
层叠三大规则(优先程度递减):
- 样式表来源
- 选择器优先级
- 源码位置
样式表来源重要排序(重要程度递增):
- 用户代理样式(浏览器默认样式)
- 用户样式表(很少有)
- 作者样式表(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
源码顺序:
- 对于@import的样式,根据@import的顺序
- 对于link和style标签的样式,根据在document中的顺序决定
由层叠概念引申出的css代码good practice
- 选择器尽量少用id
- 尽量不要用!important
- 自己的样式加载在引用库样式的后面
继承
css的值和单位
盒模型
浏览器根据视觉格式化模型(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、...
由盒模型的特性能实现哪些展现形式?
负外边距:padding、border、margin中,只有margin可以设置负值 设置左边或顶部的负外边距,元素就会相应地向左或向上移动,导致元素与它前面的元素重叠 如果设置右边或者底部的负外边距,并不会移动元素,而是将它后面的元素拉过来
布局
概述
常规流布局
块级格式化上下文(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值为table、table-row、table-row-group、table-header-group、table-footer-group(分别是 HTML table、tr、tbody、thead、tfoot 的默认值)或inline-table) overflow值不为visible、clip的块元素display值为flow-root的元素contain值为layout、content或paint的元素- 弹性元素(
display值为flex或inline-flex元素的直接子元素),如果它们本身既不是 flex、grid 也不是 table 容器 - 网格元素(
display值为grid或inline-grid元素的直接子元素),如果它们本身既不是 flex、grid 也不是 table 容器 - 多列容器(
column-count或column-width(en-US) 值不为auto,包括column-count为1) column-span值为all的元素始终会创建一个新的 BFC,即使该元素没有包裹在一个多列容器中 (规范变更, Chrome bug)
格式化上下文影响布局,通常,我们会为定位和清除浮动创建新的 BFC,而不是更改布局,因为它将:
- 包含内部浮动
- 排除外部浮动
- 阻止 外边距重叠
外边距塌陷
会产生外边距塌陷的情况:
- 两个兄弟元素之间相邻的上下外边距
- 父子元素之间相邻的上下外边距
- 内容为空元素自己上下外边距相邻
消除外边距塌陷的方法:
- 在两个相邻的上下边距之间增加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 框时,它们沿着两个轴来布局:
- 主轴(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
- 一维布局
- 基于内容
- 浏览器兼容性更好
- Grid
- 二维布局
- 基于布局
- 2017年后浏览器的版本普遍支持
- Gird for layout,Flexbox for components
- 大面积或整体布局,推荐使用Grid布局
- 小面积或组件中,或Grid Item中可以使用Flex做灵活布局
定位Position
为了我们可以在文档流的基础上,让元素移动,做出更多灵活的改变。当position属性的取值非static的时候,可以使用top,right,bottom,left对其进行定位。
层叠上下文(The Stacking Context)
文档中的层叠上下文由满足以下任意一个条件的元素形成:
-
文档根元素(
<html>); -
position值为absolute(绝对定位)或relative(相对定位)且z-index值不为auto的元素; -
position值为fixed(固定定位)或sticky(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持); -
opacity属性值小于1的元素(参见 the specification for opacity); -
mix-blend-mode属性值不为normal的元素; -
以下任意属性值不为
none的元素: -
isolation属性值为isolate的元素; -
will-change值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素(参考这篇文章); -
contain属性值为layout、paint或包含它们其中之一的合成值(比如contain: strict、contain: content)的元素。
在层叠上下文中,子元素同样也按照上面解释的规则进行层叠。重要的是,其子级层叠上下文的 z-index 值只在父级中才有意义。子级层叠上下文被自动视为父级层叠上下文的一个独立单元。
总结:
- 层叠上下文可以包含在其他层叠上下文中,并且一起创建一个层叠上下文的层级。
- 每个层叠上下文都完全独立于它的兄弟元素:当处理层叠时只考虑子元素。
- 每个层叠上下文都是自包含的:当一个元素的内容发生层叠后,该元素将被作为整体在父级层叠上下文中按顺序进行层叠。