3

I am trying to build "adjustable" css grid. I am making my blog and i want my news to be displayed in "blocks" and that they me placed like this : http://pokit.org/get/img/1dfa7b74c6be5bee6c92b886e0b8270b.jpg

And not like this what i did made here

Here is my code.
HTML

<div id="wrapper">
    <div class="d_1">1</div>
    <div class="d_2">2</div>
    <div class="d_3">3</div>
    <div class="d_4">4</div>
    <div class="d_5">5</div>
    <div class="d_6">6</div>

</div>

CSS

#wrapper{
    width:200px;

}
#wrapper div{
    background-color:lightgray;
    width:50px;

    float:left;
    margin:0px 5px 5px 0px;
}
.d_1{
    height:60px;
}
.d_2{
    height:30px;
}
.d_3{
    height:33px;
}
.d_4{
    height:70px;
}
.d_5{
    height:60px;
}
.d_6{
    height:40px;
}
Riki
  • 63
  • 8
  • "A left-floated box will shift to the left until its leftmost margin edge (or border edge if margins are absent) touches either the edge of the containing block, or **the edge of another floated box**" - http://www.smashingmagazine.com/2009/10/the-mystery-of-css-float-property/ Box 4 is colliding with box 1 before it reaches the left margin. if you flip the height of 2 and 3, you'll see box 4 stop at box 2 instead of box 1. It begins at the bottom of box 3 and begins sliding to the left until it hits something. I would like to see a solution to fix this. – hopkins-matt Aug 19 '15 at 20:36
  • Is there a website that shows a working version of the demo photo you shared? If so, please share and we can just look at that code and duplicate. – mrlemmer11 Aug 19 '15 at 20:38
  • I have no demo to show you, i am building blog on my own. Sorry – Riki Aug 19 '15 at 20:50
  • @Riki have you seen this done anywhere else? – hopkins-matt Aug 19 '15 at 20:54
  • @hopkins-matt I don't think so, i just came up with the idea of this and i didn't knew how to make this so i thought some of you has some ideas to help me – Riki Aug 19 '15 at 21:05

5 Answers5

2

I suppose that is not possible to obtain the desired result simply using one of the known layout modes (flexbox, grid-layout, inline, ...) nor using CSS columns. Every solution will lead to an unwanted result.

But you can obtain the result using a combination of CSS grid-layout and Javascipt code.

This is the wrapper CSS style block:

#wrapper{
    width: 200px; /* CSS grid-layout will expand contained divs to cover this size */
    display: grid;
    grid-template-columns: 1fr 1fr 1fr; /* "1fr" for each column */
    grid-column-gap: 10px;
    grid-row-gap: 5px;
}

And this is the Javascript code (add it after #wrapper is closed):

"strict mode";
Array.prototype.max = function() {
    return Math.max.apply(null, this);
};
function compute_gaps(a) {
    let max = a.max();
    return a.map(function(el) {
        return el - max;
    });
}
function compose_gaps(a, b) {
    return b.map(function(el, i) {
        return a[i] + el;
    });
}
var counter = 0;
var columns = 3; // number of columns
var gaps = [];
var heights = [];
for (let el of document.querySelectorAll("#wrapper > div")) {
    let colIdx = counter % columns;
    if (counter % columns === 0) {
        //compute gaps
        if (counter) gaps.push(compute_gaps(heights));
        if (gaps.length > 1) {
        gaps[gaps.length - 1] = compose_gaps(
            gaps[gaps.length - 1],
            gaps[gaps.length - 2]
        );
        }
        heights = [];
    }
    if (gaps.length) {
        el.style.marginTop = gaps[Math.floor(counter / columns - 1)][colIdx];
    }
    heights.push(el.offsetHeight); // apply gap as margin
    counter++;
}

Tested the code in a little more complex situation and worked in this way.

The code computes, in each row, gaps between the highest block and the others in the row (compute_gaps); after that, applied the gap as a CSS margin-top. Gaps are summed with the previous ones (compose_gaps).

I hope this answers your question.

bubbakk
  • 139
  • 2
  • 6
0

If you don't care about old browsers support (doesn't work with IE9 or above) then you can reorder your divs vertically by using the CSS3 column-count Property and setting it to 3 columns :

