Basic HTML/CSS - margin & display behaviour - html

I have a basic question regarding HTML/CSS and the behaviour of margins from certain elements.
To make my point clear, I created this fiddle: http://jsfiddle.net/5VA5h/
You see, I applied some kind of "reset" and added some styles to all h1.
In the first example, the margin from h1 is applied on the outside of the box, while in #c, where h1 is set display: inline;, it is applied inside the box.
Why is this so?

In your first example, with the <h1> as a block element, the top margin is collapsing (emphasis mine):
In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.
...and later:
Two margins are adjoining if and only if:
both belong to in-flow block-level boxes that participate in the same block formatting context
no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.)
both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
top margin of a box and top margin of its first in-flow child
bottom margin of box and top margin of its next in-flow following sibling
bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height
top and bottom margins of a box that does not establish a new block formatting context and that has zero computed 'min-height', zero or 'auto' computed 'height', and no in-flow children
The second example, with the <h1> as an inline element, the vertical margins do not take effect:
The 'margin' shorthand property sets the margin for all four sides while the other margin properties only set their respective side. These properties apply to all elements, but vertical margins will not have any effect on non-replaced inline elements.

Margin-Top and Margin-Bottom is not used by elements with display:inline;
See: Margin top in inline element

Top and Bottom margins in inline elements are not important. In inline elements, each element represents a word in a text.

Related

How to compute width & height of an element?

My understanding is,
Width of an element = (left border width + left padding width + content width + right padding width + right border width)
Height of an element = (top border height + top padding height + content height + bottom padding height + bottom border height)
Below is the diagram for the same.
width of an element = (10+10+140+10+10) = 180
height of an element = (10+10+150+10+10) = 190
margin is not included in the size of an element.
content & padding are only included in the click region.
Is the above formula correct on computing width and height of an html element?
It sounds like what you are describing is the offsetWidth and offsetHeight of an element, which returns the "layout width and height" of the element, i.e. the final width after all calculations.
MDN defines offsetWidth the following way:
The HTMLElement.offsetWidth read-only property returns the layout width of an element. Typically, an element's offsetWidth is a measurement which includes the element borders, the element horizontal padding, the element vertical scrollbar (if present, if rendered) and the element CSS width.
So to answer your question, the final layout width of an element is typically the sum of the element's borders, horizontal padding, vertical scrollbar width, and content width.
The final layout height (offsetHeight) would be similar.
The way CSS calculates height and width is not as simple and straightforward as it may seem.
The most direct answer to your question...
How to compute width & height of an element?
...is: It depends on the type of box being used.
According to the CSS Visual Formatting Model:
10.3 Calculating widths and margins
The values of an element's width, margin-left, margin-right,
left and right properties as used for layout depend on the type of
box generated and on each other... The following situations need to be
distinguished:
inline, non-replaced elements
inline, replaced elements
block-level, non-replaced elements in normal flow
block-level, replaced elements in normal flow
floating, non-replaced elements
floating, replaced elements
absolutely positioned, non-replaced elements
absolutely positioned, replaced elements
inline-block, non-replaced elements in normal flow
inline-block, replaced elements in normal flow
10.6 Calculating heights and margins
For calculating the values of top, margin-top, height, margin-bottom, and bottom a distinction must be made between various kinds of boxes:
same list as above
I was actually hoping to create a simple reference guide here by listing the variables that make up the width and height for at least a few of the box types. So I started with block-level and found that calculating the width, in general terms, was easy enough:
containing block width = margin-left + border-left-width + padding-left + width + padding-right + border-right-width + margin-right
However, when I got to height, I found this:
10.6.3 Block-level non-replaced elements in normal flow when overflow computes to visible
This section also applies to block-level non-replaced elements in
normal flow when overflow does not compute to visible but has been
propagated to the viewport.
If margin-top, or margin-bottom are auto, their used value is 0.
If height is auto, the height depends on whether the element has
any block-level children and whether it has padding or borders:
The element's height is the distance from its top content edge to the
first applicable of the following:
the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin does not collapse
with the element's bottom margin
the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
zero, otherwise
Only children in the normal flow are taken into account (i.e.,
floating boxes and absolutely positioned boxes are ignored, and
relatively positioned boxes are considered without their offset). Note
that the child box may be an anonymous block box.
There are many factors to consider when calculating height.
TL;DR
For an accurate and specific reading of the calculations used to determine the width or height of an HTML element, refer to the CSS Visual Formatting Model. To learn the exact height or width of an element refer to the computed values tab in developer tools.
The width CSS property specifies the width of the content area of an element. The content area is inside the padding, border, and margin of the element.
https://developer.mozilla.org/en-US/docs/Web/CSS/width
This page explains the box model in more detail: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model

How height: auto works in HTML and CSS?

In CSS and HTML how does height: auto work? What do browsers consider while calculating height of the element, for which height is set to auto?
You can split two cases:
div and other containers: the height is the one the browser will use if you don't specify anything, trying to contain the element contents. (read Mathijs's answer for more details)
images and other block elements with intrinsic dimensions (width and height): if you specify the width, then "height: auto" will scale proportionally.
So, in other words, is useless unless you need to reset the browser behaviour or keep proportions to some objects.
Here's an excerpt on this copied from the W3C CSS2 spec
If it only has inline-level children, the height is the distance
between the top of the topmost line box and the bottom of the
bottommost line box.
If it has block-level children, the height is the distance between the
top margin-edge of the topmost block-level child box and the bottom
margin-edge of the bottommost block-level child box.
Absolutely positioned children are ignored, and relatively positioned
boxes are considered without their offset. Note that the child box may
be an anonymous block box.
In addition, if the element has any floating descendants whose bottom
margin edge is below the element's bottom content edge, then the
height is increased to include those edges. Only floats that
participate in this block formatting context are taken into account,
e.g., floats inside absolutely positioned descendants or other floats
are not.

