css 教程
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

203 lines
11 KiB

# 布局
*当你构建一个组件或者页面时,有多种布局方式可供选择,本节内容是各种布局的一个概览。*
假设你是一个开发者,此时一个设计专业的同事递给你一份新的网站设计稿让你开发。这份设计稿有很多有趣的布局和组件,有二维布局,也有非常灵活可流动的布局。你怎么去选择最好的css布局方式呢?
CSS为我们提供了多种布局方式,有水平轴布局,垂直轴布局或者水平和竖直混合布局。选择一个正确的布局方式往往很困难,通常你需要多个布局方式去解决问题。为了解决这些,在接下来的几个模块,你将会学习css的布局机制。
## 二.display属性
`display`属性做了两件事。第一件事是他决定一个盒子是否表现为**inline**或者**block**。
```css
.my-element {
display: inline
}
```
inline元素被称为行内元素,行内元素就像一段语句中的一个单词。它们在行内方向上紧挨着彼此。像`<span>`和`<strong>`元素就是典型的行内元素,它们在`<p>`(段落,`<p>`是一个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项目会紧挨着彼此,并且会在块方向上(竖直方向)被拉伸,所以项目与盒子高度相同。
<iframe height="300" style="width: 100%;" scrolling="no" title="008 Layout_1" src="https://codepen.io/AhCola/embed/jOmeoOX?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/AhCola/pen/jOmeoOX">
008 Layout_1</a> by Pengfei Wang (<a href="https://codepen.io/AhCola">@AhCola</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
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;
}
```
<iframe height="300" style="width: 100%;" scrolling="no" title="008 Layout_2" src="https://codepen.io/AhCola/embed/zYwmQor?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/AhCola/pen/zYwmQor">
008 Layout_2</a> by Pengfei Wang (<a href="https://codepen.io/AhCola">@AhCola</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
你还可以通过格子布局设置二维布局。我们可以设置第一个grid项目占据两行三列的空间。
```css
.my-element :first-child {
grid-row: 1/3;
grid-column: 1/4;
}
```
通过`grid-row`和`grid-column`属性设置盒子中第一个元素水平占据空间从第一列到第四列,竖直占据空间从第一行到第三行。
<iframe height="300" style="width: 100%;" scrolling="no" title="008 Layout_3" src="https://codepen.io/AhCola/embed/MWmPdmW?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/AhCola/pen/MWmPdmW">
008 Layout_3</a> by Pengfei Wang (<a href="https://codepen.io/AhCola">@AhCola</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
### 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`等值。
<iframe height="300" style="width: 100%;" scrolling="no" title="008 Layout_4" src="https://codepen.io/AhCola/embed/PomyvEd?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/AhCola/pen/PomyvEd">
008 Layout_4</a> by Pengfei Wang (<a href="https://codepen.io/AhCola">@AhCola</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
注意:当你使用`float`属性,你要记住所有在float元素后的元素的布局都会被调整。为了防止这种情况,你可以清除float效果,可以通过设置float元素后面的元素`clear: both`属性值,也可以通过为float元素的父元素添加`display: flow-root`属性值。
#### 多列布局
如果有一个很长的列表,你可以通过`column-count`设置列表的列数,通过`column-gap`设置列表的列间距。
```css
.countries {
column-count: 2;
column-gap: 1em;
}
```
<iframe height="300" style="width: 100%;" scrolling="no" title="008 Layout_5" src="https://codepen.io/AhCola/embed/KKmGLBK?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/AhCola/pen/KKmGLBK">
008 Layout_5</a> by Pengfei Wang (<a href="https://codepen.io/AhCola">@AhCola</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
上面的例子,会自动将列表分成两列,并且在列之间添加一个空白间距。
也可以通过设置`column-width`,然后通过列表宽度,自动划分列数。
```css
.countries {
width: 100%;
column-width: 260px;
column-gap: 1em;
}
```
<iframe height="300" style="width: 100%;" scrolling="no" title="008 Layout_6" src="https://codepen.io/AhCola/embed/QWvZRBe?default-tab=html%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">
See the Pen <a href="https://codepen.io/AhCola/pen/QWvZRBe">
008 Layout_6</a> by Pengfei Wang (<a href="https://codepen.io/AhCola">@AhCola</a>)
on <a href="https://codepen.io">CodePen</a>.
</iframe>
#### 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)获得更详细的内容。
(完)