在 CSS Flexbox 中,为啥没有“justify-items”和“justify-self”属性?

Posted

技术标签:

【中文标题】在 CSS Flexbox 中,为啥没有“justify-items”和“justify-self”属性?【英文标题】:In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?在 CSS Flexbox 中,为什么没有“justify-items”和“justify-self”属性? 【发布时间】:2015-12-09 15:46:32 【问题描述】:

考虑弹性容器的主轴和交叉轴:

来源:W3C

要沿主轴对齐弹性项目,有一个属性:

justify-content

要沿交叉轴对齐弹性项目,需要三个属性:

align-content align-items align-self

在上图中,主轴是水平的,横轴是垂直的。这些是弹性容器的默认方向。

但是,这些方向可以很容易地与flex-direction 属性互换。

/* main axis is horizontal, cross axis is vertical */
flex-direction: row;
flex-direction: row-reverse;

/* main axis is vertical, cross axis is horizontal */    
flex-direction: column;
flex-direction: column-reverse;

(交叉轴始终垂直于主轴。)

我在描述轴的工作原理时的意思是,这两个方向似乎都没有什么特别之处。主轴,交叉轴,它们在重要性方面是相同的,flex-direction 可以很容易地来回切换。

那么为什么交叉轴会获得两个额外的对齐属性呢?

为什么align-contentalign-items 合并为主轴的一个属性?

为什么主轴没有得到justify-self属性?


这些属性有用的场景:

将弹性项目放置在弹性容器的角落#box3 align-self: flex-end; justify-self: flex-end;

使一组弹性项目右对齐 (justify-content: flex-end) 但第一个项目左对齐 (justify-self: flex-start)

考虑一个包含一组导航项和一个徽标的标题部分。使用justify-self,徽标可以向左对齐,而导航项保持在最右侧,并且整个事物可以平滑地调整(“弯曲”)以适应不同的屏幕尺寸。

在一排三个弹性项目中,将中间项目附加到容器的中心(justify-content: center)并将相邻项目与容器边缘对齐(@9​​87654350@ 和justify-self: flex-end)。

请注意,space-aroundspace-between 的值在 如果相邻项的宽度不同,justify-content 属性将不会使中间项以容器为中心。

#container 
  display: flex;
  justify-content: space-between;
  background-color: lightyellow;

.box 
  height: 50px;
  width: 75px;
  background-color: springgreen;

.box1 
  width: 100px;

.box3 
  width: 200px;

#center 
  text-align: center;
  margin-bottom: 5px;

#center > span 
  background-color: aqua;
  padding: 2px;
<div id="center">
  <span>TRUE CENTER</span>
</div>

<div id="container">
  <div class="box box1"></div>
  <div class="box box2"></div>
  <div class="box box3"></div>
</div>

<p>note that the middlebox will only be truly centered if adjacent boxes are equal width</p>

jsFiddle version


在撰写本文时,flexbox spec 中没有提到 justify-selfjustify-items

然而,在CSS Box Alignment Module 中,这是 W3C 的未完成提案,即建立一套通用的对齐属性以供所有盒子模型使用,有这样的:

来源:W3C

您会注意到 justify-selfjustify-items 正在考虑中...但不适用于 flexbox


我将重申主要问题:

为什么没有“justify-items”和“justify-self”属性?

【问题讨论】:

