CSS Margin calculation - html

While i do understand the overall CSS box model in theory like padding, border, margin, my understanding is restricted to this individual parts.
I often gets confused how this is actually rendered by the browser. E.g. Like padding is within the border, but how is margin calculated?
Is it wrt the box border or with respect to the screen?
If we give both left and right margins, what takes higher precedence?
If there is a width as well as left/right margins, how does the actual rendering take place like is the width of box made first,then the padding or what is it like?
What difference does a float attribute added to this box with margin make?

The box consists of 4 sizes: outer to inner:
Margin - that's the space from the parent, it stacks with the parent's padding.
Border - that's the border's width, it can be specified with border: or border-width:
Padding - that's the space inside the box, if any content/elements inside that box will be spaced that from its sides.
Width - the actual box's width, may change according to content, 100%, or a fixed width as specified in width: or max-width:
An image for illustration:
A floated element takes margin into account, so if you have
#element { margin-left: 100px; float: left; }
it will float left, but will have a 100px margin from the left side.

"E.g. Like padding is within the border, but how is margin calculated?"
Study this: http://www.w3.org/TR/css3-box/#margins
"Is it wrt the box border or with respect to the screen?"
The calculation of margins is independent from the border and the screen. The browser calculates the value for the margin separately, and then decides how it's going to be applied (rendered).
"If we give both left and right margins, what takes higher precedence?"
An algorithm is specified here: http://www.w3.org/TR/css3-box/#blockwidth
Could you give a specific example?
"If there is a width as well as left/right margins, how does the actual rendering take place like is the width of box made first,then the padding or what is it like?"
The rendering is almost instantaneous, so what counts is the end result, not the order in which the browser renders the element's properties.
"What difference does a float attribute added to this box with margin make?"
Read here: http://www.w3.org/TR/css3-box/#floating
The used values of the margins are equal to the computed values,
except that the used values of any margins computed as ‘auto’ are ‘0’.

Related

Padding increasing the total size of a box element

Is this the correct behavior for padding to increase the total size of a box element ? I'm trying to set padding to the left side of a box element which has the width set to 940px but when I add 25px in padding to the left side it adds these pixels to the width of the box element making it overlap the body-wrapper which is the parent element.
I also tried marging-left but while this doesn't add to the total width of my box element it pushes it to the right causing it to overlap as well..
What is the best way to dealing with this issue?
Please check screenshot for a visual:
It is the default behaviour of the box model. You can learn more about the box model here.
In your CSS you can define the behaviour with the box-sizing attribute. In this case you'll want:
box-sizing:border-box;
border-box takes the padding and border sizes into account when setting the width of the element, which is what you're looking for. However, it will not calculate based on margin sizes.

Why does padding add to the visible width of an element even when box-sizing is set to border-box?

So I was coding using Semantic-ui, and I have two toggle boxes (check boxes) next to each other in a flexbox container. When the window size is reduced, they wrap around so that one is on top of the other.
To get them to spread out a little, I added both right and bottom padding of around 5px. However I noticed a strange behaviour. Padding would cause the boxes to move apart horizontally, but when stacked vertically there was no space between them, even though there was bottom padding on each box.
Further investigation showed that the box-sizing property of the check boxes was set to border-box. After reading up, I found that the border-box box model calculates the width and height to include the padding and the border.
The checkboxes have a height of 1.5rem assigned.
My question is as follows. As is my understanding, padding shouldn't change the size of the element when using border-box. However this only seems to be true if definite dimensions are set as shown in the linked jsfiddle. Height is set, so the bottom padding isn't added on as an extra. But width isn't and right padding has an effect on the visible width of the divs.
Why is this the case? Surely padding should have no effect on the size of the element (unless set to something ridiculous, larger than the element itself), irrespective on whether I've defined a definite width or left it to be calculated?
JSFiddle: http://jsfiddle.net/Astridax/8cd48emn/
Please try and toggle the paddings using dev tools to see what I mean.
As is my understanding, padding shouldn't change the size of the element when using border-box.
This is where you're confused. Here's what the spec has to say on this subject: http://www.w3.org/TR/css3-ui/#box-sizing0
border-box
The specified width and height (and respective min/max
properties) on this element determine the border box of the element.
That is, any padding or border specified on the element is laid out
and drawn inside this specified width and height. The content width
and height are calculated by subtracting the border and padding widths
of the respective sides from the specified ‘width’ and ‘height’
properties. As the content width and height cannot be negative
([CSS21], section 10.2), this computation is floored at 0.
The actual effect of setting box-sizing to border-box is that specified widths will be said to include the border and the padding. The spec says nothing about unspecified widths, which are therefore treated as normal - as wide as they need to be to incorporate both the content and the padding and the border.
Edit:
What you're implying should happen is actually impossible to do, for the following reason. Imagine you have content in a div such that the auto width of the content alone would be 500px exactly. Then throw a 20px padding around that.
#myDiv {
padding: 20px;
width: auto;
}
No problem yet - you have a 540px wide div with the box-sizing at content-box by default.
Okay, so lets change the box-sizing to border-box.
#myDiv {
box-sizing: border-box;
padding: 20px;
width: auto;
}
What you're suggesting should happen is that the padding should now be ignored. So we have a div with 500px worth of content, we're going to now include the padding within that 500px instead of extending the width of the div. But wait - now the content box has shrunk to 460px to allow for the padding and the overall size of the box is 500px. But wait, we're not supposed to be accounting for the padding when calculating the width, so we'd better render the div at 460px right?
You see the problem? You could go on infinitely like this.

