css-2.1

CSS Module 英文规范:https://drafts.csswg.org/css-cascade/#value-stages

CSS2.1 英文规范:https://www.w3.org/TR/CSS2/cascade.html#q6.0

CSS2.1 中文规范: http://www.ayqy.net/doc/css2-1/visuren.html#inline-boxes

https://github.com/w3c/csswg-drafts

latest: https://www.w3.org/Style/CSS/#specs

属性赋值,层叠(Cascading)和继承

指定值,计算值和实际值

一旦用户代理已经解析了文档并构造好了 文档树,它就必须给树中的每个元素上适用于目标 媒体类型 的每个属性赋值

属性的最终值是 4 步计算的结果:先通过指定来确定值(“指定值(specified value)”),接着处理得到一个用于继承的值(“计算值(computed value)”),然后如果有必要的话转化为一个绝对值(“应用值(used value)”),最后根据本地环境限制进行转换(“实际值(actual value)”)

指定值

用户代理必须先根据下列机制(按优先顺序)给每个属性赋值一个指定值:

  1. 如果 层叠 产生了一个值,就使用它 (样式表如果指定了)
  2. 否则,如果属性是 继承的 并且该元素不是文档树的根元素,使用其父元素的计算值
  3. 否则,使用属性的初始值,每个属性的初始值都在属性定义中指出了

计算值

指定值通过层叠被处理为计算值,例如,'em' 和 'ex' 等相对单位被计算为像素或者绝对长度。计算一个值并不需要用户代理渲染文档

一个属性的计算值由属性定义中 Computed Value 行决定。当指定值为 'inherit' 时,计算值的定义见 继承 小节

即使属性不适用(于当前元素,定义在 'Applies To' 行),其计算值也存在。然而,有些属性可能根据属性是否适用于该元素来定义元素属性的计算值

应用值

处理计算值时,尽可能不要格式化文档。然而,有些值只能在文档布局完成时确定。例如,如果一个元素的宽度是其包含块的特定百分比,在包含块的宽度确定之前无法确定这个宽度。

应用值是把计算值剩余的依赖(值)都处理成绝对值后的(计算)结果

实际值

原则上,应用值应该用于渲染,但用户代理可能无法在给定的环境中利用该值。例如,用户代理或许只能用整数像素宽度渲染边框,因此不得不对宽度的计算值做近似处理,实际值是经过近似处理后的应用值

getComputedStyle()

有时候不同浏览器中使用 window.getComputedStyle 返回的值可能不一样,就是因为有的返回了计算值,有的返回应用值。

在 Firefox 中,把 window.getComputedStyle 返回的值叫做 resolved value,这个值有时是计算值有时是应用值,因属性而异。Chrome 也类似,但有时就会遇到跟 Firefox 返回值不一样的情况。

比如给一个元素 line-height: normal,然后用 window.getComputedStyle 获取它的行高,Chrome 返回计算值 normal,Firefox 返回的是具体的应用值比如 16px

(根据规范,line-height: normal 的计算值还是 normal,应用值在 1.0-1.2 之间。)

继承与初始

继承属性与非继承属性 @@@

inherit 关键字

继承属性示例

非继承示例

  <body>
    <div id="root">
      <div id="box1"></div>
    </div>
  </body>
    html,body{
      width:800px;
      height:800px;
    }
    #root{
      width:50%;
      height:50%;
      background-color: greenyellow;
    }
    #box1 {
      width:inherit;
      height:inherit;
      background-color: pink;
    }

继承属性

非继承属性

特例

line-height 是继承属性,因此给 line-height 设置百分比,子元素继承的是计算值。但是当指定值是 <number> 时,子元素会继承指定值

text-indent 是继承属性,text-indent 可以接受一个百分比值,用来乘以包含块宽度。子元素从父元素继承时,得到的也是百分比值,即指定值

初始值(Initial)

对于继承属性, 初始值 只能 被用于没有指定值的根元素上

因为不是根元素都会继承其他的父元素指定值

对于继承属性,初始值仅对没有指定值的根元素有意义,其他所有元素继承属性都是继承自根元素的

对于非继承属性 ,初始值可以被用于 任意 没有指定值的元素上

在 CSS3 中允许作者使用 initial 关键词明确的设定初始值

CSS 视觉格式化模型(visual Formatting model)

视觉格式化模型: https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Visual_formatting_model

规范 9.0 https://segmentfault.com/a/1190000003096320

规范 10.0 https://segmentfault.com/a/1190000003820437#articleHeader24

块级格式化上下文: https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context

vertcal-align:https://www.cnblogs.com/starof/p/4512284.html

vertcal-align:https://www.cnblogs.com/hykun/p/3937852.html

vertcal-align:https://www.jianshu.com/p/dda695749019

line-height:https://blog.csdn.net/u013185654/article/details/78756347

line-height:https://www.cnblogs.com/dolphinX/p/3236686.html

基本概念

概述

视觉格式化模型:用户代理 User Agent 如何在视觉媒体 Visual Media 下处理文档树 Document Tree

视觉格式化模型会根据 CSS盒子模型 将文档中的元素转换为一个个盒子,每个盒子的布局由以下因素决定:

视口 The Viewport

在连续媒体 Continuous Media 上工作的用户代理一般会向用户提供一个视口(屏幕上的一个窗口或其它可视区域)来帮助用户访问文档。用户代理可以在调整视口大小的同时改变文档的布局(见初始包含块 Initial Containing Block)。

如果视口小于渲染文档的画布区域,用户代理应提供一个滚动机制。每个画布最多有一个视口,但用户代理可以把文档渲染到多个画布上(即为相同文档提供不同视图)。

包含块 Containing Blocks

CSS2.1 中,许多盒的定位和大小都根据一个名为包含块 Containing Block 的矩形盒的边缘来计算。

一般地:

每个盒会被赋予一个相对于其包含块的位置,但它不会被局限在其包含块内;它有可能溢出。

包含块的尺寸如何计算的细节将在下章讲述。

“根元素”的包含块(初始包含块)由用户代理定义(浏览器)。在 HTML 中,根元素就是 html 元素,(部分浏览器根元素是 body)。在大多数浏览器中,初始包含块是一个视窗大小的矩形(不等同于视窗,只是大小相等)

