Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInEmail this to someone

デバイスサイズの多様化に伴って、ワンソース・マルチデバイスで対応するためにメディアクエリーを使ったレスポンシブデザインが注目されていますが、Pinterestのようなグリッドレイアウトもまた1つのマルチデバイス対応です。

Pinterest風のグリッドレイアウトを実装する

Pinterestのグリッドレイアウトとは

Pinterestは、写真メインのSNSですが、PC画面だとこんな感じで表示されます。
pinterest_pc

iPhoneで見るとこんな感じ。画面幅によってグリッドの列数が変わってます。
pinterest_mobile

自分のサイトでもPinterestのような素敵なグリッドレイアウトはどのように実装できるのかを調べたところ、以下のサイトで詳細に説明されていて、感激しました。(素敵!)

Pinterest風グリッドレイアウトを作ってみよう

私はこちらのサイトを参考にグリッドレイアウトを作ってみましたが、
上記サイト通りに実装したところ、1つ問題がありました。

「初期ロード時にコンテンツ領域がセンタリングされていない・・・」

デモページでも上記現象が発生してますが、初期ロード時のみコンテンツが左に寄っています。
ブラウザのサイズを変えて、1度でもグリッド移動が発生すると以降はセンタリングされます。

デモページ

確かに左右の余白が合ってないです。左によってます。
demo_pc
iPhoneで見ても間違いなく左によっている。
demo_iphone

なので、自力で解決しました。

JavaScriptを解析して見直したところ、初期ロード時にコンテンツ領域の幅を設定していない事が原因だとわかりました。
下記のように★1行を加えると初期ロード時にセンタリングされるはずです。

;(function($){
	$.fn.pinterestGrid = function(options){

		elements = $(this);
		winObject = $(window);
		opts = $.extend({}, $.fn.pinterestGrid.defaults, options);
		
		setCol();
		
		//★呼び出し元の幅をカラム列×表示可能列数に設定
		elements.width(colWidth * numOfCol);
				
		applyPinterestGrid();
		
		winObject.unbind('resize').resize(function(){
			var containerWidth;
			var winWidth = winObject.width() - opts.offsetX * 2;

			if(winWidth < colWidth * numOfCol){
				setCol();
				containerWidth = colWidth * (numOfCol - 1);
			}else if(winWidth > colWidth * (numOfCol + 1)){
				setCol();
				containerWidth = colWidth * (numOfCol + 1);
			}
			
			if(containerWidth){
				var current = elements.width();
				elements.width(colWidth * numOfCol);
				applyPinterestGrid();
			}
		});
		
		return this;
	}
	
	$.fn.pinterestGrid.defaults = {
		offsetX: 5,
		offsetY: 5,
		gridElement: 'div'
	};
	
	var elements,
	winObject,
	numOfCol,
	opts = {},
	colWidth,
	gridArray = [];
	
	if(!Array.prototype.indexOf){
		Array.prototype.indexOf = function(elt){
			var len = this.length >>> 0;
			
			var from = Number(arguments[1]) || 0;
			from = (from < 0) ? Math.ceil(from) : Math.floor(from);
			if(from < 0){
				from += len;
			}
			
			for(; from < len; from++){
				if(from in this && this[from] === elt){
					return from;
				}
			}
			return -1;
		}
	}
	
	function applyPinterestGrid(){
		createEmptyGridArray();
		
		elements.children(opts.gridElement).each(function(index){
			setPosition($(this));
		});
		
		var heightarr = getHeightArray(0, gridArray.length);
		elements.height(heightarr.max + opts.offsetY);
	}
	
	function setCol(){
		colWidth = $(opts.gridElement).outerWidth() + opts.offsetX * 2;
		numOfCol = Math.floor((winObject.width() - opts.offsetX * 2) / colWidth);
	}
	
	function createEmptyGridArray(){
		gridArray = [];
		for(var i = 0;i < numOfCol;i++){
			pushGridArray(i, 0, 1, -opts.offsetY);
		}
	}
	

	function pushGridArray(x, y, size, height){
		for(var i = 0;i < size; i++){
			var grid = [];
			grid.x = x + i;
			grid.size = size;
			grid.endY = y + height + opts.offsetY * 2;
			gridArray.push(grid);
		}
	}
	
	function removeGridArray(x, size){
		for(var i = 0;i < size; i++){
			var idx = getGridIndex(x + i);
			gridArray.splice(idx, 1);
		}
	}
	
	function getGridIndex(x){
		for(var i = 0;i < gridArray.length;i++){
			var obj = gridArray[i];
			if(obj.x == x){
				return i;
			}
		}
	}

	function getHeightArray(x, size){
		var heightArray = [];
		var temps = [];
		
		for(var i = 0;i < size; i++){
			var idx = getGridIndex(x + i);
			temps.push(gridArray[idx].endY);
		}
		heightArray.min = Math.min.apply(Math, temps);
		heightArray.max = Math.max.apply(Math, temps);
		heightArray.x = temps.indexOf(heightArray.min);
		
		return heightArray;
	}
	
	function getGridPosition(){
		var pos = [];
		var tempHeight = getHeightArray(0, gridArray.length);
		pos.x = tempHeight.x;
		pos.y = tempHeight.min;
		return pos;
	}
		
	function setPosition(grid){
		if(!grid.data('size') || grid.data('size') < 0){
			grid.data('size', 1);
		}
		
		var pos = getGridPosition();
		var gridWidth = colWidth - (grid.outerWidth() - grid.width());
		
		grid.css({
			'left':pos.x * colWidth,
			'top':pos.y,
			'position':'absolute'
		});
		
		removeGridArray(pos.x, grid.data('size'));
		pushGridArray(pos.x, pos.y, grid.data('size'), grid.outerHeight());
	}
	
	
})(jQuery);

※HTMLとCSSの部分は「Pinterest風グリッドレイアウトを作ってみよう」参照

いやはや、最初は焦りましたが解決して良かった。
にしてもこの処理を最初から設定して実装する人って本当凄いし、ありがたいですね。

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInEmail this to someone