Inline-block elements expanding space below - html

Creating a page layout using inline-block elements (vertically aligned to the top). The only issue, is that inline-block elements below another set of inline block elements will not fold into open space like floated elements do. It's almost as if it obeys row-like rules. Are there any fixes for this?
Layout example in JSFiddle
CSS
* {
font-family:helvetica;
font-size:18px;
}
.container {
margin:0 auto;
width:90vp;
}
.main_content {
background:red;
display:inline-block;
vertical-align:top;
box-sizing:border-box;
width:76.04%;
min-height:200px;
}
.content_details {
background:blue;
display:inline-block;
vertical-align:top;
box-sizing:border-box;
width:22.39%;
margin-left:01.56%;
min-height:250px;
}
.comments {
background:green;
display:inline-block;
vertical-align:top;
box-sizing:border-box;
width:76.04%;
min-height:150px;
}
HTML
<div class="container">
<div class="main_content">
<h1>Main Content</h1>
</div
><div class="content_details">
<h2>Details</h2>
</div
><div class="comments">
<h2>Comments</h2>
</div>
</div>
Please note I can change the mark-up to create only two inline-block elements (creating two columns), however I would like to know if there is a fix for 3 separate inline-block elements (like in the JSFiddle example), that way I wouldn't need to add extra mark-up.

No there isn't.. Not like you are talking about. You'd have to use:
<div id="col1">
<div id="maincontent"></div>
<div id="comments"></div>
</div>
<div id="details"></div>
Then you would have #col1 and #details as inline-block elements.
The whole point of an inline-block is that it is inline (i.e. on a line with other elements) it isn't acting like a table as you suggested, it's acting like a line of text (as it should) that is wider than it's container and breaking to the next line down.
See here: http://jsfiddle.net/GXmM6/ for a working example

Neither floats nor inline-block will do what you want there, unless you wrap each column in its own div. Short of that, there are JavaScript solutions for doing this, such as Masonry. (It involves a lot of positioning, though.)

Did I get it right that you wanted the .content_details to be a sidebar? Then I just changed it from display: inline-block to float: right to place .comments seamlessly beneath your .main-content. See http://jsfiddle.net/koivo/7UqqF/ for working example. Think that even works just with display: block ...
* {
font-family: helvetica;
color: white; /* added */
font-size: 18px;
}
.container {
margin: 0 auto;
width: 90vp;
}
.main_content {
background: red;
display: inline-block;
vertical-align: top;
box-sizing: border-box;
width: 76.04%;
min-height: 200px;
}
.content_details {
background: blue;
/* display: inline-block; */
float: right; /* added */
vertical-align: top;
box-sizing: border-box;
width: 22.39%;
margin-left: 01.56%;
min-height: 250px;
}
.comments {
background: green;
display: inline-block;
vertical-align: top;
box-sizing: border-box;
width: 76.04%;
min-height: 150px;
}

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!

Why doesn't the wrapper wrap around the box?