Add this to #wrapper :

-webkit-column-count: 3;
-webkit-column-fill: auto;
-moz-column-count: 3;
-moz-column-fill: auto;
column-count: 3;
column-fill: auto;

Then replace float:left; in your #wrapper div by display: inline-block;

Here is a CODEPEN DEMO.


NOTE: If browser support and div order are important then an elegant solution may be found in this StackOverFlow post : how to replicate pinterest.com's absolute div stacking layout

Community
  • 1
  • 1
Salem Ouerdani
  • 7,596
  • 3
  • 40
  • 52
  • Hmmm, i don't think this is what i wanted. Can you check once again what it should looks like http://pokit.org/get/img/1dfa7b74c6be5bee6c92b886e0b8270b.jpg – Riki Aug 19 '15 at 21:33
  • If you mean divs order is important then, according to [this](http://stackoverflow.com/questions/14925157/css-columns-with-left-right-flow); my solution will only work with extra JS code to reorder divs. You may also find useful answers to what you are trying to do in this [stackOverFlow post](http://stackoverflow.com/questions/7109362/how-to-replicate-pinterest-coms-absolute-div-stacking-layout). – Salem Ouerdani Aug 19 '15 at 22:14
0

Warning:

I am not the best at CSS and JS right now. I tend to brute force things until they work. I am pretty sure this is not the best solution, however, I want to post it so that maybe others can improve upon it. This may not be functional once all content is put in or may not by responsive or may not be dynamic enough to solve the issue, I don't know. I do know that the desired look from the question is achieved through this method, right now, without content etc.

I do welcome any and all feedback regarding why this isn't the best and/or what is wrong with it so I can learn.

With that being said, here is the fiddle:

http://jsfiddle.net/jz4p4Lzk/13/

HTML

<div id="wrapper">
<div class="d_1" id="d1">1</div>
<div class="d_2" id="d2">2</div>
<div class="d_3" id="d3">3</div>
<div class="d_4" id="d4">4</div>
<div class="d_5" id="d5">5</div>
<div class="d_6" id="d6">6</div>

CSS

#wrapper{
    width:200px;
}
#wrapper div{
    background-color:lightgray;
    width:50px;
    position:relative;
    margin:0px 5px 5px 0px;
}
.d_1{
    height:60px;
}
.d_2{
    height:30px;
}
.d_3{
    height:33px;  
} 
.d_4{
    height:70px;
}
.d_5{
    height:60px;
}
.d_6{
    height:40px;
}

JS

var d1 = document.getElementById('d1');
var d1Loc = d1.getBoundingClientRect();
var d2 = document.getElementById('d2');
var d2Loc = d2.getBoundingClientRect();
var d3 = document.getElementById('d3');
var d3Loc = d3.getBoundingClientRect();
var d4 = document.getElementById('d4');
var d4Loc = d4.getBoundingClientRect();
var d5 = document.getElementById('d5'); 
var d5Loc = d5.getBoundingClientRect();
var d6 = document.getElementById('d6');
d2.style.left = d1Loc.right -5+ "px";
d2.style.top = - d1.offsetHeight - 5 + "px";
d3.style.left = d2Loc.right + d1Loc.right -10 +"px";
d3.style.top = - d1.offsetHeight - d2.offsetHeight - 10 + "px";
d4.style.top = - d1.offsetHeight - d2.offsetHeight - d3.offsetHeight + 50 + "px";
d5.style.top =  - d1.offsetHeight - d2.offsetHeight - d3.offsetHeight - d4.offsetHeight + 15 + "px";
d6.style.top = - d1.offsetHeight - d2.offsetHeight - d3.offsetHeight - d4.offsetHeight - d5.offsetHeight +12.5 + "px";
d5.style.left = d4Loc.right  -5+ "px";
d6.style.left = d5Loc.right + d4Loc.right -10 + "px"; 
mrlemmer11
  • 347
  • 2
  • 15
  • This is very good but here is the problem. On my blog I will have a lot of these "blocks", not only 6 or 4. Also, I added classes only because I wanted to assign different height to each div but on my page divs will have height equal to image that will be in. Can this be made so it works not only for 6 but for unlimited divs? Thank you very much – Riki Aug 20 '15 at 05:45
