27

Say, I have the following unordered list. The button has width: auto. How do I style the elements, so #textField would stretch as much as possible, so the width of #textField and the button would add up to 100%? I.e. #textField's width == (100% of width) - (button's computed width).

<ul>
  <li>
    <input id="textField" type="text" /><input type="button" />
  </li>
</ul>

So, for example, let's say 100% width of li is 100 pixels: if the button's computed width is 30px, #textField's width would be 70px; if button's computed width is 25px, #textField's width would become 75px.

Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
William Niu
  • 15,798
  • 7
  • 53
  • 93

11 Answers11

53

You can quickly achieve this effect using a mixture of float and overflow: hidden:

<ul>
    <li>
        <input class="btn" type="button" value="Submit"/>
        <div class="inputbox"><input id="textField" type="text" /></div>
    </li>
</ul>

CSS:

ul { 
  list-style: none; 
  padding: 0; }
.btn { float: right; }
.inputbox { 
  padding: 0 5px 0 0;
  overflow: hidden; }
.inputbox input { 
  width: 100%;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box; }

Preview (with box-sizing): http://jsfiddle.net/Wexcode/E8uHf/546/

Here is how it looks without box-sizing: http://jsfiddle.net/Wexcode/E8uHf/

Wex
  • 15,539
  • 10
  • 64
  • 107
  • Pretty great way of doing this! – Fleep Jan 09 '12 at 06:01
  • 6
    This works great, but changes the HTML order, which changes the keyboard tab order, which will confuse many keyboard users when the button gets focused before the text input. – Doug Jan 09 '12 at 14:54
  • 2
    Couldn't you just use `tabindex` to correct any tab ordering problems? – Jonah Bishop Jan 09 '12 at 15:18
  • 3
    That could help, but keep in mind that `tabindex` overrides tab order for the *whole document*, not just the form. That is, any element with a positive `tabindex` will be moved to the front of the tab order and navigated to before any other element on the page. http://www.w3.org/TR/html401/interact/forms.html#adef-tabindex – Doug Jan 09 '12 at 16:29
  • 3
    For your average form, setting the tab order isn't too onerous. This solution is pretty solid. – Ryley Jan 10 '12 at 22:08
  • 1
    Just a note: this is called a block formatting context, take another look at a similar problem here. http://stackoverflow.com/questions/1260122/expand-div-to-take-remaining-width – Roger Oct 04 '12 at 01:52
  • What if... we want a minimum width for the .inputbox input element ; it would then result this element to be displayed underneath if it isn't big enough otherwise ? Stretching is amazing, but it should be a responsive stretch. – Cedric Jul 02 '13 at 13:31
  • @Cedric - I'm not sure what you mean. The whole point of the current implementation is to support arbitrary widths for the `.inputbox` element. – Wex Jul 02 '13 at 15:59
  • OK. The li element can be of various width. If the width of the li is so small than the text field is width 0,then it is not really convenient. On small screens, it could happen. It'd be better if on those screens, the button be bellow the text field, and not side by side. Maybe it is feasible without JS ? (Btw, note that I really love your answer, thanks for sharing this trick!!) – Cedric Jul 02 '13 at 19:01
6

Try this:

HTML

<ul>
  <li>
    <input id="textField" type="text" /><input value="Button!" class="btn"type="button" />
  </li>
</ul>

CSS

ul li {
    width:100%;
}

#textField, .btn {
    float:left;
}

#textField {
    width:70%;
}

.btn {
    width:auto;
}

Here is a demo:

http://jsfiddle.net/andresilich/RkCvf/


Here are a couple of more demos i made for your consideration.

This demo is using CSS3's flex-box model to stretch the input field across its region without a given width. There is no support for IE8 and below though.


And this demo imitates a table by only using CSS. It is supported by IE8 and above.

