Why does margin-top affect the placement of an absolute div? - html

I have two divs in this jsFiddle - http://jsfiddle.net/z4062jfn/ - with absolute positioning. I didn't expect any margin values given to the divs to affect their absolute position. And this is true for a margin-bottom value given to the top div (uncomment line 8 of CSS). But a margin-top value given to the bottom box (uncomment line 19 of CSS) does move the bottom div position down by that amount.
What is there in this situation that lets a margin rule override an absolute position rule - sometimes?
<div id="box1"><p>box 1</p></div>
<div id="box2"><p>box 2</p></div>

The simple factual explanation for why this happens is that the offset properties top, right, bottom and left actually respect the corresponding margin properties on each side. The spec says that these properties specify how far the margin edge of a box is offset from that particular side. The margin edge is defined in section 8.1.
So, when you set a top offset, the top margin is taken into account, and when you set a left offset, the left margin is taken into account.
If you had set the bottom offset instead of the top, you'll see that the bottom margin takes effect. If you then try to set a top margin, the top margin will no longer have any effect.
If you set both the top and bottom offsets, and both top and bottom margins, and a height, then the values become over-constrained and the bottom offset has no effect (and in turn neither does the bottom margin).
If you're looking to understand why the spec defines offsets this way, rather than why browsers behave this way, then it's primarily opinion-based, because all you'll get is conjecture. That said, Fabio's explanation is quite reasonable.

Because an absolutely positioned box is removed from the normal flow and is assigned a position with respect to the containing block. If you don't define a containing block, then it's body.
So, with that in mind, think of the containing block as a coordinates axis that starts at top left. If you give your element this properties:
position: absolute;
top:100px;
left:100px;
just like you did, you will have leave an empty space above and left, thus, if you apply margin-top or margin-left, it will work, because your elements are capable to virtually go through every pixel of both axises up to that 100px top and 100px left position, and same applies for negative margins. However, since position:absolute removes the element from the flow and any impact on any subsequent sibling element, it's easy to see that nothing can happen after the element "finishes", hence margin-bottom and margin-right won't work since they don't have anything to get margin from.
I have made an image to show the behavior since my explanation might be a bit obscure

Your margin bottom is not working since you put the top property in your divs. Remove top and your margin bottom will work for your #box1.

Margin-bottom affect too. See the code below, if you set a bottom reference in #box1 it will apply 20px in margin-bottom.
http://jsfiddle.net/t5ooot7u/
#box1 {
width:200px;
height: 100px;
background-color:gold;
position: absolute;
bottom:230px;
left:100px;
margin-bottom:20px;
}

Related

How do margin rules apply to elements not in the DOM flow?

