Controlling width with CSS3 box-sizing

zhouguizhi 2014-08-27

An incredibly useful CSS3 feature when you’re creating columns with floats is box-sizing. It lets you choose which box sizing model to use – whether or not an element’swidth and height include padding and border or not.

This is useful since it makes it much easier to define flexible widths where you also need padding and/or borders. A typical example is laying out forms, which can be a real pain when you want flexible widths.

The box-sizing property takes two values:

  • content-box: the normal CSS model where an element’s width and height only apply to its content area and do not include padding or borders
  • border-box: the “IE box model”, used by Internet Explorer in quirks mode, wherewidth and height determine the width and height including padding and borders

A form layout example

I’ll use a form layout example to illustrate. Say you have the following HTML snippet:

<div class="group">
    <div class="text">
        <label for="text1">First name</label>
        <input type="text" name="text1" id="text1">
    </div>
    <div class="text">
        <label for="text2">Last name</label>
        <input type="text" name="text2" id="text2">
    </div>
</div>

Putting those two input + label combos (I’ll refer to these as columns from now on) on a single row is easily accomplished by floating them. But we also want the text fields to have a flexible width determined by the available width of their parents. This is to make them easy to drop into different layouts without having to fiddle about with calculating pixel widths.

Here’s some basic CSS to do that:

.text {
    width:49%;
    float:right;
    padding:1em;
    background:#fff;
}
.text:first-child {float:left;}
.text input {
    width:100%;
    padding:8px;
    border:2px solid #cce;
}

The problems

Simple enough, but there is a problem (two, actually) with this.

  • Since width by default only applies to the actual content width, the width of the columns will be 49% of their parent width plus 2em for the left and right padding. It’s quite likely that 2em will be wider than 1%, which will make the columns too wide to fit next to each other.
  • The same reasoning applies to the width of the actual input fields. width:100%means that they will be as wide as the content area of their parents. But in addition to that they have 16px of horizontal padding and 4px of horizontal borders, so they will be 20px too wide to fit.

box-sizing to the rescue

And this is where the box-sizing property is so extremely handy. It solves these problems easily if we give it a value of border-box:

.text {
    box-sizing:border-box;
    width:49%;
    float:right;
    padding:1em;
    background:#fff;
}
.text:first-child {float:left;}
.text input {
    box-sizing:border-box;
    width:100%;
    padding:8px;
    border:2px solid #cce;
}

Now the widths of both the columns and the input fields will include their horizontal paddings and borders, resulting in a nice and flexible form row with no overlapping or dropped floats.

I’ve made a simple box-sizing demo page to show this in action.

Browser support and possible workarounds

As always when we’re talking about CSS, especially CSS3, there is the issue of browser support. It turns out that box-sizing is pretty well supported. A look at the support chart at When can I use… shows that the only relevant browser that doesn’t support it is IE 7. And that is highly ironic, since it does support the border-box model in quirks mode, as does IE 6.

To make all browsers obey you’ll need to back up the box-sizing property with a couple of vendor-prefixes, like this:

.text {
    -moz-box-sizing:border-box;
    -webkit-box-sizing:border-box;
    box-sizing:border-box;
}

And then there’s IE 7. Depending on the specifics of the layout problem you’re looking to solve, your target audience, and how far you and/or your client are willing to with respect to progressive enhancement, you may be able to just ignore it. In the case of form layout, the form will most likely still be usable, although it may look a bit ugly.

Assuming you want to do something for IE 7, there are a couple of options:

  • Use Box Sizing Behavior to patch some degree of box-sizing support into IE 7
  • Use conditional comments or CSS hacks to give IE 7 a few rules that change the column and input widths to give you a bit more margin

The demo page contains examples of both of these approaches. The box-sizing behavior is neat, but it seems to have issues with the units you use for padding (doesn’t like ems) and it has problems when one element with box-sizing:border-box is nested inside another. So in example 3, the box-sizing behavior is only applied to the column elements, not the input fields. To avoid the input fields becoming wider than their parents, I’ve made them a bit narrower for IE 7. Example 4 shows a possible workaround without using box-sizing. I’ve just reduced the widths of the columns and input fields to where they don’t become too wide until the browser window is really narrow.

View source on the demo page for HTML and CSS.

In closing, while box-sizing is well-supported, there is no solid support in IE 7 and earlier. Make sure to check that this lack of support doesn’t cause serious usability problems, and apply a bit of CSS band-aid if necessary.

相关推荐