如何使弹性容器居中但左对齐弹性项目

Posted

技术标签:

【中文标题】如何使弹性容器居中但左对齐弹性项目【英文标题】:How to center a flex container but left-align flex items 【发布时间】:2017-10-22 03:30:54 【问题描述】:

我希望弹性项目居中,但是当我们有第二行时,有 5 个(来自下图)低于 1 并且不在父项中居中。

这是我所拥有的一个例子:

ul 
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0;
  padding: 0;

li 
  list-style-type: none;
  border: 1px solid gray;
  margin: 15px;
  padding: 5px;
  width: 200px;
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>

http://jsfiddle.net/8jqbjese/2/

【问题讨论】:

【参考方案1】:

Flexbox 挑战与限制

挑战在于将一组 flex 项目居中并在环绕时左对齐。但是除非每行有固定数量的盒子,并且每个盒子都是固定宽度的,否则目前这对于 flexbox 是不可能的。

使用问题中发布的代码,我们可以创建一个新的 flex 容器来包装当前的 flex 容器 (ul),这将允许我们将 uljustify-content: center 居中。

那么ul 的弹性项目可以与justify-content: flex-start 左对齐。

#container 
    display: flex;
    justify-content: center;


ul 
    display: flex;
    justify-content: flex-start;

这会创建一组居中的左对齐弹性项目。

这种方法的问题在于,在某些屏幕尺寸下,ul 的右侧会出现一个间隙,使其不再居中显示。

发生这种情况是因为在 flex 布局(实际上是一般的 CSS)中容器:

    不知道元素何时换行; 不知道以前占用的空间现在是空的,并且 不会重新计算其宽度以收缩包裹较窄的布局。

右边空白的最大长度是容器期望的弹性项目的长度。

在下面的演示中,通过水平调整窗口大小,您可以看到空白的来来去去。

DEMO


更实用的方法

使用 inline-block媒体查询 可以在不使用 flexbox 的情况下实现所需的布局。

html

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>

CSS

ul 
    margin: 0 auto;                  /* center container */
    width: 1200px;
    padding-left: 0;                 /* remove list padding */
    font-size: 0;                    /* remove inline-block white space;
                                        see https://***.com/a/32801275/3597276 */


li 
    display: inline-block;
    font-size: 18px;                 /* restore font size removed in container */
    list-style-type: none;
    width: 150px;
    height: 50px;
    line-height: 50px;
    margin: 15px 25px;
    box-sizing: border-box;
    text-align: center;


@media screen and (max-width: 430px)  ul  width: 200px;  
@media screen and (min-width: 431px) and (max-width: 630px)  ul  width: 400px;  
@media screen and (min-width: 631px) and (max-width: 830px)  ul  width:600px;   
@media screen and (min-width: 831px) and (max-width: 1030px)  ul  width: 800px;  
@media screen and (min-width: 1031px) and (max-width: 1230px)  ul  width: 1000px;  

上面的代码渲染了一个水平居中的容器,其中包含左对齐的子元素,如下所示:

DEMO


其他选项

Properly sizing and aligning the flex item(s) on the last row

Desandro Masonry

Masonry 是一个 javascript 网格布局库。它 通过根据可用的元素将元素放置在最佳位置来工作 垂直空间,有点像石匠在墙上装石头。你有 可能在整个 Internet 上都在使用它。

来源:http://masonry.desandro.com/

CSS Grid Layout Module Level 1

这个 CSS 模块定义了一个基于网格的二维布局系统,针对用户界面设计进行了优化。在网格布局模型中,网格容器的子项可以定位到预定义的灵活或固定大小布局网格中的任意槽中。

来源:https://drafts.csswg.org/css-grid/

【讨论】:

是的,很多人想要做并最终使用 flexbox 的实际上只是创建一个网格。幸运的是,当达到更最终的状态时,CSS Grids 将覆盖这一点。 已将 this post 链接到您的。我还有另一个版本如何解决相同的问题,但它可能是一个骗局,所以请看一下并自行决定是否要关闭它。再加上 1 以获得很好的解释。 也许另一个想法是在父包装器上执行margin:0 auto,以便所有内容都以页面为中心。从那时起,所有子组件(即第一个 flex-container)只是进行正常的流行过程吗?似乎这可以变得简单。【参考方案2】:

你可以用 CSS Grid 来实现它,只需使用repeat(autofit, minmax(width-of-the-element, max-content))

ul 
       display: grid;
       grid-template-columns: repeat(auto-fit, minmax(210px, max-content));
       grid-gap: 16px;
       justify-content: center;
       padding: initial;


li 
    list-style-type: none;
    border: 1px solid gray;
    padding: 5px;
    width: 210px;
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
</ul>

http://jsfiddle.net/rwa20jkh/

【讨论】:

有趣。但不会消除右侧的间隙或使网格居中 @Red 出了点问题。我将justify-items: center 更改为justify-content:center,现在它完美居中。 我不明白minmax 中的210px 部分。我如何使用相同但没有210px 的人为限制? flexbox 没有这样的限制。我想要与 flexbox 完全相同的结果,但内容区域必须像您的解决方案一样居中。 嗨@AndreyMikhaylov-lolmaus,当您想为所有元素设置固定宽度时,此方法有效。在问题中,它表示为width:200px,在我的示例中,当我设置width:210px时,我还必须在minmax部分中添加它 @Joe82 感谢您的澄清! ? 你知道一种让它适用于任意宽度元素的方法吗?【参考方案3】:

不知何故,@Joe82 的回答对我不起作用。但是,我发现这是正确的方法。在阅读了关于auto-fitauto-fill 的this 文章后,我发现自动调整会在可能的情况下创建新列;但是,它会折叠它们,以便网格项填满整个可用空间,如果它们的最大宽度允许的话。

感兴趣的人:auto-fill 也会尽可能创建新列,但不会让它们折叠,因此它会创建空的可见列,这会占用空间。 您可以在下图中看到这一点:

因此,我将repeat(auto-fit, minmax(10rem, 1fr) 用于`grid-template-columns。

然后我将justify-items 设置为center,这将内联轴上的网格区域内的项目对齐。

我还想在列和行之间留出一些“边距”,所以我用简写添加了row-gap1remcolumn-gap

因此,我将以下 CSS 添加到我的 div 中,其中包含网格项:

.card-section 
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));

我知道这并不是 OP 想要实现的目标,但也许它可以帮助与我有同样问题并偶然发现这个问题的人。

【讨论】:

【参考方案4】:

您可以放置​​与其他元素具有相同类的不可见元素(出于展示目的已在示例中删除)并将高度设置为 0。这样,您将能够将项目对齐到网格的最开始。

示例

<div class="table-container">
  <div class="table-content">
    <p class="table-title">Table 1</p>
    <p class="mesa-price">$ 20</p>
  </div>
  
  <!-- Make stuff justified start -->
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
  <div class="table-content" style="opacity: 0; cursor: default; height: 0; margin-bottom: 0;"></div>
</div>

结果

【讨论】:

【参考方案5】:

正如@michael 所建议的,这是当前 flexbox 的一个限制。但是如果你还想使用flexjustify-content: center;,那么我们可以通过添加一个虚拟的li 元素并分配margin-left 来解决这个问题。

    const handleResize = () => 
        const item_box = document.getElementById('parentId')
        const list_length  = item_box.clientWidth
        const product_card_length = 200 // length of your child element
        const item_in_a_row = Math.round(list_length/product_card_length)
        const to_be_added = item_in_a_row - parseInt(listObject.length % item_in_a_row) // listObject is the total number items
        const left_to_set = (to_be_added - 1 ) * product_card_length // -1 : dummy item has width set, so exclude it when calculating the left margin 
        const dummy_product = document.querySelectorAll('.product-card.dummy')[0]
        dummy_product.style.marginLeft = `$left_to_setpx`
    
    handleResize() // Call it first time component mount
    window.addEventListener("resize", handleResize); 

检查此fiddle (resize and see ) 或video for reference

【讨论】:

【参考方案6】:

通过边距获得所需样式的一种方法是执行以下操作:

#container 
    display: flex;
    justify-content: center;


#innercontainer 
    display: flex;
    flex: 0.9; -> add desired % of margin
    justify-content: flex-start;

【讨论】:

【参考方案7】:

我在使用 React Native 编码时遇到了这个问题。您可以使用 FlexBox 获得一个优雅的解决方案。在我的特殊情况下,我试图使用 alignItems 将三个 flex 框(Flex:2)居中。我想出的解决方案是使用两个空 s,每个都带有 Flex: 1。

<View style=alignItems: 'center', flexWrap: 'wrap', flexDirection: 'row'>
  <View style=flex: 1 />
    // Content here
  <View style=flex: 1 />
</View>

很容易转换为 web / CSS。

【讨论】:

你误解了这个问题。 OP 没有询问如何将 3 个项目居中,他们询问如何将第二行的项目左对齐,而 all 项目作为一个组居中,因此您的解决方案不起作用。跨度> 【参考方案8】:

我发现解决此问题的最简单方法是简单地添加一些具有可见性的占位符:隐藏。这样,它在包裹时保持正确的间距。

【讨论】:

与多年前接受的答案相比,这并没有增加任何有用的东西。 我不同意。最初的问题是如何使用弹性容器来做到这一点,而公认的答案是使用弹性容器以外的东西。如果您想使用 flex 容器,只需添加一些隐藏可见性的占位符,就很容易实现 OP 的要求。这样,所有内容都保持居中,最后一行左对齐。如果/当稍后添加更多项目时,只需使用下一个占位符。有很多方法可以实现相同的目标,但如果您想使用 flex,这是一种非常简单的方法,可以很好地保持格式。 只有知道物品的包装方式后才能添加占位符。也就是说,它仅适用于一种显示尺寸。不幸的是,这不是一个通用的解决方案。 @MattCrossette -- 接受的答案(有一个答案的链接准确地说明了这一点)和这里的另一个答案已经表明了这一点,因此你的答案没有添加任何东西。此外,这个技巧已经被建议/回答了很多次,使这个问题成为重复的,所以不是添加更多的答案,而是应该投票/标记是这样的。 @JohnP -- 这是一个通用的解决方案,无论显示大小如何,都会在最后一行左对齐元素。主要技巧是确保 ghost 元素 比列少不超过 1 个,并将垂直大小属性设置为0,这样它们就不会垂直影响任何东西,例如高度,边距顶部/底部等。就像我的这个答案一样:***.com/a/44482228/2827823

以上是关于如何使弹性容器居中但左对齐弹性项目的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Flexbox 使一个弹性项目居中对齐并右对齐另一个

不知道如何沿主轴单独对齐我的弹性项目

弹性项目没有居中

如何使弹性项目不填充弹性容器的高度? [复制]

滚动弹性容器不适合居中的项目[重复]

flexbox弹性盒子布局