您希望justify-self 如何为弹性项目工作?假设你有项目 a,b,c,d 有额外的空间分布在它们周围,而弹性容器有 justify-content: space-between,所以它们最终像 |a b c d|。添加例如是什么意思justify-self: center 或 'justify-self: flex-end` 只是到项目 'b' 那里?你希望它去哪里? (我在这里的一个答案中看到了一些演示,但我没有看到它通常可以工作的明确方式。) (或者:假设我们有justify-content: flex-start,所以项目一开始就很拥挤,就像|abcd |。如果你把justify-self: [anything]放在项目'b'上,你希望它做什么那里?) @dholbert,您写道:您希望 justify-self 如何为弹性项目工作? 我想说与 auto 边距已经在弹性项目上工作没有太大区别项目。在您的第二个示例中,项目 d 上的 justify-self: flex-end 会将其移动到远端。这本身就是一个很棒的功能,auto margins 已经可以做到。我通过演示发布了答案。 我在这里主要看到更多的用例,而且用例很棒——但棘手的一点是如何将其硬塞到@987654370 的 实际 方式中@ 和 justify-self 被指定,因此有冲突的情况(如我询问的场景)被明确和明智地定义。正如我在此处的回答中所指出的,justify|align-self 是关于在一个较大的框中对齐项目,该框的大小与justify|align-self 值无关——在主轴上没有这样的框,用于对齐的弹性项目。 RE “与自动边距没有什么不同” - 我实际上是在询问您如何想象 justify-selfjustify-content 在它们发生冲突的情况下(例如我列出的场景)会如何交互。自动边距根本justify-content 交互——它们在justify-content 有机会使用它之前偷走了所有的包装空间。因此,自动边距并不能很好地模拟其工作原理。 【参考方案1】:

这是在 www 样式列表和 Tab Atkins(规范编辑)provided an answer explaining why 上提出的。我会在这里详细说明。

首先,让我们假设我们的 flex 容器是单行的 (flex-wrap: nowrap)。在这种情况下,主轴和交叉轴之间显然存在对齐差异——主轴上堆叠了多个项目,但交叉轴上只有一个项目堆叠。因此,在横轴上有一个可自定义的每个项目“align-self”是有意义的(因为每个项目都是单独对齐的,单独对齐),而在主轴上没有意义(因为在那里,项目共同对齐)。

对于多行 flexbox,相同的逻辑适用于每个“flex line”。在给定的行中,项目在交叉轴上单独对齐(因为每行只有一个项目,在交叉轴上),而不是在主轴上集体对齐。


这是另一种表达方式:所以,所有 *-self*-content 属性都是关于如何在事物周围分配额外空间。但主要区别在于 *-self 版本适用于该轴中只有一个事物的情况,而*-content 版本适用于可能存在许多事物的情况轴。单件与多件的场景是不同类型的问题,因此它们有不同类型的可用选项——例如,space-around / space-between 值对 *-content 有意义,但对 @ 没有意义987654332@.

SO:在 flexbox 的主轴中,有很多东西可以分配空间。所以*-content 属性在那里有意义,但*-self 属性没有意义。

相比之下,在交叉轴上,我们同时拥有 *-self*-content 属性。一个决定我们如何在 许多 flex 行周围分配空间 (align-content),而另一个 (align-self) 决定如何在 单个 flex 项周围分配空间在交叉轴上,在给定的柔性线内。

(我在这里忽略了*-items 属性,因为它们只是为*-self 建立默认值。)

【讨论】:

我了解justify-self 可能在轴上有多个项目而不是一个项目时出现问题。但是我真的希望他们能进一步研究它,在多个项目的情况下,justify-self 的行为如何,因为在某些情况下这可能非常有用。例如 (***.com/questions/32378953/…)。 在该邮件列表上很好找到。试图绕开它,因为我仍然看到 justify-self 的良好用例可能性。 我添加了更多的说明,解释了*-self 是关于我们只有 一个 事情要对齐的情况,而*-content 是关于我们有 许多要对齐的东西。是不是更清楚了一点? 是的,更清楚了。我很欣赏这个解释。但这似乎都归结为规范作者的简单偏好,而不是基于逻辑的特殊需求。来自mailing list you referenced:*-self 属性仅在孩子独自在该轴上时才有效。 为什么?似乎没有这个必要。这是一个武断的决定。一种偏好。事实上,auto 边距,也是规范的一部分,启用 *-self 与行中的多个项目对齐。没有明确的原因为什么关键字属性也不能。【参考方案2】:

