根据内容平衡容器内的网格列宽

Balance grid column width within container, based on content

我有两个并排的网格列。我希望网格是其容器的宽度。在那个 space 中,我想确保每一列的内容始终尽可能多地可见。

我做了这个演示,其中网格宽度为 300 像素,两列内容可编辑,因此您可以键入以更改内容长度(因此 min-contentmax-content 的值将也会随着您的输入而改变)。

我正在使用 grid-template-columns: minmax(min-content, 1fr) minmax(min-content, 1fr);,这是我实现我想要的效果的最佳尝试,但仍然不够。

html, body {
  width: 300px;
}

html * {
  border: 1px solid black;
}

span {
  cursor: pointer;
}

body {
  display: grid;
  grid-template-columns: minmax(min-content, 1fr) minmax(min-content, 1fr);
}
<span contenteditable></span>
<span contenteditable></span>

当列中没有任何内容时,网格以 50/50 平衡。每列的宽度为 150 像素。这个不错。

当一栏中的内容超过 150 像素时,它会变宽并开始扩展到另一栏可用的 space 中。这个也不错

但是:当两列内容之和大于300px时,网格开始水平溢出:

相反,我希望将网格的宽度限制为 300 像素,并且最宽的单元格应自行缩小,直到尽可能多的较小单元格的内容可见:

并且应用了单元格的 overflow-x: ellipsis

这也应该发生在另一个方向。当前和不良行为:

期望的行为:

当每个单元格本身的宽度已经超过网格的一半时,在这种情况下为 150px(当前不希望的行为):

它们都应该缩小直到比例平衡(期望的行为):

最终(可选)目标是具有代表其实际内容宽度的受限宽度:


我很惊讶我还没有找到平衡并排网格列的标准解决方案,这似乎是一个常见的用例。它与此非常相似:,除了我不知道提前的比例而且它们是相互依赖的。如果能指出我可能遗漏的任何内容,我将不胜感激。

为了尝试实现这一点,我已经尝试了多种grid-template-columns值,但似乎存在一个CSS-表现力问题,即列的宽度不能依赖于内容其他列。不幸的是 calc(min-content/100%) 似乎使 属性 值无效。我可能只是缺少用纯 CSS 来完成它的方法,如果有 CSS-only 的答案,我会欣喜若狂。

从那以后我一直在尝试使用 JavaScript 但是因为使用 JavaScript 无法轻易发现最小内容和最大内容 我想我会在这里问一下,然后再投入几个小时来寻求解决方案我暂时想到的是:让网格宽度完全无限,测量每个单元格的outerWidth,然后设置grid-template-columns为每个单元格的outerWidth / sumOfBothOuterWidth百分比。所有这些也必须放入一些 MutationObserver 回调中,以便它可以在内容更改时重新计算宽度。幸运的是,因为使用百分比值而不是硬编码的值,调整 window/container 的大小应该会自动重绘。

有人可以推荐替代解决方案吗?

最好的答案是 CSS-only,我通常更喜欢需要较少 JavaScript DOM 操作和 JavaScript 计算的解决方案。

听起来您正在寻找一个两列、固定宽度的网格,其中列宽与其包含的文本内容成比例(并且溢出的文本内容是 t运行cated)。我认为下面的内容让您更接近,但是一旦合并的文本内容超过网格的宽度,您将 运行 陷入一些问题。一旦合并的文本内容超过网格的宽度,网格列将不会继续按比例调整大小。另外,如果你真的打算在你的网格中使用 contenteditable 元素,overflow: hiddentext-overflow: ellipsis 的组合将导致一些浏览器在文本开始溢出时停止显示你的输入(这意味着如果您输入足够多的字符,该列最终将显示为空)。

.grid {
  display: grid;
  grid-template-columns: repeat(2, auto);
  width: 300px;
}

.column {
  border: 1px solid gray;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
<div class="grid">
  <div class="column" contenteditable="true">
    abcdefghijklmnop
  </div>
  <div class="column" contenteditable="true">
    abcdefghijklmnopqrstuvwxyz
  </div>
</div>

在这种情况下,我认为 flexbox 是与网格结合使用的完美解决方案。您可以在网格行中放置一个 flex 元素,它可以轻松地处理您正在寻找的增长和收缩功能,只需最少 css 且无需 JS。

在我下面的示例中,内容最多的列会变大而不会溢出到下一列,而另一列会按比例缩小。 flex 容器的子元素被设置为等长和收缩(flex: 1 1)或者占用 150px(flex: 1 1 150)可用 space 如果内容小于可用宽度。 flex-basis 设置为 150,即您指定宽度的一半。对于更大的宽度,相应地调整 flex-basis。

*, ::before, ::after {
    box-sizing: border-box;
}

body {
    width: 300px;
}
    
html * {
    border: 1px solid black;
}

.flex-col {
    display: flex;
    flex-wrap: nowrap;
    gap: 1rem;
    
}

.flex-col > * {
    flex: 1 1 150;
}

.col {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
<div class="flex-col">
        <div class="col" contenteditable>Lorem ipsum dolor sit amet consectetur adipisicing elit. </div>
        <div class="col" contenteditable>
            Alias, soluta Lorem ipsum dolor sit, amet consectetur adipisicing elit. Veritatis natus odio dolorum. Dolorem minus, labore distinctio eum praesentium eos ullam ducimus repellat, rerum vel eveniet soluta laborum odit odio sequi. </div>
</div>