Why does this floating parent calculate it's width before taking sibling into account? - css

I am trying to understand why the .item-wrap in the css below only calculates it's width *as if .floatleft2 wasn't there, and yet the .items contained by .item-wrap clearly are aware that .floatleft2 is there.
I want the .containingbox to "shrink wrap" the content, but not for the .items to wrap "prematurely" i.e. while there is still extra screen space. (see 'working' fix below).
I have already found the workaround, but what specification in CSS causes this interaction between .floatleft2, .item-wrap, and .item such that the .item-wrap width isn't wide enough to incorporate all the .items?
jsfiddle demo (code reproduced below)
jsfiddle demo with 'working' inline fix
<body>
<h1>float:left on .containingbox, with item-wrap, with floatleft2, causes premature wrapping of .item</h1>
<div class="containingbox">
<div class="floatleft2"></div>
<div class="item-wrap">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
</body>
body {
margin: 20px;
padding: 0;
font: normal 85% arial, helvetica, sans-serif;
color: #000;
background-color: #fff;
}
.containingbox {
height: 200px;
border: 1px solid #000;
float: left;
}
.item-wrap {
border: 1px solid #0FC;
height: 3px;
}
.item {
border: 1px solid #F09;
width: 50px;
float: left;
position: relative;
margin: 0 10px 0 0;
height: 75px;
}
.item::before { content: "item"; position: absolute; }
.floatleft2 {
height: 75px;
background-color: #000;
border: 1px solid #000;
float: left;
margin: 0 10px;
display: block;
width: 50px;
}

When you float .floatleft2 but not .item-wrap, .floatleft2 is taken out of the normal flow of the container box (which gets its own block formatting context from being floated itself), and .item-wrap is laid out as though .floatleft2 were not there. Since .item-wrap is not floated, it behaves like a regular block-level element, using the auto width and stretching to fit the container as per section 10.3.3.
The reason why the container is sized horizontally to just fit .item-wrap and its floated items is because, when .floatleft2 is taken out of the normal flow of the container, the container no longer needs to account for the size of .floatleft2. It only accounts for the contents of .item-wrap, which are themselves also floated.
The width of a floating element, when no explicit width is specified (it uses the auto width), is shrink-to-fit, according to section 10.3.5. CSS2.1 does not say how to implement shrink-to-fit, but it does say that an implementation should use shrink-to-fit. In this case, the container is shrunk to just the minimum width needed to fit the floating items on one line. The width of .item-wrap is never relevant except that it should stretch to fit within the bounds established by the container, as mentioned above.
What happens then is that when .floatleft2 is introduced, the floating items float to the left of that element (the same fundamental behavior you see when floating the items themselves), regardless of the layout of .item-wrap or the container. This causes some of the items to wrap to the next line since neither container element changes its size to account for .floatleft2.

you are making the div class from block level element to inline element.
you should use float:left; and remove the display:inline
.item-wrap {
/*display: inline;*/
float: left;
border: 1px solid #0FC;
height: 3px;
}
Here is the Working Demo. http://jsbin.com/vicusesu/1/edit

It is because you have float: left on .float-left2 and .item but not on .item-wrap. This effectively removes all floated items from item-wrap (they are floated) while it still keeps the same width as if they were there.
If you add a float (left or right) to your .item-wrap you will not have this issue.

Related

What does collapsing width height and margin mean for block level elements?

What does it mean that the width of block level elements can not be collapsed but the height can?
And can you please explain this text from the W3.org specification:
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 meaning of the word collapse is causing much of the confusion here.
A collapsed margin is the name given to the instance when margins of two different elements occupy the same space.
Consider the following example:
.box {
height: 50px;
width: 50px;
}
.box1 {
background: red;
margin-bottom: 25px;
}
.box2 {
background: blue;
margin-top: 50px;
}
<div class="box box1"></div>
<div class="box box2"></div>
It's difficult to tell, but that whitespace between the two boxes is only 50px. You might think it should be 75px, because I've specified a margin-bottom of 25px on the top box, and a margin-top of 50px on the bottom box. 25 + 50 = 75, so why is the whitespace only 50px?
Well, margins can't have any content within them; a margin is specifically denoting a lack of content. Considering there is no content to display in a margin, the parser thinks they might as well be combined to optimise space.
The word 'collapsed' comes about because there are technically two different 'segments' of margins existing in the same place at the same time, 'collapsing' in on each other.
Note that this doesn't happen with margin-left and margin-right:
.box {
height: 50px;
width: 50px;
float: left;
}
.box1 {
background: red;
margin-right: 25px;
}
.box2 {
background: blue;
margin-left: 50px;
}
<div class="box box1"></div>
<div class="box box2"></div>
The space above is indeed 75px. This can be a confusing concept to wrap your head around, but it's important to note that it only affects vertical margins. Further information about collapsing margins can be found at CSS Tricks and Mozilla.
It's also important to note that, by default, a block-level element takes up 100% of the width of its parent, but 0% of the height.
Here's an example illustrating this:
.parent {
background: blue;
border: 10px solid purple;
height: 50px;
width: 200px;
}
.child {
background: red;
}
<div class="parent">
<div class="child">Text</div>
</div>
In the above example, I specify both a width and a height on the parent, though I don't specify either on the child. As you can see, the child element inherits the 200px width, but does not inherit the 50px height.
Hopefully this helps clarify that a bit!

