如何使内联块元素填充行的其余部分?

208

使用CSS和两个inline-block(或其他)DIV标签,是否可能实现这样的效果,而不是使用表格?

表格版本如下(添加了边框以便查看):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
<table style="width:100%;">
<tr>
<td style="border:1px solid black;width:100px;height:10px;"></td>
<td style="border:1px solid black;height:10px;"></td>
</tr>
</table>
</body>
</html>
它生成一个带有固定宽度(而不是百分比宽度)的左侧列和一个右侧列,该列会扩展以填充该行的剩余空间。听起来很简单,对吧?此外,由于没有使用"float"属性,因此父容器的高度会适当地扩展以包含内容的高度。
--开始抱怨-- 我看过固定宽度侧栏的多列布局的“清除修正”和“至高无上”的实现,它们都很糟糕且复杂。它们会颠倒元素的顺序,使用百分比宽度或使用浮动、负边距属性,以及"left"、"right"和"margin"属性之间的关系也很复杂。此外,这些布局对子像素非常敏感,即使添加一个像素的边框、内边距或外边距也会导致整个布局崩溃并将整个列包装到下一行。例如,即使尝试在一行上放置4个元素,每个元素的宽度设置为25%,四舍五入误差也是一个问题。 --结束抱怨--
我尝试过使用"inline-block"和"white-space:nowrap;",但问题是我无法让第二个元素填充该行的剩余空间。在某些情况下,将宽度设置为"width:100%-(LeftColumWidth)px"之类的值可以解决问题,但是在宽度属性中执行计算并不受支持。

1
我认为除了将其转换为display: table-*结构之外,没有其他明智的方法可以解决这个问题。虽然这种方法可行,但也不是真正的“更语义化”(它是一个可怕的div混合体),并且会破坏IE6的兼容性。个人而言,我会坚持使用<table>,除非有人能想出一个天才简单的想法,可以在不使用<table>的情况下解决问题。 - Pekka
53
是的。我一直遇到所有这些“避免使用表格”的论点,它们的措辞让你听起来像是一个无能、懒惰的白痴,如果你仍然使用表格来进行布局。快进十年,这仍然是一个理想主义的幻想。事实是,流动布局语义对于固定但灵活的用户界面和表单布局非常不利。事实是,聪明的人会在方便的情况下使用表格,因为他们已经尝试了每种可能的CSS解决方案,并意识到它们都不完美,且比使用表格复杂得多。 - Triynko
4
浮动元素?给我一个可行的代码,其中行尾的元素不会出现不可预测的换行,边框和边距也不会破坏布局。这就是它们的问题所在。此外,自动大小的父容器是否能够正确地扩展以包含浮动元素而不需要使用“清除浮动”技巧?我觉得不行。 - Triynko
3
@Triynko: 这是我之前制作的内容:http://jsfiddle.net/thirtydot/qx32C/ - 我认为它符合你的大部分要求。请您对我创建的演示进行批评,然后我会尝试进行修正。 - thirtydot
你提到了空格,这在表格中确实有效。 - Carson Reinke
显示剩余9条评论
9个回答

176

