Margin collapse on inline-block elements? - css

Margins of blocks elements collapse, but not inline-blocks.
Is there a way to force inline-blocks margins to collapse?
.wrapper {
position: relative;
float: left;
width: 100px;
margin: 10px;
}
.wrapper .el {
display: inline-block;
width: 100%;
height: 20px;
background: #000;
margin: 10px 0;
}
.wrapper.block .el { display: block; }
<div class="wrapper">
<div class="el"></div>
<div class="el"></div>
<div class="el"></div>
</div>
<div class="wrapper block">
<div class="el"></div>
<div class="el"></div>
<div class="el"></div>
</div>
Anyone have an idea?
I have already read the documentation on MDN.

This is documented in the spec that margins of inline-block elements do not collapse:
8.3.1 Collapsing margins
Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).
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.
Margins of absolutely positioned boxes do not collapse (not even with their in-flow children).
Margins of inline-block boxes do not collapse (not even with their in-flow children).
...
Therefore the answer is No. You probably need to alter the margins of the element.

The answer is "no" because that's not how inline boxes work so it can't be forced as you asked for. Anything else would be just manipulating the margins of elements which is only a trick or hack.

If I get you right you want to remove that extra margin that inline-block elements have assign font-size: 0; to the parent element of the corresponding div.
Check this post:
http://css-tricks.com/fighting-the-space-between-inline-block-elements/

Related

left margin not working on overflow:auto element following the float

I'm currently trying to create a two column layout where the left column is floated and the right column restrains the float by forming a new block formatting context. That works. Later, I try to put some visible space between the left column and the content of right column. If I set left padding on the right column, it works. I also try to replace the left padding with left margin on the right column, and think they would have the same effect. However, to my surprise, the left margin is not working at all
I reproduce the problem with the following code. Notice that the example in the middle, setting the left margin on the right column does not really push it away from the left column
* {
margin: 0;
padding: 0;
}
.container {
height: 50px;
line-height: 50px;
width: 500px;
}
.container + .container {
margin-top: 20px
}
.left {
float: left;
width: 150px;
height: 100%;
background: orange;
text-align: center;
}
.right {
overflow: auto;
background: skyblue;
height: 100%;
}
.with-padding {
padding-left: 30px;
}
.with-margin {
margin-left: 30px;
}
<div class="container">
<div class="left">left column, floated</div>
<div class="right with-padding">
<p>left padding works</p>
</div>
</div>
<div class="container">
<div class="left">left column, floated</div>
<div class="right with-margin">
<p>left margin dost not work</p>
</div>
</div>
<div class="container">
<div class="left">left column, floated</div>
<div class="right">
<div class="with-margin">
<p>left margin works on the wrapper div</p>
</div>
</div>
</div>
I did search for this topic on the internet but don't find too much relevant information. I suspect this might be related to the concept of block formatting context (BFC). If I understand correctly, margin represents distance between the target box's outer edge and containing BFC's inner border.
If we set margin on a box which itself forms its own BFC, then margin shouldn't work? So in the third example, I place the text into an extra wrapper and set margin on that wrapper, and it looks like left margin work again. However, this is just my guess.
The critical point here is that
The border box of ... an element in the normal flow that establishes a new block formatting context (such as an element with overflow other than visible) must not overlap the margin box of any floats ...
CSS 2.2 Section 9.5 Floats
So the margin, which lies outside the border box, of such a BFC can (and in your second case does) overlap with the float, but padding, which lies inside the border box, cannot.

Why margins of such a box containing a in-flow box collapse

Here are my test code:
.div1 {
width: 100px;
background: red;
padding-top: 0.1px;
border: solid;
}
.div2 {
width: 100px;
margin: 100px;
background: pink;
}
.div3 {
overflow: visible;
}
.div4 {
overflow: hidden;
}
<p>sample 1</p>
<div class="div1">
<div class="div2"><div class="div3"></div></div>
</div>
<hr />
<p>sample 2</p>
<div class="div1">
<div class="div2"><div class="div4"></div></div>
</div>
According to the spec:
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
margins of both div2 may not collapse. However, in sample 2, margins didn't collapse as I thought, but they collapse in sample 1. So why?
According to BoltClock's explanation, margins in sample 1 collapse because the in-flow child(i.e. div3) don't establish a new BFC. I tried another test:
.div1 {
width: 100px;
background: red;
padding-top: 0.1px;
border: solid;
}
.div2 {
width: 100px;
margin: 100px;
background: pink;
}
.div5 {
overflow: visible;
float: left;
/* position: absolute;*/
}
<div class="div1">
<div class="div2"><div class="div5"></div></div>
</div>
With float value other than none, div5 establish a new BFC, so margins of div5 may not collapse accordingly. But they collapse unfortunately.
From the spec:
Note the above rules imply that:
A box's own margins collapse if the 'min-height' property is zero, and it has neither top or bottom borders nor top or bottom padding, and it has a 'height' of either 0 or 'auto', and it does not contain a line box, and all of its in-flow children's margins (if any) collapse.
Emphasis mine.
In sample 2, div4 establishes a new block formatting context. As a result, its own margins are not adjoining (i.e. it does not meet the condition that you have quoted), and so they cannot collapse. Because div4's margins do not collapse, the margins of its own div2 parent cannot collapse through it. As a result, none of the positive margins in sample 2 collapse.
Floating an element takes it out of the flow, so the margins of div2 in your new test are able to collapse because it has no in-flow children.
This is very interesting question. I never faced with this before, but now, according to some articles I found that some situation prevents margin collapsing:
http://www.sitepoint.com/web-foundations/collapsing-margins/
floated elements
absolutely positioned elements
inline-block elements
elements with overflow set to anything other than visible (They do
not collapse margins with their children.)
cleared elements (They do not collapse their top margins with their parent block’s bottom margin.)
the root element
Apparently overflow prevent margin collapsing not only if it is applied on parent element ;)
From other article I saw, that this effect is used in several micro clearfix.

