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

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.

Related

HTML element moving when viewport width changes, but no change in CSS

Having a strange issue which has happened to me before but I couldn't figure out the issue either. I can work around it but I'd prefer to understand why it's happening so that I can fix the root issue.
The position of a element is changing between 1200px and 1999px as you can see here:
1200px:
1999px:
The element is behaving like there is a breakpoint at 1200 but there isn't and the css doesn't change either according to Chrome dev tools.
You can see that the margin and position change slightly but not enough to cause such a shift in position.
I am using Bootstrap in case that matters.
Does anyone have any idea what's causing this?
This is the problem:
margin-top: 1.5%
You have a percentage based margin value, therefore, on resize, the positioning of the H2 will vary.
If you don't want it to vary, change it to another unit, for example px.
Also, you might want to specify offsets properties (left/right, top/bottom) of the element:
absolute
The element is removed from the normal document flow; no space is created
for the element in the page layout. Instead, it is positioned relative
to its closest positioned ancestor if any; otherwise, it is placed
relative to the initial containing block. Its final position is
determined by the values of top, right, bottom, and left. This value
creates a new stacking context when the value of z-index is not auto.
Absolutely positioned boxes can have margins, and they do not collapse
with any other margins. Source MDN

Why is the outline larger than its div?

UPDATE
To get the input back to the size I want it to be, I had to get rid of padding and borders. The following accomplished this:
*{padding:0; margin:0; border:0;}
Thanks to CBroe, I discovered this is unique to FF which adds to the input a default border of .75px and a padding of 1.5px. For a total of about 4.5px. Chrome does not.
UPDATE 2
The above fix only gets the child element back to the size I thought it should be. The accepted answer below shows that FF has a bug which explains why the outline didn't behave as it should, which is to outline the parent only and not expand for absolute positioned descendents.
I have two div elements stacked vertically with their outline property set to 1px. The div elements have a height of 117px.
I expect where the two div elements meet to have their outlines contiguous. It does so with no content.
When I place an absolute positioned input with top = 97px and height = 20px into the top div , the outline of that div is pushed down.
Here is a fiddle which shows this. If you remove the input, you will see how the top div outline sits next to the bottom div.
There are two things (at least) that I do not understand:
1) In examining the box using the browser's dev tools (Firefox), I see that the top div is in fact still 117px high. The outline should be drawn around the div, but appears not to be. Why?
2) The input has a top of 97px plus a height of 20px. Why would this affect the position of the outline? It looks like the outline is pushed down 4px.
That's because outlines are implementation dependent. It's not only the size:
Outlines may be non-rectangular.
From CSS3 UI,
This specification does not define the exact position or shape of the
outline, but it is typically drawn immediately outside the border box.
Firefox has historically had a tendency of making outlines bigger in various situations, e.g.
outlines are drawn outside (i.e., expanded by) box-shadow and other visual overflow
outlines are drawn outside (expanded by) outlines on descendant elements
The former was fixed, the latter seems the same as your problem.
I've 2 answers for you:
1) In examining the box using the browser's dev tools (Firefox), I see that the top div is in fact still 117px high. The outline should be drawn around the div, but appears not to be. Why?
The outline appears to be drawn around everything inside. So if an element stand out 100px at the bottom. The outline will also be moved 100px. In this case the input element stands out 8px. So the outline is 8px longer than you expected.
The input has a top of 97px plus a height of 20px. Why would this affect the position of the outline? It looks like the outline is pushed down 4px.
You were almost right there, 97px+20px is indeed 117px height. But you forgot to count 8px from the input element. This comes from a 3px thick border + 1px thick padding.

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

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;
}

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

CSS - make div's inherit a height

I'm trying to make a box with rounded corners where the height and width of the div depends on the content, so it's automatically adjust to it...
You can see the example here: http://pastehtml.com/view/1duizyf.html
The problem is that i can't get the "test_mid_left" (black background) and "test_mid_right" (turquoise background) to inherit the height from the "test_mid_center" (green background). I have tried height: 100% and auto, but none of thoose work. So how do I get them to inherit the height from the content?
(The reason why I have used "min-height: xx" in the left and right content on the example is just to show which boxes I am talking about)
As already mentioned this can't be done with floats, they can't inherit heights, they're unaware of their siblings so for example the side two floats don't know the height of the centre content, so they can't inherit from anything.
Usually inherited height has to come from either an element which has an explicit height or if height: 100%; has been passed down through the display tree to it.. The only thing I'm aware of that passes on height which hasn't come from top of the "tree" is an absolutely positioned element - so you could for example absolutely position all the top right bottom left sides and corners (you know the height and width of the corners anyway) And as you seem to know the widths (of left/right borders) and heights of top/bottom) borders, and the widths of the top/bottom centers, are easy at 100% - the only thing that needs calculating is the height of the right/left sides if the content grows -
This you can do, even without using all four positioning co-ordinates which IE6 /7 doesn't support
I've put up an example based on what you gave, it does rely on a fixed width (your frame), but I think it could work with a flexible width too? the uses of this could be cool for those fancy image borders we can't get support for until multiple background images or image borders become fully available.. who knows, I was playing, so just sticking it out there!
proof of concept example is here
The Problem
When an element is floated, its parent no longer contains it because the float is removed from the flow. The floated element is out of the natural flow, so all block elements will render as if the floated element is not even there, so a parent container will not fully expand to hold the floated child element.
Take a look at the following article to get a better idea of how the CSS Float property works:
The Mystery Of The CSS Float Property
A Potential Solution
Now, I think the following article resembles what you're trying to do. Take a look at it and see if you can solve your problem.
Equal Height Columns with Cross-Browser CSS
I hope this helps.
The negative margin trick:
http://pastehtml.com/view/1dujbt3.html
Not elegant, I suppose, but it works in some cases.
You need to take out a float: left; property... because when you use float the parent div do not grub the height of it's children... If you want the parent dive to get the children height you need to give to the parent div a css property overflow:hidden;
But to solve your problem you can use display: table-cell; instead of float... it will automatically scale the div height to its parent height...
Most of the times, the Previous parent has a heigt manually set, so you can use that value as reference, no other dirty tricks will be needed, and if the number is not the same for any reason maybe a comment can be added with the original number so in case you need to change it, by searching at the all the values, this one can be adjusted or even changed, in the time someone resolve this one for us.