width:auto for <input> fields - css

Newbie CSS question. I thought width:auto for a display:block element meant 'fill available space'. However for an <input> element this doesn't seem to be the case. For example:
<body>
<form style='background:red'>
<input type='text' style='background:green; display:block; width:auto'>
</form>
</body>
Two questions then:
Is there a definition of exactly what width:auto does mean? The CSS spec seems vague to me, but maybe I missed the relevant section.
Is there a way to achieve my expected behavior for a input field - ie. fill available space like other block level elements do?
Thanks!

An <input>'s width is generated from its size attribute. The default size is what's driving the auto width.
You could try width:100% as illustrated in my example below.
Doesn't fill width:
<form action='' method='post' style='width:200px;background:khaki'>
<input style='width:auto' />
</form>
Fills width:
<form action='' method='post' style='width:200px;background:khaki'>
<input style='width:100%' />
</form>
Smaller size, smaller width:
<form action='' method='post' style='width:200px;background:khaki'>
<input size='5' />
</form>
UPDATE
Here's the best I could do after a few minutes. It's 1px off in FF, Chrome, and Safari, and perfect in IE. (The problem is #^&* IE applies borders differently than everyone else so it's not consistent.)
<div style='padding:30px;width:200px;background:red'>
<form action='' method='post' style='width:200px;background:blue;padding:3px'>
<input size='' style='width:100%;margin:-3px;border:2px inset #eee' />
<br /><br />
<input size='' style='width:100%' />
</form>
</div>

"Is there a definition of exactly what width:auto does mean? The CSS
spec seems vague to me, but maybe I missed the relevant section."
No one actually answered the above part of the original poster's question.
Here's the answer:
http://www.456bereastreet.com/archive/201112/the_difference_between_widthauto_and_width100/
As long as the value of width is auto, the element can have horizontal
margin, padding and border without becoming wider than its container...
On the other hand, if you specify width:100%, the element’s total
width will be 100% of its containing block plus any horizontal margin,
padding and border... This may be what you want, but most likely it isn’t.
To visualise the difference I made an example:
http://www.456bereastreet.com/lab/width-auto/

ORIGINAL answer using Angular: Because input's width is controlled by it's size attribute, this is how I initialize an input width according to its content:
<input type="text" class="form-list-item-name" [size]="myInput.value.length" #myInput>
UPDATE for JavaScript (10/01/2022): My original answer was from the time I was studying Angular. If you need pure, Vanilla JavaScript the solution is even simpler:
<input type="text" oninput="this.size = this.value.length">
Or add an "input" event listener to your input html element and run a code like this:
const myInput = document.querySelector('input');
myInput.addEventListener('input', this.typing);
(...)
typing(e) {
e.target.setAttribute('size', e.target.value.length);
}
Obs: Depending on the browser, input may restore to its default size of something between 150px and 250px if/when size gets the 0 value. In this case, just add +1 to value.length:
<input type="text" oninput="this.size = this.value.length + 1">
OR:
typing(e) {
e.target.setAttribute('size', e.target.value.length + 1);
}

As stated in the other answer, width: auto doesn't work due to the width being generated by the input's size attribute, which cannot be set to "auto" or anything similar.
There are a few workarounds you can use to cause it to play nicely with the box model, but nothing fantastic as far as I know.
First you can set the padding in the field using percentages, making sure that the width adds up to 100%, e.g.:
input {
width: 98%;
padding: 1%;
}
Another thing you might try is using absolute positioning, with left and right set to 0. Using this markup:
<fieldset>
<input type="text" />
</fieldset>
And this CSS:
fieldset {
position: relative;
}
input {
position: absolute;
left: 0;
right: 0;
}
This absolute positioning will cause the input to fill the parent fieldset horizontally, regardless of the input's padding or margin. However a huge downside of this is that you now have to deal with the height of the fieldset, which will be 0 unless you set it. If your inputs are all the same height this will work for you, simply set the fieldset's height to whatever the input's height should be.
Other than this there are some JS solutions, but I don't like applying basic styling with JS.

It may not be exactly what you want, but my workaround is to apply the autowidth styling to a wrapper div - then set your input to 100%.

If you're willing to include a little JavaScript to solve this, you can get exact sizing. This doesn't rely on approximating width with size or ems, doesn't rely on any hardcoded element widths, and works for e.g., type="number", which don't accept a size attribute.
The trick is to get your input sized exactly like a span with the same content, by actually having an invisible span with the same content.
Put your input inside a div along with a span that mirrors the input's value. Give both the input and the span the same styling, give the input 100% width, then hide the span and absolute-position the input to sit on top of the span.
This way, the container (and thus the input) are automatically sized by the visual appearance of the content of the invisible span.
https://codepen.io/spiffytech/pen/abwWRqo
<div id="relative-parent">
<span id="size-calibration"></span>
<input id="autosized-input" />
</div>
<style>
#relative-parent {
position: relative;
/* Have some width if the input is empty */
min-width: 1em;
/* Adjust size to match the span */
width: min-content;
}
#size-calibration {
visibility: hidden;
/* Prevent the span from wrapping the text when input value has multiple words, or collapsing multiple spaces into one */
white-space: pre;
}
#autosized-input {
position: absolute;
left: 0;
width: 100%;
}
#size-calibration, #autosized-input {
/* Normalize styles that the browser sets differently between spans and inputs.
Ideally, use a "CSS reset" here. */
font-family: "Arial";
padding: 0;
/* Demonstrate that this works for input with custom styles */
font-size: 24px;
}
</style>
<script>
function updateSize() {
const span = document.getElementById('size-calibration');
const input = document.getElementById('autosized-input')
span.innerText = input.value;
}
document.addEventListener('DOMContentLoaded', () => {
const input = document.getElementById('autosized-input');
input.oninput = updateSize;
// Provide some initial content
input.value = "I'm sized exactly right!"
updateSize();
})
</script>