Strange margin issue with a display: inline-block child

Heres the fiddle
When I set #two to inline-block it subtracts the 16 px of top/bottom margin from the <p> and adds it to the divs content box height so it becomes 52px instead of 20px .. why is this the case?
What you're seeing is one of the stranger cases of margin collapsing.
If the parent and children are block elements and there's nothing (padding, a border, etc.) separating their vertical margins, then those margins will collapse. Collapsed margins are when two neighboring margins aren't added (as you might expect), but instead the larger of the two is displayed. In the parent-child case, the collapsed margin ends up outside the parent. You can read more details under the section Parent and first/last child in the above link.
Setting the parent to inline-block, or float:left;ing it or a number of other things (refer to the link for a more complete list) will stop the margins from collapsing. This leads to the behavior we're used to: the child's margin will appear inside the parent, adding to its total height, and the parent's margin will also be displayed.
To elaborate, and expand on the existing answers..
This behavior is known as collapsing margins.
8.3.1 Collapsing margins
In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.
To work around this, you need to establish a new block formatting context:
9.4.1 Block formatting contexts
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.
Therefore a few different ways to establish a new block formatting would be to..
Change the overflow property of the parent element to something other than the default value, visible - (updated example)
Change the display of the element to inline-block - (updated example)
Float the element - (updated example)
This has already been answered and accepted, still I'd like to point out that clearfixing it would have prevented margin collapse thus normalizing its behaviour
I'd add:
.two:before,
.two:after {
content: " ";
display: table;
}
.two:after {
clear: both;
}
See this fiddle .
Here's the Nicholas Gallagher clearfix I've used.
Paragraphs have margins built in (in most browsers).
Try this:
p
{
margin: 0px;
}

Removed margins above and below a <div> element?

I've come across a strange behavior related to the margins of a <div> element. I've added a very simple test case to jsFiddle to show you what I mean.
Interestingly the margins are used correctly when using a border. Is this the default behavior? Does this have something to do with collapsing margins? Is it possible to somehow force the margins without any hacks?
Least ugly solution so far that I thought of:
.cssContainer {
margin:10px;
padding:0.1px;
background-color:#FF0000;
}
But I don't know whether this will work in every browser.
This is another case of adding overflow:auto to the rescue!
jsFiddle example
Just add overflow:auto to your container div and voila, harmony is restored.
.cssContainer {
margin:10px;
padding:0px;
overflow:auto;
background-color:#FF0000;
}
From specs, the reason this works is because a new block formatting context is established by applying overflow other than visible, forcing margins of .cssContainer to not collapse with its in-flow children .cssElement.
From this site
the simplest way to stop the margin collapse from occurring is to add
padding or borders to each element. If we wanted 10px margins on each
element we could simply use a 9px margin and 1px of padding to get the
result we wanted
This is due to the CSS box model. The elements with the red backgrounds will not grow in height to accommodate the top and bottom padding of its children elements, but because the border was specified in the second example and encompasses the padding, the padding will show.
The overflow: auto; property works because the padding overflows its parent element. To illustrate this, in Google Chrome Developer Tools, find and click the HTML row for the green element whose bottom padding will not show. Chrome will highlight the element on the page. Notice how the padding is included in the highlighted element. The padding actually overflows the parent element. The parent element won't show it though because there's no content in or after the padding (no 'bounds').
From the css spec regarding box models:
Adjoining vertical margins collapse, except:
...
Horizontal margins never collapse.
Two margins are adjoining if and only if:
...
both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
top margin of a box and top margin of its first in-flow child
bottom margin of box and top margin of its next in-flow following sibling
bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height
...
Note the above rules imply that:
...
Margins of elements that establish new block formatting contexts (such
as floats and elements with 'overflow' other than 'visible') do not
collapse with their in-flow children.
Unfortunately, text-overflow: auto is slightly risky because the spec says:
auto
The behavior of the 'auto' value is user agent-dependent,
but should cause a scrolling mechanism to be provided for overflowing boxes
However, all browsers that I have looked at appear to implement it in the following manner:
The box is expanded to the smaller amount between:
as much as its containing box allows
as much as is necessary to display the content without clipping
Then if clipping must occur, a scrollbar is added.

Margin top in inline element

My question is pretty simple:
Why is the margin top ignored for inline elements in firefox?
Does anyone know?
This is not Firefox-only, and defined in the CSS 2.1 Specification:
8.3 Margin properties: 'margin-top', 'margin-right', 'margin-bottom', 'margin-left', and 'margin'
Margin properties specify the width of the margin area of a box. The 'margin' shorthand property sets the margin for all four sides while the other margin properties only set their respective side. These properties apply to all elements, but vertical margins will not have any effect on non-replaced inline elements.
(Emphasis at the end is mine; margin-top is a vertical margin)
inline elements can apply only margin letf and right but if you are using firefox it also appear margin bottom and top after inspect element but it doesn't apply realy