HTML
<div class="cards">
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/65/33/85/6533859c383845b498d81990c4be2a41.jpg" />
</div>
<div class="card-info">
Low-poly illustrations
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/19/dc/3d/19dc3d3f392a57378c55c32e3ef7574e.jpg" />
</div>
<div class="card-info">
Burger Bits by cronobreaker.devi... on @deviantART
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/5c/dd/72/5cdd72b452abf457e85ec9ea38aa6559.jpg" />
</div>
<div class="card-info">
Da' Monk Photo by Mnk Crew
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/89/df/1c/89df1ceeb79793465779a273794faa10.jpg" />
</div>
<div class="card-info">
vector animals <br> Photo by Çetin Can Karaduman on Behance
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/f8/e7/bf/f8e7bfc4e7523e1d050fd12e2141eb48.jpg" />
</div>
<div class="card-info">
Diet Zombie Pop by cronobreaker.devi... on @deviantART
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/0a/ec/7b/0aec7ba66f3970edbeed34168ea7e776.jpg" />
</div>
<div class="card-info">
Vectors Assemble <br> Photo by William Teal on Behance
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/8f/de/a6/8fdea6e709e1dbf66aa5f031c0e187fc.jpg" />
</div>
<div class="card-info">
Camila 2 - Urban Arts by Cristiano
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/c2/7f/4c/c27f4ce431471238a8ac08de609a3e24.jpg" />
</div>
<div class="card-info">
BMO v2.0 by shoden23.devianta... on @deviantART
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/2a/04/0f/2a040f6fd57319510e6c7a027795cb1d.jpg" />
</div>
<div class="card-info">
FORCE AWAKENS DEADPOOL-vector <br> Photo by Orlando Arocena on Behance
</div>
</div>
<div class="card">
<div class="card-image">
<img src="https://s-media-cache-ak0.pinimg.com/564x/e7/66/c2/e766c2d243ed4b6962d71ba8b48ffddf.jpg" />
</div>
<div class="card-info">
Breaking Bad by Guillaume
</div>
</div>
</div>
SCSS
* {
box-sizing: border-box;
}
body {
color: #212121;
font-size: 13px;
font-family: 'Helvetica Neue', sans-serif;
background: #ECEFF1;
padding: 2em;
}
.cards {
opacity: 0;
margin: auto;
&--loaded { opacity: 1; }
}
.card {
backface-visibility: hidden;
background: #fff;
box-shadow: 1px 1px 2px rgba(0,0,0,0.3);
border-radius: 4px;
display: inline-block;
margin-bottom: 10px;
margin-right: 10px;
min-height: 100px;
opacity: 0;
transition: all 300ms ease-in-out;
transform-origin: 50% 50% 0;
vertical-align: top;
width: 150px;
&--loaded {
opacity: 1;
}
.card-image {
img {
width: 100%;
border-radius: 4px 4px 0 0;
}
}
.card-info {
padding: 10px 16px;
}
}
JAVASCRIPT
(function(exports) {
'use strict';
function PinterestGrid(options) {
this.settings = Object.assign({
delay: 100,
shorterFirst: true,
gutter: 6
}, options);
this.loaded = false;
this.transform = _getTransformProperty();
this.$container = options.container instanceof Node ?
options.container :
document.querySelector(options.container);
if (!this.$container) {
return false;
}
this.$itemCollection = options.item instanceof NodeList ?
options.item :
this.$container.querySelectorAll(options.item);
if (!this.$itemCollection || this.$itemCollection.length === 0) {
return false;
}
if (!this.loaded) { return this.init(); }
}
PinterestGrid.prototype.init = function() {
this.loaded = true;
var gutter = parseInt(this.settings.gutter);
var callback = this.settings.callback;
this.$container.style.width = '';
var containerWidth = this.$container.getBoundingClientRect().width;
var firstChildWidth = this.$itemCollection[0].getBoundingClientRect().width + gutter;
var cols = Math.max(Math.floor((containerWidth - gutter) / firstChildWidth), 1);
containerWidth = (firstChildWidth * cols + gutter) + 'px';
this.$container.style.width = containerWidth;
this.$container.style.position = 'relative';
var itemsGutter = [];
var itemsPosX = [];
for (var g = 0; g < cols; g++) {
itemsPosX.push(g * firstChildWidth + gutter);
itemsGutter.push(gutter);
}
Array.from(this.$itemCollection).forEach(function (item, i) {
if (this.settings.shorterFirst) {
var itemIndex = itemsGutter.slice(0).sort(function(a, b) { return a - b }).shift();
itemIndex = itemsGutter.indexOf(itemIndex);
} else {
var itemIndex = i % cols;
}
var posX = itemsPosX[itemIndex];
var posY = itemsGutter[itemIndex];
item.style.position = 'absolute';
item.style.webkitBackfaceVisibility = item.style.backfaceVisibility = 'hidden';
item.style[this.transform] = 'translate3D(' + posX + 'px,' + posY + 'px, 0)';
itemsGutter[itemIndex] += item.getBoundingClientRect().height + gutter;
if (!/loaded/.test(item.className)) {
setTimeout(function() {
item.classList.add(item.className.split(' ')[0] + '--loaded');
}, (parseInt(this.settings.delay) * i));
}
}.bind(this));
var containerHeight = itemsGutter.slice(0).sort(function(a, b) { return a - b }).pop();
this.$container.style.height = containerHeight + 'px';
if (!/loaded/.test(this.$container.className)) {
this.$container.classList.add(this.$container.className.split(' ')[0] + '--loaded');
}
if (typeof callback === 'function') {
callback(this.$itemCollection);
}
}
function _getTransformProperty() {
var style = document.createElement('div').style;
var transform;
var vendorProp;
if (undefined !== style[vendorProp = 'webkitTransform']) {
transform = vendorProp;
}
if (undefined !== style[vendorProp = 'msTransform']) {
transform = vendorProp;
}
if (undefined !== style[vendorProp = 'transform']) {
transform = vendorProp;
}
return transform;
}
// AMD
if (typeof define === 'function' && define.amd) {
define(function() {
return PinterestGrid
});
}
// CommonJS
else if (typeof module !== 'undefined' && module.exports) {
module.exports = PinterestGrid;
}
// Global Property
else {
exports.PinterestGrid = PinterestGrid;
}
}(this));
(function() {
var grid = new PinterestGrid({
delay: 100,
container: '.cards',
item: '.card',
gutter: 10
});
window.addEventListener('resize', function() {
grid.init();
});
Array.from(document.querySelectorAll('.card img')).forEach(function(item) {
console.log(item);
item.addEventListener('load', function() {
grid.init();
item.removeEventListener('load');
}, false);
});
})();