111

Does anyone know why the input elements with a width of 100% go over the table's cells border.

In the simple example below input box go over the table's cells border, the result is horrible. This was tested and it happens in the same way on: Firefox, IE7 and Safari.

Does it make sense for you? Am I missing something, do you know about a possible solution?

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    
<html><head>    
   <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"> <!-- don't use closing slash in meta tag, it breaks HTML4.01 transitional -->
   <title>Test input text in table</title>
   <style type="text/css">      
      table {border-top: 1px solid #ff0000; border-left: 1px solid #ff0000;}
      table td {border-right: 1px solid #00ff00; border-bottom: 1px solid #00ff00;}
      input[type="text"] {width: 100%;} /* removing this would make input not to go over cells border, but they would be too short, I want them to fit cells size */
   </style>    
</head><body>

<table cellpadding="0" cellspacing="0">
   <tr>
      <td><p>column one hello babe babe babe</p></td>
      <td><p>column two hello babe more</p></td>
      <td><p>column three hello babe more and more</p></td>
   </tr>
   <tr>
      <td><input type="text" value="test"></td>
      <td><input type="text" value="test"></td>
      <td><input type="text" value="test"></td>
   </tr>
</table>

</body></html>
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Marco Demaio
  • 33,578
  • 33
  • 128
  • 159
  • 1
    I would suggest that, if you're just using a table for presenting the inputs, you might switch to using a `form` with the `label` s and `input` s inside a `ul` or `ol`. which is, at least slightly more semantic. Certainly though, you should be using a `form`, even if you do stick with the `table`. – David Thomas Mar 03 '10 at 16:38

14 Answers14

228

You could use the CSS3 box-sizing property to include the external padding and border:

input[type="text"] {
     width: 100%; 
     box-sizing: border-box;
     -webkit-box-sizing:border-box;
     -moz-box-sizing: border-box;
}
pricco
  • 2,763
  • 1
  • 21
  • 22
  • 1
    Sad to say but unfortuately IE 7 does not deal with box sizing correctly. Try the following in IE 7... http://www.css3.info/preview/box-sizing/ or see http://css-tricks.com/box-sizing/ – AnthonyVO May 22 '12 at 17:07
  • @AnthonyVO: true, the only workaround for IE7 is to add specific CSS for it using IE conditional comments ` – Marco Demaio Feb 05 '14 at 11:47
24

Width value doesn't take into account border or padding:

http://www.htmldog.com/reference/cssproperties/width/

You get 2px of padding in each side, plus 1px of border in each side.
100% + 2*(2px +1px) = 100% + 6px, which is more than the 100% child-content the parent td has.

You have the option of:

  • Either setting box-sizing: border-box; as per @pricco's answer;
  • Or using 0 margin and padding (avoiding the extra size).
Community
  • 1
  • 1
ANeves
  • 6,219
  • 3
  • 39
  • 63
  • further to Sr pts answer you could set the padding and border to 0px then the 100% should work. – Mauro Mar 03 '10 at 16:37
  • Indeed, even without setting any padding for td - very well added. – ANeves Mar 03 '10 at 16:41
  • 1
    Also, if the padding creates an issue, it's possible to use `text-indent` to simulate padding ahead of the leading-edge of the text, and `line-height` for vertical padding (though retaining vertical padding wouldn't affect the width anyway). – David Thomas Mar 03 '10 at 16:58
14

The problem with things like width:95%; is that they don't look right in wide flexible layouts (because 5% can then be like 30 pixels).

The following solutions works very well for me (tested in Firefox, IE 9, Safari):

<table style="background-color: blue; width: 100%;" cellpadding="0" cellspacing="0">
<tr>
    <td style="background-color: red;   padding: 3px;">
        <div style="margin-right: 3px;">
            <div style="padding-right: 3px;">
                <input type="text" style="width:100%;">
            </div>
        </div>
    </td>
    <td style="background-color: purple;   padding: 3px;">
        <div style="margin-right: 3px;">
            <div style="padding-right: 3px;">
                <input type="text" style="width:100%;">
            </div>
        </div>
    </td>
    <td style="background-color: green;   padding: 3px;">
        <div style="margin-right: 3px;">
            <div style="padding-right: 3px;">
                <input type="text" style="width:100%;">
            </div>
        </div>
    </td>
</tr>
</table>

(added the colors to make it easier to notice the correct padding)

The trick is to wrap the input with two divs, the outer has a 3px margin (which makes it 3px smaller than the td), the inner has a 3px padding. This makes the input 6px smaller than the td, which is what you wanted to begin with.

I am not sure about the mechanics of this, but it works.

In this simple example, it also works with just a single div with right margin 6. However, in the case of my web application, only the above solution works.

<table style="background-color: blue; width: 100%;" cellpadding="0" cellspacing="0">
<tr>
    <td style="background-color: red;   padding: 3px;">
        <div style="margin-right: 6px;">
                <input type="text" style="width:100%;">
        </div>
    </td>
    <td style="background-color: purple;   padding: 3px;">
        <div style="margin-right: 6px;">
                <input type="text" style="width:100%;">
        </div>
    </td>
    <td style="background-color: green;   padding: 3px;">
        <div style="margin-right: 6px;">
                <input type="text" style="width:100%;">
        </div>
    </td>
</tr>
</table>
Andreas
  • 141
  • 1
  • 2
  • It works (upvoted +1). Strangely, I inserted some text before each and added "white-space:nowrap" to keep them on the same line, then the three overflowed the table cells, if I remove "white-space:nowrap" everything works again. Weird. – Jose Manuel Abarca Rodríguez Nov 06 '18 at 16:27
8

The problem has been explained previously so I will only reiterate: width doesn't take into account border and padding. One possible answer to this not discussed but which I have found helped me out a bunch is to wrap your inputs. Here's the code, and I'll explain how this helps in a second:

<table>
  <tr>
    <td><div style="overflow:hidden"><input style="width:100%" type="text" name="name" value="hello world" /></div></td>
  </tr>
</table>

The DIV wrapping the INPUT has no padding nor does it have a border. This is the solution. A DIV will expand to its container's size, but it will also respect border and padding. Now, the INPUT will have no issue expanding to the size of its container since it is border-less and pad-less. Also note that the DIV has its overflow set to hidden. It seems that by default items can fall outside of their container with the default overflow of visible. This just ensures that the input stays inside its container and doesn't attempt to poke through.

I've tested this in Chrome and in Fire Fox. Both seem to respect this solution well.

UPDATE: Since I just got a random downvote, I would like to say that a better way to deal with overflow is with the CSS3 box-sizing attribute as described by pricco:

.myinput {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -ms-box-sizing: border-box;
    -o-box-sizing: border-box;
    box-sizing: border-box;
}

This seems to be pretty well supported by the major browsers and isn't "hacky" like the overflow trick. There are, however, some minor issues on current browsers with this approach (see http://caniuse.com/#search=box-sizing Known Issues).

David Peterson
  • 728
  • 6
  • 17
  • 3
    A short note: with `overflow: hidden;` the content still 'pokes through' to the outside of the box in exactly the same way, but it is truncated instead of being shown - so it doesn't overlap other content. – ANeves Jan 25 '12 at 16:10
2

I know that this question is 3 years old but the problem still persists for current browsers and folks are still coming here. The solution for now is calc():

input {
    width: calc(100% - 12px); /* IE 9,10 , Chrome, Firefox */
    width: -webkit-calc(100% - 12px); /*For safari 6.0*/
}

It is supported by most modern browsers.

trojan
  • 1,465
  • 19
  • 27
1

instead of this margin struggle just do

input{
    width:100%;
    background:transparent !important;
}

this way the cell border is visible and you can control row background color

bortunac
  • 4,642
  • 1
  • 32
  • 21
1

The problem is due to the input element box model. I just recently found a nice solution to the issue when trying to keep my input at 100% for mobile devices.

Wrap your input with another element, a div for example. Then apply the styling you want for your input to that the wrapper div. For example:

<div class="input-wrapper">
 <input type="text" />
</div>

.input-wrapper {
    border-raius:5px;
    padding:10px;
}
.input-wrapper input[type=text] {
    width:100%;
    font-size:16px;
}

Give .input-wrapper rounded corner padding etc, whatever you want for your input, then give the input width 100%. You have your input padded nicely with a border etc but without the annoying overflow!

hallodom
  • 6,429
  • 1
  • 23
  • 19
1

I fixed this issue starting with @hallodom's answer. All my inputs were contained within li's, so all I had to do was set the li overflow:hidden for it to remove that excess input overflow.

.ie7 form li {
  width:100%;
  overflow:hidden;
}

.ie7 input {
  width:100%;
}
chet
  • 11
  • 1
0

With some Javascript you can get the exact width of the containing TD and then assign that directly to the input element.

The following is raw javascript but jQuery would make it cleaner...

var inputs = document.getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++)
{
    var el = inputs[i];
    if (el.style.width == '100%')
    {
        var pEl = el.parentNode;  // Assumes the parent node is the TD...
        el.style.width = pEl.offsetWidth;
    }
}

The issues with this solution are:

1) If you have your inputs contained in another element such as a SPAN then you will need loop up and find the TD because elements like SPANs will wrap the input and show its size rather then being limited to the size of the TD.

2) If you have padding or margins added at different levels then you might have to explicitly subtract that from [pEl.offsetWidth]. Depending on your HTML structure that can be calculated.

3) If the table columns are sized dynamically then changing the size of one element will cause the table to reflow in some browsers and you might get a stepped effect as you sequentially "fix" the input sizes. The solution is to assign specific widths to the column either as percentages or pixels OR collect the new widths and set them after. See the code below..

var inputs = document.getElementsByTagName('input');
var newSizes = [];
for (var i = 0; i < inputs.length; i++)
{
    var el = inputs[i];
    if (el.style.width == '100%')
    {
        var pEl = el.parentNode;  // Assumes the parent node is the TD...
        newSizes.push( { el: el, width: pEl.offsetWidth });
    }
}

// Set the sizes AFTER to avoid stepping...
for (var i = 0; i < newSizes.length; i++)
{
    newSizes[i].el.style.width = newSizes[i].width;
}
AnthonyVO
  • 3,821
  • 1
  • 36
  • 41
0

I solved the problem by applying box-sizing:border-box; to the table cells themselves, besides doing the same with the input and the wrapper.

Vanco
  • 519
  • 1
  • 6
  • 11
0

I solved the problem by using this

tr td input[type=text] {
  width: 100%;
  box-sizing: border-box;
  -webkit-box-sizing:border-box;
  -moz-box-sizing: border-box;
  background:transparent !important;
  border: 0px;
}
Kevin Muchwat
  • 1,445
  • 18
  • 18
0

Take out the "http://www.w3.org/TR/html4/loose.dtd" from the DOCTYPE declaration and it fix your problem.

Cheers! :)

Lucian
  • 101
  • 2
  • 12
  • Do you mean using `http://www.w3.org/TR/html4/strict.dtd` Strict? ref. http://www.w3.org/QA/2002/04/valid-dtd-list.html Anyway this is not an option cause changing the DOCTYPE now would probably impact the rendering of many other stuf in webpages. – Marco Demaio Jul 25 '11 at 18:09
-1

I usually set the width of my inputs to 99% to fix this:

input {
    width: 99%;
}

You can also remove the default styles, but that will make it less obvious that it is a text box. However, I will show the code for that anyway:

input {
    width: 100%;
    border-width: 0;
    margin: 0;
    padding: 0;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
}

Ad@m

kirb
  • 2,033
  • 1
  • 18
  • 28
-2

The problem lies in border-width of input element. Shortly, try setting the margin-left of the input element to -2px.

table input {
  margin-left: -2px;
}
jcjr
  • 1,503
  • 24
  • 40
burek pekaric
  • 11
  • 1
  • 5