I'm struggling with a problem which seems simple:
My code:
* {
font-family: tahoma;
}
body {
background: #333;
}
.wrapper {
padding: 10px;
background: white;
width: 100%;
}
.box {
margin-top: 40px;
width: 1100px;
height: 400px;
background: #aaa;
}
<div class="wrapper">
<div class="box">
box
</div>
</div>
The box contained in the wrapper has a fixed size, which might overflow the wrapper on small screens. Why doesn't the wrapper wrap around the box? How would I do that?
You can also check out the issue in this jsFiddle.
In order to make this work:
Remove width: 100% and add to the wrapper display: inline-block.
Doing so, will enable the wrapper to have as much width as needed to wrap around the box. Putting width: 100% restricts your wrapper to the width of the screen and in case of the box having a bigger with than that of the screen, it won't work.
If you do not want to have a horizontal scrollbar, especially on narrower screens use: box-sizing: border-box on the wrapper.
CSS:
.wrapper {
display: inline-block; /* Ensures that the box stays wrapped */
padding: 10px;
background: white;
box-sizing: border-box; /* Ensures that there won't be a horizontal scrollbar */
}
Here is a working version of your jsFiddle, with both the wrapping issue mended and the horizontal scrollbar abolished.
* {
font-family: tahoma;
}
body {
background: #333;
}
.wrapper {
box-sizing: border-box display: inline-block;
padding: 10px;
background: white;
}
.box {
position: relative;
margin-top: 40px;
height: 400px;
background: #aaa;
}
<div class="wrapper">
<div class="box">
box
</div>
</div>
For reference:
display: inline-block;
box-sizing: border-box;
Use display:inline-block on the wrapper to resize the container based on the content inside.
The div element by default has display:block; so you need to change its display.
You should remove width:100%; from .wrapper class, then you can make it display:inline-block; or display:table;
*{
font-family:tahoma;
}
body{
background:#333;
}
.wrapper
{
padding:10px;
background:white;
display:inline-block;
}
.box
{
margin-top:40px;
width:1100px;
height:400px;
background:#aaa;
}
<div class="wrapper">
<div class="box">
box
</div>
</div>
Your problem occurs, because HTML documents, by default, display all elements as display: block.
There are two ways to do it as our friends have mentioned before.
First one is to use inline-block value for the display property:
body{
display: inline-block;
}
The second way is to use max-width:
div.wrapper{
max-width: 100%;
/*we have set height property to auto to have coefficient between width & height*/
height: auto;
}
For more information visit these webpages:
inline-block
max-width
You can solve the problem by using the following css:
* {
font-family: tahoma;
}
body {
background: #333;
}
.wrapper {
padding: 10px;
background: white;
display: inline-block;
}
.box {
margin-top: 40px;
width: 1100px;
height: 400px;
background: #aaa;
}
<div class="wrapper">
<div class="box">
box
</div>
</div>
The only change is I have added display: inline-block to .wrapper element.
Why wrapper doesn't wrap around the child div
The problem is all html element has some default CSS styling which gets applied by the browser.
In this case div gets a default property of display: block; It is the same property that makes a default unstyled div to take up full available width of it's parent element.
As you can see with this: snapshot of chrome dev tools
*The css style highlighted in red rectangle is the default styling applied by the browser.
*The red underlined text tells us about the width of the element. The fading out signifies that value of that property is computed by the browser.
** While we are at it I want to point you to a different problem that you might have faced with the previous code and if the goal was to make the wrapper to wrap box at all times.
If the .box div would have width far less than that of the width of the browser then another problem may arise which I have shown in the code snippet bellow.
* {
font-family: tahoma;
}
body {
background: #333;
}
.wrapper {
padding: 10px;
background: white;
}
.box {
margin-top: 40px;
width: 100px;
height: 400px;
background: #aaa;
}
<div class="wrapper">
<div class="box">
box
</div>
</div>
As you can see the box tries to cling to a side of wrapper.
You can read more about display css property here: CSS display property || CSS-Tricks

How do I vertically center an H1 in a div?

First of all, my apologies. I know there are various solutions posted for this issue here, but for the life of me I can't get any of them to work.
For a responsive website I'm trying to center an h1 in a div.
Centering horizontally is not an issue, but I'm having problems getting it centered vertically. Presumably I'm doing something wrong or misunderstanding the explanations I found here (or maybe both).
So as I'm probably interpreting earlier solutions given the wrong way, could someone please explain what exactly I have to add to the code beneath to get the h1 to center vertically?
(To make this question relevant to as much people as possible, I've already stripped the code of all my previous attempts to do so myself.)
CSS:
html, body {
height: 100%;
margin: 0;
}
#section1 {
min-height: 90%;
text-align:center
}
HTML:
<div class="section" id="section1">
<h1>Lorem ipsum</h1>
</div>
you can achieve vertical aligning with display:table-cell:
#section1 {
height: 90%;
text-align:center;
display:table;
width:100%;
}
#section1 h1 {display:table-cell; vertical-align:middle}
Example
Update - CSS3
For an alternate way to vertical align, you can use the following css 3 which should be supported in all the latest browsers:
#section1 {
height: 90%;
width:100%;
display:flex;
align-items: center;
justify-content: center;
}
Updated fiddle
You can achieve this with the display property:
html, body {
height:100%;
margin:0;
padding:0;
}
#section1 {
width:100%; /*full width*/
min-height:90%;
text-align:center;
display:table; /*acts like a table*/
}
h1{
margin:0;
padding:0;
vertical-align:middle; /*middle centred*/
display:table-cell; /*acts like a table cell*/
}
Demo: http://jsfiddle.net/a3Kns/
I've had success putting text within span tags and then setting vertical-align: middle on that span. Don't know how cross-browser compliant this is though, I've only tested it in webkit browsers.
HTML
<div id='sample'>
<span class='vertical'>Test Message</span>
</div>
CSS
#sample
{
height:100px;
width:100%;
background-color:#003366;
display:table;
text-align: center;
}
.vertical
{
color:white;
display:table-cell;
vertical-align:middle;
}
Fiddle : Demo
Flexbox is a solid well-supported way to center an h1 tag inside div.
<div class="section" id="section1">
<h1>Lorem ipsum</h1>
</div>
This is the OP:s HTML. Let's keep it like that.
Now working with CSS we can add display flex and some properties. Here is a working code snippet that shows how flexbox can do vertical alignment.
#root {
width: 90vw;
height: 90vh;
border: 2px solid green;
}
#section1 {
display: flex;
flex-direction: row;
flex: 1;
min-height: 90%;
border: 2px solid red;
background-color: orange;
text-align: center;
/* this does align h1 if h1 is wider than its containing text */
}
#section1>h1 {
flex: 1;
/* this makes the h1 take all available width in its containing div, and makes text-align: center property work inside section1 */
background-color: #666333;
align-self: center/* this is finally the property that vertically aligns the h1 title inside its containing div */
}
<!DOCTYPE html>
<html>
<header>Demo</header>
<div id="root">
<div id="section1">
<h1>Title Centered</h1>
</div>
</div>
</html>
Since the accepted answer's CSS3 option vertically aligns the containing div and not the h1 tag as requested, this answer shows how that h1 can be vertically aligned inside a pre-sized, larger containing div.
Just use padding top and bottom, it will automatically center the content vertically.