对于定位的元素:只是包含块的边界与父元素的边框相同,但是因为 left、top 的默认值是 auto,所以不影响 padding 对子元素的作用。

当 left 和 top 为 auto 时,设置了 padding 之后子元素并不会黏在父元素的边框上

此时,设置 left 和 top 为 0,子元素粘在父元素的边框上

不可替换元素

从元素本身的特点来讲,可以分为可替换元素 (replaceable element) 和不可替换元素 (none-replaceable element)。

html 的大多数元素是不可替换元素,即其内容直接表现给用户端(例如浏览器)。

如果元素的内容包含在文档之中,则为非替换元素。除了几个可替换元素,其他所有的都是不可替换元素。

可替换元素

在 CSS 中,可替换元素 (replaced element) 的展现效果不是由 CSS 来控制的。这些元素是一种外部对象,它们外观的渲染,是独立于 CSS 的。

简单来说,它们的内容不受当前文档的样式的影响。CSS 可以影响可替换元素的位置,但不会影响到可替换元素自身的内容。某些可替换元素,例如 <iframe> 元素,可能具有自己的样式表,但它们不会继承父文档的样式。

可替换元素就是浏览器根据元素的标签和属性,来决定元素的具体显示内容。

CSS 能对可替换元素产生的唯一影响在于,部分属性支持控制元素内容在其框中的位置或定位方式

推论:replaced element 之所以冠以 replaced 的形容词,是因为这类 element 的内容会被指向的外部资源给 replace 掉,通过 src 属性

典型的可替换元素有:

有些元素仅在特定情况下被作为可替换元素处理,例如:

HTML 规范也说了 <input> 元素可替换,因为 "image" 类型的 <input> 元素就像 <img> 一样被替换。但是其他形式的控制元素,包括其他类型的 <input> 元素,被明确地列为非可替换元素(non-replaced elements)。该规范用术语小挂件(Widgets)来描述它们默认的限定平台的渲染行为

Content 与 可替换元素

用 CSS content 属性插入的对象是匿名的可替换元素。它们并不存在于 HTML 标记中,因此是“匿名的”。

需要注意的是,一部分(并非全部)可替换元素,其本身具有的尺寸和基线(baseline)会被一些 CSS 属性用到,加入计算之中,例如 vertical-align,会只有可替换元素才能具有这种自带值。

可替换元素的特性

具有自己的替换宽高,以 canvas 为例,默认的画布宽高通过 html 的 width 和 height 指定

https://whatwg-cn.github.io/html/#the-canvas-element

webview 的 animation-video 组件:

  1. 使用 canvas 元素支持 afx 透明视频,且 context 为 webgl,此时 canvas 是替换元素
  2. object-fit 的默认值为 fill,同时开发者无法直接控制 canvas 的属性,可以认为 object-fit 的值保持为 fill

综上需要实现:

  1. resource-width/height,用于指定 canvas 画布的宽高,默认值均为 400
  2. 当 canvas 的 styleWidth 和 styleHeight 均有值时,canvas 画布需要拉伸以适应 style 指定的宽高(object-fit:fill)
  3. 当 styleWidth 的值为 <length><percentage> ,且 styleHeigth 为 auto 时,需要根据 canvas 画布的宽高比,计算出相应的 styleHeight,维持画布的宽高比(styleWidth 为 auto 时类似)
  4. 当 styleWidth 和 styleHeight 均为 auto 时,canvas 画布的宽高即为 canvas 元素的宽高

所有的替换元素都是内联水平元素,也就是替换元素和替换元素、替换元素和文字都是可以在一行显示的。但是,替换元素默认 的 display 值却是不一样的,有的是 inline,有的是 inline-block。

替换元素的尺寸

替换元素的尺寸从内而外分为 3 类:固有尺寸、HTML 尺寸和 CSS 尺寸。

  1. 固有尺寸指的是替换内容原本的尺寸。例如,图片、视频作为一个独立文件存在的时候,都是有着自己的宽度和高度的。
  2. HTML 尺寸只能通过 HTML 原生属性改变,这些 HTML 原生属性包括 <img> 的 width 和 height 属性、<input> 的 size 属性、<textarea> 的 cols 和 rows 属性等。
  3. CSS 尺寸特指可以通过 CSS 的 width 和 height 或者 max-width/min-width 和 max-height/min-height 设置的 尺寸,对应盒尺寸中的 content box。

这 3 层结构的计算规则具体如下

  1. 如果没有 CSS 尺寸和 HTML 尺寸,则使用固有尺寸作为最终的宽高。
  2. 如果没有 CSS 尺寸,则使用 HTML 尺寸作为最终的宽高。
  3. 如果有 CSS 尺寸,则最终尺寸由 CSS 属性决定。
  4. 如果“固有尺寸”含有固有的宽高比例,同时仅设置了宽度或仅设置了高度,则元素依然按照固有的宽高比例显示。
  5. 如果上面的条件都不符合,则最终宽度表现为 300 像素,高度为 150 像素。
  6. 内联替换元素和块级替换元素使用上面同一套尺寸计算规则。

替换元素的特有样式 Object-fit

https://www.runoob.com/cssref/pr-object-fit.html

盒的生成 Controlling Box Generation

本节描述 CSS2.1 中可生成的盒类型。盒的类型会影响其在视觉格式化模型中的表现。

盒子的生成是 CSS 视觉格式化模型的一部分,用于从文档元素生成盒子。盒子有不同的类型,不同类型的盒子的格式化方法也有所不同。盒子的类型取决于 CSS display 属性。

块级

基本概念

block:一个抽象的概念,一个块在文档流上占据一个独立的区域,块与块之间在垂直方向上按照顺序依次堆叠。

元素 elements:是 html 的概念 (与标签一一对应)

盒子 box:一个抽象的概念,由 CSS 引擎根据文档中的内容所创建,主要用于文档元素的定位、布局和格式化等用途。盒子与元素并不是一一对应的,有时多个元素会合并生成一个盒子,有时一个元素会生成多个盒子(如匿名盒子)。

这些盒子与盒模型有对应关系吗?content-box? margin-box?