So I asked this question: google chrome issue with fixed position and margin-top which finally got me to realize that top and margin-top are not the same thing. I don't know how I've missed that all these years.
Anyways that got me thinking what is the difference exactly between margin-top and top, which is how I found this question: CSS: Top vs Margin-top.
I already knew what margin-top did. But I had never extrapolated that out to think "hmm, this element is not in the DOM flow so what exactly is margin-top pushing it away from?"
From the question I asked I know that margin-top behaves in very unexpected ways when applied to an element with a fixed position. And that in Chrome at least this can lead to some crazy rules (like margin-top: -273%;).
So my Question is: How do browsers apply margin rules to elements not in the DOM flow (i.e. elements with a position value of fixed or absolute . And what about the way they are applied and rendered leads to rules, like the one described above, actually rendering the element inside the view-port?
The top property simply determines how far from the top of the containing element that the box-model should start being rendered. In the case of position: fixed, that is the window itself. In the case of position: absolute, it is the next parent element with a non-static position.
Margin, on the other hand, is part of the box-model itself. Adding margin to the top of the box increases the empty space present above the box.
Consider the following layers for a position: fixed box:
top:10px
margin-top:10px
------------border-top:1px------------
padding-top:10px
content
All of the margin, border, and padding are part of the box model. That entire element, or "piece", is just one big square when positioning. So, if you have a margin of 10px on the top of the box, and position the element 10px from the top, it will have the appearance of having 20px of margin between the top of the window and where the visible box starts.
I've also made a very simple example in jsFiddle.
If you like graphics, take this example, where the red box has a position: fixed:
As you can see in the first section, only setting position: fixed on the element doesn't actually move it anywhere. It just removes it from the flow of the document.
In the section section, adding a margin-top: 10px makes the element move down 10px because the box now has 10px of margin on the top of it. However, it hasn't actually moved anywhere. The box has just gotten taller because the box model has changed.
In the third section, using a top: 10px actually moves the box to be 10px from the top of the window container. It has the exact same box model as in the first section.
Section four is like the second section above it, except the negative margin causes it to move up ten pixels. The box model is still taller and the box still hasn't moved.
When you set an absolute position on an element, the element doesn't move at all if you don't set any other position properties. So, without a top, right, bottom, or left property set, the element stays in the position it would have been in if it had been rendered as part of the flow, it's just now removed from the flow. So adding a margin, either positive or negative, makes it appear to move up or down from that position. In reality, you're just changing the element's box model though.
You also have to realize that using a percentage on top and bottom margins (and even paddings) has nothing to do with the height. It actually uses the width to figure out how much margin is there. Saying margin-top: 10% will make that value 10% of the available width, not the available height, and making it negative will just negate that value. I mentioned this because it is relevant to that first question you linked where you were using percentages for margin-top.
I hope this covered what you were looking for. I couldn't tell what exactly you were confused about so I just explained as much as I could.

the concept of negative margins - have i understood?

i read that negative margin-top and left takes the element and pushes it in this direction. On the other hand negative bottom and right margins draw the rest of the content over the element.
Question
I have a floated element float:right; wrapped in the body tag. Negative left margin will move it to the left.
Negative RIGHT margin wont do anything at all because the document ends where this negative margin starts and there is nothing to draw over the element (or pull over it)?
Am i correct?
Negative margins will always work on block boxes the same way that positive margins do. They just move a box and/or surrounding boxes in the opposite direction that positive margins do. Heck, negative margins can even collapse.
If any overflow occurs, then related boxes will adjust and accommodate for this box's movement.
If an element is floated in a certain direction, then a margin on the side that it's being floated towards will have an effect on its own position, and a margin on the opposite site will influence it relatively to any succeeding floats.
Negative RIGHT margin wont do anything at all because the document ends where this negative margin starts and there is nothing to draw over the element (or pull over it)?
No. There is this thing called the canvas, which has a theoretically unlimited amount of space for expansion. Got a margin pushing an element out of the page body or page root? NBD, just expand the canvas in that direction, make a scrollbar in the viewport which is used to display this canvas, and done.
It's the same as if you had a negative margin on an element whose parent has overflow: auto, because the root element itself has overflow: auto by default (since you can't really have stuff visibly overflowing the browser window itself...).
jsFiddle proof-of-concept
Many people believe the same misconception about negative margins. The behavior you describe tends to match many negative margins cases, but it is explaining them from a flawed perspective. Actually, negative margins have the same effect on any side of the box, but not in terms of "move the box" or "draw other content in".
For example, a left-margin: -20px means "position the element as if its left edge were 20 pixels inwards from its true left edge". A right-margin: -20px means exactly the same thing, but for the right edge.
In the simplistic description you have provided, the negative left margin would indeed shift the element itself leftwards, because its left edge is placed adjacent to the previous element's right edge, but the browser pretends that our element's left edge is actually moved rightwards, so the content of the element itself appears moved leftwards.
With the negative right margin, the browser places the next element's left edge adjacent to our element's right edge, but it pretends that our element's right edge is moved leftwards, so the next element itself appears moved leftwards.
In both cases, the only thing that is changed is the browser's notion of the position of the element's edges.
When you have a right-floated element, the browser will position it so that its right edge will be adjacent to the left edge of the previous right-floated element, or if there is no previous right-floated element, it will be adjacent to the right edge of its position parent (which is the closest parent element with a position style that is not static). In your case you don't have a previous right-floated element, so the browser positions your element so that its right edge is adjacent to the parent's right edge, but it pretends your element's right edge is moved leftwards, so your actual content is moved rightwards, protruding outside of the parent element.
Here is a demonstration. The box with the blue border has negative left and right margins. The yellow box inside it represents how the browser considers it — it is narrower than the blue-bordered box, because the negative margins tell the browser to move its edges inwards, eating from the element's actual size. As you can see, its positioning box is placed exactly as any element would be, touching its left and right siblings on both sides. And the actual content extends in both directions by exactly the same amount, because its negative margins are the same. The perceived change is that the element itself is moved left due to its left margin, and following content is moved left due to its right margin, but as you can see, in reality, the effect is exactly the same on both sides.
Negative right margin sure works! http://fiddle.jshell.net/H6mjC/
also made a fiddle. Of course negative margin is working.
fiddle with negative margin
enter code here

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.

