New CSS Logical Properties! - The Next Step of CSS Evolution

原文链接:https://medium.com/@elad/new-...
原文作者:Elad Shechter

简介

在过去,大多数程序猿在思考布局时总是习惯于从“上下左右”的角度出发。这是因为在早期,互联网主要用于上传文档,而不是为了实现我们现在熟知的复杂网站架构。

这也是为什么没有人思考多语言网站的需求。

New CSS Logical Properties! - The Next Step of CSS Evolution

目前为止,支持类似 RTL/LTR 这种多方向网站的最佳方式,依然是使用 SASSSASS 变量。
(如果你希望了解更多内容,可以阅读我的另一篇文章《The Best Way to RTL Websites with SASS!》)。

这些新的逻辑属性让我们能够在改动最少样式的情况下控制我们的网站,而不用担心网站使用的是何种语言(无论是英语、阿拉伯语、日语还是其他语言)。

现在让我们开始吧!

思考 CSS 逻辑属性的方式

当我们讨论盒模型时,我们已经对下面这张图很熟悉了:

New CSS Logical Properties! - The Next Step of CSS Evolution
<font color=#999>盒模型物理属性(旧方案)

它在以前和现在一直是正确的,但类似 margin-left, padding-right, border-top 等经典物理特性其实已经时日不多了。

在你开始使用新的逻辑属性之前,你需要停止从 left/right 或者 top/bottom来思考问题,而是使用 inline-start/inline-endblock-start/block-end 来替代它们。

New CSS Logical Properties! - The Next Step of CSS Evolution
<font color=#999>逻辑属性(新方案)

Inline axis (译者理解为内联轴,即阅读方向)

让我们用英文作为例子,英文的阅读方向是从左到右,这是属性的内联部分。当我们想要把一系列元素排在同一行时,我们通常会使用 display: inline,照这个思路就很容易记住 inline axis 的含义了。

举例来说,padding-inline-start 会在当前语句开始位置的旁边设置一个内边距:

在英语中:       padding-inline-start = padding-left
在阿拉伯语中:padding-inline-start = padding-right
在日语中:       padding-inline-start = padding-top

Block axis (块轴)

让我们忘掉 top 和 bottom 相关属性的含义(不再表示“上下”),而是把 top 当做网站的开始,把 bottom 当做网站的结束。只要想像几个 display:block 的元素首尾相连,就很容易记住这点了。

到这时你仍然会问自己,难道这不是一贯的做法吗?

这个问题解释起来有点复杂。因为目前并没有其他解决方案,所以目前所有的网站,不管是使用的是什么语言,都是这么处理的。

要知道使用日文或者其他东方语言的网站(按布局方向)可能是从右到左,而非从上到下的!为了理解这种网站的表现,我们可以想象一下将浏览器向右旋转90度,我们会发现网站的滚动条不再是垂直方向了,它变成了水平方向!

举个例子(block cases):
在英语和阿拉伯语中: padding-block-start = padding-top
在日语中:      padding-block-start = padding-right

New CSS Logical Properties! - The Next Step of CSS Evolution
<font color=#999>(日文网站)

新的盒模型属性

(margin, padding and border)

在理解了 inlineblock axis 之后,你就可以根据需要来使用它们了。

用英文网站举例来说:

margin
margin-block-start = margin-top
margin-block-end = margin-bottom
margin-inline-start = margin-left
margin-inline-end = margin-left

padding
padding-block-start = padding-top
padding-block-end = padding-bottom
padding-inline-start = padding-left
padding-liline-end = padding-right

border
border-block-start = border-top
border-block-end = border-bottom
border-inline-start = border-left
border-inline-end = border-right

逻辑尺寸

WidthHeightinline-sizeblock-size 所取代。

WidthHeight 属性同样需要适应新的尺寸表达方法。一旦我们理解了 inline/block 方法,就非常容易理解它们的尺寸要如何用新属性来表示。在英文网站,宽度属性用 inline-size 表示,高度属性用 block-size 表示。

