How to adjust the spaces between elements in inline-block layout? - html

I am trying to create a layout without using grid or flexbox, I am using display: inline-block to achieve that but i have a problem with adjusting spaces.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.wrapper {
text-align : justify;
}
.wrapper > div {
display: block;
margin-top: 5px;
}
.header {
background: lightgreen;
margin-top: 0;
}
.footer {
background: #eee;
}
.main > div {
display: inline-block;
width: 49%;
height: 20vh;
background: #eee;
}
<div class="wrapper">
<div class="header">header</div>
<div class="main">
<div class="item">item1</div>
<div class="item">item2</div>
<div class="item">item3</div>
<div class="item">item4</div>
</div>
<div class="footer">footer</div>
</div>
I am trying to achieve the same effect as justify-content: space-between in flexbox
but i got elements that are not aligned well in the layout.
I can fix the spaces around item4 but using margin-left but i don't like this solution.

Add a hidden element to trigger the justify alignment for the last line but you will need to use a negative margin-bottom to remove the extra line added.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.wrapper {
text-align : justify;
}
.wrapper > div {
display: block;
margin-top: 5px;
}
.header {
background: lightgreen;
margin-top: 0;
}
.footer {
background: #eee;
}
.main > div {
display: inline-block;
width: 49%;
height: 20vh;
background: #eee;
}
.main:after {
content:"";
display:inline-block;
width:5%;
height:50px; /* we consider a bigger value than the line-height*/
}
.main {
margin-bottom:-50px; /*the same value defined in the pseuo element*/
}
<div class="wrapper">
<div class="header">header</div>
<div class="main">
<div class="item">item1</div>
<div class="item">item2</div>
<div class="item">item3</div>
<div class="item">item4</div>
</div>
<div class="footer">footer</div>
</div>
Or use font-size:0 trick to avoid that extra line:
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.wrapper {
text-align : justify;
}
.wrapper > div {
display: block;
margin-top: 5px;
}
.header {
background: lightgreen;
margin-top: 0;
}
.footer {
background: #eee;
}
.main > div {
display: inline-block;
width: 49%;
height: 20vh;
background: #eee;
font-size:initial;
}
.main:after {
content:"";
display:inline-block;
width:5%;
}
.main {
font-size:0;
}
<div class="wrapper">
<div class="header">header</div>
<div class="main">
<div class="item">item1</div>
<div class="item">item2</div>
<div class="item">item3</div>
<div class="item">item4</div>
</div>
<div class="footer">footer</div>
</div>

