unexpected margin with very simple html - html

I have a very simple html. The red div is inside the blue div and has a 10 px top margin. On non-ie browsers, the blue box is 10 px apart from the top of viewport and the red div is at the very top of the blue div. What I expect is the ie behavior: red div must be 10 px apart from the top of the blue div. Why does non-ie browsers render like this? (I suppose the wrong behavior is the IE's but why?)
And, what is the correct way to do this?
why blank? http://img92.imageshack.us/img92/7662/blankmr7.jpg
<html>
<head>
<style>
body { margin:0; padding:0; }
.outer
{
background-color: #00f;
height: 50px;
}
.inner
{
height: 20px;
width: 20px;
background-color: #f00;
margin: 10px 0 0 10px;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
</div>
</div>
</body>
</html>

As much as strager's answer already explains about as much as you need to know as to why it happens – namely that it happens the way it does in browsers other than IE because the specs say so – I think he picked the wrong quote from the section of the CSS 2.1 specification about collapsing margins.
The point he quoted explains how margins can collapse, not how they can "move" to a parent element.
This is rather what explains it:
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.
Or, in slightly more human-readable form in the Mozilla developer documentation:
Parent and first/last child:
If there is no border, padding, inline content, or clearance to separate the margin-top of a block with the margin-top of its first child block, or no border, padding, inline content, height, min-height, or max-height to separate the margin-bottom of a block with the margin-bottom of its last child, then those margins collapse. The collapsed margin ends up outside the parent.
As for how to fix it, I'd probably go for the overflow: auto solution Chris Lloyd suggested (as much as that may have side-effects).
But then that really depends on what exactly the rest of your code looks like. In this simple example you could easily just change the margin on the child element to a padding on the parent element.
Or you could float the child element, or absolutely position it...
Or how about an inverse clearfix if you want to get really fancy:
.outer:before {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}

The margins are being merged. The output produced by IE is probably incorrect.
In the specifications (which are down for me at the moment):
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.
You can use borders instead of margins, with border-color set to transparent.

There is a pretty fitting answer to this question: overflow: auto;
<html>
<head>
<style>
body { margin:0; padding:0; }
.outer
{
background-color: #00f;
height: 50px;
overflow: auto;
}
.inner
{
height: 20px;
width: 20px;
background-color: #f00;
margin: 10px 0 0 10px;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
</div>
</div>
</body>
</html>

Could it be IE sees the DOM as div.inner having div.outer as it's parent node(and calculates offset from it),
and that other browsers instead has both of them answering to the body element?

Ok, solution without overflow auto:
<html>
<head>
<style>
body { margin:0; padding:0; }
.outer
{
background-color: #00f;
height: 50px;
border: 1px solid transparent;
}
.inner
{
height: 20px;
width: 20px;
background-color: #f00;
margin: 10px 0 0 10px;
padding: 0;
}
</style>
</head>
<body>
<div class="outer">
<div class="inner">
</div>
</div>
</body>
</html>
The inner element is wanting something to push against, and providing a boder (or forcing the browser to consider the overflow) does this.

Related

Weird padding behaviour for inline element (bottom padding is respected but top padding doesn't)

I though I knew how inline elements worked. A nice answer explaining it can be found here: CSS display: inline vs inline-block.
What it says about inline elements:
respect left & right margins and padding, but not top & bottom
Inline elements only support right and left padding and ignores any padding given for top and bottom. But doing some tests I just found a really odd behaviour. When given a padding to an inline element, it applies it to the left and right of the element but also to the bottom but not to the top.
Is there any explanation for this behaviour?
<html>
<head>
<style>
* {
box-sizing: border-box;
padding:0;
margin:0;
}
.parent{
display:inline;
background-color: red;
padding: 10rem;
color:white;
}
</style>
</head>
<body>
<div class="parent">Whatever</div>
</body>
</html>
Use the browser tools to inspect the element and you'll see that there is also a padding-top of 10em, which is not visible in your snippet.
The reason: Although there is a padding for inline elements, it does not affect the distance above and below it - the line (i.e. baseline for the text) is at the same vertical position where it would be (or better: is) without the padding. The padding here just creates an overflowing area which you only see if there is a background defined.
See my snippet, where I added a wrapper with a 12em padding-top and some text before and after the inline div, and also before and after the wrapper div which demonstrates what happens.
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.wrap1 {
padding-top: 12em;
background: green;
/* display: block; is the default here */
}
.parent {
display: inline;
background-color: red;
padding: 10rem;
color: white;
}
.y {
background: rgba(255, 255, 0, 0.4);
border-radius: 50%;
padding: 0.6em 0.15em 0.6em 0.1em;
}
<body>
<div>This is in a separate div which preceds the inline div and its wrapper.</div>
<div class="wrap1">
this is on the same the line
<div class="parent">Whatever</div> yes it is
</div>
<div>And this is in a separate div following the inline div and its wrapper.</div>
<p>And here is another line with one (inline) <span class="y">word</span> that has a padding in a way that <em>might</em> be considered useful.</p>
</body>

Why is padding right clipped with overflow:scroll

In the snippet below, padding-right for .ctr is not visible when content starts to overflow at small viewports.
I've read other answers and I know how to fix it.
I just need to move padding:20px from .ctr to .row. Or just add margin-right:20px to last child.
But, I couldn't find the reason as to why this happens. Could someone please explain, what's going on? any resource for further learning will be highly appreciated 🙏
Thanks!
.ctr {
display: flex;
overflow-x: auto;
padding: 20px;
}
.row {
margin: 0 auto;
display: flex;
}
.child {
margin-right: 20px;
width: 600px;
height: 100px;
background: red;
}
.child:last-child {
margin-right: 0;
}
<div class="ctr">
<div class="row">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
</div>
The padding is actually there when the content overflow it hides it.
we can illustrate this using background and background-origin
.container {
display: flex;
overflow-x: auto;
padding: 20px;
width: 200px;
background: linear-gradient(red, red) no-repeat;
background-origin: content-box;
border: 1px solid;
}
.overflow {
background: pink;
min-width: 400px;
height: 100px;
border: 1px solid;
}
<div class="container">
<div class="overflow"></div>
</div>
the white space you see on the edges is the padding
background-origin: content-box; makes the background exclude border and padding which will show us that the padding isn't clipped only covered, this happens because padding is part of the parent and the content overflow the parent so it covers it.
There's nothing special about this.
Dude the reason is the rendering or calculation in browsers (or the logic or system that we have developed starts from the top/left and ends at right/bottom). So, padding the hierarchy of placement is:
margin > border > padding > content
(And, remember it starts with top/left).
Now the issue you are seeing is only because you have not increased the height of item. If you do so - You will not only find issue on the right-padding but also on the bottom-padding.
Padding is only an effort to wrap something which is flexible. When you give a 600 * 5 width to items then they take more width than available.
padding is not as strong contender like margin. Because, margin you apply on same element - whose width or height you are manipulating. padding is being applied on an element which is trying to impose restrictions on some other element (usually direct child). So, this is the difference between padding and margin and how they get applied on browsers via Box-Model.
Hope, this clarifies a bit.

Absolutely positioned div is too wide when padding: %

I have two divs, one position:static and one position:absolute. Despite having the same width and padding values, the absolutely positioned div gets about 17px wider. This only happens when I specify the horizontal padding as a percentage. How do I get these divs to be the same width without removing the % padding?
.foo {
border:2px solid blue;
background: pink;
width: 200px;
padding: 20px 20%;
}
.foo:nth-child(3) {
border-color: red;
position:absolute;
top:96px;
}
<div class="foo"></div>
<div class="foo"></div>
<div class="foo"></div>
I know how to fix this:
body {
width: 100%;
}
I'm just not 100% sure why this is happening. It probably has something to do with the absolute positioned element does not share the same containing element (body vs html) and that is what padding that uses percentages is based off of.
That's because percentages are resolved relatively to the containing block, which varies in the absolute case.
For the in-flow elements, the containing block is established by the body element, which by default has some margin, so it's narrower than the viewport.
For the absolutely positioned element, the containing block is established by the nearest positioned ancestor. Since there isn't any, it's the initial containing block, established by the viewport.
The solution is positioning body so that it establish the containing block for the absolutely positioned element:
body {
position: relative;
}
body {
position: relative; /* Establish the containing block for absolutely positioned descendants */
}
.foo {
border: 2px solid blue;
background: pink;
width: 200px;
padding: 20px 20%;
}
.foo:nth-child(3) {
border-color: red;
position: absolute;
top: 96px;
}
<div class="foo"></div>
<div class="foo"></div>
<div class="foo"></div>
The problem you're facing is in reality a pretty common one: default margin on the body.
By adding margin: 0; for the body, the issue is solved. The reason why padding: 20px 20%; behaves differently for the elements is because the percentage value is based on the width of the parent - for the statically positioned elements, this is reduced by the default margin. However, for the absolutely positioned element, this margin on the body is ignored (html rather than body is treated as its parent, which has no margin) and the 20% will be of a larger number.
This is also why you had to use top:96px; instead of top:88px (40px in padding + 8px in borders) for that absolutely-positioned element - the default margin pushed down the top two elements.
Here's your code, adjusted accordingly:
body {
margin: 0;
}
.foo {
border: 2px solid blue;
background: pink;
width: 200px;
padding: 20px 20%;
}
.foo:nth-child(3) {
border-color: red;
position: absolute;
top: 88px;
}
<div class="foo"></div>
<div class="foo"></div>
<div class="foo"></div>
I know this is an old one, but it shows up in the top spot in google for certain terms, so I thought I'd go ahead and give the correct answer.
Yes, this does have to do with inheriting parent, but not in the way described. Body inherits it's values from the html tag, meaning that the issue isn't with the body tag.
The clue is in the very specific 17 pixels. That is the default width of the scrollbar in chrome.
Looking at the code here, the width was specified in %. Setting the body to
width:100%
margin:0px
padding:0px
will set the body to be the same width as the tag
The tag in turn will be 100% of the AVAILABLE window, which means that if your content generates a scrollbar, that width is now -17 pixels wide.
The sollution is to set either your body or your html tag (yes, you can style that one too) to
width:100vw;
vw doesn't take the scrollbar into account, but instead only displays the windows width.
I hope that makes sense, and that I have managed to help you solve your problem.

Why does <p> put space outside of <div>?

Ok, we can clearly see that there is a space between the top and the <div>. Now, I know this is cause by the margin/padding of the <p> element, but why does it appear outside of the <div> and not inside of it?
body{
margin: 0px;
padding: 0px;
background-color: #808080;
}
#top-wrapper{
background-color: #ffffff;
margin: 0px;
padding: 0px;
}
<body>
<div id="top-wrapper">
<p>hello</p>
</div>
</body>
This is due to margin collapsing.
Top and bottom margins of blocks are sometimes combined (collapsed)
into a single margin whose size is the largest of the margins combined
into it, a behavior known as margin collapsing.
To (prevent this and) provide the behaviour you anticipate, add overflow: auto; to the div, or alternatively overflow:hidden; This enforces the block formatting context
Demo Fiddle
A block formatting context is a part of a visual CSS rendering of a
Web page. It is the region in which the layout of block boxes occurs
and in which floats interact with each other.
body {
margin: 0px;
padding: 0px;
background-color: #808080;
}
#top-wrapper {
background-color: #ffffff;
margin: 0px;
padding: 0px;
overflow: auto;
}
<body>
<div id="top-wrapper">
<p>hello</p>
</div>
</body>
This is the expected behavior. This is because the top margin of paragraph collapsed with the top margin of its parent div (and likewise for bottom margin). This causes the div to appear as if it has a margin.
Margin collapsing is described here:
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.

What should I take into consideration when using margin & padding to space elements?

I have been tasked with modifying the layout of a site so that it meets the criteria of the client's corporate style guide.
The guide is requiring that I ensure certain elements are spaced [X]px from other elements, and that elements of this type are lined up with elements of that type.
So as I'm doing this, I can see that the existing spacings are defined in some cases using padding, and in other cases using margin.
Is there a preferred way of doing this? When should I use one in favour of the other?
In layman terms.
If you have two div's next to one another, the space between the two is referred to as the margin.
If you have text inside a div, the space between the edge of the div(top,right,bottom,left) and text is referred to as padding.
That really depends somehow. Margin and Padding are two different things. However in some cases you will not notice a difference.
A figure which shows you the difference:
Source: http://www.edition-w3c.de/TR/1998/REC-CSS2-19980512/bilder/boxdim.gif
So for example: If you want to define the space between the border and your content you will only achieve this with padding(while having a visible border).
The difference is best explained visually.
Try this out:
<html>
<head>
<style>
body { background-color: #E342FF; margin: 0; padding: 0; }
#mydiv { border: 2px solid #000000; width: 50%; height: 20%; margin: 50px 0 0 50px; }
#mydiv2 { border: 2px solid #000000; width: 50%; height: 20%; padding: 50px 0 0 50px; }
</style>
</head>
<body>
<div id="mydiv">
</div>
<div id="mydiv2">
</div>
</body>
</html>
You should see that the margin is simply moving the div, and the padding is actually making it larger.