举个栗子(inline/block size):
在英文与阿拉伯语中(LTR/RTL)
Width = inline-size
Height = block-size

在一个阅读顺序是每行里自上而下的语言中,比如日语,我们会看到相反的表达方式:
inline-size = Heightblock-size = Width

对于 min/max 属性,只需要把 min/max 书写在属性前面:min-inline-size: 300px; max-block-size: 100px;

New CSS Logical Properties! - The Next Step of CSS Evolution
<font color=#999>新旧盒模型属性对比

CSS Positions

top/right/bottom/left这些旧的位置属性已经发展出了一组新的属性名,它们都带有 inset 前缀,分别是:
inset-block-start / inset-inline-end / inset-block-end / inset-inline-start

在英文网站中(LTR):
top = inset-block-start
bottom = inset-block-end
left = inset-inline-start
right = inset-inline-end

/* OLD TECHIQUE */
.popup {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
} 

/* NEW TECHIQUE */
.popup {
    position: fixed;
    inset-block-start: 0;  /*top - in English*/
    inset-block-end: 0;    /*bottom - in English*/
    inset-inline-start: 0; /*left - in English*/
    inset-inline-end: 0;   /*right - in English*/
}

第一眼看到这些代码,你可能会质疑为什么我们需要如此复杂的命名?!其实这是有充分理由的。在新的属性名中,这些属性依然可以使用类似 padding/margin/border 的书写方式混合起来,而这种新的位置简写特性在以前是不存在的(如下所示)。

.popup{
   position:fixed;
   inset:0 0 0 0;   /*top, right, bottom, left - in English*/
}

New CSS Logical Properties! - The Next Step of CSS Evolution
New CSS Logical Properties! - The Next Step of CSS Evolution

CSS Floats

Float 非常简单,它只有2个值 left/right,分别用 inline-start/inline-end 来代替。

在英文网站中(LTR):
float: left = float: inline-start
float: right = float: inline-end

Text-align

它比 floats 更简单,只需要用 start/end 代替 left/right 即可。

在英文网站中(LTR):
text-align: left = text-align: start
text-align: right = text-align: end

更多

Resize:常用于 <textarea>,它的值 horizontal/vertical 升级为 inline/block 代替。

在英文网站中(LTR):
resize: horizontal = resize: inline
resize: vertical = resize: block

background-position:目前为止还没有任何浏览器中针对该属性进行过修改,但如果你研究的足够深入,你就会在 Mozilla 的 MDN 中找到有关 background-position-inline & background-position-block 的资料。虽然这些文档还不够完善,但工作人员已经在进行相关的工作了。

其他:正如其他与方向有关的属性一样,我们还可以预测类似 transform-origin 这样的属性也会被更新。

CSS Grid & CSS Flexbox

这两个特性本身已经使用了新的逻辑属性方法进行构建,因此如果你之前已经使用了这两个特性,那么没有必要用本文提到的新方法去替代它们。

理解逻辑属性的工作流程

虽然刚开始看起来很复杂,但实际上是非常容易使用的。在写样式时,不再需要考虑跨语言支持的问题。你只需要使用逻辑属性替代旧的物理属性,然后让它们匹配你喜欢的语言即可。

根据语言来应用对齐

当我们学习了所有新逻辑属性的更新后,我们就可以运用2个特性来分别定义块轴对齐(block axis alignment)(网站文档流方向)和内联轴对齐(文字阅读方向)。

Writing-mode 属性(块轴)

在定义网站文档流时,大多数时候是从上到下的。但正如上文提到的,特定语言有可能从右到左(日语),甚至从左到右(蒙语)。在这两种情况中,我们就得使用水平滚动条来替代惯用的垂直滚动条。

注意:writing-mode 有3个主要的值:horizontal-tb / vertical-rl / vertical-lr
这3个值的名称有一点令人困惑。这是因为他们既可以表示块轴方向,还可以表示内联轴的文字对齐(inline-axis)。这显然让人很不爽,因为文字对齐其实是多余的,这只能让人感到困惑。

为了消除这个困惑,建议忽略属性值内表示内联轴的部分,只关注块轴部分。

