排序弹性项

弹性盒子(flexbox)和网格(grid)等布局方法可以控制内容的顺序。在本文中,我们将探讨使用弹性盒子时可以改变内容视觉顺序的方法。我们还将探讨重新排序对可访问性的影响。

反转项目的显示顺序

flex-direction 属性可取以下四个值之一:

  • row
  • column
  • row-reverse
  • column-reverse

前两个值会保持项目在文档源代码中出现的顺序,并从起始线开始依次显示它们。

The items are displayed in a row starting on the left.

The items are displayed as a column starting from the top

后两个值通过交换起始线和结束线来反转项目。

The items are displayed in reverse order starting on the right-hand line.

The items are displayed in a column in reverse order starting at the bottom line.

请记住,起始线与书写模式有关。上面与行相关的示例演示了 rowrow-reverse 在从左到右书写的语言(如英语)中是如何工作的。如果你正在使用从右到左书写的语言(如阿拉伯语),那么 row 将从右侧开始,row-reverse 将从左侧开始。

Flex containers with Arabic letters showing how row starts from the right-hand side and row-reverse from the left.

这看起来像是一种以相反顺序显示内容的简单方法。但是,你应该注意,项目只是在*视觉上*以相反的顺序显示。弹性布局的重新排序功能只影响视觉渲染。Tab 键顺序和语音顺序遵循源代码的顺序。这意味着只有视觉呈现发生了变化;源代码顺序保持不变,这为非 CSS 用户代理(比如 Siri 或 Alexa)和辅助技术用户提供了不同的用户体验。如果你更改了导航栏的顺序,Tab 键顺序仍然是文档源代码顺序,而不是你的视觉顺序,这可能会在认知上造成混淆。

如果你正在使用反向值,或者以其他方式重新排序你的项目,你应该考虑是否真的应该更改源代码中的逻辑顺序。

弹性盒子布局规范警告我们不要使用重新排序来修复源代码问题:

“作者绝不能使用 order 或 flex-flow/flex-direction 的 *-reverse 值来代替正确的源代码顺序,因为这会破坏文档的可访问性。”

当你在下面的实时示例中从一个链接切换到另一个链接时,焦点样式会高亮显示,这表明使用 flex-direction 更改弹性项目的顺序不会改变 Tab 键顺序,它将继续遵循源代码的顺序。

html
<div class="box">
  <div><a href="#">One</a></div>
  <div><a href="#">Two</a></div>
  <div><a href="#">Three</a></div>
</div>
css
.box > * {
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
  padding: 10px;
}

.box > * a:focus {
  background-color: yellow;
  color: black;
}

.box {
  border: 2px dotted rgb(96 139 168);
  display: flex;
  flex-direction: row-reverse;
}

就像更改 flex-direction 的值不会改变 Tab 键顺序一样,更改此值也不会改变绘制顺序。它仅仅是项目在视觉上的反转。

order 属性

除了反转弹性项目的视觉显示顺序外,你还可以针对单个项目,并使用 order 属性更改它们在视觉顺序中出现的位置。

order 属性旨在将项目按序数组进行布局。这意味着为项目分配一个代表其组别的整数。然后,项目会根据该整数按视觉顺序放置,值越小的越靠前。如果多个项目具有相同的整数值,那么在该组内,项目将按照源代码顺序进行布局。

例如,为五个弹性项目分配 order 值如下:

  • 源项目 1:order: 2
  • 源项目 2:order: 3
  • 源项目 3:order: 1
  • 源项目 4:order: 3
  • 源项目 5:order: 1

这些项目将按以下顺序显示在页面上:

  • 源项目 3:order: 1
  • 源项目 5:order: 1
  • 源项目 1:order: 2
  • 源项目 2:order: 3
  • 源项目 4:order: 3

Items have a number showing their source order which has been rearranged.

在下面的实时示例中尝试调整这些值,看看顺序会如何变化。此外,尝试将 flex-direction 更改为 row-reverse,看看会发生什么——起始线被切换了,所以排序从相反的一侧开始。

html
<div class="box">
  <div><a href="#">1</a></div>
  <div><a href="#">2</a></div>
  <div><a href="#">3</a></div>
  <div><a href="#">4</a></div>
  <div><a href="#">5</a></div>
</div>
css
.box > * {
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
  padding: 10px;
}

