Simple jQuery Plugin To Create Pinterest Style Grid Layout

By · March 9, 2016 · 7 comments

When I was looking for an alternative to Masonry to produce a responsive Pinterest style grid that was a lot simpler and lighter weight I came across this jQuery plugin on www.jqueryscript.net that is very simple and works well.

However, It has a few issues which I needed to fix before I could use it.

1. The columns do not take up the full width of the container because the width calculation includes horizontal margin on all columns. It should exclude the margin on the final column.

2. The height calculation is inaccurate as it does not include vertical padding on every element. I needs to include padding for each element except the last one.

3. The function that runs to calculate and adjust sizes calls the window resize event handler every time it runs, which is not necessary, and results in the resize event running constantly. It is possible this was intended to handle loading of images, which effects the size calculation, which I deal with in issue 4.

4. If images are not loaded when the script runs then it can't calculate the height required correctly. To accommodate this, I run the resize event each time an image is loaded within the container.

Here's the final code. See the page on www.jqueryscript.net for instructions on how to use it.

UPDATE 13 April 2017: I've made some further improvements and fixes to this script. The new script allows you to create multiple breakpoints each with a specific number of columns. See my new post, Enhanced simple Pinterest Style Grid Layout jQuery Plugin.

Note that the comments in the code show changes I made.

 /*
Pinterest Grid Plugin
Copyright 2014 Mediademons
@author smm 16/04/2014

usage:

$(document).ready(function() {
$('#blog-landing').pinterest_grid({
no_columns: 4
});
});
*/
; (function ($, window, document, undefined) {
var pluginName = 'pinterest_grid',
defaults = {
padding_x: 10,
padding_y: 10,
no_columns: 3,
margin_bottom: 50,
single_column_breakpoint: 700
},
columns,
$article,
article_width;

function Plugin(element, options) {
this.element = element;
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}

Plugin.prototype.init = function () {
var self = this,
resize_finish;

$(".blog-landing img").load(function () {
$(window).resize();
});

$(window).resize(function () {
clearTimeout(resize_finish);
resize_finish = setTimeout(function () {
self.make_layout_change(self);
}, 11);
});

self.make_layout_change(self);

setTimeout(function () {
$(window).resize();
}, 500);
};

Plugin.prototype.calculate = function (single_column_mode) {
var self = this,
tallest = 0,
row = 0,
$container = $(this.element),
container_width = $container.width();
$article = $(this.element).children();

if (single_column_mode === true) {
article_width = $container.width() - self.options.padding_x;
} else {
//article_width = ($container.width() - self.options.padding_x * self.options.no_columns) / self.options.no_columns;
article_width = ($container.width() - self.options.padding_x * (self.options.no_columns - 1)) / self.options.no_columns;
}

$article.each(function () {
$(this).css('width', article_width);
});

columns = self.options.no_columns;

$article.each(function (index) {
var current_column,
left_out = 0,
top = 0,
$this = $(this),
prevAll = $this.prevAll(),
tallest = 0;

if (single_column_mode === false) {
current_column = (index % columns);
} else {
current_column = 0;
}

for (var t = 0; t < columns; t++) {
$this.removeClass('c' + t);
}

if (index % columns === 0) {
row++;
}

$this.addClass('c' + current_column);
$this.addClass('r' + row);

prevAll.each(function (index) {
if ($(this).hasClass('c' + current_column)) {
top += $(this).outerHeight() + self.options.padding_y;
}
});

if (single_column_mode === true) {
left_out = 0;
} else {
left_out = (index % columns) * (article_width + self.options.padding_x);
}

$this.css({
'left': left_out,
'top': top
});
});

this.tallest($container);
//$(window).resize();
};

Plugin.prototype.tallest = function (_container) {
var column_heights = [],
largest = 0;

var paddingy = this.options.padding_y;

for (var z = 0; z < columns; z++) {
var temp_height = 0;
_container.find('.c' + z).each(function () {
//temp_height += $(this).outerHeight();
temp_height += $(this).outerHeight() + paddingy;
});
column_heights[z] = temp_height;
}

//largest = Math.max.apply(Math, column_heights);
largest = Math.max.apply(Math, column_heights) - paddingy;
//_container.css('height', largest + (this.options.padding_y + this.options.margin_bottom));
_container.css('height', largest + this.options.margin_bottom);
};

Plugin.prototype.make_layout_change = function (_self) {
if ($(window).width() < _self.options.single_column_breakpoint) {
_self.calculate(true);
} else {
_self.calculate(false);
}
};

$.fn[pluginName] = function (options) {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new Plugin(this, options));
}
});
}

})(jQuery, window, document);


