Shrink-to-fit menu items - first item grows

One way I've dealt with this issue is to apply width: 1px; to every <TH> where I'd like their cells to shrink. Then on each individual cell where I want to shrink to the content, I apply white-space: nowrap;. This prevents the cell from actually shrinking to 1px.

I'm currently using this method on a table of financial figures so I'm not sure if it works with longer paragraphs of text.


Welcome to the year 2014

Let's get flexible

We can now look forward to the future when Flexbox is standard. Currently a W3C Candidate Recommendation, Flexbox is currently limited by browser support (importantly, only IE 11 supports the current model).

Flexible navigation with a larger first-child

The markup

<nav>
    <a href="#">Fill</a>
    <a href="#">Item</a>
    <a href="#">Item</a>
    <a href="#">Item</a>
</nav>

The flex

The regular links get flex: 0 0 auto:

  • 0 - don't grow
  • 0 - don't shrink
  • auto - don't let the text overflow (auto is supposedly default, but text overflows without it set)

The first link gets flex: 1 0 auto:

  • 1 - take up the remaining width
  • 0 - don't shrink
  • auto - don't let the text overflow
nav {
  display: flex;
}
nav a {
  flex: 0 0 auto; 
}
nav a:first-child {
  flex: 1 0 auto;
}

This Flexbox guide is very helpful.

The combination (with added fluff)

Run the snippet below

/* 
For the purpose of this demo:
toggle active class on click
*/

$('nav a').on('click', function() {
  $('nav a').removeClass('active');
  $(this).toggleClass('active');
});
/* Foundation Properties */
nav {
  display: flex;
}
nav a {
  flex: 0 0 auto;
  text-align: center;
}
nav a:first-child {
  flex: 1 0 auto;
  text-align: right;
}

/* Fluff Properties */
body {
  background: #f5f5f5;
  margin: 0;
}
nav {
  max-width: 900px;
  margin: 0 auto;
  background: #3f51b5;
}
nav a {
  font-family: Helvetica;
  color: #c5cae9;
  font-size: 0.8em;
  text-transform: uppercase;
  text-decoration: none;
  border-bottom: solid 2px #3f51b5;
  padding: 4em 1em 0;
  transition: all 0.5s;
}
nav a.active {
  color: #fce4ec;
  border-bottom: solid 2px #fce4ec;
}
nav a:hover {
  color: #FFF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<nav>
  <a href="#" class="active">Fill</a>
  <a href="#">Item</a>
  <a href="#">Item</a>
  <a href="#">Item</a>
</nav>

Why not use a float instead? Just reverse the order of your menu items.

#menubar {
  background-color: lime;
  width: 100%;
}
.menuitem {
  float: right;
  padding-right: 10px;
  padding-left: 10px;
}

/* Clear float */
#menubar:after {
  content: ' ';
  display: block;
  clear: right;
}
<div id="menubar">
  <div class="menuitem">item</div>
  <div class="menuitem">item</div>
  <div class="menuitem">item</div>
  <div class="menuitem">item</div>
  <div class="menuitem">fill</div>
</div>

Alternate way to use display: inline-block that fills the width:

#menubar {
  width: 100%;
  text-align: right;
}
.menuitem {
  display: inline-block;
  background-color: aqua;
}
.filled {
  width: 100%;
  background-color: gray;
}
<div id="menubar">
  <div class="menuitem filled">fill
    <div class="menuitem">item</div>
    <div class="menuitem">item</div>
    <div class="menuitem">item</div>
  </div>
</div>

The only downfall with this second method is that the menu item's are actually contained within the first menu item / filled. It does the trick for filling width:100%... If they are drop-down menus you will probably want to do some z-index work and collapse borders / set padding / etc...


For those who want to do it with a table, you can give the first "td" a class and set it to a ridiculously large width, then it will push and force the other columns to shrink as much as it can. It works because tables can't expand more than the width to which they were set.

For example:

<!DOCTYPE html>
<html>
<head>
<style type="text/css">
table td {
    border:solid 1px #000;
}
table td.fill {
    width:9999em;
    text-align:right;
}
table {
    width:300px;
    border-collapse:collapse;
}
</style>
</head>
<body>
    <table>
        <tr><td class="fill">Fill</td><td>item</td><td>item</td><td>item</td></tr>
    </table>
</body>
</html>

In the old example that worked in Firefox and IE only I set the "td" width to 0, then it shrinked the column as much as it could.

You can set all columns to shrink-to-fit by setting the td width to something small, like 1px when you don't set the table width, this works in Chrome, Firefox and IE.

table td {
  width:1px;
}

You might want to set white-space:nowrap; too, otherwise all the words will wrap, or give the td some larger width

Tags:

Html

Css