是否可以在 flexbox 项目之间创建灵活的间距?

Posted

技术标签:

【中文标题】是否可以在 flexbox 项目之间创建灵活的间距?【英文标题】:Is it possible to create flexible spacing between flexbox items? 【发布时间】:2020-11-14 02:40:48 【问题描述】:

我正在尝试创建一个在项目之间具有灵活间距的水平导航菜单。 Flexbox 似乎是合适的选择,但我无法让它按我的预期工作。

要求是:

如果有足够的可用空间,则在每个项目之间留出 4rems 的空间 随着视口宽度的减小,均匀地缩小项目之间的空间,最小为 2rem 如果视口宽度进一步减小,则保持 2rem 间距并缩小项目本身

我希望它能够容纳可变数量的项目(会有一个最大值)。

我得到的最接近的方法是在项目上使用 2rem 填充,然后使项目本身成为弹性容器,并缩小伪元素,但缩小非常不均匀。

html

<div class="container">
  <div class="item">
    Item 1
  </div>
  <div class="item">
    Item 2
  </div>
  <div class="item">
    Item 3 With Long Name
  </div>
  <div class="item">
    Item4WithLongNameNoSpaces
  </div>
  <div class="item">
    Item 5
  </div>
</div>

CSS

.container 
  display: flex;


.item + .item 
  display: flex;
  padding-left: 2rem;


.item + .item:before 
  content: "";
  display: block;
  width: 2rem;
  flex-shrink: 1000;

Codepen:https://codepen.io/qubaji/pen/PoZLEbW

如果我能找到 flex-grow/flex-shrink 值的正确组合,似乎 flexbox 可以做到这一点,但我不能完全做到。非常感谢任何帮助!

【问题讨论】:

@MrT 那是我最初的尝试,但是这对项目之间的空间没有上限,而我希望它有一个最大值 编辑:哦,你删除了关于 justify-content: space-between 的评论,但我'会在这里留下我的回复,以防其他人有同样的问题 是的,对不起,没想到你会这么快拿起它:) 这是一个好问题,我可能会尝试 justify-content: space-evenly 或 space-between 并在您的项目之间放置 max-width: 2rem 的空 div。有时使用空 div 作为间隔是一个非常有用的解决方案 @Warden330 justify-content: space-evenlyspace-between 不符合要求,但间隔 div 是一个很好的选择 【参考方案1】:

我会考虑 display:contents 让您的伪元素与弹性项目处于同一级别,但这可能会限制您可以应用于项目的 CSS:

.container 
  display: flex;
  outline:1px solid red;


.item 
  display: contents;


.item + .item::before 
  content: "";
  width: 4rem;
  min-width:2rem;
  flex-shrink:9999;
  outline:1px solid green;
<div class="container">
  <div class="item">
    Item 1
  </div>
  <div class="item">
    Item 2
  </div>
  <div class="item">
    Item 3 With Long Name
  </div>
  <div class="item">
    Item4WithLong
  </div>
  <div class="item">
    Item 5
  </div>
</div>

既然你说你的元素将被限制在一个最大数量,这里是一个 CSS 网格的想法:

/* extra container to hide the overflow */
.wrapper 
  overflow:hidden; 
  outline:1px solid red;

/**/
.container 
  display: inline-grid;
  vertical-align:top;
  /* the item will take only the auto (even columns)
     the 1fr will define the shrinkable gap
  */
  grid-auto-columns:1fr auto; 
  justify-content:flex-start;
  grid-auto-flow:column; /* column flow */
  margin-left:-2rem; /* to hide the pseudo element */

/* this will define the size if the 1fr */
.container:before 
  content:"";
  width:2rem;

/* */

.item + .item 
  padding-left:2rem; /* the fixed gap */


/* you can easily generate the below using SASS/Less*/
.item:nth-child(1) grid-column:2
.item:nth-child(2) grid-column:4
.item:nth-child(3) grid-column:6
.item:nth-child(4) grid-column:8
.item:nth-child(5) grid-column:10
.item:nth-child(6) grid-column:12
.item:nth-child(7) grid-column:14
.item:nth-child(8) grid-column:16
.item:nth-child(9) grid-column:18
.item:nth-child(10) grid-column:20
<div class="wrapper">
  <div class="container">
    <div class="item">
      Item 1
    </div>
    <div class="item">
    Item 2
  </div>
    <div class="item">
      Item 3 With Long Name
    </div>
    <div class="item">
      Item4WithLong
    </div>
    <div class="item">
      Item 5
    </div>
  </div>
</div>

【讨论】:

谢谢,我没有听说过 display: contents;,它看起来很棒而且效果很好 - 但不幸的是,目前这似乎没有得到很好的支持 (caniuse.com/#feat=css-display-contents) 这也是一个很酷的主意!不幸的是,由于文本换行,您要么必须使用white-space: nowrap;,要么在换行时处理元素之间的额外空间。我已经意识到这是 CSS 的一个限制(或功能!),父母无法知道它的子元素何时换行。本质上我想“收缩包装”这些元素,但它看起来不像纯 CSS 是可能的。 @piemanji 是的,您无法处理多余的空间,因为这就是 CSS 的工作原理。父母不知道内容何时会换行。相关:***.com/a/37413580/8620333【参考方案2】:

Warden330 建议的使用间隔 div 的可能解决方案(或近似值)。

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

.item 
  white-space: nowrap;

.spacer 
  min-width: 2rem;
  max-width: 4rem;
  width: 100%;
  flex-shrink: 2;
<div class="container">
  <div class="item">
    Item 1
  </div>
  <div class="spacer"></div>
  <div class="item">
    Item 2
  </div>
  <div class="spacer"></div>
  <div class="item">
    Item 3 With Long Name
  </div>
  <div class="spacer"></div>
  <div class="item">
    Item4WithLongNameNoSpaces
  </div>
  <div class="spacer"></div>
  <div class="item">
    Item 5
  </div>
</div>

【讨论】:

感谢您的建议。我确实尝试了一些非常相似的东西,但我不想使用white-space: nowrap,因为我确实想要包裹物品 - 但发现 flexbox 不知道什么时候会发生这种情况,所以你最终会得到什么看起来像是一个包裹物品和下一个物品之间的巨大空间。使用white-space: nowrap;,这实际上适用于我最初的想法,没有间隔。 有时我们会坚持简单的想法,但通常最明显的答案是最好的。我的意思是在你的情况下使用媒体查询,给菜单更多的间距,实际上可以给你更高的精度,带来更好的结果。只是一个建议

以上是关于是否可以在 flexbox 项目之间创建灵活的间距?的主要内容,如果未能解决你的问题,请参考以下文章

给包装的 flexbox 项目提供垂直间距

使用 flexbox 列换行的 Chrome v Firefox 中的垂直间距差异

如何使用 flexbox 使 flex 容器的子 div 具有相同的间距? [复制]

如何创建一个水平菜单,每个项目之间的宽度和间距相等?

Flexbox 布局续

在堆栈视图中设置某些项之间的空间