Placing 2 50% width input elements in a row, understanding box-sizing - html

I'm trying to place 2 input elements inline with 50% width each. Why do I have to subtract the border width from the input elements even when I use box-sizing: border-box?
http://jsfiddle.net/Nmvk6/
HTML
<form class="form">
<div class="form-group">
<label>Type</label>
<button class="btn btn-default">
<span class="glyphicon glyphicon-plus-sign"></span>
</button>
</div>
<div class="form-group">
<select class="form-control half-width-form-control">
<option value="foo">foo</option>
<option value="bar">bar</option>
</select>
<input class="form-control half-width-form-control" type="number"></input>
</div>
</form>
CSS
.half-width-form-control {
display: inline-block;
width: calc(50% - 2px);
/*width: 50%;*/
/*box-sizing: border-box;*/
}

The problem you have here is related to inline-block.
display:inline-block tells the browser to treat the element as a block with regard to its contents, but as an inline element with regard to its surroundings.
The problem for you here is that the surrounding around the two elements includes some white space. Specifically, you have some white space between the two elements. White space is relevant for inline elements, and thus also for inline-block elements.
In a nutshell, it's as if the two elements were words in a sentence. The white space between them is seen as the space between two words.
What you end up with is 50% width + width of one space character + 50% width.
This is a well-known issue with inline-block, but does trip people up a lot.
The quick+dirty solution is therefore to remove the space -- close up the gap between the end of the <select> and the begining of the <input> so that there is no space there.
Other alternatives include using comments to remove the gap (ugly), styling the container element to font-size:0px;, and various other hacky solutions.
Alternatively, you could throw away the inline-blocks. There are a number of other options which can achieve the same or similar results -- notably float, display:table-cell, and flex-box, but others also exist.
But my suggestion is just to remove the spaces between the two elements. Quick, easy fix.

Two issues:
You need -webkit-box-sizing and -moz-box-sizing if you want to make it work on all current browsers. See MDN page.
There was a space (actually a return and some spaces, but they collapse to 1 space) between the two controls, so the total width was 100% plus the space.
Solution: add the prefixed properties and remove the space from the markup.
http://jsfiddle.net/Nmvk6/7/

Specify
float:left
And it fixes it.
http://jsfiddle.net/Nmvk6/8/

Related

Why div element will separate when re sizing even though I have inline-block?

