CSS overflow:hidden with floats - html

I read the following code on w3schools and do not understand how the overflow property would impact whether text appears to the right of the ul or not.
ul {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
}
li {
float: left;
}
a {
display: block;
width: 60px;
background-color: #dddddd;
padding: 8px;
}
<ul>
<li>Home</li>
<li>News</li>
<li>Contact</li>
<li>About</li>
</ul>
<p><b>Note:</b> overflow:hidden is added to the ul element to prevent li elements from going outside of the list.</p>
I know that overflow:hidden is used to handle content that goes outside of the box but don't understand how it applies in this instance.

I try to end the confusion:
ul is a block-level element as is the p element (they stretch to 100% of the parent width). That is why per default the p will appear below the ul if no width or display is declared on those elements.
Now in your example the ul contains only floated elements. This makes it collapse to a height of 0px (It still has 100% width though as you can see in the example). The adjacent p will appear to the right of the floated lis because they are considered as normal floated elements.
Now declaring overflow (any value other than visible) establishes a new block formatting context, which makes the ul contains its children. Suddenly the ul "reappears", not having size 0px anymore. The p is getting pushed to the bottom. You could also declare position:absolute to achieve the same "clearing" effect (with the side effect that now the ul is taken out of the normal element flow - the ps will be overlapped by the ul.)
See the example fiddle
If you are into the technical stuff, compare the according paragraphs of the CSS spec:
§10.6.3 Block-level non-replaced elements in normal flow when 'overflow' computes to 'visible'
and
§10.6.7 'Auto' heights for block formatting context roots. (Thanks to BoltClock for digging out the links).
ul{
list-style-type:none;
margin:0; padding:0;
background-color:#dddddd;
border:2px solid red;
}
li{
float:left;
}
a{
display:block;
width:60px;
background-color:#555;
color:white;
}
p{
margin:0;
outline:2px dotted blue;
}
#two{
clear:both;
overflow:hidden;
}
No overflow:
<ul>
<li>Home</li>
<li>News</li>
<li>Contact</li>
<li>About</li>
</ul>
<p>Notice the collapsed ul - no background-color visible, collapsed border and this paragraph treats the lis as regular floats </p>
<br>
With overflow: hidden
<ul id="two">
<li>Home</li>
<li>News</li>
<li>Contact</li>
<li>About</li>
</ul>
<p>the ul reappeared - it now contains the child li's - the float is cleared</p>

Setting overflow: hidden on an element causes a new float context to be created, so elements that are floated inside an element that has overflow: hidden applied are cleared.
http://www.w3.org/TR/CSS2/visuren.html#block-formatting

To quote from HTML & CSS Is Hard
To summarize, when you have an extra unfloated HTML element at the
bottom of a container div, use the clear solution. Otherwise, add an
overflow: hidden declaration to the container element. The underlying
idea for both options is that you need a way to tell the browser to
incorporate floats into the height of their container element

Instead of the overflow:hidden; use clear:both; for the <p>. here it is in use http://jsfiddle.net/Mvv8w/. Basically overflow:hidden will clear anything that is aside it just as clear:both; does.

This is why w3schools is not a reliable source for web designer/developers. You are correct, it is a terrible example.
It doesn't because, in this example, the parent element does not have a fixed with. Furthermore, it's an un-ordered list tag, which is going to stretch to the size of it's children regardless.
http://jsfiddle.net/EhphH/
CSS
.parent {
width: 150px;
height: 100px;
padding: 10px;
background: yellow;
overflow: hidden;
}
.child {
float: left;
width: 75px;
height: 120px;
margin: 10px;
background: blue;
}
.baby {
width: 200px;
height: 25px;
background: green;
}
Markup
<div class="parent">
<div class="child">
<div class="baby">
</div>
</div>
<div class="child">
</div>
</div>

Related

Block Formatting Contexts, Collapsing Margins and Floating Containers

