【问题标题】:How to specify line breaks in a multi-line flexbox layout?如何在多行 flexbox 布局中指定换行符?
【发布时间】:2015-06-26 06:35:40
【问题描述】:

有没有办法在多行flexbox中换行?

例如在this CodePen 中的每个第 3 项之后中断。

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
.item:nth-child(3n) {
  background: silver;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

喜欢

.item:nth-child(3n){
  /* line-break: after; */    
}

【问题讨论】:

  • 我有同样或非常相似的问题;我想打破每 4 个项目,所以我只是将每个 flex 项目的宽度设置为 25vw(或 25%)。因此,在您的情况下,对于每第三个项目,您将使用 33.3vw(或 33.3%)。完美地满足了我的需求。如果他们正在寻找更简单的方法,可能会对其他人有所帮助。
  • 本克拉克!太感谢了!你的答案是唯一有效的。您可以考虑将其添加为答案。 :-)

标签: html css flexbox


【解决方案1】:

最简单、最可靠的解决方案是在正确的位置插入弹性项目。如果它们足够宽 (width: 100%),它们将强制换行。

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}
.item:nth-child(4n - 1) {
  background: silver;
}
.line-break {
  width: 100%;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="line-break"></div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="line-break"></div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="line-break"></div>
  <div class="item">10</div>
</div>

但这很丑陋而且没有语义。相反,我们可以在 flex 容器内生成伪元素,并使用order 将它们移动到正确的位置。

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}
.item:nth-child(3n) {
  background: silver;
}
.container::before, .container::after {
  content: '';
  width: 100%;
  order: 1;
}
.item:nth-child(n + 4) {
  order: 1;
}
.item:nth-child(n + 7) {
  order: 2;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
</div>

但是有一个限制:flex 容器只能有一个::before 和一个::after 伪元素。这意味着您只能强制换行 2 次。

为了解决这个问题,您可以在 flex 项目中而不是在 flex 容器中生成伪元素。这样你就不会被限制为 2 个。但是那些伪元素不会是弹性项目,所以它们将无法强制换行。

不过幸运的是,CSS Display L3 已经引入了display: contents(目前只支持 Firefox 37):

元素本身不会生成任何框,但它的子元素和 伪元素仍然照常生成盒子。出于以下目的 框生成和布局,必须将元素视为具有 在文档中被其子元素和伪元素替换 树。

因此,您可以将display: contents 应用于 flex 容器的子容器,并将每个容器的内容包装在一个额外的包装器中。然后,弹性项目将是那些额外的包装器和子元素的伪元素。

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  display: contents;
}
.item > div {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
.item:nth-child(3n) > div {
  background: silver;
}
.item:nth-child(3n)::after {
  content: '';
  width: 100%;
}
<div class="container">
  <div class="item"><div>1</div></div>
  <div class="item"><div>2</div></div>
  <div class="item"><div>3</div></div>
  <div class="item"><div>4</div></div>
  <div class="item"><div>5</div></div>
  <div class="item"><div>6</div></div>
  <div class="item"><div>7</div></div>
  <div class="item"><div>8</div></div>
  <div class="item"><div>9</div></div>
  <div class="item"><div>10</div></div>
</div>

另外,根据 an old version of the spec,Flexbox 允许使用 break-beforebreak-after 或其旧 CSS 2.1 别名进行强制中断:

.item:nth-child(3n) {
  page-break-after: always; /* CSS 2.1 syntax */
  break-after: always; /* CSS 3 syntax */
}

但是这些强制换行符只适用于 Firefox,我认为它们不应该按照当前规范工作。新提议的方式(未在任何地方实施)是wrap-before or wrap-after

.item:nth-child(3n) {
  wrap-after: flex; /* New proposed syntax */
}

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}
.item:nth-child(3n) {
  page-break-after: always;
  break-after: always;
  wrap-after: flex;
  background: silver;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

【讨论】:

  • @nacho4d 因为不应修改 HTML 以用于样式目的。如果您改变主意并决定要 4 列而不是 3 列,则可能需要修改大量 HTML。与 break-after 解决方案相比,它只需要修改样式表中的选择器。
  • 我需要将 display: block; 添加到 .container ::before::after 伪类中,以使第二个解决方案在 IE 中工作。 YMMV!
  • @twined 这很奇怪,因为弹性项目应该被自动阻止。
  • 由于分页符显然已从规范中删除,是否有可能让您的第二个 sn-p 在列方向上运行而不让它扩展其容器的高度?我没有运气,将 flex-basis 设置为 100% / items 会拉伸它的高度。
  • 您的第二个建议似乎在 IE10 中不起作用。 IE11 和我测试过的所有其他浏览器都很好,但是 IE10 忽略了伪元素的顺序。
【解决方案2】:

对于以后的问题,也可以使用float属性并在每3个元素中清除它。

这是我做的一个例子。

.grid {
  display: inline-block;
}

.cell {
  display: inline-block;
  position: relative;
  float: left;
  margin: 8px;
  width: 48px;
  height: 48px;
  background-color: #bdbdbd;
  font-family: 'Helvetica', 'Arial', sans-serif;
  font-size: 14px;
  font-weight: 400;
  line-height: 20px;
  text-indent: 4px;
  color: #fff;
}

.cell:nth-child(3n) + .cell {
  clear: both;
}
<div class="grid">
  <div class="cell">1</div>
  <div class="cell">2</div>
  <div class="cell">3</div>
  <div class="cell">4</div>
  <div class="cell">5</div>
  <div class="cell">6</div>
  <div class="cell">7</div>
  <div class="cell">8</div>
  <div class="cell">9</div>
  <div class="cell">10</div>
</div>

【讨论】:

  • 这里的问题是 OP 声明解决方案必须使用 flexbox 或 display: flex;,而不是 display: inline-block;
  • 你可以写成.cell:nth-child(3n + 1)
【解决方案3】:

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}

