布局

CSS 播客 - 009:布局

假设您是一名开发者,一位设计师同事为您提供一个全新网站的设计。该设计具有各种有趣的布局和组合:考虑视口宽度和高度的二维布局,以及需要流动和灵活的布局。如何确定使用 CSS 来设置这些样式的最佳方式?

CSS 为我们提供了各种方法来解决横轴、纵轴或两者上的布局问题。为上下文选择正确的布局方法可能并非易事,并且通常您可能需要多种布局方法才能解决问题。为帮助完成这项工作,在接下来的模块中,您将了解每种 CSS 布局机制的独特功能,并据此做出明智的决策。

布局:简述

在 Web 发展初期,使用 <table> 元素进行布局的设计会比简单的文档更加复杂。当 CSS 在 90 年代后期浏览器得到广泛采用后,您就可以更轻松地将 HTML 与视觉样式分离开来。 CSS 让开发者能够在不接触 HTML 的情况下完全改变网站的外观和风格。 这项新功能激发了 The CSS Zen Garden 等项目的灵感,该项目旨在展示 CSS 的强大功能,鼓励更多开发者学习 CSS。

随着我们对网页设计和浏览器技术的需求不断演变,CSS 也在不断发展。 您可以阅读 Rachel Andrew 撰写的这篇文章,了解 CSS 布局以及我们的布局方法是如何不断改进的。

展示 CSS 这些年的发展历程(从 1996 年到 2021 年)的时间轴

布局:现在和未来

现代 CSS 拥有极其强大的布局工具。 我们有专门的布局系统,在深入探讨 Flexbox 和 Grid 的后续模块之前,先大致了解我们可以使用哪些布局。

了解 display 属性

display 属性会执行两项操作。它首先确定应用它所应用的框是 inline 还是块。

.my-element {
  display: inline;
}

内嵌元素的行为类似于句子中的字词。它们在内嵌方向上并排显示。 <span><strong> 等元素通常用于为所含元素(如 <p> [段落])中的文本段设置样式,它们默认采用内嵌样式。它们还会保留周围的空白。

一张示意图,显示了所有不同尺寸的方框以及每个尺寸部分的开始和结束位置

您无法为内嵌元素设置明确的宽度和高度。周围的元素会忽略任何块级的外边距和内边距。

.my-element {
    display: block;
}

块元素不会并排放置。 他们会自行另起一行。除非被其他 CSS 代码更改,否则块元素将展开为内嵌尺寸,因此在水平书写模式下会跨越整个宽度。将采用 block 元素所有侧边的外边距。

.my-element {
    display: flex;
}

display 属性还决定了元素的子元素的行为方式。例如,将 display 属性设置为 display: flex 会使该框成为块级框,并将其子项转换为弹性项。这会启用用于控制对齐、排序和流动的灵活属性。

Flexbox 和网格

为多个元素创建布局规则的主要布局机制是 flexboxgrid。它们虽然有相似之处,但旨在解决不同的布局问题。

Flexbox

.my-element {
    display: flex;
}

Flexbox 是一维布局的布局机制。沿单轴布局(水平或垂直)。 默认情况下,Flexbox 将在内嵌方向上彼此相邻地对齐元素的子元素,并在块方向上拉伸这些子元素,使它们的高度相同。

各项内容将保持在同一轴上,且在空间用尽时不会换行。 相反,它们会尝试各自挤入同一行。 可以使用 align-itemsjustify-contentflex-wrap 属性更改此行为。

Flexbox 还会将子元素转换为弹性项,这意味着您可以编写规则来控制这些子元素在 Flex 容器中的行为。您可以更改单个内容的对齐方式、顺序和对齐方式。 您还可以使用 flex 属性更改其收缩方式。

.my-element div {
    flex: 1 0 auto;
}

flex 属性是 flex-growflex-shrinkflex-basis 的简写形式。您可以按如下方式扩展上面的示例:

.my-element div {
 flex-grow: 1;
 flex-shrink: 0;
 flex-basis: auto;
}

开发者提供这些低级规则,可以提示浏览器在受到内容和视口尺寸挑战时布局应表现出怎样的行为。这使得它成为响应性网页设计非常有用的机制。

网格

.my-element {
    display: grid;
}

网格在很多方面与 Flexbox 类似,但其设计是为了控制多轴布局,而不是单轴布局(垂直或水平空间)。

借助网格,您可以针对具有 display: grid 的元素编写布局规则,并引入了一些用于布局样式的新基元,例如 repeat()minmax() 函数。一种实用的网格单元是 fr 单元(剩余空间的一小部分),您可以构建传统的 12 列网格,每个项之间有间隔,并具有 3 个 CSS 属性:

.my-element {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 1rem;
}

上面的此示例展示了一个单轴布局。 Flexbox 主要将各个项视为一个组,而网格可让您在两个维度上精确控制项的位置。我们可以定义此网格中的第一项占据 2 行 3 列:

.my-element :first-child {
  grid-row: 1/3;
  grid-column: 1/4;
}

grid-rowgrid-column 属性指示网格中的第一个元素从第一列跨越到第四列的起始位置,然后从第一行跨越到第三行。

