Simple jQuery Plugin To Create Pinterest Style Grid Layout

By · March 9, 2016 · 3 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 (3)

# 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
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. *