tags:

views:

6165

answers:

7

Hi,

I'm trying to let an <input type="text"> (henceforth referred to as “textbox”) fill a parent container by settings its width to 100%. This works until I give the textbox a padding. This is then added to the content width and the input field overflows. Notice that in Firefox this only happens when rendering the content as standards compliant. In quirks mode, another box model seems to apply.

Here's a minimal code to reproduce the behaviour in all modern browsers.

<!DOCTYPE html 
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
>
<html>
    <head xmlns="http://www.w3.org/1999/xhtml"&gt;
        <title>Test</title>
        <style type="text/css">
            #x {
                background: salmon;
                padding: 1em;
            }

            #y {
                background: red;
                padding: 0 20px;
                width: 100%;
            }

            input {
                background: red;
                padding: 0 20px;
                width: 100%;
            }
        </style>
    </head>
    <body>
        <div id="x">
            <div id="y">x</div>
            <input type="text"/>
        </div>
    </body>
</html>

My question: How do I get the textbox to fit the container?

Notice: for the <div id="y">, this is straightforward: simply set width: auto. However, if I try to do this for the textbox, the effect is different and the textbox takes its default row count as width (even if I set display: block for the textbox).

/EDIT: David's “solution” would of course work. However, I do not want to modify the HTML – I do especially not want to add dummy elements with no semantic functionality. This is a typical case of divitis that I want to avoid at all cost. This can only be a last-resort hack.

A: 

i believe you can counter the overflow with a negative margin. ie

margin: -1em;
Darren Kopp
+6  A: 

You can surround the textbox with a <div> and give that <div> padding: 0 20px. Your problem is that the 100% width does not include any padding or margin values; these values are added on top of the 100% width, thus the overflow.

David Kolar
+1  A: 

This behavior is caused by the different interpretations of the box model. The correct box model states that the width applies only to the content and padding and margin add on to it. So therefore your are getting 100% plus a 20px right and left padding equaling 100%+40px as the total width. The original IE box model, also known as quirks mode, includes padding and margin in the width. So the width of your content would be 100% - 40px in this case. This is why you see two different behaviors. As far as I know there is no solution for this there is however a work around by setting the width to say 98% and the padding to 1% on each side.

Matthew M. Osborn
what about negative padding? if negative margin don't work. Can you even have negative padding?
Sekhat
A: 

If I recall, width: auto should work. But it's much more of an "in theory" thing; I don't know whether or not it's supported.

You may also need to change the display to block (or, I think, inline-block) in order for the width property to be interpreted in such a way that auto makes sense.

Let me know if that works! I sympathize with your CSS woes :).

Domenic
+1  A: 

@Domenic this does not work. width auto does nothing more then the default behavior of that element because the initial value of width is auto ( see page 164, Cascading Style Sheets Level 2 Revision 1 Specification). Assigning a display of type block does not work either, this simply tell the broswer to use a block box when displaying the element and does not assign a default behavior of taking as muc space as possible like a div does ( see page 121, Cascading Style Sheets Level 2 Revision 1 Specification). That behavior is handeled by the visual user agent not CSS or HTML difinition.

Matthew M. Osborn
+3  A: 

Because of the way the Box-Modell is defined and implemented I don't think there is a css-only solution to this problem. (Apart from what Matthew described: using percentage for the padding as well, e.g. width: 94%; padding: 0 3%;)

You could however build some Javascript-Code to calculate the width dynmically on page-load... hm, and that value would of course also have to be updated every time the browserwindow is resized.

Interesting by-product of some testing I've done: Firefox does set the width of an input field to 100% if additionally to width: 100%; you also set max-width to 100%. This doesn't work in Opera 9.5 or IE 7 though (haven't tested older versions).

Ben
+2  A: 

This is unfortunately not possible with pure CSS; HTML or Javascript modifications are necessary for any non-trivial flexible-but-constrained UI behavior. CSS3 columns will help in this regard somewhat, but not in scenarios like yours.

David's solution is the cleanest. It's not really a case of divitis -- you're not adding a bunch of divs unnecessarily, or giving them classnames like "p" and "h1". It's serving a specific purpose, and the nice thing in this case is that it's also an extensible solution -- e.g. you can then add rounded corners at any time without adding anything further. Accessibility also isn't affected, as they're empty divs.

Fwiw, here's how I implement all of my textboxes:

<div class="textbox" id="username">
    <div class="before"></div>
    <div class="during">
        <input type="text" value="" />
    </div>
    <div class="after"></div>
</div>

You're then free to use CSS to add rounded corners, add padding like in your case, etc., but you also don't have to -- you're free to hide those side divs altogether and have just a regular input textbox.

Other solutions are to use tables, e.g. Amazon uses tables in order to get flexible-but-constrained layout, or to use Javascript to tweak the sizes and update them on window resizes, e.g. Google Docs, Maps, etc. all do this.

Anyway, my two cents: don't let idealism get in the way of practicality in cases like this. :) David's solution works and hardly clutters up HTML at all (and in fact, using semantic classnames like "before" and "after" is still very clean imo).

Aseem Kishore