Uncollapse a vertical margin in two adjacent elements

There are multiple ways posted here to uncollapse a vertical PARENT margin, but nothing about uncollapsing vertical margins of adjacent elements. The only solution I found was in this answer (back in 2009):
<div style="overflow: hidden; height: 0px; width: 0px;"> </div>
Almost 7 years passed since there. Is some better way to do this (possibly using some CSS3)?
Basically, suppose you have: http://jsfiddle.net/ok2u3o3c/
<div class="one"></div>
<div class="two"></div>
div {
width: 300px;
height: 200px;
}
.one {
margin-bottom: 10px;
background-color: blue;
}
.two {
margin-top: 20px;
background-color: red;
}
What would be the most elegant way to make the distance between these 2 boxes 30px instead of 20px (where the first margin contributes 10px and doesn't collapses)?
Let's start with the relevant documentation explaining the behavior of collapsing margins:
8 Box model - 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.
The following rules apply, which means that there are a things that you can do to prevent the margins from collapsing for sibling elements:
Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children)
Therefore if you float the elements with collapsing margins, they will no longer collapse:
.collapsing-margins {
margin: 100px 0;
background: #f00;
float: left;
width: 100%;
}
<div class="parent">
<div class="collapsing-margins">Element</div>
<div class="collapsing-margins">Element</div>
</div>
Margins of inline-block boxes do not collapse (not even with their in-flow children).
Therefore you could also add change the display of the elements to inline-block:
.collapsing-margins {
margin: 100px 0;
background: #f00;
display: inline-block;
width: 100%;
}
<div class="parent">
<div class="collapsing-margins">Element</div>
<div class="collapsing-margins">Element</div>
</div>

Margin-top doesn't work after floated elements despite clear:both

Consider the following:
<div style='float: left; width: 50%'>content</div>
<div style='float: right; width: 50%'>content</div>
<div style='clear: both; margin-top: 50px'>content</div>
Why does margin-top doesn't work here? The third element is still glued to the first two elements.
You need to try to add margin-bottom to the floats.
Or you can try to add
<div style='overflow:hidden'>
<div style='float: left; width: 50%'>content</div>
<div style='float: right; width: 50%'>content</div>
<div style='clear: both; margin-top: 50px'>content</div>
JSFIDDLE DEMO
From the W3C specs
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.
Adjoining vertical margins collapse [...]
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
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
check it over here may be you need the same
https://jsfiddle.net/chaitanyaah/yychtp8t/
<div style='overflow:hidden'>
<div style='float: left; width: 50%;background:#bbb'>content</div>
<div style='float: right; width: 49%;background:#bbb'>content</div>
<div style='clear: both; margin-top: 0px;border:2px solid #ddd'>content</div>
</div>

How to make <div> inline? All <div>, even when their total width more than width of their parent?

I need to make <div> displayed inline and hide them with "overflow: hidden" for their parent.
Width for <div> is set to 20% with "box-sizing" property, so they are exactly 20% of their parent width.
The usual method, using "float: left" doesn't help, because it makes only 5 <div> displayed in one line, and the rest of them shown in new line under the first 5 <div>.
How to make all <div> displayd inline and hide the rest of them if they are too wide to be shown inside of their parent, using "overflow: hidden"?
I have the following document structure:
<body>
<div class="column">
<div class="header">Some text</div>
<ul class="item_list">
<li class="simple">Some text<br></li>
<li class="simple">Some text<br></li>
<li class="simple">Some text<br></li>
...
</ul>
</div>
You can see what I mean here. But I've made it using javascript (setted for <div> "position: absolute" and generated "margin-left" for each elemet) and it causes great problems for future development.
DEMO: http://jsfiddle.net/marcuswhybrow/7YDfE/3/
Use display: inline-block and white-space: nowrap in combination:
<div class="wrapper">
<div class="inline"></div>
<div class="inline"></div>
<div class="inline"></div>
</div>
Then use the appropriate CSS:
div.wrapper {
width: 200px; /* or whatever */
overflow: hidden;
white-space: nowrap;
}
div.inline {
display: inline-block;
}
The demo contains a little jQuery animation to illustrate the effect:
DEMO: http://jsfiddle.net/marcuswhybrow/7YDfE/3/
If the div elements are display: inline then applying white-space: nowrap; to the parent element will prevent their wrapping to new lines.
Since you have a known number of divs, have you tried using absolute positioning instead of floats, and specifying left:20% left:40%, etc.?
If you set the container div's height to a fixed value, and give all the inner elements display: inline-block, this should do the trick. inline-block will make each element align to the left, but keep it's dimensions, while the fixed height container will hide any that overflow to a new line.
This will do what you want with the addition of removing the white space between while allowing nice code formatting. The container gets font-size:0px ftw.
Markup
<div class="wrapper">
<div class="inline">Some text </div>
<div class="inline">Some sample text </div>
<div class="inline">Some Other text </div>
</div>
CSS
div.wrapper {
width: 250px; /* or whatever */
overflow: hidden;
white-space: nowrap;
border: 1px solid red;
font-size:0px;
}
div.inline {
display: inline-block;
width: 80px;
height: 20px;
background-color: black;
color:white;
margin: 0; padding: 0;
border: 1px solid blue;
font-size:12px;
}

Resources