Simple jQuery Plugin To Create Pinterest Style Grid Layout
by johna | March 9, 2016 | Jquery/Javascript Responsive Web Design Web Development
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.
UPDATE 16 Nov 2017: There's a new version available of this script available now that puts content in the shortest column rather than just in the next row/column position.
Note that the comments in the code show changes I made.
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):
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.
UPDATE 16 Nov 2017: There's a new version available of this script available now that puts content in the shortest column rather than just in the next row/column position.
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;
Related Posts
Converting dBase IV programs to run in the browser
by johna | September 13, 2024
Some pointless entertainment trying to get some old dBase programs running in the browser.
How to set up a debugging using the Turnkey Linux LAMP stack and VS Code
by johna | December 19, 2023
The second part in my guide to setting up a website and database using the Turnkey Linux LAMP stack.
How to set up a website and database using the Turnkey Linux LAMP stack
by johna | November 18, 2023
If you need to host your own website for the purposes of web development, Turnkey Linux LAMP Stack is an easy to install all-in-one solution that you can set up on a spare computer or a VM (Virtual Machine).
Comments
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
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
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
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
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
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
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