0

you know that there is an actual "css grid" that you can use? It doesn't quite work yet in IE (it does, but only somewhat), but in all other relevant browsers it works well. Basically, you specify gridlines and then place the boxes that you want to within them. I made a codepen so you can see it in action. (oh, and no javascript needed)

https://codepen.io/quibble/pen/NaKdMo

#wrapper{
  display:grid;
  grid-gap:10px;
  grid-template-columns:50px 50px 50px;
  grid-template-rows: 30px 3px 27px 13px 17px 40px; /*the pixels add up to the corresponding bottoms of each grid container. There are a few ways to do this but I like this one.*/
  grid-template-areas:
    /*This allows you to specify which grid blocks go where. Notice that some are repeated, this just means they span two or more grid areas. For example, box 3 is 33 px so must span one column and two rows (the 30 and 3px one)*/
    "one two three"
    "one five three"
    "one five six"
    "four five six"
    "four five ."
    "four . .";/* the . is for a blank gridspace */
}
#wrapper>div{
  background-color:gray;
}
.d_1{
  grid-area:one;
}
.d_2{
  grid-area:two;
}
.d_3{
  grid-area:three;
}
.d_4{
  grid-area:four;
}
.d_5{
  grid-area:five;
}
.d_6{
  grid-area:six;
}

I'm pretty sure this is exactly what you want. You can even mess around with the order of the numbers (in case you want to rearrange your blog posts or pictures) and you can add more pretty easily. You even have "grid-template-areas:" which allows you to specify EXACTLY where each item will go. NO MORE HACKING FOR POSITIONSSS

Good luck out there! Please mark right if this helped. (P.S., if you need more information on grid, one of the people that pushed for it very heavily (Rachel Andrew) made a tutorial: https://gridbyexample.com/)

Quibble
  • 173
  • 1
  • 7
0

This seems similar to another topic: how-create-grid-out-of-images-of-different-sizes

I fully agree with @Quibble on this. He basically used the layout you wanted. I made a different one, it just has a different approach, though areas are the more elegant way. Just something to bear in mind, you can do it in several ways, none of which involve JS-based coding. My JSfiddle example.

.container {
  display: grid;
  padding: 60pt;
  grid-template-columns: 2fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 2fr;
  /* there are five values for five columns, each column gets a relative 
           width in relation to the grid*/
  grid-template-rows: 10% 45% 35% 10%;
  grid-column-gap: 10px;
  grid-row-gap: 5px;
  /*this means there are three rows*/
}

.container div img {
  width: 100%;
  height: 100%;
}

.main_1 {
  grid-column: 2/5;
  grid-row: 2/3;
}

.main_2 {
  grid-column: 5/8;
  grid-row: 2/3;
}

.main_3 {
  grid-column: 8/11;
  grid-row: 2/3;
}

.main_4 {
  grid-column: 2/4;
  grid-row: 3/4;
}

.main_5 {
  grid-column: 4/7;
  grid-row: 3/4;
}

.main_6 {
  grid-column: 7/11;
  grid-row: 3/4;
}

.footer {
  grid-row: 4/5;
  grid-column: 1/6;
}
Programina
  • 31
  • 6