28

Given a <select> and an <input> element, both specified to be 200px wide:

<!doctype html>
<body>
<select style="width: 200px"></select><br/>
<input  style="width: 200px" type="text">
</body>
<html>

One ends up wider1,2,3, 4 than the other:

enter image description here

What is the reason for this?

If someone can give the reason, perhaps the solution would be obvious, and not a hack&pray.

Layout

The applied layout is perfectly reasonable:

enter image description here


Update 1: While i was writing this question Chrome updated itself from 17 to 19.

Update 2: Changing padding in the <input> from 1 to zero:

<!doctype html>
<body>
<select style="width: 200px"></select><br/>
<input style="width: 200px; padding: 0" type="text">
</body>
<html>

doesn't make the <input> 200px wide (i.e. doesn't fix it).

Update 3: Applying a CSS reset:

<!doctype html>
<head>
<style type="text/css">
   * {
       padding: 0;
       margin: 0;
   }
</style>
<body>
<select style="width: 200px"></select><br/>
<input style="width: 200px; padding: 0" type="text">
</body>
<html>

Does not solve the problem:

enter image description here

Also, i am less interested in a solution than an explanation.

Footnotes

  • 1,2,3 Chrome 1719, Firefox, Internet Explorer 9
  • 4 on Windows 7 64-bit

Bonus Reading

Community
  • 1
  • 1
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219

4 Answers4

28

Your <input> isn't too wide; your <select> is too narrow!

The real issue is that the <select> element doesn't behave like most elements do. It uses a

box-sizing: border-box;

where width is the width of the element after padding and borders are applied; behaving as though it alone were in "quirks" mode.

This runs counter to every other standards mode html element, which use:

box-sizing: content-box; 

To fix it, change the <select> to use the same box model as the rest of html:

select { box-sizing: content-box; }

OR change the <input> to use the same box model as the select:

input { box-sizing: border-box; }

The input element behaves like most elements do, using a content-box model, where the width is the width of the element before padding and borders are applied.

There are default padding and borders set by your browser, so it is larger than you might want and/or expect. I always use a "CSS reset" at the top of my stylesheets, like so:

* {
    padding: 0;
    margin: 0;
}

That will ensure there are no default padding or margins on any element.

The select element is a different case though, where is behaves more like an element with box-sizing: border-box enabled, where it takes into account borders and padding into its width specification.

If you add box-sizing: border-box to your input element, it will behave exactly as you expect/want.

EDIT: Bolded the part that may be relevant to you. An alternate solution is reducing the specified width of the input element by a few pixels, so that it matches the width of the select box.

Fiddle demonstrating both solutions: http://jsfiddle.net/n4yT2/2/