Why does a percentage margin cause a new line?

<div style = "float : left; background-color: #dd3fb8;">
<a style = "margin-left : 10%;">a</a>
<a>b</a>
<a>c</a>
</div>
In the example above, the letter "c" would be on new line, but if I set "margin-left" to px unit, "c" would be on the same line as "a" and "b". Why does this happen?
Unfortunately, the CSS2.1 spec doesn't appear to have a clear answer to this. In fact, I would say this is well within the realm of undefined behavior.
Here are the relevant points I can find:
Floats without a specified width will shrink to fit their contents. In the case of floats with only inline content, the float needs to be made just wide enough to fit its contents on a single line (notwithstanding explicit line breaks) and no more.
Percentage margins are calculated based on the width of the containing block.
Note that it says:
If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.
... but as far as I can see, the behavior is consistent across all browsers.
That being said, the reason this statement applies is because since the margin of the inline element falls within the content bounds of the float, it can be said that the width of the float (the containing block of the inline elements) depends on the this element (the element having the margin).
Here's what I can deduce based on the points above:
When the margin is specified as a percentage, the width of the float is calculated without taking the margin into account, because it's not possible to calculate the margin until the width of the float has been determined.
The margin is then calculated based on the used width of the float, and the letter "c" wraps to a new line as a result of being pushed forward by the margin on "a". The width of the float does not change.
Again, none of this behavior is specified at all, and so technically it's not in violation of the spec. However, it seems sensible.
When the margin is specified as a pixel value, the margin is calculated first. The width of the float is then calculated taking this margin into account (remember that horizontal margins do apply to inline elements as normal). Per the shrink-to-fit algorithm, this is the preferred width: just wide enough to contain all the inline elements on a single line.
Unlike with percentage margins, this is very clear-cut, as implementations should have no trouble calculating computing absolute values for margins first.
I would be hard-pressed to call this a bug in any of the browsers, especially since they all behave consistently.
Lastly, of course, you can avoid this undefined behavior entirely simply by giving your floats explicit widths where possible. It does help to understand why you should do so, however.
Since your div is floated, and its width is auto (implicitly), http://www.w3.org/TR/CSS21/visudet.html#float-width applies:
If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width.
“shrink-to-fit” width basically means, let the element be as wide as its content requires it to be.
Now without the margin-left, that is no problem: All three of your a elements are inline elements that contain a specific character each – easy enough to determine their individual widths, and add them up.
But now you want a margin-left in percent, and here things get complicated – if we look at the definition for margin-left, it says:
Percentages: refer to width of containing block
Now, that leaves us in a bit of a pickle, since the width of the containing block (which is established by the floated div element), is computed based on its content – but now this margin-left would change the overall width of that content, but is in itself dependent on the width of the containing block, which it itself influences …
That’s a classical problem of two measurements that are dependent on each other … and that is therefor basically unsolveable.
http://www.w3.org/TR/CSS21/box.html#margin-properties says,
 The percentage is calculated with respect to the width of the generated box's containing block. […]
