# 布局 *当你构建一个组件或者页面时,有多种布局方式可供选择,本节内容是各种布局的一个概览。* 假设你是一个开发者,此时一个设计专业的同事递给你一份新的网站设计稿让你开发。这份设计稿有很多有趣的布局和组件,有二维布局,也有非常灵活可流动的布局。你怎么去选择最好的css布局方式呢? CSS为我们提供了多种布局方式,有水平轴布局,垂直轴布局或者水平和竖直混合布局。选择一个正确的布局方式往往很困难,通常你需要多个布局方式去解决问题。为了解决这些,在接下来的几个模块,你将会学习css的布局机制。 ## 二.display属性 `display`属性做了两件事。第一件事是他决定一个盒子是否表现为**inline**或者**block**。 ```css .my-element { display: inline } ``` inline元素被称为行内元素,行内元素就像一段语句中的一个单词。它们在行内方向上紧挨着彼此。像``和``元素就是典型的行内元素,它们在`

`(段落,`

`是一个block元素,后面将会介绍block元素)中都是紧挨着彼此的。它们同样拥有周围的空间,即`padding`、`border`和`margin`属性都是有效的。 ![css布局](https://cdn.jsdelivr.net/gh/pengfeiw/PengfeiBlog@1.0.0/image/120.jpg) 你无法设置行内元素的`width`和`height`属性。block层级的margin和padding将会被周围的元素忽略(这句话的英文原文是*Any block level margin and padding will be ignored by the surrounding elements*,我不清楚这样翻译是否合适)。 block元素,即块元素,它们并不是紧挨着其他元素的。它们在页面中会自动生成新的一行。块元素在行内方向上会扩展尺寸,因此它们会占据水平方向100%宽度。块元素任意方向的边距将不会被忽略。 ```css .my-element { display: block; } ``` `display`属性还可以决定元素的子元素的行为。例如设置`display: flex`,使元素盒子成为一个block层级的盒子(块元素),并且将子元素变成flex项目(item)。这会启用flex属性,flex属性可以用来控制子元素的布局方式(对其、排序、流动)。 ## 二.flex和Grid flex(弹性布局)和grid(格子布局)是为多个元素创建布局规则的两种主要布局机制。它们有很多共同点,但是却是被设计出来去解决不同的布局问题的。 > 在后面的章节内容,我将会更详细的介绍弹性布局和格子布局的内容。但是目前我们仅大致看下这两种布局方式,了解它们的功能。 首先明确两个概念: - flex/grid盒子(简称盒子):`display`属性设置为`flex`或者`grid`的元素被称为盒子。 - flex/grid项目(简称项目):flex/grid盒子元素的直接子元素,不包含孙子元素。 ### 弹性布局 ```css .my-element { display: flex; } ``` 弹性布局主要用于一维布局。布局方向是单轴的,可以是水平方向或者竖直方向。默认情况下,弹性布局会在内联方向上(水平方向)排列元素,flex项目会紧挨着彼此,并且会在块方向上(竖直方向)被拉伸,所以项目与盒子高度相同。 flex项目会保持同轴排列,在超过flex盒子范围时,并不会换行,而是被自动压缩宽度排列。可以通过`align-items`、 `justify-content`和`flex-wrap`改变这一默认行为。 你也可以通过`flex`属性设置flex项目如何压缩、拉伸尺寸。 ```css .my-element { flex: 1 0 auto; } ``` `flex`属性是`flex-grow`、`flex-shrink`、`flex-basis`三个属性的混合写法。你可以将上面的例子改写为: ```css .my-element { flex-grow: 1; flex-shrink: 0; flex-basis: auto; } ``` 开发人员提供这些低级规则,以提示浏览器当视口尺寸发生变化时如何布局元素。这使得弹性布局非常适合设计响应式网页。 ### 格子布局 ```css .my-element { display: grid; } ``` 格子布局(Grid)与弹性布局(flex)非常相似,但是格子布局是为多轴布局而设计的。 格子布局引入了一些新的布局基础规则,例如`repeat()`和`minmax()`函数。还有一个`fr`单位,用来描述分配剩余空间的弹性系数。你可以创建一个12列,每列之间有一个空白间距的布局。 ```css .my-element { display: grid; grid-template-columns: repeat(12, 1fr); gap: 1rem; } ``` 你还可以通过格子布局设置二维布局。我们可以设置第一个grid项目占据两行三列的空间。 ```css .my-element :first-child { grid-row: 1/3; grid-column: 1/4; } ``` 通过`grid-row`和`grid-column`属性设置盒子中第一个元素水平占据空间从第一列到第四列,竖直占据空间从第一行到第三行。 ### flow布局 如果不使用弹性布局和格子布局,你的元素将会显示为正常文档流。还有一些布局方式可以在正常文档流中改变元素的行为和位置。 #### inline-block 前面提到过,内联元素的块方向上的边距(margin和padding)将会被周围的元素忽略。通过设置`inline-block`,可以使内联元素的块方向上的边距不会被忽略。 ```css p span { display: inline-block; } ``` 使用`inline-block`可以让一个盒子拥有块元素的一些特性,但是仍然在处于内联文档流中,与其他元素紧挨着。 ```css p span { margin-top: 0.5rem; } ``` #### Floats 如果一个段落中有一张图片,但是你想让文字环绕在图片周围,就像杂志一样。你可以使用floats特征去完成这种效果: ```css img { float: left; margin-right: 1em; } ``` `float`属性指示元素朝着指定方向流动。例子中的图片被指示朝着左侧流动,并且允许它的姐妹元素环绕着它。你可以设置`float`属性为`left`、`right`、`inherit`等值。 注意:当你使用`float`属性,你要记住所有在float元素后的元素的布局都会被调整。为了防止这种情况,你可以清除float效果,可以通过设置float元素后面的元素`clear: both`属性值,也可以通过为float元素的父元素添加`display: flow-root`属性值。 #### 多列布局 如果有一个很长的列表,你可以通过`column-count`设置列表的列数,通过`column-gap`设置列表的列间距。 ```css .countries { column-count: 2; column-gap: 1em; } ``` 上面的例子,会自动将列表分成两列,并且在列之间添加一个空白间距。 也可以通过设置`column-width`,然后通过列表宽度,自动划分列数。 ```css .countries { width: 100%; column-width: 260px; column-gap: 1em; } ``` #### position `position`属性会改变元素在正常文档流中的表现和它与其他元素之间的关系。可用的属性值由`static`、`relative`、`absolute`、`fixed`和`sticky`。默认值为`static`。 - static:该关键字指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时 top, right, bottom, left 和 z-index 属性无效。 - relative: 该关键字下,元素先放置在未添加定位时的位置,再在不改变页面布局的前提下调整元素位置(因此会在此元素未添加定位时所在位置留下空白)。position:relative对table-row, table-column, table-cell, table-caption 元素无效。 - absolute:元素会被移出正常文档流,并不为元素预留空间,通过指定元素相对于最近的非 static定位祖先元素的偏移,来确定元素位置。绝对定位的元素可以设置外边距(margins),且不会与其他边距合并。 - fixed:元素会被移出正常文档流,并不为元素预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在的每页的固定位置。fixed属性会创建新的层叠上下文。当元素祖先的transform,perspective或filter属性非 none 时,容器由视口改为该祖先。 - sticky:元素根据正常文档流进行定位,然后相对它的最近滚动祖先(nearest scrolling ancestor)和containing block(最近块级祖先nearest block-level ancestor),包括table-related元素,基于top、right、bottom和left的值进行偏移。偏移值不会影响任何其他元素的位置。 可以在[这里](https://developer.mozilla.org/zh-CN/docs/Web/CSS/position)获得更详细的内容。 (完)