我知道这不是一个答案,但我愿意为这件事做出贡献。如果他们可以为 flexbox 发布 justify-self 以使其真正灵活,那就太好了。

我相信,当轴上有多个项目时,justify-self 最合乎逻辑的行为方式是将自身与其最近的邻居(或边缘)对齐,如下所示。

我真的希望 W3C 注意到这一点,并且至少会考虑它。 =)

这样,无论左右框的大小如何,您都可以拥有真正居中的项目。当其中一个盒子到达中心盒子的点时,它会简单地推动它,直到没有更多空间可以分配。

制作精美布局的难易程度无穷无尽,看看这个“复杂”的例子。

【讨论】:

@Mark 这太棒了!感谢您抽出宝贵时间起草此文件。我希望你不介意,但我已经在这里提交了:discourse.wicg.io/t/flexbox-justify-self-property/1146 @Zaqx 当然,曝光越多越好。真诚地希望他们能找到一种方法来实现这一点,我很乐意在这方面弄脏我的手。 嗨,马克,@Zaqx,我发布了一个答案,可能涵盖了这个答案中提到的一些用例。我发现在不需要justify-selfjustify-items 的情况下仍然可以在主轴上做很多事情。 @Michael_B 很高兴您正在了解有关 flexbox 的更多信息,并感谢您花时间将笔记格式化为答案。 Margin: auto 确实很酷(尽管您会发现实现 2009 和 2012 版本的 flexbox 规范的浏览器没有等效的功能,这大大降低了在生产站点上使用它的能力)。但是,即使使用支持 margin:auto 的浏览器,如果没有 justify-self 属性或类似属性,在存在空间时相对于其容器居中的项目的主要用例仍然是不可能的。 @Zaqx,感谢您的反馈。是的,我同意你的看法,auto 边距不能完全替代 justify-self。我很小心地通过说auto 边距将涵盖一些用例来表达我之前的评论。正如您所指出的,当相邻项目的大小不同时,它无法将项目居中。但是,它确实提供了更多对齐弹性项目的选项。当我第一次开始学习 flexbox 时,我认为 justify-content 和不可见的间隔项是唯一的方法。【参考方案3】:

沿主轴对齐 Flex 项目的方法

如问题所述:

要沿主轴对齐弹性项目,有一个属性:justify-content

要沿交叉轴对齐弹性项目,需要三个属性:align-contentalign-items and align-self

问题接着问:

为什么没有justify-itemsjustify-self 属性?

一个答案可能是:因为它们不是必需的。

flexbox specification 提供了两种方法来沿主轴对齐弹性项目:

    justify-content 关键字属性,以及 auto margins

调整内容

justify-content 属性沿弹性容器的主轴对齐弹性项目。

它应用于弹性容器,但只影响弹性项目。

有五个对齐选项:

flex-start ~ Flex 项目在行首被打包。

flex-end ~ Flex 项目在行尾打包。

center ~ 弹性物品被包装到线的中心。

space-between ~ Flex 项目是均匀分布的,第一个项目与容器的一个边缘对齐,最后一个项目与另一边对齐。第一项和最后一项使用的边取决于flex-direction 和writing mode(ltrrtl)。

space-around ~ 与space-between 相同,只是两端有半角空格。


自动边距

使用auto margins,弹性项目可以居中、隔开或打包到子组中。

与应用于弹性容器的justify-content 不同,auto 边距用于弹性项目。

它们通过消耗指定方向上的所有可用空间来工作。


将一组弹性项目向右对齐,但第一个项目向左对齐

来自问题的场景:

使一组弹性项目右对齐 (justify-content: flex-end) 但让第一项左对齐 (justify-self: flex-start)

考虑一个包含一组导航项和一个徽标的标题部分。和 justify-self 徽标可以左对齐,而导航项目保持不变 最右边,整个事情顺利调整(“弯曲”)到 不同的屏幕尺寸。