In order to understand what does a block formatting context do, I'm trying to find out what's going on when a BFC is not created.
I took the following demo from Everything you Know about Clearfix is Wrong:
.wrapper {
width: 740px;
background: #cccccc;
}
.leftSidebar {
float: left;
width: 200px;
}
.rightSidebar {
float: right;
width: 200px;
}
.mainContent {
padding-right: 200px;
padding-left: 200px;
}
.floatMe {
float: left;
background: teal;
color: #fff;
}
<div class="wrapper">
<div class="leftSidebar">
<h2>Heading</h2>
<pre>.leftSidebar {
float:left;
width:200px;
}</pre>
</div>
<div class="rightSidebar">
<h2>Heading</h2>
<pre>.rightSidebar {
float:right;
width:200px;
}</pre>
</div>
<div class="mainContent">
<h2>Heading</h2>
<pre>.mainContent {
padding-right:200px;
padding-left:200px;
}</pre>
<div class="floatMe">
<pre>.floatMe {
float:left;
background:teal;
color:#fff;
}</pre>
</div>
</div>
</div>
According to that article(emphasis mine):
In modern browsers:
All elements belong to the same block formatting context so adjacent
margins collapse. The heading’s margin “sticks out” of the wrapper to
butt against the p. Unlike in IE, it is that margin (not the one on
the black box) that creates the gap above the wrapper.
I cannot understand what does "the same block formatting context" refers to. I want to know why such a weird layout is produced without a block formatting context.
I've tried to figure out the exact layout by adding * {border: 1px solid blue;} to CSS, but the overall layout changed greatly after this change: now it behaves as if wrapper is a block formatting context!
.wrapper {
width: 740px;
background: #cccccc;
}
.leftSidebar {
float: left;
width: 200px;
}
.rightSidebar {
float: right;
width: 200px;
}
.mainContent {
padding-right: 200px;
padding-left: 200px;
}
.floatMe {
float: left;
background: teal;
color: #fff;
}
* {
border: 1px solid blue;
}
<div class="wrapper">
<div class="leftSidebar">
<h2>Heading</h2>
<pre>.leftSidebar {
float:left;
width:200px;
}</pre>
</div>
<div class="rightSidebar">
<h2>Heading</h2>
<pre>.rightSidebar {
float:right;
width:200px;
}</pre>
</div>
<div class="mainContent">
<h2>Heading</h2>
<pre>.mainContent {
padding-right:200px;
padding-left:200px;
}</pre>
<div class="floatMe">
<pre>.floatMe {
float:left;
background:teal;
color:#fff;
}</pre>
</div>
</div>
</div>
Please tell me what's going on.
Good question, got me thinking a lot!
There are lot of concepts at play here, so I'll get to them one by one:
Buggy IE:
Whatever is mentioned in this old article about IE can be easily ignored if you do not have to design for IE7 or IE8 compatibility mode. This behavior is due to hasLayout property used internally by IE7.
See this MSDN doc for IE7:
What is "HasLayout" and why is it important?
There are several bugs in
Internet Explorer that can be worked around by forcing "a layout" (an
IE internal data structure) on an element.
Clearly this is a non-standard workaround and along with brings up a lot of inconsistencies. Read about this here too.
Block Formatting Context (BFC):
Excerpts from this MDN doc:
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.
BFCs are very important for positioning and clearing of floated elements- floated elements affects only within the same BFCs. When you float an element, it is taken out of the flow and reinserted by "floating".
See the examples below:
The inside of wrapper is a BFC where you float one div to left and another to the right.
The floated elements are reinserted into the BFC while rendering around the element that is not floated.
As you have not cleared the floating in the BFC, the wrapper height will extend to the size of the element that is not floated.
body{
margin: 0;
}
*{
box-sizing: border-box;
}
.wrapper{
border: 1px solid;
}
.wrapper > * {
display: inline-block;
border: 1px solid red;
width: 33.33%;
height: 100px;
}
.left{
float: left;
}
.right{
float: right;
}
.center{
height: 50px;
}
<div class="wrapper">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right">Right</div>
</div>
See what happens when you clear the floating in the BFC- now the heights will behave normally in the wrapper BFC.
body{
margin: 0;
}
*{
box-sizing: border-box;
}
.wrapper{
border: 1px solid;
}
.wrapper > * {
display: inline-block;
border: 1px solid red;
width: 33.33%;
height: 100px;
}
.left{
float: left;
}
.right{
float: right;
}
.center{
height: 50px;
}
.wrapper:after{
content: '';
display: block;
clear: both;
}
<div class="wrapper">
<div class="left">Left</div>
<div class="center">Center</div>
<div class="right">Right</div>
</div>
Collapsing Margins:
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.
Margins collapse for adjacent blocks, parent and first/last child and empty blocks. See more about margin collapsing in this MDN doc.
Also note that:
Margins of floating and absolutely positioned elements never collapse.
So what really happens here?
So now you will have understood about BFCs and also how floating containers work in first case (when you have no borders specified) - that's why floatMe stays out of its immediate mainContent wrapper and exactly why the height of wrapper and mainContent is as it looks there.
Layout and IE referred to are only in IE7 and is non-standard.
Everything else that happens is because of margin collapsing:
a. h2 and pre margins collapse (adjacent siblings)
b. mainContent shifts a little bit to the top to collapse with the margin on the body (Parent and first/last child)
c. As wrapper takes the height of mainContent, the wrapper height is also shifted upwards.
d. What happens when you apply borders is that the margin collapsing in (b) above is nullified! (see MDN doc above as to why)
Hope things are looking better now. Cheers!