@tribalvibes:像这个?还是这个 - thirtydot
18
"overflow:hidden"不是解决方案。假设你不想隐藏右侧容器的溢出内容,但这并不能使右侧容器的大小填满行中剩余的空间。这是一个两年前的问题,我至今仍未标记答案,因为仍然没有令人满意的答案。 - Triynko
3
即使你使用了'overflow:hidden',通常不会隐藏任何东西(至少如果你只在其中放置文本)。div内部的文本/元素将被排列以适应div的大小(当然,如果你有一个比div更大的元素,则除外)。 - CpnCrunch
很遗憾,如果你左右反转,这个就不起作用了 :( - Srneczek
1
@RMorrisey:可能只是需要在div上添加一些box-sizing:border-box。 只是一个猜测,因为您没有提供展示您描述的行为的演示文稿。 话虽如此,基于display:table的解决方案通常更好。 这是一个非常古老的问题,但我认为在这个问题中,由于OP的行为,我尝试避免与表格有关的任何内容。 - thirtydot
显示剩余2条评论

73

使用Flexbox的现代解决方案:

.container {
    display: flex;
}
.container > div {
    border: 1px solid black;
    height: 10px;
}

.left {
   width: 100px;
}

.right {
    width: 100%;
    background-color:#ddd;
}
<div class="container">
  <div class="left"></div>
  <div class="right"></div>
</div>

http://jsfiddle.net/m5Xz2/100/


4
显示弹性布局并设置宽度为100%...记住。 - dreamerkumar
12
在使用flex布局时,为什么不用width: 100%而是使用flex: 1 - Itai Bar-Haim
对于那些刚接触 flexbox 的人来说:flex: 1flex-grow: 1 的简写。它是一个组合属性:flex: <grow> <shrink> <basis> - tanius
1
只是一个快速的提示,display: flex在IE < 11中不受支持,在11中非常有缺陷。 - Eric Shields
1
@EricShields 这不应该阻止任何人使用Flexbox。现在我们有 flexbugs,你知道的。 - Neurotransmitter

48
与常见的现代浏览器兼容(IE 8+):http://jsfiddle.net/m5Xz2/3/

.lineContainer {
    display:table;
    border-collapse:collapse;
    width:100%;
}
.lineContainer div {
    display:table-cell;
    border:1px solid black;
    height:10px;
}
.left {
    width:100px;
}
 <div class="lineContainer">
    <div class="left">left</div>
    <div class="right">right</div>
</div>


11
反对使用表格的论点与其呈现特性无关,而与难以管理的标记、样式/文档混淆和不当语义有关。这些论点都不适用于"display:table"。 - Rich Remer
2
这并没有回答如何使 inline-block 填充行的其余部分。 - Neurotransmitter
2
@TranslucentCloud 我同意我的答案并没有完全回答问题的标题,但是它提供了一种使用div填充可用宽度的方法,正如问题主体所要求的那样。 - Maxime Pacary
1
我非常喜欢这个解决方案。你不必使用一些奇怪的样式,这些样式来自隐藏的CSS逻辑(例如overflow hidden)。 - Chaoste

7
您可以在流体元素上使用calc(100%-100px),以及为两个元素设置display:inline-block。
请注意,标签之间不应有任何空格,否则您还需要在计算中考虑该空格。
.left{
    display:inline-block;
    width:100px;
}
.right{
    display:inline-block;
    width:calc(100% - 100px);
}


<div class=“left”></div><div class=“right”></div>

快速示例:http://jsfiddle.net/dw689mt4/1/

3

我使用了flex-grow属性来实现这个目标。你需要为父容器设置display: flex,然后你需要为你想要填充剩余空间的块设置flex-grow: 1,或者像tanius在评论中提到的那样,只需设置flex: 1


0

0

如果您不能使用overflow: hidden(因为您不想使用overflow: hidden)或者您不喜欢CSS hack/解决方法,那么您可以使用JavaScript。请注意,由于它是JavaScript,可能效果不如CSS。

var parent = document.getElementsByClassName("lineContainer")[0];
var left = document.getElementsByClassName("left")[0];
var right = document.getElementsByClassName("right")[0];
right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
window.onresize = function() {
  right.style.width = (parent.offsetWidth - left.offsetWidth) + "px";
}
.lineContainer {
  width: 100% border: 1px solid #000;
  font-size: 0px;
  /* You need to do this because inline block puts an invisible space between them and they won't fit on the same line */
}

.lineContainer div {
  height: 10px;
  display: inline-block;
}

.left {
  width: 100px;
  background: red
}

.right {
  background: blue
}
<div class="lineContainer">
  <div class="left"></div>
  <div class="right"></div>
</div>

http://jsfiddle.net/ys2eogxm/


0
一种使用网格布局和分数单位(fr)的解决方案:

/* For debugging and visibility */
html, body {
    border: 2px  solid navy;
}
.grid-layout { 
    border: thick solid sandybrown;
    background-color: gray;
} 
.grid-layout div:nth-child(odd) {
    border: 2px solid brown;
    background-color: azure;
}
.grid-layout div:nth-child(even) {
    border: 2px solid red;
    background-color: lightyellow;
}

/* Grid layout.
 * Horizontal and vertical gaps.
 * two columns, fixed and responsive.
 * Note no containing div per line.
 */
.grid-layout {
    display: grid;
    gap: 4px 2px ;
    grid-template-columns: 100px 1fr;
}
<p>How to make an element fill the remainder of the line?</p>
<p>Note no encompassing div per line.</p>

<div class="grid-layout">
    <div>Lorem ipsum line 1</div>
    <div>Lorem ipsum dolor sit amet,
         consectetur adipiscing elit,
         sed do eiusmod tempor incididunt ut labore
         et dolore magna aliqua.</div>
    <div>Lorem ipsum line 2</div>
    <div>Ut enim ad minim veniam,
         quis nostrud exercitation ullamco laboris
         nisi ut aliquip ex ea commodo consequat.</div>
</div>

一个类似的解决方案是使用包含 div 元素:

 .lineContainer {
   display: grid;
   gap: 2px 4px;
   grid-template-columns: 100px 1fr;
 }
<p>Display grid per line.</p>
<div class="lineContainer">
  <div style="border:1px solid black; ">
    Lorem ipsum &hellip;
  </div>
  <div style="border:1px solid black; ">
    Lorem ipsum dolor sit amet,
    consectetur adipiscing elit,
    sed do eiusmod tempor incididunt ut labore
    et dolore magna aliqua.
  </div>
</div>


0

如果像我一样,您想要的是即使左侧框换行也能扩展到行尾的内容,那么JavaScript是唯一的选择。

我会利用calc功能来实现这个目标:

Array.from(document.querySelectorAll(".right")).forEach((el) => {
  el.style.width = `calc(100% - ${el.offsetLeft + 1}px)`;
});
.container {
    outline: 1px solid black;
}

.left {
   outline: 1px solid red;
}

.right {
    outline: 1px solid green;
}
<div class="container">
  <span class="left">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin tristique aliquet quam, at commodo lorem fringilla quis.</span>
  <input class="right" type="text" />
</div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接