Tianhe Gao

css-understand-layout-algorithms

[Understanding Layout Algorithms](https://www.joshwcomeau.com/css/understanding-layout-algorithms/)

CSS 不仅仅是一系列属性的集合,它是一群相互连接的布局算法,每个算法都是一个复杂的系统,有着各自的规则和秘密机制。

​## 布局算法

​### 哪些是布局算法?

  1. Flexbox
  2. Positioned(例如,`position: absolute`)
  3. Grid
  4. Table
  5. Flow(除去 flex、grid 以外的布局)

```css .box { z-index: 10; } ```

以上 CSS 展示的是流式布局,但是 `z-index` 并不起作用,因为 `z-index` 要[配合 `position` 才能使用](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index)。`z-index` 在流式布局算法中并无实现,所以如果我想要其产生效果需要改成另外一种页面布局算法。

Flow 是非表格元素的默认布局算法。如果在流式布局中设置宽高,那么它所表示的就是元素的实际宽高;而在 Flex 布局中,宽高则是一种假设的尺寸,如果窗口宽度足够(`2000px`),元素宽度就是 `2000px`;反之,元素宽度会自动缩小以适应窗口宽度。

对于 Flow 布局和 Flex 布局,它们以不同的方式实现 `width`。

我们写入的属性是输入,就像传递给函数的参数一样,如何处理这些输入依赖于布局算法。

​## 识别布局算法

在某些情况下,一个 CSS 属性的使用就标志着使用了某种布局算法:

```css .help-widget { * Uses Positioned layout, because of this declaration: * position: fixed; right: 0; bottom: 0; } .floated { * Uses Float layout, because of this declaration: * float: left; margin-right: 32px; } ```

在其他情况下,需要看父元素的属性:

```html <style> .row { display: flex; } </style> <ul class="row"> <li class="item"></li> <li class="item"></li> <li class="item"></li> </ul> ```

当为父元素设置 `display: flex;` 时,我们不是为父元素 `.row` 设置 Flex 布局,相反,我们是为它的子元素设置了 Flex 布局。

从技术角度,`display: flex;` 创建了一个弹性格式化上下文。所有的直接子元素都在这个上下文中,,这意味着它们应用的是 Flex 布局,而不是默认的 Flow 布局。

(`display: flex;` 也会把行内元素变成块级元素,如 `<span>`,所以它也对父级元素有一定影响。但这并不会改变所使用的布局算法。)

​### 布局算法变体

一些布局算法可以分成几个变体。

当使用 `Positioned` 布局时,它被分为几个定位方案:

  • relative
  • absolute
  • fixed
  • sticky

​### 冲突

当一个元素被应用多种元素时会发生什么?

```html <style> .row { display: flex; } .primary.item { position: absolute; } </style> <ul class="row"> <li class="item"></li> <li class="primary item"></li> <li class="item"></li> </ul> ```

中间那个子元素使用了 Positioned 布局,而这个布局的优先级高于 Flex 的,所以对于三个子元素来说,中间一个是 Positioned,上下两个是 Flex。

​## 行内魔法空格

在 Flow 布局中,以下代码片段所展示的页面,会有一些空白在图片(`<img>`)和它的父元素(`<div>`)之间:

```html <style> .photo-wrapper { border: 1px solid; }

.cat-photo { width: 250px; max-width: 100%; } </style>

<div class="photo-wrapper"> <img class="cat-photo" alt="A basketful of cats" src="/images/cats.jpg" /> </div> ```

为什么会有这种空白?

So, bringing this back to our mystery: why does our image have a few extra pixels of space? Because images are inline elements by default!

​### Flow 布局

Flow 布局是为文档设计的一种布局算法。

文档的结构特点:

  • 单个字符组成单词和句子。当水平空间不足时,这些元素会呈现三种形态:行内、并列、换行
  • 段落被认为是块,像标题和图片一样。块将被垂直堆叠,一块接着一块,从上到下。

Flow 布局基于这种结构。

In order to make sure that inline elements don't negatively affect the legibility of the surrounding text, a bit of extra vertical space is added.

So, bringing this back to our mystery: why does our image have a few extra pixels of space? Because images are inline elements by default!

​### 解决办法

如何消除行内魔法空白?

  1. 将图片设置为 `display: block;`
  2. 将图片设置为 `display: flex;`
  3. 将图片设置为 `line-height: 0;`(这种做法不利于可访问性)

​## 构建直觉

> If you were focusing exclusively on studying what specific CSS properties do, you'd never understand where this mysterious space is coming from. It isn't explained in the MDN pages for `display` or `line-height`.


No notes link to this note