Left Para text forced to bottom from Right li float?

So the intent for this snippet is to allow the paragraph on left to display a right border spanning the height of the parent container, which it manages to do under display:table for both the container article and paragraph if said rules are set. The ul following it is meant to be placed right to it, that too is working. The list entities are preferably allowed to float such that more than one bullet can be on a single line.
Now, when float:left is added to the li tags... the para text goes from starting up top in its cell, to starting below the last line of bulleted entries.
I know float:left is the problem since removing it rectifies the issue, but it then makes the list 1 bullet/line... something I'd rather not do.
Why is the float for the li tag repositioning the text on an item it isn't written to affect? I tried inspecting elements and I don't see any text-alignment being calculated afaik.
The HTML:
<article class="foo" id="bar">
<p> List on right causes my text to move down?</p>
<ul>
<li>why</li>
<li>yes</li>
<li>we</li>
<li>do!</li>
<li>why</li>
<li>yes</li>
<li>we</li>
<li>do!</li>
</ul>
The CSS:
.foo {
display:table;
width: 20em;
}
.foo p {
text-align: right;
padding: 0 1em 0 0;
border-right: 1px solid #999;
display: table-cell;
width: 10em;
}
#bar ul
{
width: 10em;
}
#bar li {
float: left;
width:2em;
margin-right:3em;
}
The JSFiddle snippet can be seen here: http://jsfiddle.net/U39ab/1/
Change
float:left;
to
display:inline;
JSFiddle
Answer 2
Keep float:left; in #bar li
but .foo p should have
vertical-align:top;
in its properties.
Then you can change padding to: (optional)
padding: 20px 1em 0 0;
to align it with the rest.
JSFiddle 2
just add position:absolute in
#bar ul
{
width: 10em;
position:absolute
}
DEMO
OR BeatAlex's answer
check display:inline here CSS display: inline vs inline-block

<li> will not take 100% height of the parent <ul>