举例来说:

  • writing-mode: horizontal-tb; = Top to Bottom Flow,英文(默认)
  • writing-mode: vertical-rl; = Right to Left Flow,日语
  • writing-mode: vertical-lr; = Left to Right Flow,蒙语

就我而言,我更倾向于让属性值只包括:tb/rl/lr (block-axis part),以此消除潜在的困惑。

日语中 writing-mode 是这么定义的:

html {
    writing-mode: vertical-rl;
}

New CSS Logical Properties! - The Next Step of CSS Evolution

Direction property (inline axis) - 方向属性(内联轴)

只有在 writing-mode 属性处于默认的水平模式时,方向属性才能够定义文字方向是 left-to-right 还是 right-to-left。如果我们将 writing-mode 改为垂直模式中的一种后,文字方向就会发生改变:
left-to-right 会变为 top-to-bottomright-to-left 会变为 bottom-to-top

以阿拉伯语为例:

html {
    direction: rtl;
}

令人惊奇的是,将一个自上而下的网站变为一个带有横向滚动条的自右向左的网站是多么的容易。

这里是我写的一个demo,在 Firefox 中浏览最佳(目前为止 Firefox 支持更多的新属性)

Live Example (试试选择其他语言选项):

浏览器支持情况

  • 除 Edge 外,大部分主流浏览器支持所有的盒模型属性(margin / padding / border)以及新的 width / height (inline-size, block-size) 属性。
  • 除 Edge 外,大部分主流浏览器支持 text-align 的新属性值。
  • Floats / Positions / Resize 的值或属性只被 Firefox 所支持。

关于逻辑属性的相关问题

随着这些新属性的诞生,我们也必须面对随之而来的新问题。比如,当我们想用简写的方式把所有 margin 属性写出来时,像这样:

margin: 1px 2px 3px 4px;

你是无法预测它会如何被浏览器解析的。

因为如果网站使用的是物理属性,这些属性值就会被解析为:margin-top / margin-right / margin-bottom / margin-left,但如果网站使用的是逻辑属性,这些值就应该是:margin-block-start / margin-inline-end / margin-block-end / margin-inline-start

在英文网站中,物理属性与逻辑属性的表现是一致的。在使用其他语言的网站中,当我们使用类似 margin 的简写时,我们希望它能够根据 direction 属性或 writing-mode 属性来工作。

但如何能让简写自动根据directionwriting-mode 去解析呢?这一直是个悬而未决的问题。针对该问题,我曾给出一些建议:++suggestion that can solve the issue at github csswg-drafts++。如果你有更好的解决方案,欢迎你在链接中评论!

如果你现在要使用逻辑属性,那你就必须把它们的属性名完整地写出来,而不能使用简写。

在这里我给出一个可选的解决方案:

html{
   flow-mode:physical; 
       /*or*/
   flow-mode:logical;
}
.box{
  /*will be interpreted according to the HTML flow-mode value*/
   margin:10px 5px 6px 3px;
   padding:5px 10px 2px 7px;
}

关于响应式设计的问题

为了制作一个完善的 demo,我尝试在媒体查询里使用 max-width 的新属性 max-inline-size,在 left-to-right 的条件下,max-inline-size 的效果会与 max-width 一样,而在 right-to-left 的条件下,比如日语这样的语言,新属性的效果就会与 max-height 一样。有点遗憾的是目前浏览器并不支持在媒体查询(media query)中解析新属性。

/*Not Working*/
@media (max-inline-size:1000px){
  .main-content{
    background:red;
    grid-template-columns:auto;
  }
}

一些值得思考的变化

在深入学习并理解了逻辑属性的概念后,我一边写文章一边想,还有一些被忽略的改动也应该被纳入未来的更新范围中:

  • line-height 可以改为 line-size
  • border-width 可以改为 border-size

不过真实情况似乎不太一样,至少 border-width 和我想的不一样。它更新为逻辑属性后,属性名中依然带有 Width
举个例子:border-block-start-width

相关推荐