Two inline-block elements, each 50% wide, do not fit side by side in a single row

<!DOCTYPE html>
<html>
<head>
<title>Width issue</title>
<style type="text/css">
body {
margin: 0;
}
#left {
width: 50%;
background: lightblue;
display: inline-block;
}
#right {
width: 50%;
background: orange;
display: inline-block;
}
</style>
</head>
<body>
<div id="left">Left</div>
<div id="right">Right</div>
</body>
</html>
JSFiddle: http://jsfiddle.net/5EcPK/
The above code is trying to place the #left div and the #right div, side by side, in a single row. But as you can see in the above JSFiddle URL, this is not the case.
I am able to resolve the issue reducing the width of one of the divs to 49%. See http://jsfiddle.net/mUKSC/ . But this is not an ideal solution because a small gap appears between the two divs.
Another way I am able to solve the problem is by floating both the divs. See http://jsfiddle.net/VptQm/ . This works fine.
But my original question remains. Why when both the divs are kept as inline-block elements, they do not fit side by side?
Update: as it's 2021, use flexbox or even better - CSS grid layout instead of inline-block.
When using inline-block elements, there will always be an whitespace issue between those elements (that space is about ~ 4px wide).
So, your two divs, which both have 50% width, plus that whitespace(~ 4px) is more than 100% in width, and so it breaks. Example of your problem:
body{
margin: 0; /* removing the default body margin */
}
div{
display: inline-block;
width: 50%;
}
.left{
background-color: aqua;
}
.right{
background-color: gold;
}
<div class="left">foo</div>
<div class="right">bar</div>
There is a few ways to fix that:
1. No space between those elements
body{
margin: 0; /* removing the default body margin */
}
div{
display: inline-block;
width: 50%;
}
.left{
background-color: aqua;
}
.right{
background-color: gold;
}
<div class="left">foo</div><div class="right">bar</div>
2. Using HTML comments
body{
margin: 0; /* removing the default body margin */
}
div{
display: inline-block;
width: 50%;
}
.left{
background-color: aqua;
}
.right{
background-color: gold;
}
<div class="left">foo</div><!--
--><div class="right">bar</div>
3. Set the parents font-size to 0, and then adding some value to inline-block elements
body{
margin: 0; /* removing the default body margin */
}
.parent{
font-size: 0; /* parent value */
}
.parent > div{
display: inline-block;
width: 50%;
font-size: 16px; /* some value */
}
.left{
background-color: aqua;
}
.right{
background-color: gold;
}
<div class="parent">
<div class="left">foo</div>
<div class="right">bar</div>
</div>
4. Using a negative margin between them (not preferable)
body{
margin: 0; /* removing the default body margin */
}
div{
display: inline-block;
width: 50%;
margin-right: -4px; /* negative margin */
}
.left{
background-color: aqua;
}
.right{
background-color: gold;
}
<div class="left">foo</div>
<div class="right">bar</div>
5. Dropping closing angle
body{
margin: 0; /* removing the default body margin */
}
div{
display: inline-block;
width: 50%;
}
.left{
background-color: aqua;
}
.right{
background-color: gold;
}
<div class="left">foo</div
><div class="right">bar</div>
<hr>
<div class="left">foo</div><div class="right">
bar</div>
6. Skipping certain HTML closing tags (thanks #thirtydot for the reference)
body{
margin: 0; /* removing the default body margin */
}
ul{
margin: 0; /* removing the default ul margin */
padding: 0; /* removing the default ul padding */
}
li{
display: inline-block;
width: 50%;
}
.left{
background-color: aqua;
}
.right{
background-color: gold;
}
<ul>
<li class="left">foo
<li class="right">bar
</ul>
References:
Fighting the Space Between Inline Block Elements on CSS Tricks
Remove Whitespace Between Inline-Block Elements by David Walsh
How to remove the space between inline-block elements?
As #MarcosPérezGude said, the best way is to use rem, and add some default value to font-size on the html tag (like in HTML5Boilerplate). Example:
html{
font-size: 1em;
}
.ib-parent{ /* ib -> inline-block */
font-size: 0;
}
.ib-child{
display: inline-block;
font-size: 1rem;
}
good answer in css3 is:
white-space: nowrap;
in parent node, and :
white-space: normal;
vertical-align: top;
in div (or other) at 50%
exemple : http://jsfiddle.net/YpTMh/19/
EDIT:
there is another way with :
font-size: 0;
for parent node and override it in child node
EDIT 2021 : personaly, I recommand use flexbox now : https://the-echoplex.net/flexyboxes/
It's because the whitespace between your two divs is being interpreted as a space. If you put your <div> tags in line as shown below the problem is corrected:
<div id="left"></div><div id="right"></div>
Because there is a space between the elements. If you remove all whitespace, they will fit.
<div id="left">Left</div><div id="right">Right</div>
Either make them block instead of inline-block. This will render divs ignoring spaces between them.
display:block;
or remove space between tags
<div id='left'></div><div id='right'></div>
or add
margin: -1en;
to one of the divs in order to mitigate space taken by single space rendered.
Please check below code:
body {
margin: 0;
}
#left {
width: 50%;
background: lightblue;
display: inline-block;
float:left;
}
#right {
width: 50%;
background: orange;
display: inline-block;
float:left;
}
<div id="left">Left</div>
<div id="right">Right</div>
It can be done by adding the css display:inline to the div that holds the inline elements.
While removing the white space using margin with a negative value it becomes necessary to add it to this particular element. As adding it to a class will affect places where this class has been used.
So it would be safer to use display:inline;
Flexbox example - this would be used for the parent class holding the two side by side elements.
.parentclass {
display: flex;
justify-content: center;
align-items: center;
}
Taken from Vertically centering a div inside another div
add float: left; to both div tags.
div {
float: left;
}