justisb
  • 7,081
  • 2
  • 26
  • 44
  • Using `box-sizing: border-box` is used to enable *Netscape/Quirks mode* when interpreting what a `width` means. CSS dictated that a `width` would no longer specify the **width** of a box, but the **width** of stuff *in* the box. This would seem to indicate that `` is the one that is wrong (i.e. just cause i told it to be `200px` wide doesn't mean it should **be** 200px wide). So, really, i should be applying `box-sixing: content-box` to the **input**. Either way, it doesn't explain *why* removing all padding/borders doesn't work. – Ian Boyd Jun 20 '12 at 18:47
  • `content-box` is the default `box-sizing` property for most elements, where is specifies the width of the "stuff within the box." `border-box` specifies the total width of the element, which is what the `select` element uses by default, which is why its true width is 200px when you specify the CSS width to be 200px. – justisb Jun 20 '12 at 18:50
  • *"`content-box` is the default `box-sizing` property"* Except on in `` of knocking over the lamp, when really it's the ` – Ian Boyd Jun 20 '12 at 18:51
  • No, your browser is just applying a default border and padding to the input element. If you set `style="border: 0; padding: 0; width: 200px;"` on the `input`, its "true" width will be 200px. If you add a 2px border to both sides, its true width will be 204px. This is how the `content-box` model works. – justisb Jun 20 '12 at 18:54
  • Ah okay, saw the edit to your comment from when you originally posted it backward. You got it now, yeah. – justisb Jun 20 '12 at 18:56
  • Yeah, sorry about that. i had it *completely* backwards. i scrolled up to my diagram, and realized i'd screwed it up. – Ian Boyd Jun 20 '12 at 19:59
  • @IanBoyd Are you sure the big title you added to this answer is correct? I thought you were claiming the input was too wide, and that the select box was the right size. – justisb Jun 21 '12 at 21:40
  • 1
    Oh for gods sake i did it again. Just shoot me. :( The *header* part was wrong, but the guts were right. – Ian Boyd Jun 22 '12 at 14:09
  • 1
    This just solved the problem I was having so thank you! don't forget to use the relevant vendor prefixes though: -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; – Brighty Aug 29 '13 at 07:46
3

It all goes back to Netscape.

It's amazing how many people think the IE box model was:

It's even funnier that:

  • the box model that Netscape created was objectively "right" (archive)
  • when the W3C decided to standardize a box model, they chose a box model that was objectively "wrong"
  • they chose a box model that no browser was doing, and that no web-site was using

Netscape and IE had already agreed that if you tell something to be 200px wide: it was going to be 200px wide. People then had to live with the strangeness of that nonsensical W3C box model, e.g.:

  • you tell something to be to be 200px wide, and in a standard conforming browser it will be 204px wide
  • you tell a select to be 200px wide, and in a standard conforming browser it will be 200px wide

HTML5 finally fixes the W3C broken box model

It is so strange that a 200px wide item doesn't end up being 200px wide, that in HTML5 we finally have the ability to return to the original (correct) Netscape/IE box model:

box-sizing: border-box

Where a button 75px wide is 75px wide.

enter image description here

* {

}

td {
}

.correct {
    box-sizing: border-box;
}
<table>
<thead>
    <tr><th></th><th>Correct</th><th>W3C</th></tr>
</thead>
<tbody>
    <tr>
        <td>text input</td>
        <td><input type="text" class="correct" style="width: 100px;">
        <td><input type="text" style="width: 100px;">
    </tr>
    <tr>
        <td>select</td>
        <td><select class="correct" style="width: 100px;">foo</select>
        <td><select style="width: 100px;">foo</select>
    </tr>
    <tr>
        <td>button</td>
        <td><input type="button" class="correct" style="width: 100px;">
        <td><input type="button" style="width: 100px;">
    </tr>
    <tr>
        <td>image</td>
        <td><input type="image" class="correct" style="width: 100px; border: 1px solid black;">
        <td><input type="image" style="width: 100px; border: 1px solid black;">
    </tr>
    <tr>
        <td>password</td>
        <td><input type="password" class="correct" style="width: 100px;">
        <td><input type="password" style="width: 100px;">
    </tr>
    <tr>
        <td>submit</td>
        <td><input type="submit" class="correct" style="width: 100px;">
        <td><input type="submit" style="width: 100px;">
    </tr>   
    

</tbody>
</table>
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
2

Because browsers do things with the dimensions of input boxes (adding default borders, padding, changing box sizing, etc) to match them to their (or the operating system's) native GUI control equivalents.

The hack-and-pray solution, though, is the obvious one, unfortunately.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
1

It seems that <select> elements behave like they had box-sizing: border-box. Trying to change it to box-sizing: content-box doesn't work, though (at least on Chrome 19, OSX 10.7.4).

After you applied the CSS reset, the size difference remains due to the borders on the input box. If you remove them, both elements will be exactly 200px wide. See demo.

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • And now that i know the answer, it's easy to google for (http://stackoverflow.com/questions/1450587/inconsistent-box-model-between-input-type-submit-and-input-type-text) – Ian Boyd Jun 20 '12 at 18:54