:盒的边界,有些翻译用于指代盒子,如行内框,实指行内盒 inline box

块级元素 block-level element:

块级盒子 block-level box:

块盒子 block box:

块容器盒子

这看起来也许有些奇怪,这与上文提到的匿名块盒子有关, 它保证 BFC 内只有块级盒子, 下文将会有详细的讲解

为什么没有提到 只包含块级盒子就创建一个块级格式化上下文呢?因为开启 BFC 需要那几个条件,否则只需要自身参与到块级格式化上上下文即可

匿名块盒

在某些情况下进行视觉格式化时,需要添加一些增补性的盒子,这些盒子不能用 CSS 选择符选中,因此称为匿名盒子(anonymous boxes)

CSS 选择器不能作用于匿名盒子 (anonymous boxes),所以它不能被样式表赋予样式。也就是说,此时所有可继承的 CSS 属性值都为 inherit ,而所有不可继承的 CSS 属性值都为 initial

情况一

  <div>Some inline text <p>followed by a paragraph</p> followed by more inline text.</div>

1553066995197.png

  Some inline text
  followed by a paragraph
  followed by more inline text.

从情况一可知

情况二

从情况二可知:

注意:

  p{
    display:inline;
    border:solid red; /*不可继承*/
    background:yellow; /*不可继承*/
    color:red; /*可继承*/
  }
  span{
    display:block;
  }

1553081068612.png

行内级

基本概念

行内级元素 Inline-level Element:

行内级盒 Inline-level Boxes :

行内盒 Inline Boxes:

原子行内级盒 Atomic Inline-level Boxes :@

1553082284515.png

匿名行内盒

Anonymous Inline Boxes

任何被直接包含在一个块容器元素(不是包含在行内元素)的文本必须作为匿名行内元素来对待。

如下:

<p>Some <em>emphasized</em> text</p>

p 产生一个块盒,其中包含了一些行内盒。emphasized 的盒是一个由行内元素 em 生成的行内盒,但其他盒(sometext 的)是由块级元素 p 生成的行内盒。后面这种盒被称作匿名行内盒,因为它们没有相关的行内级元素。

这些匿名行内盒的可继承属性将从它们的父级块盒中继承。非继承性属性取其初始值。在上面例子中,匿名行内盒的 colorp 那里继承,但 backgroundtransparent

空白内容,根据 white-space 属性,如果可被折叠则不会产生任何匿名行内盒。

本规范中,如果可根据上下文来清晰界定一个匿名盒的类型,则匿名行内盒和匿名块盒都可被简称为匿名盒。

在格式化表格时,还会有更多类型的匿名盒出现。

Run-in Boxed 插入盒

为使章节号同之前的草案一致,特保留此节。display: run-in 现已定义至 CSS3(参见 CSS 基本盒模型)。

Display 属性

block 元素产生一个块盒。

inline-block 元素产生一个行内级块容器。行内块的内部会被当作块盒来格式化,而此元素本身会被当作原子行内级盒来格式化。

inline 元素产生一个或多个的行内框。@@@

none 元素不出现在格式化结构中(也就是说,在视觉媒体中元素既不产生盒也不影响布局)。其后代元素也不产生任何盒:该元素及其内容会被从格式化结构中完全移除。对后代元素设定 display 属性不能覆盖这个表现。

请注意 none 值不产生可见盒;它根本就不生成盒。CSS 中有使元素在格式化结构中产生盒并影响格式化,但盒本身不可见的机制。请访问 visibility 的章节了解详情。

除定位元素和浮动元素以及根元素外(见下文)计算值与指定值相同。根元素的计算值按下文所述改变。

注意,尽管 display 初始值是 inline,但用户代理的默认样式表规则可能覆盖该值。请见附录中的 HTML4 参考样式表。

定位体系 Positioning Schemes

在 CSS2.1 中,盒子根据以下三种体系来布局:

浮动元素、绝对定位元素、根元素都被称为脱离文档流 Out of Flow;其他元素被称为文档流内 In-flow

元素 A 的排版流由 A 在文档流内且最近的脱离文档流的祖先是 A 的元素构成。??

常规流 Normal Flow

常规流中的盒子都属于某个格式化上下文,要么块格式化上下文,要么行内格式化上下文,总之不能二者得兼。块级盒参与块格式化上下文,行内级盒参与行内格式化上下文。

块级格式化上下文

将为其内容创建一个新的块级格式化上下文。

当开启元素的 BFC 以后,元素将会具有如下的特性:

  1. 在块格式化上下文中,盒从包含块顶部一个接一个地垂直摆放。两个同胞盒间的垂直距离取决于 margin 属性。同一个块格式化上下文中的相邻块级盒的垂直外边距将折叠。
  2. 在块格式化上下文中,每个盒的左外边缘紧贴包含块的左边缘(从右到左的格式里,则为盒右外边缘紧贴包含块右边缘),甚至有浮动也是如此(尽管盒里的行盒可能由于浮动而收缩),除非盒创建了一个新的块格式化上下文(在这种情况下盒子本身可能由于浮动而变窄)
  3. BFC 区域不会与 float box 重叠
  4. 计算 BFC 的高度时,浮动元素也参与计算。
  5. BFC 就是页面上一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之亦然

产生 BFC 的元素,在它产生的 BFC 内无法管理自己,只能管理内部的 block-level box

行内格式化上下文

在行内格式化上下文中,盒从包含块的顶部一个接一个地水平摆放。盒水平方向的外边距、边框和内边距在布局时都会考虑在内。

盒的垂直对齐方式则不一:可能按底部或者顶部对齐,又或者按它们内容文本的基线对齐。

行盒

包含了一行里所有盒的矩形区域被称为行盒 Line Box

行盒的宽度取决于包含块以及浮动。行盒的高度取决于在行盒高度计算章节所给出的规则。

行盒的高总是足以容纳其包含的所有盒

一般来说,在同一行内格式化上下文中的行盒是等宽的(包含块的宽度)行盒的左边缘紧贴其包含块的左边缘,其右边缘紧贴包含块的右边缘。然而,如果行盒内的元素开启了浮动,浮动盒可能被置于包含块和行盒边缘之间。由于浮动会造成可用的水平空间减少,行盒的宽度仍可能变动。同一行内格式化上下文中的行盒在高度上通常是变动的(比如,一行可能包含图片但其他行仅包含文本)。

