163

Why does display:block;width:auto; on my text input not behave like a div and fill the container width?

I was under the impression that a div is simply a block element with auto width. In the following code shouldn't the div and the input have identical dimensions?

How do I get the input to fill the width? 100% width won't work, because the input has padding and a border (causing a final width of 1 pixel + 5 pixels + 100% + 5 pixels + 1 pixels). Fixed widths aren't an option, and I'm looking for something more flexible.

I'd prefer a direct answer to a workaround. This seems like a CSS quirk and understanding it may be useful later.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>width:auto</title>

        <style>
        div, input {
            border: 1px solid red;
            height: 5px;
            padding: 5px;
        }
        input, form {
            display: block;
            width: auto;
        }
        </style>
    </head>

    <body>
        <div></div>
        <form>
            <input type="text" name="foo" />
        </form>
    </body>
</html>

I should point out I can already do this with wrapper workarounds. Apart from this screwing with the page semantics and CSS selector relationships I'm trying to understand the nature of the problem and whether it can be overcome by changing the nature of the INPUT itself.

Ok, this is TRULY strange! I've found that the solution is to simply add max-width:100% to an input with width:100%;padding:5px;. However this raises even more questions (which I'll ask in a separate question), but it seems that width uses the normal CSS box model and max-width uses the Internet Explorer border-box model. How very odd.

Ok, that last one appears to be a bug in Firefox 3. Internet Explorer 8 and Safari 4 limit the max-width to 100% + padding + border which is what the spec says to do. Finally, Internet Explorer got something right.

Oh my god, this is awesome! In the process of playing with this, and with much help from the venerable gurus Dean Edwards and Erik Arvidsson, I managed to piece together three separate solutions to make a true cross-browser 100% width on elements with arbitrary padding and borders. See answer below. This solution does not require any extra HTML markup, just a class (or selector) and an optional behaviour for legacy Internet Explorer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
SpliFF
  • 38,186
  • 16
  • 91
  • 120
  • Exact duplicate of [http://stackoverflow.com/questions/628500/can-i-stop-100-width-text-boxes-from-extending-beyond-their-containers](http://stackoverflow.com/questions/628500/can-i-stop-100-width-text-boxes-from-extending-beyond-their-containers) – Christophe Eblé Jun 23 '09 at 06:08
  • 8
    @SleepyCod that's not an exact duplicate. This question deals with the problem of `input` elements apparently not abiding to CSS 2.1 specification, while the question you linked to asks how to prevent overflowing boxes which occurs perfectly within bounds of CSS 2.1 spec by the way. Both the questions and their solutions overlap but calling them exact duplicates is simply **wrong.** – Armen Michaeli May 27 '13 at 16:39

7 Answers7

134

Check out what I came up with, a solution using the relatively unknown box-sizing:border-box style from CSS 3. This allows a 'true' 100% width on any element regardless of that elements' padding and/or borders.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">

        <title>Cross-browser CSS box-sizing:border-box</title>

        <style type="text/css">
            form {display:block; margin:0; padding:0; width:50%; border:1px solid green; overflow:visible}
            div, input {display:block; border:1px solid red; padding:5px; width:100%; font:normal 12px Arial}

            /* The voodoo starts here */
            .bb {
                box-sizing: border-box; /* CSS 3 rec */
                -moz-box-sizing: border-box; /* Firefox 2 */
                -ms-box-sizing: border-box; /* Internet Explorer 8 */
                -webkit-box-sizing: border-box; /* Safari 3 */
                -khtml-box-sizing: border-box; /* Konqueror */
            }
        </style>

        <!-- The voodoo gets scary. Force Internet Explorer 6 and Internet Explorer 7 to support Internet Explorer 5's box model -->
        <!--[if lt IE 8]><style>.bb {behavior:url("boxsizing.htc");}</style><![endif]-->
    </head>

    <body>
        <form name="foo" action="#">
            <div class="bb">div</div>
            <input class="bb" size="20" name="bar" value="field">
        </form>
    </body>
</html>

This solution supports Internet Explorer 6 and Internet Explorer 7 via a behaviour written by Erik Arvidsson with some tweaks from Dean Edwards to support percentage and other non-pixel widths.

Working example
Behaviour (boxsizing.htc)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
SpliFF
  • 38,186
  • 16
  • 91
  • 120
  • This looks like an amazing solution, but doesn't work in IE8 (the div & field boxes are not wide enough). Do you know if there's been any update on this method? Thanks! – rocketmonkeys Nov 09 '11 at 17:44
  • 2
    This polyfill by Schepp updates the IE6/7 polyfill to handle more edge cases and work with IE8 over at github: https://github.com/Schepp/box-sizing-polyfill – nicjohnson Feb 10 '12 at 00:21
  • Thanks! I couldn't work out why and were different widths when I'd set them both to be 300px wide. This solved it! Note that two years later you _still_ need to use the -moz- prefix for latest version of Firefox. http://caniuse.com/#feat=css3-boxsizing – Darren Cook Jul 06 '12 at 06:00
  • 4
    Unfortunately, this approach cannot be used to eliminate the wrapper div if you also need to add margins (because margins don't work right on any element if you use width: 100%) – SystemParadox Jul 16 '12 at 10:55
  • SystemParadox: This solution doesn't require `width:100%`. What it does is ensure that whatever width you give it is consistent with other types of block content. – SpliFF Jul 18 '12 at 02:50
  • 6
    That doesn't fix the problem though. Yes it works if you use `width:100%` but it doesn't if you use `width:auto`, see here: http://jsfiddle.net/hGuzE/ – Julian Krispel-Samsel May 16 '13 at 09:23
  • +1 to SpliFF, SystemParadox & nimrod. Out of curiosity, I proved it doesnt work when the element has margins (because of the 100% width): http://jsfiddle.net/hGuzE/15/ – Aximili Mar 13 '14 at 23:57
  • It does answer his question. He specifically said: "How do I get the input to fill the width. 100% width won't work because the input has padding and a border (causing a final width of 1px + 5px + 100% + 5px + 1px)" There was no concern about margins on the element itself. In my case I needed space so instead of adding margins to the element, I added padding to the parent. – Craig Jacobs Jun 21 '14 at 00:52
  • I had the same problem like @SystemParadox that I needed to use margins for layouts with other floating elements. My workaround was to simply use a wrapping div with margins and `width: auto` around the input-element, so I can use `width: 100%` on the input element. – Jay Dinse Sep 01 '15 at 16:22
  • you can eventually use `width: calc(100% - XXpx);` if you need margins, even if i'm not really satisfied by this solution. I previously eard calc might impact performances ? and it's not fully supported – Anne Claire Sep 12 '16 at 15:49
10

Your best bet is to wrap the input in a div with your border, margins, etc., and have the input inside with width 100% and no border, no margins, etc.

For example,

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>width:auto</title>

        <style>
            div {
                border: 1px solid red;
                padding: 5px;
            }
            input, form {
                display: block;
                width: 100%;
            }
        </style>
    </head>

    <body>
        <form>
            <div><input type="text" name="foo" /></div>
        </form>
    </body>
</html>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jonathan Fingland
  • 56,385
  • 11
  • 85
  • 79
  • 1
    Yeah, it'll work but that's more of a workaround than an answer. i'm trying to establish why input seems to ignore the block behaviour. – SpliFF Jun 23 '09 at 05:57
  • 2
    Jonathan, please forgive my apparent rudeness here, but I came here looking for the right(tm) answer, and also gladly read the part where @SpliFF specifically mentions he would prefer a "direct answer to a workaround, yet you still add another redundant (as in, repeated many times both at SO and elsewhere on the Internet) answer, seemingly ignoring the contract of the question. May I ask you - **why?** Thank you in advance. -Curiously yours. – Armen Michaeli May 27 '13 at 16:35
10

The reason this happens is that a text input's size is determined by its size attribute. add size="50" inside the <input> tag. Then change it to size="100" -- see what I mean?

I suspect there's a better solution, but the only one that comes to mind is something I found on the "Hidden features of HTML" question on SO: Use a content-editable div, instead of an input. Passing the user input to the enclosing form (if that's what you need to) might be a little tricky.

Hidden features of HTML

Community
  • 1
  • 1
Tyler
  • 21,762
  • 11
  • 61
  • 90
  • 9
    I'm curious to know how the CSS people justify this. If width can override size explictly with pixels/percentage I don't see why it should continue to honor it when the element is a block. – SpliFF Jun 23 '09 at 06:27
  • 1
    However the same happens to `button` as well which doesn't have a `size` attribute? – zanona Dec 12 '13 at 19:59
  • 1
    A question that focuses more on the "why is the standard like this" part like this answer: http://stackoverflow.com/questions/4567988/what-is-it-in-the-css-dom-that-prevents-an-input-box-with-display-block-from-ex The top claim there is that it is because `input` is a replaced element. – Ciro Santilli OurBigBook.com Oct 27 '14 at 09:01
2

Add this to your style:

box-sizing: border-box;
Julian
  • 33,915
  • 22
  • 119
  • 174
1

You could fake it, like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>width:auto</title>

        <style>
        div, #inputWrapper {
            border: 1px solid red;
        }
        #topDiv {
            padding: 5px;
            height: 5px;
        }
        form {
            display: block;
        }
        #inputWrapper {
            overflow: hidden;
            height: 15px;
        }
        input {
            display: block;
            width: 100%;
            border-style: none;
            padding-left: 5px;
            padding-right: 5px;
            height: 15px;
        }
        </style>
    </head>

    <body>
        <div id="topDiv"></div>
        <form>
          <div id="inputWrapper">
            <input type="text" name="foo" />
          </div>
        </form>
    </body>