流式布局

如果不使用网格或 Flexbox,您的元素会以正常流程显示。在正常流程中,您可以使用多种布局方法来调整项目的行为和位置。

内嵌块

还记得周围元素如何不遵循内嵌元素的块外边距和内边距吗?借助 inline-block,您可以做到这一点。

p span {
    display: inline-block;
}

使用 inline-block 会得到一个具备块级元素一些特性的框,但该框仍然内嵌在文本中。

p span {
    margin-top: 0.5rem;
}

浮点数

如果某张图片包含在一段文本中,那么这段文字会不会很方便,就像您在报纸中看到的那样?您可以使用浮点数执行此操作。

img {
    float: left;
    margin-right: 1em;
}

float 属性指示元素“浮动”到指定的方向。此示例中的图像被指示向左浮动,然后同级元素可以“环绕”它。您可以指示某个元素悬浮 leftrightinherit

多列布局

如果您的元素列表非常长,例如全世界所有国家/地区的列表,则可能会导致用户进行大量的滚动操作并浪费时间。它还会导致网页上产生多余的空白。 借助 CSS 多列,您可以将此列拆分为多列,以解决这两个问题。

<h1>All countries</h1>
<ul class="countries">
  <li>Argentina</li>
  <li>Aland Islands</li>
  <li>Albania</li>
  <li>Algeria</li>
  <li>American Samoa</li>
  <li>Andorra</li>
  …
</ul>
.countries {
    column-count: 2;
    column-gap: 1em;
}

这会自动将这个长列表拆分成两列,并在两列之间添加一个间距。

.countries {
    width: 100%;
    column-width: 260px;
    column-gap: 1em;
}

您还可以使用 column-width 定义所需的最小宽度,而不是设置拆分的列数。随着视口中的可用空间增多,系统会自动创建更多列,随着空间的减少,列数也会减少。这在响应性网页设计环境中非常有用。

Positioning

关于布局机制概述的最后一个内容是定位。 position 属性可更改元素在文档正常流程中的行为方式,以及元素与其他元素的关系。可用选项包括 relativeabsolutefixedsticky,默认值为 static

.my-element {
  position: relative;
  top: 10px;
}

此元素相对于其自身位置,基于其在文档中的当前位置向下微移 10 像素。将 position: relative 添加到元素也会使其成为包含 position: absolute 的任何子元素的包含块。这意味着,当对其应用了绝对位置时,其子元素将重新定位到此特定元素,而不是最顶层的相对父元素。

.my-element {
  position: relative;
  width: 100px;
  height: 100px;
}

.another-element {
    position: absolute;
    bottom: 0;
    right: 0;
    width: 50px;
    height: 50px;
}

如果将 position 设置为 absolute,则会将该元素脱离当前文档流程。这意味着有两个方面:

  1. 您可以将此元素放到任何位置,只需在其最近的相对父项中使用 toprightbottomleft 即可。
  2. 绝对元素周围的所有内容都会重排,以填充该元素所剩的剩余空间。

position 值为 fixed 的元素的行为与 absolute 类似,其父级是根 <html> 元素。固定位置元素会根据您设置的 toprightbottomleft 值保持在左上角锚定。

您可以使用 sticky 实现 fixed 的锚定固定方面以及 relative 的可预测性更强的文档流遵循方面。使用此值时,当视口滚动经过该元素时,它会固定在您设置的 toprightbottomleft 值上。

小结

CSS 布局有很多选择余地,也很灵活。 要深入了解 CSS FlexboxGrid 的强大功能,请继续学习接下来的几个模块。

检查您的掌握程度

测试您对布局知识的掌握情况

display 属性有什么两件事?

确定 inlineblocknone
布局引擎需要了解此框是否全宽,是否需要另起一行。
确定网格布局框架。
display 属性可以将 display 属性设置为 grid,但它与布局框架没有任何关系。
确定子级的行为方式。
Flexbox 和网格可以为孩子提供观点和新功能。
确定框是否应滚动。
那就是 overflow 属性。

要将多个段落分成多个列,哪个 CSS 属性最适合此任务?

display: grid
虽然 grid 可以将多个段落放入列中,但这些列是它们各自的列,而不是从一个段落流向下一个段落。
column-count
段落将从一列的结尾延伸到下一列的开头,就像杂志或报纸那样。
display: flex
虽然 flex 可以将多个段落放入列中,但这些列是各自的列,不需要像他们一样从一个段落流向下一个段落。
float
再试一次!

如果某个方块没有流动,意味着什么?

它卡在河边了。
这里的上下文是 CSS,而不是地理位置。
已为其指定 topleft 位置值。
只具备这些属性并不能拖延整个流程。
不再根据同级子位置进行定位。
例如,带有 position: absolute 的框现在使用基于所在块的 x 和 y 坐标(而不是它与其他同级元素的顺序)进行放置。

Flexbox 和 Grid 会默认封装其子项吗?

True
必须通过 flex-wrap: wraprepeat(auto-fit, 30ch) 选择启用。
False
Flexbox 和 Grid 具有特殊的封装功能,需要其他样式才能应用。