当一行中的行内盒的总宽度小于包含它们的包含块的时候,它们在行里的水平分布取决于 text-align 属性。如果取 justify 值,用户代理可能拉伸行内盒(inline-tableinline-block 盒除外)中的空格和字间距。

当行内盒的宽度超过行盒宽度时,行内盒将被分为多个盒,被分解出的盒则又分布在多个行盒中。如果一个行内盒不可切割(比如,行内盒包含的是单个字符或者语言指定的断字规则不允许断字,又或者行内盒的 white-space 属性值为 nowrappre),那么该行内盒将溢出行盒。

当行内盒被分割,外边距、边框和内边距在任何断点处都不会产生视觉影响。

行内盒也可能由于双向文本处理而在一个行盒内被切割成多个盒。

为了包含行内格式化上下文中的行内级内容,行盒按需创建。有的行盒不包含文本、保留空白、外边距或内边距或边框不为零的行内元素、其他文档流内 In-flow 内容(如图片、行内块或行内表格),并且不以保留的换行符结尾,如果是为决定它们所包含的元素的定位,则必须视其为零高度的行盒,除此之外的其他目的下应视其为不存在。

示例

  <style type="text/css">
    em {
      padding: 2px; 
      margin: 1em;
      border-width: medium;
      border-style: dashed;
      line-height: 2.4em;
    }
  </style>
  
  <p>Several <em>emphasized words</em> appear here.</p>

相对定位 Relative Positioning

一旦一个盒遵循常规流或者浮动而布局好位置后,它有可能根据这个位置来相对位移。这被称作相对定位。通过这种方式移动盒(B1)对随后的盒(B2)没有影响:B2 被赋予了一个如同 B1 没有位移的位置,并且 B2B1 移动后不会重定位。这意味着相对定位可能造成盒重叠。然而,如果相对定位造成一个 overflow:autooverflow:scroll 的盒溢出,客户端必须通过创建滚动条来让用户可以访问到该内容(在其偏移位置),这可能影响布局。

一个相对定位盒保持其常规流中的大小,包括断行和原本为其保留的空间。包含块一节解释了相对定位盒创建新的包含块的情况。

对于相对定位元素而言,leftright 在不改变盒大小的同时使其水平位移。left 使盒向右移动,right 时期向左。leftright 没有造成盒的分割或拉伸,因此应用的值始终满足:left 等于 -right

请看下面的例子,这三条规则是等效的

div.a8 {
   position: relative;
   direction: ltr;
   left: -1em;
   right: auto
}
div.a8 {
   position: relative;
   direction: ltr;
   left: auto;
   right: 1em
}
div.a8 {
   position: relative;
   direction: ltr;
   left: -1em;
   right: 5em
}

topbottom 属性在不改变相对定位元素的大小的同时使其上下位移。top 使其下移,bottom 则使其上移。topbottom 没有造成盒的分割或拉伸,因此应用的值始终满足:top 等于 -bottom 。如果二者均为 auto,其值则均为 0。如果其中一个值为 auto,则该属性取另一属性的负值。如果二者均不为 autobottom 将被忽略(也就是说,bottom 应用值为 top 的负值)。

注:在脚本环境中动态移动相对定位盒可以产生动画效果(见 visibility 属性)。尽管相对定位可被用于上标和下标效果,但行高在自动调整时不会将其定位纳入计算。参见行高计算一节的描述了解更多信息。 @@@

相对定位的例子将在对比常规流、浮动和相对定位一节中提供。

浮动

绝对定位

Display Position Float 之间的关系

尺寸体系

https://www.zhangxinxu.com/wordpress/2016/05/css3-width-max-contnet-min-content-fit-content/

https://blog.csdn.net/tian361zyc/article/details/76444567

http://www.divcss5.com/rumen/r422.shtml

Width 与 Margin

为什么没有 border 和 padding 呢?

计算值与应用值,padding 的初始值是 0,应用值与计算值永远都是一致的,border 也类似。

但是 width 初始值是 auto

margin 初始值是 0,可以选择 auto

元素的 'width''margin-left''margin-right''left''right' 属性用于布局的值,取决于生成盒的类型以及相互影响(用于布局的值有时被称为 应用值)。原则上,应用值与计算值一样,都是把 'auto' 替换成一些合适的值,百分比相对其包含块来计算,但也存在例外。以下情况需要加以区分:

Height 与 Margin

行高详述

https://segmentfault.com/a/1190000003820437#articleHeader24

行高概念

行高类似于我们上学单线本,单线本是一行一行,线与线之间的距离就是行高,

基线:字母 X 下边缘的位置,微软雅黑完美压线,各个字体略有不同

中线:基线 +1/2 字母 x 的高度的位置

可见,中线的位置与 font-size 有关

行高:上下文本行的基线间的距离,由 line-height 属性值确定

为什么需要两行?其实一行也是有行高的,由两行这个概念上的定义可以确定一行的行高

内容区:底线和顶线包裹的区域,是一种围绕文字的盒子,大小与 font-sizefont-family 相关

在页面中选中文字的时候的蓝色背景就是 content-area,实际上就是 em-box

行内元素 display:inline 可以通过 background-color 属性显示出来

行距:一行底线到下一行顶线的垂直距离,行距默认情况下会均分到内容区的两侧

在 simsun 字体下,内容区高度等于文字大小值:行间距=行高 - font-size,为了降低难度,以下的 demo 都是 simsun 字体,新宋

其他字体,行间距 = 行高 - 内容区大小

行内盒 (inline box):即是行内框,行中的每个元素都会生成一个内容区,内容区的大小由字体和字号确定,将行距/2 分别应用到内容区的顶部和底部,其结果就是该元素的行内盒

将 line-height 的计算值减去 font-size 的计算值,这个值就是行距,这个值可能是个负值,

行盒 (line box):即是行框,行盒是指一个虚拟的矩形盒,默认情况下行盒高度等于本行内所有元素的行内盒最大的值

一行上垂直对齐时以行高值最大的行内盒为基准,其他行内盒采用自己的对齐方式向基准对齐,最终计算行盒的高度 ,还会收到 vertical-align 属性的影响

