网格、逻辑值和书写模式

在这些指南中,我已经触及了网格布局的一个重要特性:对规范中内置的不同书写模式的支持。在本指南中,我们将研究网格和其他现代布局方法的这一特性,并在此过程中学习一些关于书写模式和逻辑与物理属性的知识。

逻辑和物理属性及值

CSS 充满了 **物理** 定位关键字——左和右,上和下。如果我们使用绝对定位来定位一个项目,我们会使用这些物理关键字作为偏移值来推动项目移动。在下面的代码片段中,该项目被放置在容器顶部 20 像素,左侧 30 像素的地方

css
.container {
  position: relative;
}
.item {
  position: absolute;
  top: 20px;
  left: 30px;
}
html
<div class="container">
  <div class="item">Item</div>
</div>

您可能会在使用 text-align: right 将文本对齐到右侧时看到物理关键字的使用。CSS 中还有物理 **属性**。我们使用 margin-leftpadding-left 等这些物理属性来添加边距、填充和边框。

我们将这些关键字和属性称为“物理”属性,因为它们与您正在查看的屏幕相关。无论您的文本运行方向如何,左侧始终是左侧。

物理属性的问题

在开发一个必须在多种语言(包括文本从右开始而不是从左开始的语言)中工作的网站时,这可能会成为一个问题。浏览器在处理文本方向方面做得很好,您甚至不需要使用 rtl 语言就可以看一下。在下面的示例中,我有两个段落。第一个段落设置了 text-alignleft,第二个段落没有设置 text-align 属性。我在 html 元素中添加了 dir="rtl",它将书写模式从英语文档的默认值 ltr 切换。您可以看到,由于 text-align 值为 left,第一个段落仍然是左对齐的。但是,第二个段落切换了方向,文本从右到左运行。

这是一个使用 CSS 中的物理值和属性时所面临问题的非常简单的示例。它们阻止浏览器能够完成切换书写模式的工作,因为它们假设文本是从左到右、从上到下流动的。

逻辑属性和值

逻辑属性和值不假设文本方向。这就是为什么在网格布局中,我们在将某个东西对齐到容器的开头时使用关键字 start。对我来说,在英语中,start 很有可能在左侧,但它并不一定要在左侧,而且单词 start 没有暗示任何物理位置。

块级和内联

一旦我们开始处理逻辑属性而不是物理属性,我们就不会再以从左到右、从上到下的方式看待世界。我们需要一个新的参考点,这就是我们之前在对齐指南中遇到的 *块* 和 *内联* 轴的理解变得非常有用的地方。如果你能开始从块和内联的角度来看布局,那么网格的工作方式就会变得更有意义。

An image showing the default direction of the Block and Inline Axes.

CSS 书写模式

我将在这里介绍另一个规范,我将在我的示例中使用它:CSS 写入模式规范。该规范详细说明了我们如何在 CSS 中使用这些不同的写入模式,不仅是为了支持与英语具有不同写入模式的语言,而且还用于创意目的。我将使用 writing-mode 属性来更改应用于我们网格的写入模式,以演示逻辑值如何工作。但是,如果你想进一步深入研究写入模式,那么我建议你阅读 Jen Simmons 关于 CSS 写入模式 的优秀文章。这比我们在这里讨论的更深入地介绍了该规范。

writing-mode

写入模式不仅仅是左右和从右到左的文本,writing-mode 属性帮助我们以其他方向显示文本。 writing-mode 属性可以具有以下值:

  • horizontal-tb
  • vertical-rl
  • vertical-lr
  • sideways-rl
  • sideways-lr

horizontal-tb 是网络上文本的默认值。这是你阅读本指南的方向。其他属性将改变文本在我们文档中的流动方式,匹配世界各地发现的不同写入模式。作为一个简单的例子,我在下面有两段文字。第一段使用默认的 horizontal-tb,第二段使用 vertical-rl。在这种模式下,文本仍然从左到右运行,但是文本的方向是垂直的 - 内联文本现在沿页面向下运行,从上到下。