I don't think you can achieve this without setting the spacing. As you probably know, you can get better control of inline-block layouts setting negative letter-spacing on the container and resetting on the item: .main {letter-spacing: -4px} .item {letter-spacing: 0} (You need to test if 4px works).
Or (since we're not using flex :), you could float odd and even divs left and right: .item:nth-child(odd) {clear: left; float: left} .item:nth-child(even) {float: right}

Related

Unexpected result from margin-top next to a floated element

I'm having issues with a layout like this:
.wrapper {
clear: both;
background-color: #ccc;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
The .main and .side elements need to be aligned. As you can see in the above snippet, everything is fine unless the .top element has no height in which case the margin-top rule causes them to be skewed. All of the following "fix" the issue but each has a drawback:
adding border to .wrapper (I might be able to live with a transparent border but I really don't like this since it feels like a dirty hack and I'd rather not add a border. For some reason the border needs to have a width of at least 1px or this doesn't work)
.wrapper {
clear: both;
background-color: #ccc;
border: 1px solid #000;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
adding overflow: hidden to .wrapper (this hides parts of some elements and causes others to fall in the wrong place)
adding overflow: auto to .wrapper (this adds scroll bars in some scenarios)
Those last two are not apparent in my snippet but in the real world application they cause problems as mentioned here.
I have a strong suspicion the issue is related to Why doesn't the height of a container element increase if it contains floated elements? and CSS container doesn't stretch to accommodate floats but I've tried many of those suggestions and none seem to quite solve the issue - perhaps because one of my divs is floated and the other is not.
Since this is part of a large application, I don't want to drastically change the layout, just have some css that will keep .main and .side aligned regardless of the content before those elements.
You can make the main element to be inline-block and use calc to set the width. This shouldn't affect your layout a lot and you will get the correct output:
.main {
width:calc(100% - 100px);
display:inline-block;
background: lightgreen;
}
Full code:
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
width:calc(100% - 100px);
display:inline-block;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
Another hacky idea is to make sure your top element is never empty:
.top:empty {
font-size:0;
}
.top:empty::before {
content: "\80"; /* a random character */
}
Full code
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
.top:empty {
font-size:0;
}
.top:empty::before {
content: "\80"; /* a random character */
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
You can also consider the same trick but using a pseudo element on the main wrapper:
.wrapper::before {
content: "\80"; /* a random character */
display:block;
font-size:0;
}
Full code
.wrapper {
background-color: #ccc;
clear: both;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
.wrapper::before {
content: "\80"; /* a random character */
display:block;
font-size:0;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
You can also make the wrapper inline-block with a width equal to 100% and it will behave almost the same as a block element:
.wrapper {
background-color: #ccc;
display:inline-block;
width:100%;
vertical-align:top; /* avoid some unwanted white space issue*/
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
margin-top: 20px;
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
width: 100px;
float: left;
background: lightblue;
}
.main {
margin-left: 100px;
background: lightgreen;
}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>
For the explanation, you are facing a margin collpasing issue like described in the specification:
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 (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.)
both belong to vertically-adjacent box edges, i.e. form one of:
top margin of a box and top margin of its first in-flow child
You can do this much more elegantly with grid. Here is the grid code:
.wrapper {
display: grid;
grid-template-areas:
"top top"
"side main";
grid-template-columns: 100px 1fr;
}
.top{grid-area:top}
.side{grid-area:side}
.main{grid-area:main}
Notice how many other elements I was able to comment out and still keep the desired layout.
.wrapper {
/*clear: both;*/
background-color: #ccc;
}
.wrapper+.wrapper {
margin-top: 50px;
}
.side,
.main {
height: 100px;
padding: 10px;
box-sizing: border-box;
/*margin-top: 20px;*/
}
.box {
padding: 10px;
}
.top {
background: yellow;
}
.side {
/*width: 100px;
float: left;*/
background: lightblue;
}
.main {
/*margin-left: 100px;*/
background: lightgreen;
}
.wrapper {
display: grid;
grid-template-areas:
"top top"
"side main";
grid-template-columns: 100px 1fr;
}
.top{grid-area:top}
.side{grid-area:side}
.main{grid-area:main}
<div class="wrapper">
<div class="top"></div>
<div class="side">side</div>
<div class="main">main</div>
</div>
<div class="wrapper">
<div class="top">
<div class="box">top</div>
</div>
<div class="side">side</div>
<div class="main">main</div>
</div>

some issue with margin in flex container

need some help. How to fix bug with .half-img2{ margin-top: 10px; }
http://prntscr.com/94uqok
These 2 imgs height must be equal to main-img
http://plnkr.co/edit/Dvj5HfG6hJqvYPxr0ljJ?p=preview
Html:
<style type="text/css">
.test{
display: flex;
}
.test>div{
flex: 1;
}
.test .main-img{
flex-grow: 2;
}
img{
width: 100%;
}
.half-img{
margin-left: 10px;
}
.half-img2{
margin-top: 10px;
}
</style>
<div class="test">
<div class="main-img">
<img src="http://fakeimg.pl/350x200/00CED1/FFF/?text=img+placeholder">
</div>
<div class="half-img">
<div class="half-img1">
<img src="http://fakeimg.pl/350x200/00CED1/FFF/?text=img+placeholder">
</div>
<div class="half-img2">
<img src="http://fakeimg.pl/350x200/00CED1/FFF/?text=img+placeholder">
</div>
</div>
</div>
I'll ignore the images sizes as these are not really relevant to the div layout issue.
A judicious use of margins and flex-column div layout seems to be required.
Layout would be something like this.
* {
box-sizing: border-box;
}
.test {
display: flex;
width: 80%;
margin: 1em auto;
border:1px solid green;
}
img {
display: block;
}
.test div {
}
.main-img {
flex:2;
margin-right: 10px;
background: lightblue;
}
.half-img {
display: flex;
flex-direction: column;
height: 250px;
}
.half-img {
flex:1;
display: flex;
flex-direction: column;
}
.half-img div {
flex:1;
background: lightblue;
}
.half-img1 {
margin-bottom: 5px;
}
.half-img2 {
margin-top: 5px;
}
<div class="test">
<div class="main-img">
</div>
<div class="half-img">
<div class="half-img1">
</div>
<div class="half-img2">
</div>
</div>
</div>

Dynamic grid system with different widths css3?

I need to perform a dynamic grid system like this:
Each section is an article that contains an image, a title and a link/button to that article.
The problem is that each section is loaded dynamically and i only have the html of the section so i need to put each section on the correct position dynamically from the CSS. The one i know is that there are 5 sections.
The html code of each section and the container of all the sections is this:
<section class="scroll">
<!-- ARTICLES -->
<!-- ARTICLE -->
<div class="article-content">
<img class="article-image" src="${item.imgPath}" />
<div class="article-texts">
<h1 class="article-title">${item.title}</h1>
<a class="article-button" href="${item.link}.html" role="button">Read Article ></a>
</div>
</div>
<div class="clear"></div>
<!-- END ARTICLE -->
<!-- END ARTICLES -->
</section>
If you have control over the dimensions of your sections, you can use a fixed width container and float the sections inside that. Clear the float on the fourth section.
Example Fiddle: http://jsfiddle.net/abhitalks/mbuf9957/3/
Example Snippet:
* { box-sizing: border-box; padding: 0; margin:0; }
div { width: 380px; overflow: hidden; }
section { border: 1px solid #666; float: left; }
section:nth-child(1) { width: 240px; height: 240px; }
section:nth-child(2) { width: 120px; height: 120px; }
section:nth-child(3) { width: 120px; height: 120px; }
section:nth-child(4) { width: 120px; height: 120px; clear: left; }
section:nth-child(5) { width: 240px; height: 120px; }
<div>
<section>1</section>
<section>2</section>
<section>3</section>
<section>4</section>
<section>5</section>
</div>
Since you have tagged this as CSS3, I think Flexbox would be an option. You could set display:flex on the parent and then have percentage widths for each box's flex-basis and set the flex-grow property to the amount of space, relative to other boxes, you want them to take up in the container and set flex-shrink to 0 since you don't need them to shrink.
CSS/HTML:
.grid-system {
/* Uncomment the next line to see the container */
/* border:1px solid black; */
}
.grid-system .box-width-2 {
border:1px solid black;
-webkit-flex:2 0 65%;
flex: 2 0 65%;
}
.grid-system .box-width-1 {
border:1px solid black;
-webkit-flex:1 0 32%;
flex: 1 0 32%;
}
.grid-system .box-height-2 {
-webkit-flex-grow:2;
flex-grow:2;
}
.grid-system .box-height-1 {
-webkit-flex-grow:1;
flex-grow:1;
}
.grid-system .flex-row {
display:-webkit-flex;
display:flex;
-webkit-flex-flow:row nowrap;
flex-flow:row nowrap;
-webkit-justify-content:flext-start;
justify-content:flex-start;
}
.grid-system .flex-column {
display:-webkit-flex;
display:flex;
-webkit-flex-flow:column nowrap;
flex-flow:column nowrap;
width:32%;
}
.grid-system .flex-row > div {
margin:0.5%
}
.grid-system .box-width-1.box-height-1 {
margin-bottom:0.5%;
-webkit-flex-grow:1;
flex-grow:1;
}
.grid-system .box-width-1.box-height-1.end {
margin-bottom:0px;
}
<div class="grid-system">
<div class="flex-row">
<div class="box-width-2 box-height-2">1</div>
<div class="flex-column">
<div class="box-width-1 box-height-1">2</div>
<div class="box-width-1 box-height-1 end">3</div>
</div>
</div>
<div class="flex-row">
<div class="box-width-1">4</div>
<div class="box-width-2">5</div>
</div>
</div>
jsFiddle
A solution only involving floats can reproduce your layout. Compatibility IE8+ (and even below but nobody cares). Pseudo-class :nth-child() (compat. IE9+) is used here to give an arbitrary width and height for demo, you'll have your own layout in real conditions.
* { box-sizing: border-box; }
div { width: 360px; }
section { border: 1px solid #666; }
.left { float: left; }
.right { float: right; }
.clear { clear: both; }
section:nth-child(1) { width: 240px; height: 240px; }
section:nth-child(2) { width: 120px; height: 100px; }
section:nth-child(3) { width: 120px; height: 80px; }
section:nth-child(4) { width: 200px; height: 120px; }
section:nth-child(5) { width: 160px; height: 100px; }
<div>
<section class="left">1</section>
<section class="right">2</section>
<section class="right">3</section>
<section class="left clear">4</section>
<section class="right">5</section>
</div>

Move elements to the right but keep their order in the HTML?

I need a number of elements to line up horizontally in the order in which they appear in the HTML. I need them to move to the right of their container.
If I float the items to the right then the order changes.
If I display as inline-block and make the container's text aligned to the right then there are spaces between them.
I can change the HTML however I cant remove all the white space (which may fix the issue with the inline-blocks). Can this be solved?
http://codepen.io/anon/pen/xbLbLE
<div class="cont">
<div class='itemA'>1</div>
<div class='itemA'>2</div>
<div class='itemA'>3</div>
<div class='itemA'>4</div>
</div>
<div class="cont contB">
<div class='itemB'>1</div>
<div class='itemB'>2</div>
<div class='itemB'>3</div>
<div class='itemB'>4</div>
</div>
.itemA,
.itemB {
width: 50px;
height: 50px;
}
.itemA {
background: green;
float: right;
}
.contB {
text-align: right;
}
.itemB {
background: red;
display: inline-block;
}
Float the elements that need to be in the correct order to the left and float their container to the right.
HTML
<div class="cont">
<div class='itemA'>1</div>
<div class='itemA'>2</div>
<div class='itemA'>3</div>
<div class='itemA'>4</div>
</div>
<div class="cont contB">
<div class='itemB'>1</div>
<div class='itemB'>2</div>
<div class='itemB'>3</div>
<div class='itemB'>4</div>
</div>
CSS
.itemA,
.itemB {
width: 50px;
height: 50px;
}
.itemA {
background: green;
}
.itemB {
background: red;
}
.cont {
float: right;
}
.cont div {
float: left;
}
and the jsFiddle: http://jsfiddle.net/enaeLr60/
The downside, as you have noticed, with using display: inline-block is that any space between each inline-block will be rendered as a single space. I prefer to float items to fix this versus the options like the following as they a not preferred.
<div>1</div><div>2</div> - no spaced between elements
<div>1</div><!-- comment block --><div>2</div> - comment between
elements
use a negative margin
UPDATE
My original answer forgot to include a wrapper around the .cont DIVs. As a result the DIVs with .itemA appear after the .itemB DIVs. See updated code to correct this.
HTML
<div class="list-container">
<div class="cont">
<div class='itemA'>1</div>
<div class='itemA'>2</div>
<div class='itemA'>3</div>
<div class='itemA'>4</div>
</div>
<div class="cont contB">
<div class='itemB'>1</div>
<div class='itemB'>2</div>
<div class='itemB'>3</div>
<div class='itemB'>4</div>
</div>
</div>
CSS
.itemA,
.itemB {
width: 50px;
height: 50px;
}
.itemA {
background: green;
}
.itemB {
background: red;
}
.list-container {
float: right;
}
.cont,
.cont div {
float: left;
}
updated jsFiddle: http://jsfiddle.net/enaeLr60/1
I am not sure if I am understanding your problem correctly, but can you give this CSS and try and see if it is what you are attempting to do.
.cont{
display:inline;
float:right
}
.itemA,
.itemB {
width: 50px;
height: 50px;
display: inline-block;
margin-right:-4px;
}
.itemA:last-child, .itemB:last-child{
margin-right:0;
}
.itemA {
background: green;
}
.contB {
text-align: right;
}
.itemB {
background: red;
}
The margin-right:4px is a hack around the display:inline-block; so, this may not be desirable.
My answer involves adding a wrapper around it all: http://codepen.io/anon/pen/KwvwyL
<div class="wrapper">
<div class="cont contA">
<div class='itemA'>1</div>
<div class='itemA'>2</div>
<div class='itemA'>3</div>
<div class='itemA'>4</div>
</div>
<div class="cont contB">
<div class='itemB'>1</div>
<div class='itemB'>2</div>
<div class='itemB'>3</div>
<div class='itemB'>4</div>
</div>
</div>
Then in the CSS:
.wrapper {
float: right;
}
.contA {
float: left;
background: green;
}
.contB {
float: left;
background: red;
}
.itemA, .itemB {
float: left;
}
.itemA,
.itemB {
width: 50px;
height: 50px;
display:inline-block;
}
.itemA { background: green; }
.cont { display:inline-block; word-spacing: -100%; }
.contB { float:right; }
.itemB { background: red; }
CodeOpen

How to stretch parent div to fit children div?

How to stretch parent div to fit children div?
I tried to add element with clear: both; after content but it didn't work for me.
HTML:
<div id="wrapper">
<div class="left-menu">
</div>
<div class="right-bar">
<div class="right-content">
<div class="content">
<div class="content-wrapper">
<div class="content-body">
Here is content
</div
</div>
</div>
</div>
</div>
</div>
CSS:
.left-menu {
background-color: #0B0C0E;
width: 20%;
height: 100%;
float: left;
}
.right-bar {
background-color: #F0F0F0;
height: 100%;
width: 100%;
}
.right-content {
float: left;
width: 80%;
}
.right-content > .content {
padding: 21px 0 0 42px;
}
.right-content > .content > .content-wrapper {
width: 98%;
height: 70%;
}
.right-content > .content .content-body {
background-color: #FAFAFA;
padding: 20px;
font-size: 24px;
border: 1px solid #D0D0D0;
}
sandbox for test: http://roonce.com/en/room/SwZuEJYB
Thanks in advance.
Use "clear-fix" technique. http://css-tricks.com/snippets/css/clear-fix/
This will allow the parent div to be the appropriate size of the floated elements within. Note this works specifically on #wrapper. (http://jsbin.com/huqehuta/1/edit)
.clear-fix:after {
content: "";
display: table;
clear: both;
}