Andres I Perez
  • 75,075
  • 21
  • 157
  • 138
  • I don't want to give `#textField` a set width; I want it to stretch. For example, if `li`'s width is 100px, and button's computed width is 30px, #textField would be 70px; and when button's computed width becomes 40px, #textField would change to 60px. – William Niu Jan 05 '12 at 04:18
  • 3
    @WilliamNiu Are you ok with CSS3's flex-box? here is a demo: http://jsfiddle.net/andresilich/NFEab/ – Andres I Perez Jan 05 '12 at 04:36
  • This seems like a nice alternative, but IE doesn't seem to support it... :-/ – William Niu Jan 05 '12 at 05:24
  • 1
    How far back are you supporting IE? There is the `display:table-cell` property that can be used to get the end result as well, it is supported by IE8+ though. – Andres I Perez Jan 05 '12 at 12:30
  • Another nice suggestion yet! Why don't you put the two suggestions in your answer? I'm quite willing to at least upvote this answer. – William Niu Jan 05 '12 at 15:44
5

This is possible with CSS in user agents with CSS-2.x-supporting layout engines:

  …
  <style type="text/css">
    .full-width {
      width: 100%;
    }

    .table {
      display: table;
    }

    .row {
      display: table-row;
    }

    .cell {
      display: table-cell;
    }
  </style>
</head>

<body>
  <ul class="table">
    <li class="row">
      <span class="cell full-width">
        <input type="text" id="textField" class="full-width" />
      </span>
      <span class="cell">
        <input type="button" value="foobar" />
      </span>
    </li>
  </ul>
</body>

Tested positive in the following browsers:

  • Chromium 16.0.912.75 (Developer Build 116452 Linux), Apple WebCore 535.7
  • Chromium 16.0.912.63 (Developer Build 113337 Linux), Apple WebCore 535.1

Please note that paddings and margins on input elements will interfere because of the fixed width.

But: I can see no good reason why you should not use a table element here (tables and CSS do mix). Semantically it would make sense (the table would be serializable), and compatibility will be very likely better than with the CSS display property values above:

<body>
  <ul>
    <li>
      <table class="full-width"
             summary="Input text field with &#8220;foobar&#8221; button">
        <tr>
          <td class="full-width">
            <input type="text" id="textField" class="full-width" />
          </td>
          <td>
            <input type="button" value="foobar" />
          </td>
        </tr>
      </table>
    </li>
  </ul>
</body>

It is also possible that you should have used only a table element here in the first place.

PointedEars
  • 14,752
  • 4
  • 34
  • 33
  • Not the downvoter, but I'm guessing it's because you're still using tables for layout, despite styling them. CSS purists really don't like that. – Bryan Boettcher Jan 11 '12 at 16:57
  • 1
    Then maybe that person, too, has not really read the answer because I am *not* using a `table` element in the solution. The second variant is only an alternative. – PointedEars Jan 11 '12 at 19:39
  • Preaching to the choir, have an upvote for two alternative viable solutions. – Bryan Boettcher Jan 11 '12 at 23:23
  • 2
    The reason you shouldn't use a table is that the form data is not tabular. – Samuel Edwin Ward Jan 12 '12 at 17:37
  • @SamuelEdwinWard Depends. Try to look at it this way: We have data here – the `input` element – that is in a row-relation with other data – the button to process it. Many other forms are more obviously tabular: a label in a row-relation with a form control that it describes and refers to (by `for` attribute). I would rather use a serializable table, like this, with a `summary` attribute to describe its content (for accessibility) than seeing the "CSS-only" solution falling apart in a browser. However, I am going to create a testcase to see how compatible the "CSS-only" solution is already. – PointedEars Jan 12 '12 at 18:47
3

I ended up using a table and stretch the cell that contains the text field:

<ul>
  <li>
    <table>
      <tr>
        <td width="100%"><input width="100%" id="textField" type="text" /></td>
        <td><input type="button" width="auto" /></td>
      </tr>
    </table>
  </li>
</ul>
William Niu
  • 15,798
  • 7
  • 53
  • 93
  • 2
    Do you have a better suggestion, Litso? – William Niu Sep 10 '10 at 08:41
  • 1
    For starters, CSS has several different values for the 'display' property that do the same thing as table elements. http://w3.org/tr/css21/visuren.html#propdef-display – reisio Jan 06 '12 at 01:26
  • 3
    I don't think rejecting table-based solutions just because they use a table is instantly correct. They sometimes have a place. None of the other presented solutions are as simple as this one. – Ryley Jan 10 '12 at 22:11
  • I do. Using a table in this manner undermines HTML's entire purpose. – reisio Jan 10 '12 at 23:09
-1

How about this?

<ul>
  <li>
    <input id='textField' style='width: 80%'/><input type='button' style='width: 20%'/>
  </li>
