Can't properly position multy column grid with Javascript

Hi everyone,

I have a set of divs with different heights - all absolutely positioned within the main div container. Number of columns is supposed to be customizable and it should depend on the window width. I can’t make it working. Could anyone let me know what is wrong with the code? Thank you.


<div id="grid_container">
    <div style="height: 140px;"><div>1</div></div>
    <div style="height: 200px;"><div>2</div></div>
    <div style="height: 120px;"><div>3</div></div>
    <div style="height: 180px;"><div>4</div></div>
    <div style="height: 150px;"><div>5</div></div>
    <div style="height: 160px;"><div>6</div></div>
    <div style="height: 180px;"><div>7</div></div>
    <div style="height: 170px;"><div>8</div></div>
    <div style="height: 160px;"><div>9</div></div>
    <div style="height: 180px;"><div>10</div></div>
    <div style="height: 150px;"><div>11</div></div>
    <div style="height: 160px;"><div>12</div></div>
    <div style="height: 130px;"><div>13</div></div>
    <div style="height: 140px;"><div>14</div></div>
    <div style="height: 210px;"><div>15</div></div>
</div>


window.addEventListener('load', renderGrid, false);
window.addEventListener('resize', renderGrid, false);

function renderGrid(){
			
	var blocks = document.getElementById("grid_container").children;
	var pad = 10, cols, newleft, newtop;
		
	if(window.innerWidth<400){
		cols = 2;
	}
	else{
		cols = 3;
	}
				
	for(var i=1; i<blocks.length; i++){
			
		if(i % cols == 0){

			newtop = (blocks[i-cols].offsetTop + blocks[i-cols].offsetHeight) + pad;
			blocks[i].style.top = newtop + "px";
				
		}
		else{
			if(blocks[i-cols]){
					
				newtop = (blocks[i-cols].offsetTop + blocks[i-cols].offsetHeight) + pad;
				blocks[i].style.top = newtop + "px";
					
			}
				
			newleft = (blocks[i-1].offsetLeft + blocks[i-1].offsetWidth) + pad;
			blocks[i].style.left = newleft + "px";
				
		}		
	}
}

I can’t see anywhere in that code where you set the divs as position:absolute

Also from my understanding of what you are trying to do the arrangement of the divs would be far easier to do with CSS without any JavaScript involvement at all.

Would something like this serve your purposes? (Try that out and resize the browser).

Try something like this:

<!DOCTYPE html>
<style>
.r { background: red; }
.g {background: green; }
.b {background: blue; }
div { height: 100px; float: left; width: 100px }
</style>
<div class="r">1</div>
<div class="g">2</div>
<div class="b">3</div>
<div class="r">4</div>
<div class="g">5</div>
<div class="b">6</div>
<div class="r">7</div>
<div class="g">8</div>
<div class="b">9</div>
<div class="r">10</div>
<div class="g">11</div>
<div class="b">12</div>

Thank you for your response. I know it might be easier to do it with CSS, but it’s almost done already and it doesn’t look overwhelming doing it with JavaScript. Here is the code that it looks like it should work but it doesn’t:


if(window.innerWidth<400){
	cols = 2;
}
else{
	cols = 3;
}

Here is the CSS:


<style type="text/css">
div#grid_container{
	width: 900px;
	margin: 0px auto;
	height: 860px;
	border: #999 1px dashed;
}
div#grid_container > div{
	position: absolute;
	width: 291px;
	border: #000 1px solid;
}	
div#grid_container > div:nth-child(2n+0){
	background: #FFDC64;
}
div#grid_container > div:nth-child(2n+1){
	background: #FEC910;
}
div#grid_container > div > div{
	padding: 20px;
	font-size: 27px;
	color: #D9A800;
}
</style>

Thanks again.

Thank you for your response. All divs have different heights so floating left wouldn’t work.

How about this:

<!DOCTYPE html>
<style>
.r { background: red; }
.g {background: green; }
.b {background: blue; }
div { float: left; width: 100px }
body > div { height:110px; background:#aaa; }
</style>
<body>
<div><div class="r" style="height:100px">1</div></div>
<div><div class="g" style="height:40px">2</div></div>
<div><div class="b" style="height:60px">3</div></div>
<div><div class="r" style="height:50px">4</div></div>
<div><div class="g" style="height:30px">5</div></div>
<div><div class="b" style="height:110px">6</div></div>
<div><div class="r" style="height:40px">7</div></div>
<div><div class="g" style="height:60px">8</div></div>
<div><div class="b" style="height:80px">9</div></div>
<div><div class="r" style="height:30px">10</div></div>
<div><div class="g" style="height:50px">11</div></div>
<div><div class="b" style="height:70px">12</div></div>
</body>

I know it might be easier to do it with CSS, but it’s almost done already
The principle reason I’m posting CSS-based solutions is because I don’t really understand the behavior you want and that makes it very difficult to work out what’s wrong with your JavaScript. Not that I couldn’t do it but so far when I try to write your code I don’t manage to get far enough to see what you are doing wrong before my mind baulks and goes “Hang on couldn’t this just be done with CSS?!”

In this case I believe this laziness on my part actually coincides with the better way to do it and it sounds as if you are suffering from some sunk cost bias. So I would like to point out, if there is an acceptable CSS-based solution, then that is definitely your better option. Not just because it is considerably easier but it will play better with other page elements, have better performance, and be easier to change later. If the code I’ve just posted provides the behavior you’re seeking I recommend you throw away your JavaScript and forget about it; there’ll be plenty of other opportunities to write JavaScript.

Let me know, however, if this most recent CSS-based solution of mine doesn’t give you the behavior you are looking for.