html
<div class="wrapper">
  <p style="writing-mode: horizontal-tb">
    I have writing mode set to the default <code>horizontal-tb</code>
  </p>
  <p style="writing-mode: vertical-rl">
    I have writing mode set to <code>vertical-rl</code>
  </p>
</div>

网格布局中的书写模式

如果我们现在看一下网格布局示例,我们可以看到更改写入模式意味着更改我们对块和内联轴在哪里运行的理解。

默认写入模式

此示例中的网格具有三列和两行轨道。这意味着有三条轨道沿块轴向下运行。在默认写入模式下,网格自动放置项目,从左上角开始,向右移动,填充内联轴上的三个单元格。然后它移动到下一行,创建一个新的行轨道,并填充更多项目。

css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(2, 100px);
  gap: 10px;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
  <div class="item5">Item 5</div>
</div>

设置写入模式

如果我们在网格容器中添加 writing-mode: vertical-lr,我们可以看到块和内联轴现在沿不同的方向运行。块或 *列* 轴现在从左到右横跨页面运行,内联沿页面向下运行,从上到下创建行。

css
.wrapper {
  writing-mode: vertical-lr;
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(2, 100px);
  gap: 10px;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
  <div class="item5">Item 5</div>
</div>

用于对齐的逻辑值

随着块和内联轴能够改变方向,对齐属性的逻辑值开始变得更有意义。

在下一个示例中,我使用对齐来对齐设置为 writing-mode: vertical-lr 的网格内的项目。startend 属性以与它们在默认写入模式中完全相同的方式工作,并且以使用左和右、上和下对齐项目的方式保持逻辑。当我们将网格翻转到侧面时,就会发生这种情况。

css
.wrapper {
  writing-mode: vertical-lr;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
  gap: 10px;
}

.item1 {
  grid-column: 1 / 4;
  align-self: start;
}

.item2 {
  grid-column: 1 / 3;
  grid-row: 2 / 4;
  align-self: start;
}

.item3 {
  grid-column: 3;
  grid-row: 2 / 4;
  align-self: end;
  justify-self: end;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
</div>

如果你想看看它们如何在从右到左以及从上到下的写入模式下工作,请将 vertical-lr 切换到 vertical-rl,这是一种从右到左运行的垂直写入模式。

自动放置和书写模式

在已经显示的示例中,你可以看到写入模式如何更改项目在网格上放置自己的方向。默认情况下,项目会沿内联轴放置自己,然后移动到新行。但是,该内联轴可能并不总是从左到右运行。

基于行的放置和书写模式

记住通过行号放置项目时要记住的关键是,无论你使用哪种写入模式,行 1 都是起始行。行 -1 是结束行,无论你使用哪种写入模式。

基于行的放置,文本从左到右

在下一个示例中,我有一个网格,它处于默认的 ltr 方向。我已经使用基于行的放置定位了三个项目。

  • 项目 1 从列行 1 开始,跨越一个轨道。
  • 项目 2 从列行 -1 开始,跨越到 -3。
  • 项目 3 从列行 1 开始,跨越到列行 3。
css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 100px);
  gap: 10px;
}
.item1 {
  grid-column: 1;
}
.item2 {
  grid-column: -1 / -3;
}
.item3 {
  grid-column: 1 / 3;
  grid-row: 2;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
</div>

基于行的放置,文本从右到左

如果我现在将 direction 属性的值设置为网格容器的 rtl,那么行 1 将成为网格的右侧,行 -1 位于左侧。

css
.wrapper {
  direction: rtl;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 100px);
  gap: 10px;
}
.item1 {
  grid-column: 1;
}
.item2 {
  grid-column: -1 / -3;
}
.item3 {
  grid-column: 1 / 3;
  grid-row: 2;
}
html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
</div>

这表明,如果你正在切换文本的方向,无论是整个页面还是页面的一部分,并且正在使用行:如果你不希望布局完全切换方向,你可能需要命名你的行。对于某些事情,例如,当网格包含文本内容时,这种切换可能正是你想要的。对于其他用法可能不是。