It's also easy to change the number of columns when it changes to "single column" mode by changing the Plugin.prototype.calculate method. Here's what the first part of this method should be changed to (comments show changes):

Plugin.prototype.calculate = function (single_column_mode) {
var self = this,
tallest = 0,
row = 0,
$container = $(this.element),
container_width = $container.width();
$article = $(this.element).children();

//these next lines are new
if (single_column_mode === true) {
columns = 2;
single_column_mode = false;
}
else {
columns = self.options.no_columns;
}

if(single_column_mode === true) {
article_width = $container.width() - self.options.padding_x;
} else {
//this next line has been changed
article_width = ($container.width() - self.options.padding_x * (columns - 1)) / columns;
}

$article.each(function() {
$(this).css('width', article_width);
});

//this next line should be removed
//columns = self.options.no_columns;

Get the latest posts delivered to your inbox.

Comments (7)

# Posted by Maxim Usik · April 12, 2017

hi! thank you for your nice fixes! maybe you can help me with a little advice, please?

i would like to have a grid which changes from 3 columns at a desktop to 2 columns at ipad and 1 at iphone.
is it possible to do? and if yes how can i do it?

thank you very much!

Reply

Maxim Usik
# Posted by John Avis · April 12, 2017

hi maxim. that's a great suggestion. i've made some changes to this script and it can now handle multiple breakpoints each with a specific number of columns. see my new post:
http://blog.johnavis.com/blog/828/enhanced-simple-pinterest-style-grid-layout-jquery-plugin/

Reply

John Avis
# Posted by Maxim Usik · April 16, 2017

Wau! John, thank you very much for your quick answer! I will read it now! Thank you very much.

Reply

Maxim Usik
# Posted by Kurt Hosna · May 17, 2017

This is great, thats for the post. I have a quick question, how can I control the width of the overall container. I know how to adjust the number of columns but I'd like the default width overall to be wider.

Reply

Kurt Hosna
# Posted by John Avis · May 17, 2017

Kurt, not sure I understand - the columns will be spaced evenly and will occupy the entire width of the element that you apply this to.You can put a fixed width on this element or it can be fluid. The plugin doesn't need to be "told" the width as it is responsive, and adapts to the available width on load and at resize.

Reply

John Avis
# Posted by John Avis · June 29, 2017

@kldamr, I'm not sure I understand. The plugin stacks the items from left to right, so the first one is top left, then each one is placed to the right and then down. Are you saying it is putting the first one not in the top left position? Do you have an example to look at?

You could modify the plugin fairly easy for RTL instead of LTR. If you need help with this I can have a look.

Reply

John Avis
# Posted by kldamr · June 30, 2017

thanks for you answer, In my case I use this pluc in with bootstrap-rtl, It's true that it stacks the items as you says (if I understand the logic of this plugin's code the order is assured by the two classes 'r' and 'c') i changer the order of the two classes but as I said before the first item still start in the middle. If you can help me to modify this plugin to use in RTL I will be highly grateful.

Reply

kldamr
Leave a Comment

All comments are moderated and rel="nofollow" is in use. Avatars are sourced from gravatar.com – a globally recognised avatar.

Type the numbers from the picture above

About me
John Avis ...mostly about web development and programming, with a little bit of anything else related to the Internet, computers and technology.

profile for John at Stack Overflow, Q&A for professional and enthusiast programmers
Subscribe

Get the latest posts delivered to your inbox. *