每一行只能有一个行盒,行内嵌套宽度由内容撑开,仍然只一个行内盒而已

注意:

Line-height

适用元素:all

是否继承:可继承

属性值

normal:让用户代理设使用值为一个基于元素字体的“合理”值。该值与< number >意义相同。我们推荐 normal 的使用值在 1.0 到 1.2 之间。计算值为 normal

normal 具体的表现是数值,具体的数值由用户代理决定,在 1-1.2 之间

chrome:微软雅黑,1.32,/ sinsum,1.14

firefox: 微软雅黑,1.32 / sinsum,1.144

计算方法:font-size:100px; container.clientHeight/100

<length>:指定长度用于行盒高度计算。负值非法。

<number>:本属性的应用值为此数值乘以本元素的字号。负值非法。

<percentage>:本属性的计算值为此百分比乘以自身的字号计算值。负值非法。

inherit:对于某些可替换元素,可能 line-height 的默认值不是 normal,需要使用 inherit 重置

示例

可替换行内元素

在此文中,请简单理解为图片

line-height 属性值没有意义,对图片没有任何影响

不可替换行内元素

在此文中,请简单理解为文本

line-height 指定用于计算行盒高度的高度

即使行高设定的比内容区高度还要小(内容区大小取决于字体大小),行内盒的高度仍然是由 line-height 决定

内联元素的实际高度是由 line-height 决定的,这和我们学习的块元素的盒子模型完全不同

对于行内盒而言可以做到撑开父级的只有一个属性:line-height,其他的盒模型部分都是不相关的,包括垂直方向上的 margin、border、padding、content,全都没有办法撑开父元素的高度

也就是说:内联元素在垂直方向上的位置只会受到:font-size,line-height,vertical-align 的影响

行内盒的位置会受到字体的影响因为,行距 = line-height - font-size

文字会默认在行高中垂直居中显示,这是因为行距默认等分在内容区的两边

注意:内容区的大小会影响横向的排列,比如

text line-height 为 0,无法改变行盒的高度,但是 font-size 变化会影响横向的排列

height 是由内容撑开的,font-size 变化,平分线也跟着变化

使用 simsun 字体,并且 line-height 为 1,可以把内容区看作行内盒的边框,也就是上图中粉色的背景区域

块级容器元素

一般情况下,line-height 指定该容器内行盒最小高度

与 heigt 属性值做区分,height 值一旦指定,容器的高度就不会在发生变化,因此子元素可能溢出

验证:line-height 指定该容器内行盒最小高度,而不是该容器的最小高度,区别于 min-height

<div id='container'>
</div>
  #container{
    position: relative;
    line-height: 100px;
    font-size:36px;
    font-family: 'simsun';
    background-color: rgb(200, 200, 200);
  }

此时容器是没有高度,但是如果指定的是 min-height,则容器会保持这个高度

那么指定行盒的最小高度要怎么理解呢?为了解决这个疑惑,我们需要引入一个重要的概念:支柱

支柱 Strut

对于块容器元素而言,line-height 属性值的另一个重要的意义在于被支柱继承

line-height 是继承属性,因此 line-height 任何情况下都有默认值。line-height 的默认值是 normal,那么 line-height 的计算值就是该元素的字号*normal

font-size 也是可继承的,因此 font-size 任何情况下都有默认值

该值同样是由用户代理决定的,以 chrome 为例,默认的 font-size 为 16px

因此:对内容由行内级元素组成的块容器元素而言

<div id='container'>
  <span>xxx</span>
</div>
#container{
  /* 块容器的行高:16*normal */
  /* 同时也是支柱的行高 */
  background-color: rgb(200, 200, 200);
}
span{
  /*span的行高小于支柱:12*normal */
  font-size:12px;
  background-color: white;
}

可以看到,容器的高度比 span 的高度还要高,这是因为容器此时被支柱给撑开了

因此,对于非空的块容器元素而言,可以认为 line-height 指定了容器的最小高度

如果容器是空的,即使指定了 line-height 容器也是没有高度的,说明容器的高度不是 line-height 指定的,而是被支柱继承了之后撑开的

更准确的理解:容器的 line-height 属性,设置了支柱的高度,当支柱存在时,可以确定行盒以及容器的最小高度

支柱出现的条件

如果容器标签体为空则不会出现支柱

如果有文字或者图片

支柱的本质:不是 html 排版的空白符,而是浏览器默认添加的隐匿文本节点,空白符

行盒的高度

块容器可以设置高度 height,line-height 指定其实是支柱的高度

对于块容器而言,容器的高度是由行盒撑开的,能够撑开行盒:

**验证:**撑开父元素的是不可替换行内元素的 line-height,而不是内容区

#container{
  line-height:0px;
  font-size:0px;
  font-family: 'simsun';
  background-color: rgb(200, 200, 200);
}
span{
  line-height:36px;
  background-color: white;
}

可以看到父元素还是被撑开了,此时支柱的行高和字号都是 0,也就是说父容器的高度被 span 的 line-height 属性决定的,这一点适用于所有不可替换行内元素,也包括支柱

确定基线和中线

为了方便理解,以下所有 demo 中我们根据以下的标准进行探讨:

<div id='container'>
  <span id='strut'>llx</span>
  <span id='text'>textYyx</span>
  <img src="./img/img2-middle.jpg" alt="123"/>
</div>
  #container{
    position: relative;
    line-height: 100px;
    font-size:36px;
    font-family: 'simsun';
    background-color: rgb(200, 200, 200);
  }
  #text{
    line-height: normal;
    font-size:36px;
    position: relative;
    background-color: pink;
    vertical-align: baseline;
  }
  #strut{
    position: relative;
    font-size:inherit;
    line-height: inherit;
    background-color: pink;
    border:1px greenyellow solid;
  }
  img{
    position: relative;
    line-height:normal;
    font-size:36px;
    width: 15px;
    height: 15px;
    vertical-align: baseline;
  }

为了更加直观的理解,css 的属性都是显式写出,支柱相关属性都是继承于块容器

开启相对定位,用伪元素标识出元素的平分线,容器的平分线为红色,文本的平分线为绿色,图片的平分线为黑色