.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
<div class="container">
  <div>
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
  </div>
  <div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
  </div>
  <div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
  </div>
  <div class="item">10</div>
</div>

您可以尝试将项目包装在像这里这样的 dom 元素中。有了这个,你不必知道很多 css,只要有一个好的结构就可以解决问题。

【讨论】:

  • 你可以让容器成为一个普通的display: block 并让那些新的 2 层 div 弹性盒。这适用于行。使用列模式时,将 div 替换为 span。
【解决方案4】:

@Oriol 有一个很好的答案,可悲的是,截至 2017 年 10 月,display:contentspage-break-after 都没有得到广泛支持,最好说是 Firefox 支持这个但不支持其他玩家,我想出了以下“hack”我认为这比在每 3 个元素之后的休息时间中进行硬编码更好,因为这会使页面变得对移动设备友好变得非常困难。

正如所说的那样,这是一个 hack,缺点是你需要添加很多额外的元素,但它可以做到这一点并且即使在过时的 IE11 上也可以跨浏览器工作。

“hack”是在每个 div 之后简单地添加一个附加元素,该元素设置为 display:none,然后使用 css nth-child 来决定其中哪一个应该实际可见,从而强制像这样的线刹车:

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}
.item:nth-child(3n-1) {
  background: silver;
}
.breaker {
  display: none;
}
.breaker:nth-child(3n) {
  display: block;
  width: 100%;
  height: 0;
}
<div class="container">
  <div class="item">1</div>
  <p class="breaker"></p>
  
  <div class="item">2</div>
  <p class="breaker"></p>
  
  <div class="item">3</div>
  <p class="breaker"></p>
  
  <div class="item">4</div>
  <p class="breaker"></p>
  
  <div class="item">5</div>
  <p class="breaker"></p>
  
  <div class="item">6</div>
  <p class="breaker"></p>
  
  <div class="item">7</div>
  <p class="breaker"></p>
  
  <div class="item">8</div>
  <p class="breaker"></p>
  
  <div class="item">9</div>
  <p class="breaker"></p>
  
  <div class="item">10</div>
  <p class="breaker"></p>
</div>