Vertical align multiple lines of text to the middle

I need to align multiple lines of text to the middle. Here is a rough guide of the markup I am working with.
<ul>
<li>
<a href='#'>This should be centered.</a>
<li>
</ul>
So as you can see from my image, the "work" link should be centered vertically. I have the width and height set with vertical-align: middle;. I know you need to set the line height for it to actually work but theres the problem. If I set the line height to 72px (the height of the element) then some of the links will stretch down the page due to them taking up two lines.
Is there a way of aligning multiple lines of text to the middle without using line-height?
Use display:table-cell; in your li element.
li {
width:200px;
height:200px;
vertical-align:middle;
display:table-cell;
}
This will give you this effect:
write like this
a{
display:inline-block;
vertical-align:middle;
}
& you can give display:table-cell; to it like this
li {
vertical-align:middle;
display:table-cell;
}
but it's not work in IE7 & below
I came up with this to handle vertically-aligned 100% height/width anchors inside containers:
http://jsfiddle.net/khaustic/KDfN6/
markup:
<div class="links one">
One
</div>
<div class="links two">
Two Two
</div>
css:
* {
/*ie box model forever!*/
box-sizing:border-box;
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
}
.links {
height: 5.0em;
text-align:center;
outline: 1px solid #333;
float:left;
margin: 0 1.0em;
overflow:hidden;
}
.links.one { width: 8em; }
.links.two { width: 4em; }
.links a {
width:10em;
text-align: center;
display: table-cell;
vertical-align:middle;
height: inherit;
}
You can try to change display to block for hyperlink and use paddings:
li a {display: block; padding: 30px 10px 30px 10px}