首先:我们可以认为父元素的基线就是支柱的基线,因为支柱的所有性质都继承于父元素,假设在支柱内有一个字母 x,那么这个字母 x 的下边缘就是基线

基线永远在小写字母 x 的下边缘

确定基线的偏移,不论支柱是否是行内盒的最高盒,基线总是向上偏移半行距。基线的偏移直接受到父元素 line-height 属性值的影响:

基线的偏移间接受到父元素 font-size 属性值的影响,本质上是影响了行距,因为 行距 = line-height - font-size

基线的位置再加上 1/2 x 的高度就是中线的位置

中线也是相对绝对性,永远在基线上方 1/2 字母 x 的高度处,因此也会受到 line-heightfont-size 的影响

Line-height 规范解读

https://drafts.csswg.org/css2/#propdef-line-height

https://drafts.csswg.org/css-inline/#line-height-property

Name: line-height
Value: normal | <number>| <length> | <percentage>| inherit
Initial: normal
Applies to: *
Inherited: yes
Percentages: refer to the font size of the element itself
Computed value: for <length> and <percentage> the absolute value; otherwise as specified
Canonical order: per grammar
Media: visual

On a block container element whose content is composed of inline-level elements, line-height specifies the minimal height of line boxes within the element. The minimum height consists of a minimum height above the baseline and a minimum depth below it, exactly as if each line box starts with a zero-width inline box with the element’s font and line height properties. We call that imaginary box a "strut." (The name is inspired by TeX.).

The height and depth of the font above and below the baseline are assumed to be metrics that are contained in the font. (For more details, see CSS level 3.)

On a non-replaced inline element, line-height specifies the height that is used in the calculation of the line box height.

Values for this property have the following meanings:

属性值

Note. When there is only one value of line-height (other than normal) for all inline boxes in a block container box and they all use the same first available font (and there are no replaced elements, inline-block elements, etc.), the above will ensure that baselines of successive lines are exactly line-height apart. This is important when columns of text in different fonts have to be aligned, for example in a table.

Vertical-align

此属性影响行内级元素生成盒在行盒内的垂直定位。

属性

起作用的前提

行内级元素

结语

现在我们准确的捕捉到了基线的所在,这样理解 vertical-align 属性就很简单了,只要找准支柱,主要属性都试一遍,也就理解了 90% 了。剩下的主要是一些边际情况和实际运用,我会在下一篇文章讲解

行盒高度的计算

行盒高度的计算,最后这个高度会撑开父容器

行盒的高度决定如下:

  1. 计算行盒内每个行内级盒的高度

    • 对于可替换元素、行内块元素以及行内表格元素,高度是其外边距盒的高度;

    • 对于行内盒:就是其line-height 属性值

      设置 line-height,定死了行内盒的高度,不论文字溢出与否容器的实际高度不变

      区别于块容器,设置的最小高度

    • 对于支柱:根据父元素的 line-height 和 font-size 确定支柱的 line-height,根据支柱的 line-height 和 font-size 确定基线,根据基线确定中线、顶线、底线

  2. 行内级盒根据其 vertical-align 属性垂直对齐。

    如果它们对齐 topbottom,它们必须以能最小化行盒高度的方式对齐。如果这些盒足够高,则有多种解决方案并且 CSS2.1 没有规定此行盒的基线的位置(即,支柱 Strut 位置)

      <div id="root">
        <h1>line-height&vertical-aling</h1>
        <div id='container'>
          <span>xxx</span>
          <img src="./img/img2.jpg" alt="123">
        </div>
      </div>
    
      #container{
        line-height:16px;
        font-size:36px;
        font-family: 'simsun';
        background-color: rgb(200, 200, 200);
      }
      span{
        line-height:0px;
        background-color: pink;
      }
      img{
        width: 10px;
        height: 10px;
        vertical-align: baseline;
      }
    
    • 假如没有图片,无论父元素的 font-size 怎么变化,行高都不收影响,如果有图片,会被图片的对齐方式影响行高

      1557637961740

  3. 行盒高度是最上盒顶部到最下盒底部的距离。(包括支柱)

    1557722129003

    text 的行高为 0,但是行内盒依然存在,line-height-font-size = 行距,所以总是收缩在平分线处,当平分线上升到了容器的最顶部,此时高度为 0 的行内盒就是最上盒,所以即使高度为 0,也可以撑开容器

Inline-block

类比于块容器,块容器此时生成一个行内级格式化上下文

height 为 auto 时

1557722701927

1557717139077

如果 inline-block 里面什么都没有,基线就是 margin,如果行内级元素,那就是里面的行盒的基线决定,如果有多个行盒,就由最后一个行盒的基线决定整个 inline-block 的基线

为什么背景会分布在 x 两边?是因为文字有默认居中的特性,为了基线对齐,看起来就像是整个盒子往下移动了

inline-block 内部有支柱吗?有,特性和块容器的完全一致

背景永远都是黏在行内盒的顶端,因为行内级盒子默认在父容器内自从左上开始排列,所以增加 height,是向下延伸

增加 line-height,背景向上移动,行距默认分布在内容区的两边

1559096116352

.square 的 line-height,是 136px,square 是高 50px,所以刚好在内容区的正上方

实践

全局行高使用经验

body{font-size:14px;line-height:?}

博客:1.5

匹配 20 像素,行高的默认值是 20px line-height:1.4286

单行文本垂直居中

直接使用 line-height

#content{
  font-size:36px;
  line-height:500px;
}
span{
  line-height:0px;
  background-color: pink;
}

1557640161117

其他什么都不需要,因为 line-height 值被平均分配在内容区的两边,支柱和容器一样高,基线对齐,字体大小一致

如果文本的字体大小和支柱的字体大小不一致,把支柱的字体设为 0,此时支柱四线合一,控制文本 vertical-align :middle 即可,因为 font-size 为零,此时 text-top 和 text-bottom 失效,表现与 middle 一致,只有 baseline 仍然存在

如果没有 line-height,无法使用 text-top 和 text-bottom

使用 middle,绿线与红线的距离等于绿线到 x 中间的距离

图片的 3px 空隙

1557713705205

单个图片的垂直居中