【讨论】:

  • 我还发现“display:contents”和“page-break-after”方法都不起作用,于是求助于这个“hack”。这被报告为一个 Chrome 错误,并标记为“WontFix”(参见bugs.chromium.org/p/chromium/issues/detail?id=473481),并解释为:“根据 CSS 工作组的说法,目前没有在使用 CSS 的弹性框中强制换行的方法。 "
  • 您可以使用选择器.container&gt;p 省去一点混乱。那么所有这些&lt;p&gt;&lt;/p&gt; 标签都不需要class 属性。当然不是重要。只是我懒惰的大脑为您的聪明解决方案找到了一个微小的、节省空间的调整。当然,它还依赖于没有其他&lt;p&gt; 标记作为.container div 的直接子级的用户。从技术上讲,您可以对所有其他 &lt;div&gt; 孩子做同样的事情,但是您在 .container 中拥有其他 &lt;div&gt;s 的可能性比在 &lt;p&gt;s 中的可能性要大得多,所以可能不是明智之举.
  • 用番茄、金、银的赞美
【解决方案5】:

我认为传统方式灵活且相当容易理解:

标记

<div class="flex-grid">
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>

    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>

    <div class="col-3">.col-3</div>
    <div class="col-9">.col-9</div>

    <div class="col-6">.col-6</div>
    <div class="col-6">.col-6</div>
</div>

创建 grid.css 文件:

.flex-grid {
  display: flex;
  flex-flow: wrap;
}

.col-1 {flex: 0 0 8.3333%}
.col-2 {flex: 0 0 16.6666%}
.col-3 {flex: 0 0 25%}
.col-4 {flex: 0 0 33.3333%}
.col-5 {flex: 0 0 41.6666%}
.col-6 {flex: 0 0 50%}
.col-7 {flex: 0 0 58.3333%}
.col-8 {flex: 0 0 66.6666%}
.col-9 {flex: 0 0 75%}
.col-10 {flex: 0 0 83.3333%}
.col-11 {flex: 0 0 91.6666%}
.col-12 {flex: 0 0 100%}

[class*="col-"] {
  margin: 0 0 10px 0;

  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

@media (max-width: 400px) {
  .flex-grid {
    display: block;
  }
}

我创建了一个example (jsfiddle)

尝试将窗口大小调整到 400px 以下,它是响应式的!

【讨论】:

  • 在这个解决方案中,元素是在一起的,想法是在它们之间留一个很长的空格。
【解决方案6】:

从我的角度来看,在弹性项目之间使用&lt;hr&gt;elements as line breaks 更符合语义。

.container {
  display: flex;
  flex-flow: wrap;
}

.container hr {
  width: 100%;
}
<div class="container">
  <div>1</div>
  <div>2</div>
  <hr>
  <div>3</div>
  <div>2</div>
  ...
</div>

在 Chrome 66、Firefox 60 和 Safari 11 中测试。

【讨论】:

  • 我也是这样做的,效果很好。添加 hr { flex-basis: 100%;高度:0;边距:0;边框:0; } 让休息变得无缝。
  • 我喜欢这种方法。注意:当使用gap: 10px; 时,行间距实际上是20px。要解决此问题,请指定一半大小的行间隙:gap: 5px 10px;
  • @Besworks:border 应设置为 none,而不是 0
  • @mark, border:0;border:none; 一样有效。见:stackoverflow.com/questions/2922909/…
  • 我怀疑这个解决方案的语义价值,但它确实有效。
【解决方案7】:

你想要一个语义换行符?

然后考虑使用&lt;br&gt;。 W3Schools 可能会建议您 BR 仅用于写诗(我的即将推出),但您可以更改样式,使其表现为 100% 宽度的块元素,将您的内容推送到下一行。如果“br”表示休息,那么它似乎比使用 hr 或 100% div 更适合我,并使 html 更具可读性。

在需要换行符的地方插入&lt;br&gt;,并像这样设置它的样式。

 // Use `>` to avoid styling `<br>` inside your boxes 
 .container > br 
 {
    width: 100%;
    content: '';
 }

您可以disable &lt;br&gt; with media queries,将display: 设置为blocknone(我已经包含了一个示例,但将其注释掉了)。

如果需要,您也可以使用order: 设置顺序。

您可以根据需要放置任意数量,使用不同的类或名称 :-)

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}

.container > br
{
  width: 100%;
  content: '';
}

// .linebreak1 
// { 
//    display: none;
// }

// @media (min-width: 768px) 
// {
//    .linebreak1
//    {
//       display: block;
//    }
// }
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <br class="linebreak1"/>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

无需局限于 W3Schools 所说的内容:

【讨论】:

  • 技术的一个扩展是在每第二个项目之后加上&lt;br class="2col"&gt;,在每三分之一之后加上&lt;br class="3col"&gt;。然后将一个类 cols-2 应用到容器并创建 css 以只为该数量的列启用适当的换行符。例如。 br { display: none; } .cols-2 br.2col { display: block; }
  • 不,br 不适用于 elements 的换行,它适用于 textdeveloper.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/…
  • 我会改变我的措辞,以免将其呈现为完美的解决方案,但在某些情况下,我认为这并不比其他 div 或伪元素解决方案更糟糕。也许我现在就去写一首关于它的诗。
  • 是的......一首诗会很好,不要忘记在这里发布一个链接:)......关于一个完美的解决方案,有一个(break-*显示在接受答案)虽然不幸的是它还没有到达跨浏览器,所以第二好的是使用一个本机填充其父级宽度的元素并将任何下一个兄弟姐妹推到他们自己的一行中,这再次在接受的答案中给出。因此,使用除块之外的任何其他元素在语义上会更糟,例如br
  • 请记住,您发布的是 W3Schools,而不是 W3C,它们没有关联。
【解决方案8】:

另一个不需要添加任何额外标记的可能解决方案是添加一些动态边距来分隔元素。

在例子的情况下,这可以在calc()的帮助下完成,只需将margin-leftmargin-right添加到3n+2元素(2、5、8)

.item:nth-child(3n+2) {
  background: silver;
  margin: 10px calc(50% - 175px);
}

片段示例

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
.item:nth-child(3n+2) {
  background: silver;
  margin: 10px calc(50% - 175px);
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

【讨论】:

  • 这值得一票。使用 flex 和 margin 的组合是支持换行符的一种非常简单的方法。如本答案所述,它也适用于calc
  • 我更喜欢这个,只是margin-right: 1px该项目,它会使下一个项目从新行开始。
  • @arvil 你能发布一个解决方案吗?
【解决方案9】:

我在这里尝试了几个答案,但都没有奏效。具有讽刺意味的是,真正起作用的是人们可以尝试的&lt;br/&gt; 的最简单替代方案:

&lt;div style="flex-basis: 100%;"&gt;&lt;/div&gt;

或者你也可以这样做:

&lt;div style="width: 100%;"&gt;&lt;/div&gt;

把它放在你想要换行的地方。它似乎甚至可以与相邻的&lt;span&gt; 一起使用,但我将它与相邻的&lt;div&gt; 一起使用。

【讨论】:

  • 100% 宽度的 div 是接受的答案中给出的第一个解决方案。
  • 没错,有点。他们被看不起的理由很糟糕(丑陋,真的吗?)。另外,我的回答是flex-basis
【解决方案10】:

我只是想把这个答案混在一起,旨在提醒您——在适当的条件下——你有时不需要过度考虑手头的问题。使用 flex: wrapmax-width 而不是 :nth-child 可能会实现您想要的。

ul {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  max-width: 420px;
  list-style-type: none;
  background-color: tomato;
  margin: 0 auto;
  padding: 0;
}

li {
  display: inline-block;
  background-color: #ccc;
  border: 1px solid #333;
  width: 23px;
  height: 23px;
  text-align: center;
  font-size: 1rem;
  line-height: 1.5;
  margin: 0.2rem;
  flex-shrink: 0;
}
<div class="root">
  <ul>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>
    <li>F</li>
    <li>G</li>
    <li>H</li>
    <li>I</li>
    <li>J</li>
    <li>K</li>
    <li>L</li>
    <li>M</li>
    <li>N</li>
    <li>O</li>
    <li>P</li>
    <li>Q</li>
    <li>R</li>
    <li>S</li>
    <li>T</li>
    <li>U</li>
    <li>V</li>
    <li>W</li>
    <li>X</li>
    <li>Y</li>
    <li>Z</li>
  </ul>
</div>

https://jsfiddle.net/age3qp4d/

【讨论】:

  • 请直接在答案中发布代码,而不是链接到其他地方,这样会更有帮助
猜你喜欢
  • 1970-01-01
  • 2016-01-02
  • 2014-01-11
  • 1970-01-01
  • 2017-06-07
  • 2014-08-04
  • 2017-06-14
  • 2021-05-19
相关资源
最近更新 更多