grid-area 属性中值的奇怪顺序

你可以使用 grid-area 属性将网格区域的所有四行指定为一个值。当人们第一次遇到它时,他们经常会惊讶地发现这些值没有遵循与边距速记相同的顺序 - 它是顺时针方向:上、右、下、左。

grid-area 值的顺序是

  • grid-row-start
  • grid-column-start
  • grid-row-end
  • grid-column-end

对于英语,从左到右意味着顺序是

  • top
  • left
  • bottom
  • right

这是逆时针方向!所以与我们对边距和填充的处理方式相反。一旦你意识到 grid-area 将世界视为“块和内联”,你就可以记住我们正在设置两个开始,然后设置两个结束。一旦你知道了,它就会变得更加合乎逻辑!

混合书写模式和网格布局

除了显示文档之外,使用适合语言的正确写入模式,写入模式可以在其他情况下为 ltr 的文档中以创造性的方式使用。在下一个示例中,我有一个网格布局,其中一侧有一组链接。我使用写入模式将它们在列轨道中侧向翻转。

css
.wrapper {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 1fr auto;
  font:
    1em Helvetica,
    Arial,
    sans-serif;
}
.wrapper nav {
  writing-mode: vertical-lr;
}
.wrapper ul {
  list-style: none;
  margin: 0;
  padding: 1em;
  display: flex;
  justify-content: space-between;
}
.wrapper a {
  text-decoration: none;
}
html
<div class="wrapper">
  <div class="content">
    <p>
      Turnip greens yarrow ricebean rutabaga endive cauliflower sea lettuce
      kohlrabi amaranth water spinach avocado daikon napa cabbage asparagus
      winter purslane kale. Celery potato scallion desert raisin horseradish
      spinach carrot soko. Lotus root water spinach fennel kombu maize bamboo
      shoot green bean swiss chard seakale pumpkin onion chickpea gram corn pea.
      Brussels sprout coriander water chestnut gourd swiss chard wakame kohlrabi
      beetroot carrot watercress. Corn amaranth salsify bunya nuts nori azuki
      bean chickweed potato bell pepper artichoke.
    </p>
    <p>
      Nori grape silver beet broccoli kombu beet greens fava bean potato
      quandong celery. Bunya nuts black-eyed pea prairie turnip leek lentil
      turnip greens parsnip. Sea lettuce water chestnut eggplant winter purslane
      fennel azuki bean earthnut pea sierra leone bologi leek soko chicory
      celtuce parsley jícama salsify.
    </p>
  </div>
  <nav>
    <ul>
      <li><a href="">Link 1</a></li>
      <li><a href="">Link 2</a></li>
      <li><a href="">Link 3</a></li>
    </ul>
  </nav>
</div>

物理值和网格布局

我们在构建网站时经常遇到物理属性,虽然网格放置和对齐属性和值尊重写入模式,但你可能想要对网格执行一些操作,这些操作迫使你使用物理属性和值。在关于 框对齐和网格 的指南中,我演示了自动边距在网格区域中的工作方式。使用自动边距将一个项目推离其他项目也是一个常见的 flexbox 技巧,但是这也将布局绑定到物理空间。

如果你在网格区域内使用绝对定位,那么你将再次使用物理偏移量将项目推到网格区域内。关键是要意识到,是物理属性和逻辑属性和值之间的张力。例如,请注意你可能需要更改你的 CSS 以适应从 ltrrtl 的切换。

所有内容的逻辑属性!

我们新的布局方法使我们能够使用这些逻辑值来放置项目,但是,一旦我们开始将它们与用于边距和填充的物理属性结合起来,我们需要记住这些物理属性不会根据写入模式而改变。

CSS 逻辑属性规范 意味着你可以在你的 CSS 中使用 逻辑等效项 作为属性,例如 margin-leftmargin-right。这些属性和值在现代浏览器中得到了很好的支持。你对块和内联的了解,通过网格,将帮助你了解如何使用它们。