After tried methods all above and failed, I workaround by modifying   width property in style by unit em:
tgt.style.width = `${(tgt.value.length + 1) / 2}em`

The only option I can think of is using width:100%. If you want to have a padding on the input field too, than just place a container label around it, move the formatting to that label instead, while also specify the padding to the label. Input fields are rigid.

Answer 1 - "response" gave a nice answer/link for it. To put it in short, "auto" is the default, so it is like removing any changes in the width of an element
Answer 2 - use width: 100% instead. It will fill the 100% of the parent container, in this case, the "form".

Using JQuery
$(document).on('input', '.input-fit-width', (e) => {
$(e.currentTarget).attr('size',e.currentTarget.value.length);
})

Nowdays, flex or grid makes it much easier , it overrides default style/behaviors of https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#size which has a default value set at 20 see : https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#size
Giving you 2 plain CSS options without requiring JavaScript nor setting width to 100% and deal with box-sizing.
flex/flex-grow
<form style='background:red;display:flex;'>
<input type='text' style='background:green; flex-grow:1'>
</form>
grid
<form style='background:red;display:grid;'>
<input type='text' style='background:green;'>
</form>

Jquery way of adjusting size of input automatically.
In general:
$('#my_input_id').width( ($('#my_input_id').val().length) + "ch" );
On text input:
$(document).on("input", '#my_input_id', function () {
$(this).width( ($(this).val().length) + "ch" );
});

I think the simplest solution is to set parent element's width:
form{
width: 100%!important;
}

Related

How to prevent div of variable height from moving other elements?