只设置 line-height 的话并没有真正的居中,向下偏移了

支柱的 font-size 为 0,然后图片 middle

1557570724729

1557570768007

多行文本垂直水平居中

1557581435771

大小不固定的图片和多行文字的垂直居中

支柱的 font-size 为 0,中线基线合一,控制图片 middle,控制文本 middle 即可

如果 font-size 不为 0:

插入一个大的 inline-block,inline-block:middle,对准了支柱的中线,此时容器由插入的元素撑开,支柱的中线就调整到了平分线的位置,然后全部 middle 即可垂直居中对齐

关键就是:使得支柱的中线与容器的平分线重合,这样无论是图片还是文本都可以通过 vertical-align 居中

无论容器的 line-height 属性究竟是多少,这两个方法都是万能的

Code

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name='viewport' content='width=device-width,initial-scale=1.0,user-scalable=no'>
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Page Title</title>
</head>
<style>
  * {
    margin: 0;
    padding: 0;
  }
  h1{
    line-height: 72px;
    background-color: white;
  }
  #root{
    height:1000px;
  }
  #container{
    position: relative;
    line-height: 100px;
    font-size:36px;
    font-family: 'simsun';
    background-color: rgb(200, 200, 200);
  }
  #text{
    line-height: normal;
    font-size:36px;
    position: relative;
    background-color: pink;
    vertical-align: baseline;
  }
  #strut{
    position: relative;
    font-size:inherit;
    line-height: inherit;
    background-color: pink;
    border:1px greenyellow solid;
  }
  img{
    position: relative;
    line-height:normal;
    font-size:36px;
    width: 15px;
    height: 20px;
    vertical-align: baseline;
  }
  .square{
    line-height: normal;
    font-size:36px;
    position: relative;
    width: 50px;
    height: 50px;
    display: inline-block;
    background-color: deeppink;
    vertical-align: baseline;
  }
  #inner_text{
    background-color: pink;
  }
  #inner_strut{
    line-height:0;
    font-size:0px;
  }
  #empty{
    line-height: normal;
    font-size:36px;
    position: relative;
    background-color: pink;
    vertical-align: baseline;
  }
  #container:before{
    position: absolute;
    content:" ";
    top:50%;
    width: 100%;
    border-top: 1px red solid;
  }
/*   #container:after{
    content: "";
    display: inline-block;
    height: 150px;
    width: 0;
    background: pink;
    vertical-align: middle;
  }    */
  .square::before,#text::before,#strut::before{
    position: absolute;
    content:" ";
    top:50%;
    width: 100%;
    border-top: 1px green solid;
  }
</style>

<body>
  <div id="root">
    <h2>line-height&vertical-align</h2>
    <div id='container'>
      <span id='strut'>llx</span>
      <span id='text'>textYyx</span>
      <img src="./img/img2-middle.jpg" alt="123"/>
      <span id='empty'></span>
      <span class="square">
        <span id='inner_text'>x</span>
      </span>
      <span class="square">
        <span id="inner_strut">llx</span>
      </span>
      <span class="square">
        <img src="./img//img2-middle.jpg" alt="456">
      </span>
    </div>
  </div>
<script>
</script>
</body>
</html>

垂直外边距的重叠

review-date: 2023-08-23

外边距重合问题

在网页中相邻的垂直方向的外边距会发生外边距的重叠,水平方向的相邻外边距不会重叠,而是求和

垂直水平 margin 都是会发生重叠的,但是一般只考虑垂直的,因为块级元素不可能水平,如果浮动了也同时开启了 BFC,不会发生 margin 重叠

所谓的垂直外边距重叠指兄弟元素之间相邻外边距会取最大值不是取和

如果父子元素垂直外边距相邻了,则子元素的外边距会设置给父元素,0+margin-top

开启 BFC

css-2.1

插入元素间隔开来

  1. 在子元素上插入(非空或者有高度的空元素)一个元素(且该元素不可以浮动)
  2. 插入一个空的 table 也 OK,用 css display:table

父子 Case

  1. 为子元素设置一个上边框或者为父元素设置一个上边框
  2. 设子置上 padding,再刨去 1px,保持平衡
  3. 为父元素设置垂直上内边距,内容区被撑大,再刨去内边距大小的高度

高度塌陷

review-date: 2023-08-23

在文档流中,父元素的高度默认是被子元素撑开的,也就是子元素多高,父元素就多高。

子元素脱离文档流,此时将会导致子元素无法撑起父元素的高度,导致父元素的高度塌陷。

由于父元素的高度塌陷了,则父元素下的所有元素都会向上移动,这样将会导致页面布局混乱

重点:绝对定位导致的高度塌陷

自己也开始绝对定位,通过 4 个 0,自动拉伸到宽高,适用于祖父存在的情况

或者开启相对定位,定义宽高 100%

如果祖父即是文档本身,则无法修复坍塌

方案一:设置高度

在开发中一定要避免出现高度塌陷的问题,我们可以将父元素的高度写死,以避免塌陷的问题出现

缺点:一旦高度写死,父元素的高度将不能自动适应子元素的高度,所以这种方案是不推荐使用的。

方案二:开启 Block Formatting Context

浮动时代的过时方案

方案三:空 div+clear

clear,只能作用于兄弟元素,所以不能直接解决高度坍塌的问题

可以直接在高度塌陷的父元素的最后,添加一个空白的 div,由于这个 div 并没有浮动,所以他是可以撑开父元素的高度的

然后在对其进行清除浮动,这样可以通过这个空白的 div 来撑开父元素的高度,基本没有副作用,兼容各种浏览器

使用这种方式虽然可以解决问题,但是会在页面中添加多余的结构。

方案三完善:伪类

通过 after 伪类,选中 box1 的后边,可以通过 after 伪类向元素的最后添加一个空白的块元素,然后对其清除浮动,

这样做和添加一个 div 的原理一样,可以达到一个相同的效果

必须转换为块元素,**因为清除浮动实际上是通过增加外边距来达到相似的效果,**而内联元素不支持垂直方向的外边距

在 IE6 中不支持 after 伪类, 所以在 IE6 中还需要使用 hasLayout 来处理