If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.
Edit: Basically the same as what BoltClock said in his answer, just took me a little longer …
The link has a left margin of 10%, 10% of how much? The parent element is floated left which means it does not have a width of its own, instead it expands as much as its contents. If you try to imitate how the browser would compute the resulting box and you will find yourself in a fix:
Let the width of the content (and therefore the container) be 30px
Add 10% of 30px = 3px left margin to the link
The resulting width of the container is 30 + 3 = 33px
This creates a loop where margin increases as outer width is increased and outer width increases as the margin is increased (10% of 33px = 3.3px means container width changes from 33px to 33.3px and so forth). For such computations the resulting behavior is undefined (as pointed out by CBroe).
The browser seems to avoid the loop and sticks with the 30px width. The 3px margin introduced after calculation causes the third link to flow into second row. The browser again avoids the loop by sticking with 30px width.

How does browser combine two block elements?

I'm confused by the calculation of elements. I know how the browser calculates the size of the element but I don't know how the browser treat two elements or more. Say I have two block elements, which have paddings, margins, and borders. How does browser treat them when:
one is on the left and another one is on the right?
one is on the top and another one is on the bottom?
one is inside another one?
I'm going to assume that the block elements do not have a set width.
Let's work backwards...
One inside the other: all margins, borders and padding are cumulative. The inner block will expand to fill the outer block unless otherwise specified. And the outer block will expand to fill the width of its container unless otherwise specified. The width of the inner block will be calculated based on the overall container width minus the combined margins, borders and padding of both the outer block and inner block itself.
One above the other: under normal circumstances the bottom margin of the top block and top margin of the bottom block will collapse so that your overall margin between the two is the greater of the two. Borders and padding remain unaltered. The 2 block elements will expand to take up the available width of their container unless otherwise specified.
One beside the other: there are basically 2 ways to make this happen: by setting the display property of the elements to inline-block or by floating both elements. Since your question specifically states "block elements", I won't deal with inline-block. As far as floating goes, all margins, borders and padding remain unaltered. As already mentioned, block elements will take up the width of their container unless otherwise specified. This means they won't float next to one another unless you set the width of each so that the combined width + margin + border + padding of both blocks is equal to or less than the width of the container.
Hope that helps.
Your question is a bit ambiguous, all elements have unique IDs or classes that's how the browser treats them all differently and you can add different styles to each one
<div id="container">
<div class="element1"></div>
<div class="element2"></div>
</div>
css styles
.element1 {
float:left;
background:red;
border-style: solid 2px
}
.element2{
float:right;
background:yellow;
border-style: solid 5px
}

Why does CSS padding increase size of element?

I am trying to give my div and textarea some padding. When I do this, it increases the size of the element, instead of shrinking the content area inside of it. Is there any way to achieve what I am trying to do?
You could add box-sizing:border-box to the container element, to be able to specify a width and height that don't vary when you add padding and/or border to the element.
See here (MDN) for specifications.
Update (copied comment to answer)
Right now, the value border-box is supported in all major browsers, according to MDN Specs
Some browsers of course requires proper prefix i.e. -webkit and -moz as you can clearly see here
According to CSS2 specs, the rendered width of a box type element is equal to the sum of its width, left/right border and left/right padding (left/right margin comes into play as well). If your box has a width of '100%' and also has margin, border and padding, they will affect (increase) the width occupied by the object.
So, if your textarea needs to be 100% wide, assign values to width, margin-left/right, border-left/right and padding-left/right in such a way that their sum equals 100%.
In CSS3 we have three box-sizing models. You can use border-box model:
The specified width and height (and respective min/max properties) on
this element determine the border box of the element. That is, any
padding or border specified on the element is laid out and drawn
inside this specified width and height. The content width and height
are calculated by subtracting the border and padding widths of the
respective sides from the specified ‘width’ and ‘height’ properties.
This was a mess on W3C part and various browsers only added to this complexity with their own versions of box models. Personally, instead of thinking which browser or CSS setting will do the trick I just wrap the box' content in yet another DIV statement and use margins on that DIV, instead of using padding, like this:
<div id="container" style="width: 300px; border: 10px solid red;">
<div id="content" style="width: 250px; margin: 25px;">
Some content
</div>
</div>
Although this only works for fixed size containers
It depends on the browser and it's implementation of the box model. What you are experiencing is the correct behavior.
IE traditionally got it wrong: http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug
For a more cross-browser solution, you can avoid this behavior, by wrapping whatever tag that needs padding into another tag with fixed width, and giving it width:auto. This way, if the parent has a width of x, and you add padding to the child, the child will inherit the full width of x, applying the padding correctly without modifying the parent width or its own.
A div by default takes the width of its parent container, so to avoid browser compatibility issues, you could add a child div in the specified div then add the required padding to the child div.
N.B - don't specify width to the child div because it would increase if you add padding