</ul>
Goutham
  • 819
  • 6
  • 10
-1
<ul>
  <li style="position:relative; width:100%;">
    <input id="textField" type="text" style="position:absolute; left:0px; right:80px" />
    <input type="button" value="Submit" style="position:absolute; right:0; width:auto" />
  </li>
</ul>

Adjust right:80px to set margin between textbox and button;

Jeaf Gilbert
  • 11,495
  • 19
  • 78
  • 105
  • Interesting idea, but that didn't work. When you make an element position absolute, you need to explicitly set the position and size, which isn't what I want. I want the text field to be resizable. – William Niu Sep 10 '10 at 08:08
  • I defined `left` and `right` to make it anchored to its container (must have `position:relative`) not to define its size, it is resizable. – Jeaf Gilbert Sep 10 '10 at 08:31
  • First of all, for some reason the `right` property doesn't work for me (in Safari). Secondly, I don't want to define the `right` property, as I would like it to automatically adjust with the `button` to the right. – William Niu Sep 13 '10 at 00:31
-1

Do it per javascript. take width of li minus length of button and set the width of the textbox to this. But keep the boxmodel in mind. Without javascript I have not really an idea.

Sven Bieder
  • 5,515
  • 2
  • 21
  • 27
-1

Tables and positioning are not required at all. The answer is to float one element left, and the other right.

http://jsfiddle.net/johnallan/HeUSN/

HTML:

<ul>
<li class="media attribution">
<button class="button" >Press Me</button>
<div class="copy">b blah blah blah blah blah blah blah blah blahblah blah blahblah blah blah  blah blah blahblah blah blahblah blah blahblah blah blah blah blah blahlah blah blah</div>
</li>
</ul>

CSS:

.media{ border:1px solid black }
.media, .copy{overflow:hidden; _overflow:visible; zoom:1;}
.media .button{float:left; margin-right: 10px;}
-1

Maybe this can help, if you can define maxlength on the input box:

/* CSS */

ul{ 
    float:left; 
    border:1px solid #000; 
    padding:0; 
    position:relative; 
    width:20%; 
    height:25px; 
}

ul li{ 
    float:left; 
    margin:0; 
    padding:0; 
    border:0; 
    list-style-type:none; 
    width:100%; height:100%; 
    position:relative; 
}

ul li input{ 
    margin:0; padding:0; border:0; 
}

ul li input[type='text']{ 
    float:left; 
    width:100%; height:100%; 
    text-indent:10px;  
}

ul li input[type='submit']{  
    position:absolute; right:0; 
    width:auto; height:100%; 
}

/* HTML */

<body>

    <ul>
        <li>
            <input type="text" /><input type="submit" value="Submit" />
        </li>
    </ul>

</body>

The code basically keeps the input[type='text'] to a width of 100% and positions the button absolute to the parent li. This width of the button is auto and the height is 100% to cover up the textbox. You can then set a maxlength on the textbox to prevent the text from being hidden by the button.

Sagar Patil
  • 1,938
  • 13
  • 21
-1
/* ROBOTICCSS*/
/*  test in ff - works*/

ul{
width: auto;
padding: 0 80px 0 0;/* right padding >= button width */
list-style:none;
}

input.text_area{
width: 100%;
}

input.submit_button{
float: right;
margin: 0 -80px 0 0;/* match above value */
}
<!--HTML -->
<ul>
  <li>
      <input class="text_area" type="text" />
      <input class="submit_button" type="button" value="Submit"/>
  </li>
</ul>
Community
  • 1
  • 1
  • Welcome to Stackoverflow. Thanks for the solution, we will appreciate it even more if you can add a little bit of description about the code you are posting. Thanks. – Vivek Oct 28 '12 at 14:08
-1

This is pretty close to the desired result:

<!DOCTYPE html>
<html lang="en">
<head>
<style>
li { width: 100%; border: 1px solid black; display: block; text-align: justify; }
span { display: inline-block; }
span { width: 100%; }
#foo { display: inline-block; width: 90%; border: 1px solid red; }
#foo input { display: block; width: 100%; }
</style>
</head>

<ul>
  <li>
    <object id="foo"><input type="text"></object> <object><input type="button" value="1234567890"></object>
      <span></span>
  </li>
</ul>

</html>
Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265