When I shrink the browser + button separated between checkbox event though both div have inline-block
Please see the mini version of the code:
<div style="display: inline-block;">
<a class="plus" data-toggle="collapse" data-target="#data" href="#">
<i class="fa fa-plus-circle"></i><span></span>
</a>
</div>
<div class="checkbox name" style="font-size: 17px; display: inline-block; margin-left: 5px;">
<label>
<input name="unique_id" value="" type="checkbox">
<div id="unique_id">name - address <span class="label label-info">display</span>
</div>
</label>
</div>
But I just want + button and check box will place together when re sizing like this image( without re size )
When using inline-block on your elements they wrap with the parent width. So if you have a parent DIV to your structure juste add white-space: nowrap; to it. It will prevent the children with ìnline-block`to wrap (go under).
EDIT : You could also simplify your HTML structure, you have a lot of elements for a simple thing.
Set the width to both Div or add "float:left" to both div with some width to second div.
white-space: nowrap;
will force the content to stay on one line
Does it fit nicely if you made one of the divs a little shorter?
Reason because even with inline-block, two divs with a width of 50% might not actually fit in one row. There's a little space in between them. Not sure where it comes from; someone here should be able to provide the exact reason why.
But for me personally, what I'll do is wrap the two divs and give that parent div style="font-size:0;". Only caveat with this is that you must explicitly set the font sizes of the children div.
See JSFiddle

Strange behavior of an input html element with display: block

I'm trying to make some html form with help of bootstrap. Some of my inputs must have no gap from left or right side. But bootstrap .col-XX-Y blocks have gutter via paddings from left and right. So my idea was to use negative margin for my input elements, and display: block. And here I'm stuck.
Please refer to this codepen example. I was faced with several strange things for me:
Why input with display: block doesn't fill all it's parent
container, like div does? It fills the container only with: width:100%; (comment width for red-bordered input in codepen example)
Why if I'm apply negative margin-left to compensate parent container's
left padding, my input shifts to the left, but keeps it's original width (like if left css property was used). Doesn't it have to behave
like a block element (e.g. div): shifts to the left and keep
filling of all width of it's parent, excluding right padding?
When I'm apply negative right margin for my input to compensate parent's right padding, then nothing happens (look my example, compare orange div
with red input). Why? What about of a behavior like block element?
If this is normal behavior, can you give me some link to html standard docs with explanations of that.
If you don't want the padding on a grid parent element to effect its children, surround all its children elements in a block element with a class of row.
Bootstrap input elements are meant to span the whole width of there parent elements even without display block style attribute.
<div class="col-md-12">
<div class="row"> <!--this is what you need -->
</div>
</div>
full example code
<div class="col-md-12">
<div class="row">
<input type="text" placeholder='I\'m some damned input' />
</div>
<div class="row">
<div>I am some div</div>
</div>
</div>
Form elements do not behave the same way as regular block level elements. When you display an <input> field as block it will not fill the full width.
For this reason you need to make give the element width: 100%. This is how Bootstrap styles form elements.
Like any other block element, giving it a width of 100% will allow it to fill the width of its container. When you apply a negative margin-left, the width will still be the same (100% = containers width) which will cause the gap to appear.
I would suggest wrapping the <input> field in a <div> and apply the negative margin to that instead:
.wrap {
margin: 0 -20px;
}
.wrap input {
width: 100%;
display: block;
}

Select box to fill remaining space

On my form I am trying to have my select box take up the row except enough room to show the button on the same row.
I am after a responsive design, so as I resize the page then of course with size of the select box should resize as well to take into account that size.
I can set a percentage on the select, but as it goes up and down sometimes I end up with a large gap, or the button goes onto a new line.
html
<form class="form-horizontal">
<div class="form-group">
<label class="col-xs-3 control-label" for="droplist">Select item:</label>
<div class="col-xs-9">
<select id="droplist">
<option>Value 1</option>
<option>Value 2</option>
</select>
<button class="btn btn-primary">Action!</button>
</div>
</div>
</form>
css
select {
width: 80%;
}
Is there a way to have both the select and the button on the same line, and the select just resizes with the page?
fiddle; http://jsfiddle.net/sJT6C/
If you insist on the button having fixed width, you can use advanced CSS layouts (flex or grid, now experimental in Firefox) or alter the HTML markup and play with float CSS property as follows.
HTML:
<form class="form-horizontal">
<div class="form-group">
<label class="col-xs-3 control-label" for="droplist">Select item:</label>
<div class="col-xs-9">
<button class="btn btn-primary">Action!</button>
<div class="wrapper">
<select id="droplist">
<option>Value 1</option>
<option>Value 2</option>
</select>
</div>
</div>
</div>
</form>
CSS:
.wrapper {
margin-right: 70px;
margin-top: .5ex;
}
select {
width: 100%;
}
button {
float: right;
}
JsFiddle
In the markup, I swapped the select and the button and wrapped the select in a div with class wrapper. The wrapper is needed to get the select to take as much space as possible, without specifying its width. (If width: 100% is specified without a wrapper, there will be no room for the button.)
The stylesheet tells select to stretch to the full width of its parent, which is .wrapper. The wrapper has no width specified, but as a block element it tries to take as much space as possible. Now we have a select that behaves like a well-behaved block element.
Now the floating part. The wrapper is given right margin of the size of button width (including padding and border). It would be best to ensure that the button never exceeds this size, but I did not focus on that. The button is told to float to the right. Thus it fills the space reserved by wrapper’s right margin. (If I did not swap the elements in markup, the button would move down by the height of the wrapper.)
And yeah, I forgot to mention the margin-top: .5ex of .wrapper. Originally select and button used to have their baselines aligned. My hack breaks this alignment and this margin is quite a poor attempt to fix it. Vertical alignment is a darn complicated thing in CSS and I did not find it important enough to really solve it here.
To add to Palec's answer, if you have a variable width for your button (or buttons), then margin-right will not be an adequate solution. Instead, replace with the overflow attribute:
CSS:
.wrapper {
overflow: hidden;
margin-top: .5ex;
}
select {
width: 100%;
}
button {
float: right;
}
(HTML unchanged from original answer)
JsFiddle
It is important that the button element is placed before the select box. It will not work the other way around (though I have not been able to determine why that is).
Note: this solution (like Palec's) will result in the tab index of the elements being reversed: the button will be tabbed to first, then the select box.

Why does setting the margin on a div not affect the position of child content?

I'd like to understand a little more clearly how css margins work with divs and child content.
If I try this...
<div style="clear: both; margin-top: 2em;">
<input type="submit" value="Save" />
</div>
...the Save button is right up against the User Role (margin fail):
Margin Fail :( http://img697.imageshack.us/img697/8459/nomargin.jpg
If I change it to this...
<div style="clear: both;">
<input style="margin-top: 2em;" type="submit" value="Save" />
</div>
...there is a gap between the Save button and the User Role (margin win):
Margin Win :) http://img20.imageshack.us/img20/1973/yesmargin.jpg
Questions:
Can someone explain what I'm observing? Why doesn't putting a margin on the div cause the input to move down? Why must I put the margin on the input itself? There must be some fundamental law of css I am not grasping.
This would be because the the div doesn't have an element to "push itself away from". It would seem that the select that comes before the div is floated. This causes it to be taken out of the normal page flow, and it doesn't act as reference for margin calculations anymore. The div is clearing the float, i.e. it drops below it, then tests if there's a 2em margin to the next element above it that is within the same "flow". Apparently there is, so it doesn't move down any further.
Setting the margin on the submit on the other hand is very clear cut, since the frame of reference for it is the parent div.
Putting a margin on an element affects that element's margin only. Are you expecting it to be inherited or something? It isn't. Perhaps you're thinking of padding? Try:
<div style="clear: both; padding-top: 2em;">
<input type="submit" value="Save" />
</div>
See Box Model:
Another thing to note about margins is that they merge. So:
<div>one</div>
<div>two</div>
with:
div { margin: 1em; }
will only result in a 1em gap between them not 2em. See 8.3.1 Collapsing Margins:
Vertical margins may collapse between
certain boxes:
Two or more adjoining vertical margins of block boxes in the
normal flow collapse. The
resulting margin width is the maximum
of the adjoining margin widths. In the
case of negative margins, the maximum
of the absolute values of the negative
adjoining margins is deducted from the
maximum of the positive adjoining
margins. If there are no positive
margins, the absolute maximum of the
negative adjoining margins is deducted
from zero. Note. Adjoining boxes
may be generated by elements that are
not related as siblings or ancestors.
So one possible explanation for what you're seeing is that the element preceding your div already has a margin (at the bottom), which is why it's not being pushed down by adding a margin to your div.
Basically put borders around things and you should see what's happening.
What's happening in the first example is that the floating elements above the button is floating outside it's parent element.
The margin is working just fine, but it's not between the floating elements and tbe button, it's between the floating element's parent element and the button. The parent element doesn't have any non-floating elements, so it's height is zero, and the floating elements overlap the margin.
In your first example, you are setting a margin on the DIV itself. Think of the DIV as a block holding the nested elements. In this case, the nested element would be the button. If you do the following as you did:
<div style="clear: both; margin-top: 2em;">
<input type="submit" value="Save" />
</div>
You are not affecting the child elements style. Although the relative position of your button may change, your are not actually changing the style of the child element. Now by doing:
<div style="clear: both; margin-top: 2em;">
<input type="submit" value="Save" />
</div>
You are now setting the child elements margin. This will have a different result. Setting this child elements margin will not have an affect on the parent element (the DIV).

How to not wrap contents of a div?

I've got a fixed-width div with two buttons in it. If the labels of the buttons are too long, they wrap – one button stays on the first line, and the next button follows underneath it instead of adjacent to it.
How can I force the div to expand so that both buttons are on one line?
Try white-space: nowrap;
Documentation: https://developer.mozilla.org/docs/Web/CSS/white-space
A combination of both float: left; white-space: nowrap; worked for me.
Each of them independently didn't accomplish the desired result.
I don't know the reasoning behind this, but I set my parent container to display:flex and the child containers to display:inline-block and they stayed inline despite the combined width of the children exceeding the parent.
Didn't need to toy with max-width, max-height, white-space, or anything else.
Hope that helps someone.
If you don't care about a minimum width for the div and really just don't want the div to expand across the whole container, you can float it left -- floated divs by default expand to support their contents, like so:
<form>
<div style="float: left; background-color: blue">
<input type="button" name="blah" value="lots and lots of characters"/>
<input type="button" name="blah2" value="some characters"/>
</div>
</form>
If your div has a fixed-width it shouldn't expand, because you've fixed its width. However, modern browsers support a min-width CSS property.
You can emulate the min-width property in old IE browsers by using CSS expressions or by using auto width and having a spacer object in the container. This solution isn't elegant but may do the trick:
<div id="container" style="float: left">
<div id="spacer" style="height: 1px; width: 300px"></div>
<button>Button 1 text</button>
<button>Button 2 text</button>
</div>
Forcing the buttons stay in the same line will make them go beyond the fixed width of the div they are in. If you are okay with that then you can make another div inside the div you already have. The new div in turn will hold the buttons and have the fixed width of however much space the two buttons need to stay in one line.
Here is an example:
<div id="parentDiv" style="width: [less-than-what-buttons-need]px;">
<div id="holdsButtons" style="width: [>=-than-buttons-need]px;">
<button id="button1">1</button>
<button id="button2">2</button>
</div>
</div>
You may want to consider overflow property for the chunk of the content outside of the parentDiv border.
Good luck!