[css] How to make an inline-block element fill the remainder of the line?

Is such a thing possible using CSS and two inline-block (or whatever) DIV tags instead of using a table?

The table version is this (borders added so you can see it):

<!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>

It produces a left column with a FIXED WIDTH (not a percentage width), and a right column that expands to fill THE REMAINING SPACE on the line. Sounds pretty simple, right? Furthermore, since nothing is "floated", the parent container's height properly expands to encompass the height of the content.

--BEGIN RANT--
I've seen the "clear fix" and "holy grail" implementations for multi-column layouts with fixed-width side column, and they suck and they're complicated. They reverse the order of elements, they use percentage widths, or they use floats, negative margins, and the relationship between the "left", "right", and "margin" attributes are complex. Furthermore, the layouts are sub-pixel sensitive so that adding even a single pixel of borders, padding, or margins will break the whole layout, and send entire columns wrapping to the next line. For example, rounding errors are a problem even if you try to do something simple, like put 4 elements on a line, with each one's width set to 25%.
--END RANT--

I've tried using "inline-block" and "white-space:nowrap;", but the problem is I just can't get the 2nd element to fill the remaining space on the line. Setting the width to something like "width:100%-(LeftColumWidth)px" will work in some cases, but performing a calculation in a width property is not really supported.

This question is related to css layout fixed-width

The answer is


You can use calc (100% - 100px) on the fluid element, along with display:inline-block for both elements.

Be aware that there should not be any space between the tags, otherwise you will have to consider that space in your calc too.

.left{
    display:inline-block;
    width:100px;
}
.right{
    display:inline-block;
    width:calc(100% - 100px);
}


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

Quick example: http://jsfiddle.net/dw689mt4/1/


When you give up the inline blocks

.post-container {
    border: 5px solid #333;
    overflow:auto;
}
.post-thumb {
    float: left;
    display:block;
    background:#ccc;
    width:200px;
    height:200px;
}
.post-content{
    display:block;
    overflow:hidden;
}

http://jsfiddle.net/RXrvZ/3731/

(from CSS Float: Floating an image to the left of the text)


Compatible with common modern browers (IE 8+): http://jsfiddle.net/m5Xz2/3/

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


If you can't use overflow: hidden (because you don't want overflow: hidden) or if you dislike CSS hacks/workarounds, you could use JavaScript instead. Note that it may not work as well because it's JavaScript.

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

http://jsfiddle.net/ys2eogxm/


See: http://jsfiddle.net/qx32C/36/

_x000D_
_x000D_
.lineContainer {_x000D_
    overflow: hidden; /* clear the float */_x000D_
    border: 1px solid #000_x000D_
}_x000D_
.lineContainer div {_x000D_
    height: 20px_x000D_
} _x000D_
.left {_x000D_
    width: 100px;_x000D_
    float: left;_x000D_
    border-right: 1px solid #000_x000D_
}_x000D_
.right {_x000D_
    overflow: hidden;_x000D_
    background: #ccc_x000D_
}
_x000D_
<div class="lineContainer">_x000D_
    <div class="left">left</div>_x000D_
    <div class="right">right</div>_x000D_
</div>
_x000D_
_x000D_
_x000D_


Why did I replace margin-left: 100px with overflow: hidden on .right?

EDIT: Here are two mirrors for the above (dead) link:


I've used flex-grow property to achieve this goal. You'll have to set display: flex for parent container, then you need to set flex-grow: 1 for the block you want to fill remaining space, or just flex: 1 as tanius mentioned in the comments.


A modern solution using flexbox:

_x000D_
_x000D_
.container {_x000D_
    display: flex;_x000D_
}_x000D_
.container > div {_x000D_
    border: 1px solid black;_x000D_
    height: 10px;_x000D_
}_x000D_
_x000D_
.left {_x000D_
   width: 100px;_x000D_
}_x000D_
_x000D_
.right {_x000D_
    width: 100%;_x000D_
    background-color:#ddd;_x000D_
}
_x000D_
<div class="container">_x000D_
  <div class="left"></div>_x000D_
  <div class="right"></div>_x000D_
</div>
_x000D_
_x000D_
_x000D_

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