Why this behaviour (on ALL browsers) with margin-top?

This is my code :
HTML
<div class='father'>
<div class='son'>Son</div>
</div>
CSS
.father
{
background-color:blue;
}
.son
{
margin-top:50px;
background-color:red;
height:50px;
}
Where is the background-color blue of the father?
I know how to fix this problem (putting padding-top:1px to the father) but I'd like to know why of this behaviour!
For me it doesnt make sense, because on every browsers, not only IE, this is the behaviour.
This is a result of Collapsing Margins. You can read a good article by Eric Meyer on this topic where he illustrates this exact behavior. The following image is from his article.
Here's what the CSS2 specification has to say about it.
8.3.1 Collapsing margins
If the top and bottom margins of a box are adjoining, then it is
possible for margins to collapse through it. In this case, the
position of the element depends on its relationship with the other
elements whose margins are being collapsed.
If the element's margins are collapsed with its parent's top margin, the top border edge of the box is defined to be the same as
the parent's.
Otherwise, either the element's parent is not taking part in the margin collapsing, or only the parent's bottom margin is involved.
The position of the element's top border edge is the same as it
would have been if the element had a non-zero bottom border.
Note that the positions of elements that have been collapsed through
have no effect on the positions of the other elements with whose
margins they are being collapsed; the top border edge position is only
required for laying out descendants of these elements.
Source: http://www.w3.org/TR/CSS2/box.html#collapsing-margins
This is because the div is a block-level element. Certain block-level elements don't contain any padding by default. Divs are one such element. Block-level elements will take up the entire height and width of the container while respecting any padding it may contain.
W3C Visual formatting model
The parent element's height is set to its content's height by default. Once you set a height on the parent, that's no longer the default. Checking up on it, I believe that the padding adds to the height. So, the height is originally determined by the content unless otherwise stated in the CSS. Then, in most cases (IE 6 may be the exception), the padding is added to the height.
Good thing about SO, it helps us be much more detailed in our responses. :)
In CSS, block level elements naturally fills the elements content area, so your "son" div is filling your "father" div completely. Of course, you can bypass this by adding margin/padding/height to your parent div.
You're setting blue explicitly:
.father {
background-color:blue;
}
It's overridden (thanks to the "C" in CSS a.k.a cascading) but the style remains on your parent element (here, appropriately named "father").
If your .father box receives any height at all (check in the Firebug/Chrome dev tools inspector) than the blue is going to show through. I am guessing this is what you're seeing in IE (that or perhaps there's a flash of content before your child element style comes in). I don't think the IE debug tools show bounding boxes but you can test the element for it's height using JavaScript.
Moving outwards from the content, you have padding, border, and margin (as you probably know). Background covers only padding, but not margin.

Top & Left vs margin-top & margin-left

What is the difference between using top and left properties and top and left margins?
I know top and left are usually used in position:absolute situation but I'm still wondering if there is any major difference.
ex:
position:absolute;
top:5px;
left:5px;
-vs-
margin-top:5px;
margin-left:5px;
Well, the main difference is that absolutely positioned elements are pulled out of the content flow.
But also with relatively positioned elements, the surrounding content may become obfuscated.
Margins on the other hand are added to the element's size while the surrounding content flows accordingly.
See this sample fiddle with some differences.
Surely there are situations where both deliver the same results, but under normal conditions, these two aproaches aren't simply exchangeable nor comparable.
A There's a semantic difference. Box offsets like top specify how far a box's margin edge (dotted edges in the image below) is offset from a reference edge (For absolutely positioned elements, that's the top edge of the box's containing block). Margin properties like margin-top specify the width of the margin area of a box (The distance TM between the dotted edge and and solid edge in the image below).
B top and left apply only to positioned elements (elements with position set to anything other than static) while margin-top and margin-left apply to all elements except elements with table display types other than table-caption, table and inline-table.
Margin describes the space between your box and adjacent boxes. Boxes that are positioned relatively (i.e. that are part of the normal flow) will keep the sufficient space between them that each one's "margin" requirements are met (called "margin collapsing").
top and left on the other hand are positional attributes that specify where your box is located; for absolutely positioned boxes the values are taken relative to the nearest containing box which is itself absolutely positioned. The top/left/bottom/right attributes specify the location of the respective edge of your box including its margin.
In short, the two are entirely different concepts. For normally flowed boxes you should use margin to control the spacing between neighbouring boxes.