如何居中放置弹性容器,但将弹性项目左对齐


91

我希望将flex项居中,但是当我们有第二行时,将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/

Answers:


79

Flexbox挑战与局限

挑战在于将一组弹性项目居中并在包装上将它们左对齐。但是,除非每行有固定数量的框,并且每个框都是固定宽度,否则flexbox目前无法做到这一点。

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

然后,的flex项目ul可以与左对齐justify-content: flex-start

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

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

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

此方法的问题在于,在某些屏幕尺寸下,的右侧将有一个缝隙ul,使其不再居中。

在此处输入图片说明 在此处输入图片说明

发生这种情况是因为在Flex布局(实际上是CSS)中,容器:

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

右边空白的最大长度是容器预期在其中的flex项目的长度。

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

演示


更实用的方法

无需flexbox使用inline-block媒体查询就可以实现所需的布局。

的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://stackoverflow.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; } }

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

在此处输入图片说明

演示


其他选择


3
是的,人们想要做的很多事情最终都使用flexbox,实际上只是创建一个网格。幸运的是,当达到更最终的状态时,CSS网格将涵盖此问题。
TylerH '16

1
将此文章链接到您的文章。我在那里还有一个解决相同问题的方法,不过它可能是一个骗子,因此请看看并自己决定是否要关闭它。加上1来说明这一点。
艾森(Ason)

也许另一个想法是margin:0 auto在父包装上执行,以便所有内容都集中在页面上。从这一点来看,所有子组件(即第一个flex容器)都只是正常的流行处理?似乎可以简化此操作。
klewis

12

您可以使用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/


有趣。但是并不能消除右侧的间隙或居中对齐
红色

2
@Red一件事错了。我更改justify-items: centerjustify-content:center,现在它居中完美。
Joe82

我不明白210px里面的部分minmax。在没有人为限制的情况下,我该怎么做210px?flexbox没有这种限制。我希望得到与flexbox完全相同的结果,但是内容区域必须像解决方案中那样居中。
Andrey Mikhaylov-lolmaus

1
@ AndreyMikhaylov-lolmaus,您好,当您要为所有元素设置固定宽度时,此方法有效。在问题中,它表示为width:200px,在我的示例中,按照我的设置width:210px,我还必须在minmax部分中添加它
Joe82

@ Joe82感谢您的澄清!🙏您知道一种使其适用于任意宽度元素的方法吗?
Andrey Mikhaylov-lolmaus

0

正如@michael所建议的,这是当前flexbox的限制。但是,如果您仍然想使用flexand justify-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_set}px`
    }
    handleResize() // Call it first time component mount
    window.addEventListener("resize", handleResize); 

检查此小提琴(调整大小并查看)视频以供参考


0

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

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

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

0

您可以放置​​与其他类相同的不可见元素(出于示例目的,在示例中删除了该元素),并将高度设置为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>

结果

在此处输入图片说明


-1

我在用React Native编码时遇到了这个问题。使用FlexBox可以找到一个优雅的解决方案。在我的特定情况下,我试图使用alignItems将三个flex框(Flex:2)居中放置在另一个中。我想出的解决方案是使用两个empty,每个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个项目居中,而是询问如何使第2行上的项目左对齐,而所有项目都作为一个组居中,因此您的解决方案不起作用。
艾森
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.