What's the impact of the negative bottom margin

First, here is the html:
<div class="first">
<div class="second">
<div class="third">
Hello, margin collapsing!
</div>
</div>
</div>
Then here is the CSS:
.first {
background-color: red;
padding: 20px;
}
.second {
background-color: green;
margin-bottom: -20px;
}
.third {
background-color: yellow;
margin-bottom: 20px;
}
In the final layout, the third div looks like it doesn't have the bottom margin. I know it must be the effect of the second div whose bottom margin is negative. But I don't understand how it works. Could you please provide an explanation?
Padding - Creates, easy said, a invisible border inside your element. You provide with it the spaces inside of your element (arround the content).
.first {
background-color: red;
padding: 20px;
}
So here you tell, any content of first hast to be 20px away from each side (each side cause you did not provide any declaration like padding-top)
Margin - On the other hand creates the opposite, it creates space arround your element.
.second {
background-color: green;
margin-bottom: -20px;
}
So this one says the second block has a space on the bottom outside. Its defined negative, which means the following items float in your element.
This explains it awfully: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model

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>

float divs inside container, text leaks out the bottom of the container, I want it inside the container.

I have 2 divs inside a container, Each of the inside divs are floated to the left and right, I want to make 2 columns for data inside the main content div.
Currently, text leaks out the bottom of content-left and content-right, even though they are contained within content.
Here is a jsfiddle
<div id="content">
<div id="content-left">I want to put content in here<br/><br/><br/>This is outside? why? </div>
<div id="content-right">and more in here</div>
Maybe other content here, inside the content
</div>
And the CSS
#content-left{
width: 50%;
border: 1px dotted #aaa;
float: left;
}
#content-right{
width: 49%;
float: right;
border: 1px dotted #aaa;
}
#content{
background-color: #eee;
width: 95%; /* Width of Main Content Div, % for Fluid*/
height: auto;
max-width: 1350px; /*Max width, To wide on big monitor*/
margin: 0 auto;
padding: 10px;
padding-left: 20px;
padding-right: 20px;
}
Also, any tips about floating items would be great and might earn reps if I find them useful, I thought I had it mastered but obviously not! :P
You just need to add a clearing br inside the last div
Maybe other content here, but this should be below the 2 above divs in the rendered view.
<br style="clear:both;" />
</div>
http://jsfiddle.net/jasongennaro/sahbz/9/
This is happening because the floated elements are taken out of the document flow.
Currently, text leaks out the bottom of content-left and
content-right, even though they are contained within content.
You need to "clear/contain your floats", more information here: http://www.ejeliot.com/blog/59
One simple way to do that is to add overflow: hidden to #content.
See: http://jsfiddle.net/sahbz/8/
Pure CSS
.content:after {
clear: both;
content: '';
display: block;
}

My div is breaking out of its container div

I have a containing div that is NOT restricting the width of its child divs. The divs are stretching all the way to the full width of the screen, when i have a set width on both the container and the child. Why is this happening. I do NOT have any positioning or floating going on.
Please view my HTML:
<ul class="tabs_commentArea">
<li class="">Starstream</li>
<li class="">Comments</li>
</ul>
<div id="paneWrap">
<div class="panes_comments">
<div class="comments">member pane 1</div>
<div class="comments">member pane 2</div>
<div class="comments">member pane 3</div>
</div>
My CSS, the relevant parts of it at least:
#MembersColumnContainer {
width: 590px;
float: left;
padding-right: 0px;
clear: none;
padding-bottom: 20px;
padding-left: 2px;
}
ul.tabs_commentArea {
list-style:none;
margin-top: 2px !important;
padding:0;
border-bottom:0px solid #666;
height:30px;
}
ul.tabs_commentArea li {
text-indent:0;
margin: !important;
list-style-image:none !important;
padding-top: 0;
padding-right: 0;
padding-bottom: 0;
padding-left: 0;
float: right;
}
#paneWrap {
border: solid 3px #000000;
}
.panes_comments div {
display: ;
padding: px px;
/*border:medium solid #000000;*/
height:150px;
width: 588px;
background-color: #FFFF99;
}
You could set max-width on either, or both, of the div elements to prevent their expansion:
#containerDiv {
min-width: 400px; /* prevents the div being squashed by an 'extreme' page-resize */
width: 50%; /* defines the normal width of the div */
max-width: 700px; /* prevents the div expanding beyond 700px */
}
It might also be that you're allowing the div's overflowed contents to be visible, as opposed to hidden (or auto). But without specific examples of your mark-up and css it's very difficult to guess.
Generally giving elements layout is pretty straight forward (always assuming you have a good understanding of floating, positioning and the box model), and in most cases you wouldn't have to use max- min-width to control elements on the page.
My two cents: If I was you, I'd start stripping out code (starting with the !important rule), and see when the problem is solved. De-constructing the code like that is a good way to find bugs.
Sorry I couldn't help, but I'm reluctant to give advice since the code you provided shows a lot of other stuff going on elsewhere that might be contributing to your problem (like having to use !important).
:D
I figured out the problem. The file that was calling in the css was conflicting with another external css file that had the same element with the same name in it. Thank you all for your help though.

Resources