HTML:
<div id="autocomplete" hidden></div>
<input type = "button" id = "search" value = "Search">
The autocomplete div holds various input tags generated by jQuery. When the input tags are created, they shift the button down the screen in order to fit the autocomplete content. What I want to do is to have the autocomplete div overlay on top of the the button rather than shifting the button down.
I have tried using z-index, but it seems to only work if autocomplete is placed after the button in HTML, the using negative margin to shift autocomplete back up. I don't like this solution since it messes up when viewed from other screen sizes.
Is there another way?
I think you have to use absolute positioning to keep the button over the inserting elements.
You can do something like this:
$('#autocomplete').append($('<div>').text('WOW1'))
$('#autocomplete').append($('<div>').text('WOW2'))
$('#autocomplete').append($('<div>').text('WOW3'))
$('#autocomplete').append($('<div>').text('WOW4'))
#container {
position: relative;
}
#search {
position: absolute;
top: 0;
}
#autocomplete {
padding-top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container">
<div id="autocomplete" ></div>
<input type = "button" id = "search" value = "Search">
</div>
EDIT:
Here is a link to see how CSS position works:
https://developer.mozilla.org/en-US/docs/Web/CSS/position
Also I recommend you to check this stack overflow answer about relative vs absolute positioning it has a very natural response (Position Relative vs Absolute?)
This tells the browser that whatever is going to be positioned should
be removed from the normal flow of the document and will be placed in
an exact location on the page. It won't affect how the elements before
it or after it in the HTML are positioned on the Web page however it
will be subject to it's parents' positioning unless you override it.
This is the general method to have the items inside the autocomplete div not affect the flow of the other elements on the page (your button in this case).
#autocomplete {
position: relative;
}
#autocomplete > * {
position: absolute;
}
A few comments to improve this code:
Don't use IDs (#) on your css. Better stick to class names.
Don't use the wildcard (*) - preferably add the items that will exist inside the autocomplete, which are not shown on the question. And better, wrap them all in another element so you don't have to absolute position all of them individually

How to set an input width to match the placeholder text width

Example http://dabblet.com/gist/5859946
If you have a long placeholder, the input by default does not display wide enough to show all the placeholder text.
e.g.
<input placeholder="Please enter your name, address and shoe size">
Without setting a fixed width, and preferably no javascript, can you set the input to show all the placeholder text?
This can be done only via javascript by setting the size = placeholder length:
input.setAttribute('size',input.getAttribute('placeholder').length);
Here is a code that dose that for all the inputs:
http://jsfiddle.net/KU5kN/
Just in case someone wants to use this with jQuery, that code would be below. Also, if the placeholder attribute doesn't exist in the accepted answer, you'll get errors, which is taken care of as well in the jQuery example below.
$("input[placeholder]").each(function () {
$(this).attr('size', $(this).attr('placeholder').length);
});
I went with Avner Solomon's solution, as proposed in the comments of one of the above sections.
You need a div element wrapping an input and another div element that contains your label:
<div class="input-container">
<!-- this element is hidden from display and screen readers. -->
<div class="input-hidden-label"
aria-hidden="true">
Your placeholder text
</div>
<input class="input"
type="text"
placeholder="Your placeholder text"/>
</div>
Assuming the font styles for the input-hidden-label and the input are the same, you will see a line of text alongside the input. The text will be the same length as the input, give or take a few pixels.
You can then apply these styles:
.input-container {
display: inline-block;
margin-bottom: 2em;
}
.input {
display: inline;
width: 100%;
font-size: 16px;
font-family: Times;
}
.input-hidden-label {
height: 0;
visibility: hidden;
}
This hides the label by giving it height: 0, and removing visibility. But, the width remains. The div that contains the input and the label matches the width of its longest child. If you then set the input to width: 100%, it will match the parent width, which already matches the placeholder.
See this fiddle.
Caveats
This idea is not very accessible, nor is this solution. You should include a label for the input, and not rely on the placeholder itself as a label.
A workaround i thought of:
Make a span element with the same text as placeholder.
Measure width of the span element.
Set input to the width of the span element.
hide span element. display none will not work, use other method.
http://jsfiddle.net/Timar/cwLp3rbo/
var input = document.getElementById('input-1');
// measure width of same text as placeholder
var placeholder = document.getElementById('input-1-placeholder');
input.style.width = placeholder.offsetWidth + "px"

Defining multiple rows with css table display