.clearfix:after{
 /*添加一个内容*/
 content: "";
 /*转换为一个块元素*/
 display: block;
 /*清除两侧的浮动*/
 clear: both;
}
.clearfix {
  zoom:1;
}

方案四:display:table; 兼容垂直外边距

子元素和父元素相邻的垂直外边距会发生重叠,子元素的外边距会传递给父元素

使用空的 table 标签可以隔离父子元素的外边距,阻止外边距的重叠

.clearfix:before,
.clearfix:after{
 content: "";
 display: table;
 clear: both;
}
.clearfix{
 zoom: 1; //兼容IE6
}

经过修改后的 clearfix 是一个多功能的,既可以解决高度塌陷,又可以确保父元素和子元素的垂直外边距不会重叠

问题来了:方案四 before 和 after 都用了,而且都是 table,为什么 block 不行?还有兄弟元素间的重叠怎么解决呢?

在移动端,因为没有 ie 浏览器,所以一般都是直接用 overflow:hidden 解决

总结 @@@

clearfix,使用空 table 而不使用空 div 的原因是:必须是块级元素,因为清除浮动是外边距,而内联元素不支持垂直外边距,使用 table 的原因是:插入非空元素或者元素具有高度,才可以防止垂直外边距重叠,而插入空的 table 就可以

层叠上下文

层叠上下文 @@@

失效的 position:fixed

https://www.cnblogs.com/coco1s/p/7358830.html

当元素祖先的 transform 属性非 none 时,容器由视口改为该祖先

指定了 position:fixed 的元素,如果其祖先元素存在非 none 的 transform 值 ,那么该元素将相对于设定了 transform 的祖先元素进行定位。

那么,为什么会发生这种情况呢?说好的相对视口(Viewport)定位呢?

这个问题,就牵涉到了 Stacking Context ,也就是堆叠上下文的概念了。解释上面的问题分为两步:

  1. 任何非 none 的 transform 值都会导致一个堆叠上下文(Stacking Context)和包含块(Containing Block)的创建。
  2. 由于堆叠上下文的创建,该元素会影响其子元素的固定定位。设置了 position:fixed 的子元素将不会基于 viewport 定位,而是基于这个父元素。

下述 3 种方式目前都会使得 position:fixed 定位的基准元素改变(本文重点):

  1. transform 属性值不为 none 的元素
  2. perspective 值不为 none 的元素
  3. will-change 中指定了任意 CSS 属性

上面也谈到了,上述结论是在最新的 Chrome 浏览器下(Blink 内核),经过测试发现,火狐,edge 同样

在 MAC 下的 Safari 浏览器(WebKit 内核,Version 9.1.2 (11601.7.7))和 IE Trident/ 内核及 Edge 浏览器下,上述三种方式都不会改变 position: fixed 的表现!

试了一下最新的 safari,貌似也会被改变了

所以,当遇到 position: fixed 定位基准元素改变的时候,需要具体问题具体分析,多尝试一下,根据需要兼容适配的浏览器作出调整,不能一概而论。

概念

堆叠上下文(Stacking Context):堆叠上下文是 HTML 元素的三维概念,这些 HTML 元素在一条假想的相对于面向(电脑屏幕的)视窗或者网页的用户的 z 轴上延伸,HTML 元素依据其自身属性按照优先级顺序占用层叠上下文的空间。

生成了 Stacking Context 的元素会影响该元素的层叠关系与定位关系

形成条件

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

特点

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

给一个 HTML 元素定位和 z-index 赋值创建一个层叠上下文,(opacity 值不为 1 的也是相同)。

层叠上下文可以包含在其他层叠上下文中,并且一起创建一个有层级的层叠上下文。

每个层叠上下文完全独立于它的兄弟元素:当处理层叠时只考虑子元素。

每个层叠上下文是自包含的:当元素的内容发生层叠后,整个该元素将会 在父层叠上下文中 按顺序进行层叠。

示例

在这个例子中,每个被定位的元素都创建了独自的层叠上下文,因为他们被指定了定位属性和 z-index 值。我们把层叠上下文的层级列在下面:

Root
  DIV #1
  DIV #2
  DIV #3
    DIV #4
    DIV #5
    DIV #6

分辨出层叠的元素在 Z 轴上的渲染顺序的一个简单方法是将它们想象成一系列的版本号,子元素是其父元素版本号之下的次要版本。通过这个方法我们可以轻松得看出为什么一个 z-index 为 1 的元素(DIV #5)层叠于一个 z-index 为 2 的元素(DIV #2)之上,而一个 z-index 为 6 的元素(DIV #4)层叠于 z-index 为 5 的元素(DIV #1)之下。在我们的例子中(依照最终渲染次序排列):

Z-index:0 和 z-index:auto

z-index 为 0 是会创建新的层叠上下文。

z-index: 0 与 z-index 不设置,也就是 z-index: auto 在同一层级内没有高低之分,文档流中后出现的会覆盖先出现的。

前提是得有层级,如果是默认的文档流里面的,那还是会被 绝对定位的节点覆盖,必须得是 relative 或者是 absolute 定位的才行
前端项目中有简洁的z-index的约束规则(管理方案)吗? - 知乎
⚖️ Element 黑魔法,统一多组件库的层叠顺序 - 掘金
Sass管理复杂的z-index_Preprocessor, Sass, SCSS, z-index 教程_W3cplus
WEB三层设计结构------管理z-index的神方案 · Issue #2 · lijinghust/lijinghust.github.com · GitHub

FAQ

#faq/ui

对 CSS 盒模型的理解

  1. 盒模型分为:内容(content)、填充(padding)、边界(margin)、边框(border)四个部分
  2. 盒模型有两种:IE 盒模型和标准盒模型。两者的区别是标准和模型的宽高不包含 border 和 padding,而 IE 盒模型的宽高包含 border 和 padding
  3. 使用 box-sizing 属性可以切换和模型,默认值为 content-box,即标准盒模型,border-box 则是 IE 盒模型. 无论是可替换元素还是不可替换元素, 内容区的概念是不受 box-sizing 影响的, 都会从内容区开始布局.
  4. 在 CSS 视觉格式化模型中分为块级的各种盒子和行内级的各种盒子, 通过 BFC 和 IFC 详细定义了各种布局的细节.