I have a <ul> with several <li> items in it all in a single row. The <li> has a nested <span> and an <img>. The <img> height is all the same across all items. But the <span> items contain text which can span on a single line or two lines (depends on text).
I have tried appying display:block, float:left, height:100%, and few other suggestions I found, but the shorter <li> items will not take the same height as the taller <li> items. So I am left with a space below the shorter <li> items.
Anyone has any suggestions on this?
In this case, when you set height:100% it isn't inheriting any height from its parent. If you want the list items to have 100% height of the div #wrapper, then you should set the ul's height to 100% and set a height on the div #wrapper in pixels or em's:
http://jsfiddle.net/SF9Za/1/
#wrapper {
background: transparent;
width: 350px;
color: white;
height:250px;
}
#wrapper ul {
list-style-type: none;
display: block;
float: left;
background: green;
height:100%;
}
If you'd rather have it stretch to the full height of the browser window, then you need to set the height of html, body in your css to 100%, and then all of the elements down to the li (html, body, div#wrapper, ul.list, and li) must have 100% height:
http://jsfiddle.net/YdGra/
html, body{
height:100%;
margin:0;
padding:0;
}
#wrapper {
background: transparent;
width: 350px;
color: white;
height:100%;
}
#wrapper ul {
list-style-type: none;
display: block;
float: left;
background: green;
height:100%;
}
Here's some other links that you might want to check out that talk about this:
CSS 100% height layout
Setting height: 100% on my label element doesn't work
http://webdesign.about.com/od/csstutorials/f/set-css-height-100-percent.htm
An easy fix is to add display:table on your ul element. The hieght will align with the content.
maybe it fix if you change list-style-position of the container ul

Using z-index to put some objects behind, others in front

I've got a horizontal navigation bar on my page which is pushed down a few pixels to overlap with the content of the div below. I want to have some of the links placed behind the background of the content div, but I can't figure out a way to keep some of the links (such as the link to the current page) in front. Here is what I have:
<div id="header">
<ul id="nav">
<li>index</li>
<li>project[]</li>
<li>contact</li>
<li>about</li>
</ul>
</div>
<div id="content">
</div>
Relevant CSS:
div#content {
background:#444;
border-radius:15px;
padding:40px 30px 30px 30px;
clear:left
}
div#header {
position: relative;
margin-left:20px;
top: 13px;
}
ul#nav {
list-style-type: none;
margin: 0;
padding: 0;
white-space: nowrap;
}
ul#nav li {
display:inline;
}
ul#nav a {
text-decoration:none;
color: #444;
font-size: 30px;
}
I'm using the class of each link to determine if it points to the current page, so I'd like that link to stick out. The problem is that the stacking context for each of these is inside the div or ul.
Try this fiddle: http://jsfiddle.net/PNC7g/ : I tried it on IE7+ and Firefox 9.
The idea is to set position: relative; z-index: 1 to the #content and to every link and the content has the property top: -13px defined. Even if they share the same z-index order position, #content is defined after the list of links (inside the markup), so it will overlap the navigation menu.
But if you later set z-index: 2 to a link (with a special class, like .current), the selected item will be able to overlap the div.

Why does margin-top get applied to the containing element here?

I'm sure this has been asked many times but I couldn't work out what to search for.
I have the following HTML and CSS (see jsfiddle for a live example):
<!--HTML-->
<body>
<div id="container">
<div id="header">
<ul>
<li>Item1</li>
<li>Item2</li>
</ul>
</div>
</div>
</body>
/* CSS */
#container {
background-color: red;
width: 400px;
height: 200px;
margin: auto;
}
#header ul {
list-style: none;
margin-top: 20px; /* I want this to be the margin at the top of the ul, not the container */
}
#header li {
float: left;
margin-right: 10px;
}
The problem I'm having is with the margin-top of the <ul>. It's adding space above the #container <div>, not above the <ul>. I must be missing something fundamental about CSS, because I just don't get this behaviour. Could someone enlighten me please?
Due to margin collapsing, if it touches the top of the body then that's where the margin lives. Easy fix is to just rely on top padding.
Try the padding. I've also found that using a CSS reset is helpful in getting everything to behave more similarly across browsers.
http://meyerweb.com/eric/tools/css/reset/