I've built an edit page with field-label divs and field-editor divs as per usual ASP.Net MVC, resulting in the following HTML:
<div class="editor-label">
<label for="Code">Project Code</label>
</div>
<div class="editor-field">
<input id="Code" name="Code" type="text" value="" />
</div>
The above pair of divs would be repeated for as many editable fields there are on my form. By default these just display one below the other on the page. What I'd like to achieve is to use CSS to display the page in a table layout. So my CSS is something like this:
.field-label, .field-editor{
display: table-cell;
}
This just displays them all in cells next to each other, wrapping at the end of the browser window. How could I force a new row after each field-editor div (or before each field-label div) without adding additional markup to the view? I understand that this would be simple by adding additional markup to the view, like a new div to which I assign display: table-row. But I'd have to add this markup between each set of label/editor combination, and that just feels like a violation of the DRY principle. So I'd like to do this without needing to do this additional markup.
Given the above HTML, the following CSS will work:
.editor-label, .editor-field {
display: inline-block;
width: 48%;
}
.editor-label {
text-align: right;
}
This will allow the elements to share the same line, and take an assigned width (in this case relative to the width of the parent element). The text-align declaration is simply to place the text of the label visually close to the input element.
JS fiddle demo.
You could, of course, achieve the same result using different widths and without wrapping the the label and input elements needlessly in divs.
With a slightly more tidied-up version:
label, input {
display: inline-block;
}
label {
text-align: right;
width: 20%;
}
input {
width: 30%;
margin-right: 30%;
}
JS Fiddle demo.
The margin-right is declared simply so that the cumulative width of the label, the input and its margin-right leaves insufficient space for the next label to occupy the same line.

What's keeping my input element from displaying like a block element?

http://jsfiddle.net/aam7J/
How would I induce div-like behaviour on the input element? Specifically, how can I induce the width to expand such that its outer width including margin fills up the container? width: 100% doesn't work, because it doesn't take into account the other box model attributes.
I use a "hack" to account for the input border width something like this...
<div>hello world</div>
​
<div class="adjustForTheInputBorder">
<input type="text" />
</div>
input
{
width:100%;
border-width:2px;
}
div.adjustForTheInputBorder
{
margin-right: 4px; /* or 2x whatever your input border width is */
}
div
{
background-color: pink;
}
My adjustForTheInputBorder class tends to have a name which more appropriately conveys my hatred of css though... :)
P.S. div renders as display:block by default, you don't need that there.

How do I set the size of an HTML text box?

How do I set the size of an HTML text box?
Just use:
textarea {
width: 200px;
}
or
input[type="text"] {
width: 200px;
}
Depending on what you mean by 'textbox'.
Your markup:
<input type="text" class="resizedTextbox" />
The CSS:
.resizedTextbox {width: 100px; height: 20px}
Keep in mind that text box size is a "victim" of the W3C box model. What I mean by victim is that the height and width of a text box is the sum of the height/width properties assigned above, in addition to the padding height/width, and the border width. For this reason, your text boxes will be slightly different sizes in different browsers depending on the default padding in different browsers. Although different browsers tend to define different padding to text boxes, most reset style sheets don't tend to include <input /> tags in their reset sheets, so this is something to keep in mind.
You can standardize this by defining your own padding. Here is your CSS with specified padding, so the text box looks the same in all browsers:
.resizedTextbox {width: 100px; height: 20px; padding: 1px}
I added 1 pixel padding because some browsers tend to make the text box look too crammed if the padding is 0px. Depending on your design, you may want to add even more padding, but it is highly recommend you define the padding yourself, otherwise you'll be leaving it up to different browsers to decide for themselves. For even more consistency across browsers, you should also define the border yourself.
input[type="text"]
{
width:200px
}
Your textbox code:
<input type="text" class="textboxclass" />
Your CSS code:
input[type="text"] {
height: 10px;
width: 80px;
}
or
.textboxclass {
height: 10px;
width: 80px;
}
So, first you select your element with attributes (look at first example) or classes(look last example). Later, you assign height and width values to your element.
This works for me in IE 10 and FF 23
<input type="text" size="100" />
If you don't want to use the class method you can use parent-child method to make changes in the text box.
For eg. I've made a form in my form div.
HTML Code:
<div class="form">
<textarea name="message" rows="10" cols="30" >Describe your project in detail.</textarea>
</div>
Now CSS code will be like:
.form textarea {
height: 220px;
width: 342px;
}
Problem solved.
Lookout! The width attribute is clipped by the max-width attribute.
So I used....
<form method="post" style="width:1200px">
<h4 style="width:1200px">URI <input type="text" name="srcURI" id="srcURI" value="#m.SrcURI" style="width:600px;max-width:600px"/></h4>
You can make the dependent input width versus container width.
.container {
width: 360px;
}
.container input {
width: 100%;
}
Try:
input[type="text"]{
padding:10px 0;}
This is way it remains independent of what textsize has been set for the textbox. You are increasing the height using padding instead
Elements can be sized with the height and width attributes.

Resources