</html>
Jacob
  • 77,566
  • 24
  • 149
  • 228
  • 1
    I've done the fake approach in the past but to be honest I'm getting sick of it. I end up with all sorts of retarded hacks like using 99% width to get inputs and selects to match. I really want a way to treat an input like a div and I was hoping I'd just overlooked something. – SpliFF Jun 23 '09 at 06:05
  • 3
    also your input will overflow inputWrapper because it still has width:100% with an internal padding. – SpliFF Jun 23 '09 at 06:29
1

Also you could fake it, like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>width:auto</title>

        <style>

            .container {
                width:90%;
            }

            .container div{
                border: 1px solid red;
                padding: 5px;
                font-size:12px;
                width:100%;
            }

            input{
                  width:100%;
                border: 1px solid red;
                font-size:12px;
                padding: 5px;
            }

            form {

                margin:0px;
                padding:0px;
            }

        </style>
    </head>

    <body>
        <div class="container">
            <div>
                asdasd
            </div>
            <form action="">
                <input type="text" name="foo" />
            </form>
        </div>
    </body>
</html>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AlexC
  • 9,657
  • 17
  • 64
  • 98
1

Try this:

form { padding-right: 12px; overflow: visible; }
input { display: block; width: 100%; }
Mike
  • 1,825
  • 3
  • 21
  • 26
  • 1
    you left out out the input padding and border. I was about to say you're wrong until I realised what you're doing. Now I get what merkuro was trying to do (his code is still wrong, but the concept was almost there). The padding-right changes the meaning of 100% by 12px (border plus padding of input). The drawback of this approach though is that all other children of form are affected by the padding too and need to compensate as well. – SpliFF Jun 23 '09 at 14:04