.box {
  border: 2px dotted rgb(96 139 168);
  display: flex;
  flex-direction: row;
}
.box :nth-child(1) {
  order: 2;
}
.box :nth-child(2) {
  order: 3;
}
.box :nth-child(3) {
  order: 1;
}
.box :nth-child(4) {
  order: 3;
}
.box :nth-child(5) {
  order: 1;
}

弹性项目的默认 order 值为 0。因此,整数值大于 0 的项目将显示在任何未被赋予明确 order 值的项目之后。

你也可以对 order 使用负值,这非常有用。如果你想让一个项目显示在最前面,并保持所有其他项目的顺序不变,你可以给该项目一个 -1 的 order 值。由于这个值小于 0,该项目将始终显示在最前面。

在下面的实时代码示例中,项目使用弹性盒子布局。通过在 HTML 中更改哪个项目被分配了 active 类,你可以改变哪个项目首先显示,从而在布局顶部占据全部宽度,而其他项目则显示在它下面。

html
<div class="box">
  <div><a href="#">1</a></div>
  <div><a href="#">2</a></div>
  <div class="active"><a href="#">3</a></div>
  <div><a href="#">4</a></div>
  <div><a href="#">5</a></div>
</div>
css
* {
  box-sizing: border-box;
}

.box > * {
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
  padding: 10px;
}

.box {
  width: 500px;
  border: 2px dotted rgb(96 139 168);
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
}

.active {
  order: -1;
  flex: 1 0 100%;
}

项目以*经顺序修改的文档顺序*显示,这意味着在显示项目之前会考虑 order 属性的值。

Order 也会改变项目的绘制顺序;order 值较低的项目会先被绘制,order 值较高的项目会后被绘制。

order 属性与可访问性

使用 order 属性对可访问性的影响与使用 flex-direction 改变方向相同。使用 order 会改变项目的绘制顺序以及它们在视觉上出现的顺序,但它不会改变项目的顺序导航顺序。因此,如果用户使用键盘通过 Tab 键在页面内容中切换,他们可能会发现自己以一种非常混乱的方式在内容中跳转。

通过在本页的任何实时示例中按 Tab 键,你可以看到 order 对于不使用鼠标等指针设备的人来说,可能会造成多么奇怪的体验。要了解更多关于视觉顺序和逻辑顺序脱节以及它可能引发的一些可访问性问题,请参阅以下资源。

order 的用例

在某些用例中,弹性项目的逻辑顺序(即阅读顺序)与视觉顺序分离是很有帮助的。如果小心使用,order 属性可以轻松实现一些有用的常见模式。

你可能有一个设计,比如一个显示新闻条目的卡片。新闻的标题是需要突出的关键内容,也是用户在标题之间切换以查找想阅读的内容时可能会跳转到的元素。卡片上还有一个日期;我们想要创建的最终设计是这样的。

A design component with a date, then heading and then content.

在视觉上,日期出现在标题上方。然而,在源代码中,如果这张卡片被屏幕阅读器读出,我更希望先读出标题,然后再读出发布日期。我们可以用 order 属性来实现这一点。

这张卡片是我们的弹性容器,flex-direction 设置为 column。我们给日期一个 -1order 值,将它置于标题之上。

html
<div class="wrapper">
  <div class="card">
    <h3>News item title</h3>
    <div class="date">1 Nov 2017</div>
    <p>This is the content of my news item. Very newsworthy.</p>
  </div>
  <div class="card">
    <h3>Another title</h3>
    <div class="date">6 Nov 2017</div>
    <p>This is the content of my news item. Very newsworthy.</p>
  </div>
</div>
css
body {
  font-family: sans-serif;
}

.wrapper {
  display: flex;
  flex: 1 1 200px;
  gap: 1em;
}

.card {
  border: 2px solid rgb(96 139 168);
  border-radius: 5px;
  background-color: rgb(96 139 168 / 0.2);
  padding: 1em;
  display: flex;
  flex-direction: column;
}

.date {
  order: -1;
  text-align: right;
}

这些小调整正是 order 属性发挥作用的场景。保持逻辑顺序与文档的阅读和 Tab 键顺序一致,并以最易访问和结构化的方式维护它。然后将 order 用于纯粹的视觉设计调整。不要对会接收键盘焦点的项目进行重新排序。请确保始终只用键盘而不是鼠标或触摸屏来测试你的内容;这将揭示你的开发选择是否使内容导航变得更加复杂。

另见