其他有用的场景:


在角落放置一个弹性项目

来自问题的场景:

将弹性项目放在角落.box align-self: flex-end; justify-self: flex-end;


将弹性项目垂直和水平居中

margin: autojustify-content: centeralign-items: center 的替代品。

在 flex 容器上代替这段代码:

.container 
    justify-content: center;
    align-items: center;

您可以在弹性项目上使用它:

.box56 
    margin: auto;

centering a flex item that overflows the container 时,此替代方案很有用。


居中一个弹性项目,并在第一个和边缘之间居中第二个弹性项目

弹性容器通过分配可用空间来对齐弹性项目。

因此,为了创建相等的平衡,使中间项目可以在容器中居中,旁边有单个项目,必须引入平衡。

在下面的示例中,引入了不可见的第三个弹性项目(方框 61 和 68)以平衡“真实”项目(方框 63 和 66)。

当然,这种方法在语义上也没什么大不了的。

或者,您可以使用伪元素代替实际的 DOM 元素。或者您可以使用绝对定位。此处介绍了所有三种方法:Center and bottom-align flex items

注意:上面的示例仅在最外面的项目高度/宽度相等时才有效 - 就真正的居中而言。当弹性项目的长度不同时,请参见下一个示例。


当相邻项目的大小不同时将弹性项目居中

来自问题的场景:

在一行三个弹性项目中,将中间的项目贴在容器的中心(justify-content: center)并对齐相邻的 项目到容器边缘(justify-self: flex-startjustify-self: flex-end)。

请注意,如果相邻项具有不同的宽度 (see demo),justify-content 属性上的值 space-aroundspace-between 将不会使中间项相对于容器居中。

如前所述,除非所有 flex 项目的宽度或高度相同(取决于flex-direction),否则中间项目不能真正居中。这个问题为justify-self 属性提供了一个强有力的案例(当然是为了处理任务而设计的)。

#container 
  display: flex;
  justify-content: space-between;
  background-color: lightyellow;

.box 
  height: 50px;
  width: 75px;
  background-color: springgreen;

.box1 
  width: 100px;

.box3 
  width: 200px;

#center 
  text-align: center;
  margin-bottom: 5px;

#center > span 
  background-color: aqua;
  padding: 2px;
<div id="center">
  <span>TRUE CENTER</span>
</div>

<div id="container">
  <div class="box box1"></div>
  <div class="box box2"></div>
  <div class="box box3"></div>
</div>

<p>The middle box will be truly centered only if adjacent boxes are equal width.</p>

这里有两种解决这个问题的方法:

解决方案 #1:绝对定位

flexbox 规范允许absolute positioning of flex items。这允许中间项完全居中,而不管其兄弟项的大小。

请记住,与所有绝对定位元素一样,这些项目将从document flow 中删除。这意味着它们不会占用容器中的空间并且可以重叠它们的兄弟姐妹。

在下面的示例中,中间项目以绝对定位居中,外部项目保持流入。但同样的布局可以通过反向方式实现:以justify-content: center 居中中间项目,绝对定位外部项目。

解决方案 #2:嵌套 Flex 容器(无绝对定位)

.container 
  display: flex;

.box 
  flex: 1;
  display: flex;
  justify-content: center;

.box71 > span  margin-right: auto; 
.box73 > span  margin-left: auto;  

/* non-essential */
.box 
  align-items: center;
  border: 1px solid #ccc;
  background-color: lightgreen;
  height: 40px;
<div class="container">
  <div class="box box71"><span>71 short</span></div>
  <div class="box box72"><span>72 centered</span></div>
  <div class="box box73"><span>73 loooooooooooooooong</span></div>
</div>

它是这样工作的:

*** div (.container) 是一个弹性容器。 每个子 div (.box) 现在都是一个弹性项目。 为每个.box 项目分配flex: 1,以便平均分配容器空间。 现在项目占用了行中的所有空间并且宽度相等。 使每个项目成为(嵌套的)弹性容器并添加justify-content: center。 现在每个span 元素都是居中的弹性项目。 使用 flex auto 边距将外部 spans 左右移动。

您也可以放弃 justify-content 并专门使用 auto 边距。

但是justify-content 可以在这里工作,因为auto 边距始终具有优先权。来自规范:

8.1. Aligning with auto margins

在通过justify-contentalign-self 对齐之前,任何 正的可用空间分配到该维度的自动边距。


justify-content:空间相同(概念)

回到justify-content 一会儿,这里有一个更多选项的想法。

space-same ~ space-betweenspace-around 的混合体。 Flex 项目是均匀分布的(如 space-between),除了两端不是半角空格(如 space-around),两端都有全角空格。

这种布局可以通过弹性容器上的::before::after 伪元素来实现。

(信用:@oriol 为代码,@crl 为标签)

更新:浏览器已经开始实现 space-evenly,它完成了上述工作。详情见此贴:Equal space between flex items


PLAYGROUND(包括以上所有示例的代码)

【讨论】:

上面的答案涵盖了主轴justify-contentauto边距。对于硬币的另一面——交叉轴align-itemsalign-selfalign-content——见这篇文章:***.com/q/42613359/3597276 @MarkW,您正在为justify-self 属性提供案例...auto 边距很有帮助,但justify-self: center 将是理想的。解决您提出的问题的方法是在对面创建不可见的重复项。在这里查看我的答案:***.com/q/38948102/3597276 您的space-same 概念现在已成为现实。它叫space-evenly,但目前只有Firefox支持:developer.mozilla.org/en-US/docs/Web/CSS/justify-content @benface,是的,你是对的。感谢您指出了这一点。实际上,我在其他答案中一直在写 space-evenly:***.com/q/45134400/3597276 我真的希望 CSS Consortium 的人(或者他们如何称呼自己)能够考虑到 justify-self 的想法......我有时觉得你有时必须采取多么复杂的变通办法来做到这一点很荒谬实现问题解决方案......好像有人真的知道你上面提到的那些“技巧”;)【参考方案4】:

我知道这不使用 flexbox,但是对于三个项目的简单用例(一个在左侧,一个在中心,一个在右侧),这可以通过在父级上使用 display: grid 轻松完成,@ 987654323@ 用于孩子,justify-self 用于定位这些孩子。

<div style="border: 1px solid red; display: grid; width: 100px; height: 25px;">
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: left;"></div>
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: center;"></div>
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: right;"></div>
</div>

【讨论】:

感谢您的回答,但它并没有真正解决问题。此外,还有一种更简单的方法来完成您的布局:jsfiddle.net/fga89m2o【参考方案5】:

我刚刚找到了解决这个问题的方法,或者至少是我的问题。 我使用的是justify-content: space-around 而不是justify-content: space-between;

这样结束元素会粘在顶部和底部,如果需要,您可以自定义边距。

【讨论】:

【参考方案6】:

这是由于 flexbox 的一维特性,沿轴可能有多个项目,因此无法证明单个项目的合理性。要在 flexbox 中沿主内联轴对齐项目,请使用 justify-content 属性。

参考:Box alignment in CSS Grid Layout

【讨论】:

以上是关于在 CSS Flexbox 中,为啥没有“justify-items”和“justify-self”属性?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 flexbox 中的宽高比 CSS 属性有时会被忽略? [复制]

CSS Flexbox 问题:为啥我的 flexchildren 的宽度会受到其内容的影响?

为啥这个 flexbox 布局在 Safari 中被破坏了?

为啥 Haskell 中没有隐式并行性?

为啥 flexbox 不像 div 中的其他元素那样居中我的图像?

css [css:centering]没有flexbox的css居中的注释。 #css