サイト制作に関するメモ書き

HOME > JavaScript > jQuery > 高さの異なる要素を隙間なく配置するjQueryプラグインを作ってみた

高さの異なる要素を隙間なく配置するjQueryプラグインを作ってみた

高さの異なる要素を隙間なく配置するプラグイン「stonewall.js」を作りました。
「stonewall.js」のデモページはこちらから
「stonewall.js」のダウンロード

設定方法

jQueryとstonewall.jsを読み込みます。

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="stonewall.js"></script>

HTML

<div id="contents">
	<div class="panel"><img src="./img01.jpg" width="220" height="146" alt="" /></div>
	<div class="panel"><img src="./img02.jpg" width="220" height="146" alt="" /></div>
~略~
	<div class="panel"><img src="./img14.jpg" width="220" height="180" alt="" /></div>
	<div class="panel"><img src="./img15.jpg" width="220" height="331" alt="" /></div>
</div>

CSS

#contents {
	position: relative;
}
#contents .panel {
	float: left;
	margin: 10px;
}

cssは最低限親要素にposition: relative;を指定しておいてもらえれば大丈夫です。
あとは、JavaScriptオフ時は要素が縦にずらっと並んでしまうので、
並べる要素にはfloatをかけておいてもいいかもしれません。

JavaScript

$(function() {
	$('#contents').stonewall();
});

オプション

オプションは現状要素の間隔のみ。そのうち拡張したい。

$(function() {
	$('#grid').stonewall({
		margin: 20
	});
});

 

プラグインの解説

プラグイン内での処理をざっくり解説。

(function($) {
	$.fn.stonewall = function(options) {
		var target = this;
		var defaults = {
			margin: 15
		};
		var setting = $.extend(defaults, options);

		// 配置する要素の幅
		var panelWidth = target.children().outerWidth();

		// 配置する要素の初期設定
		target.children().css({
			position: 'absolute',
			float: 'none'
		});

		// 配置させる関数
		function panelFit(type) {
			// 親要素の幅
			var parentWidth = target.width();
			// 列数
			var line = Math.floor(parentWidth / (panelWidth + setting.margin))
			if(((line + 1) * panelWidth) + (line * setting.margin) <= parentWidth) {
				line += 1;
			}
			// 各列の高さ管理用
			var spotArr = [];
			for(var i = 0; i < line; i++) {
				spotArr[i] = 0;
			}

			var compare = 0;
			var parentHeight = 0;
			target.children().each(function(e) {
				// 各列から現在一番高さの低いものを探す
				for(var i = 0; i < spotArr.length; i++) {
					compare = Math.min(compare, spotArr[i]);
				}
				// 対象要素をどの列に入れるか
				lineIndex = $.inArray(compare, spotArr);

				if(type != 'animation') {
					// アクセス時はアニメーションなしで配置
					$(this).css({
						top: spotArr[lineIndex],
						left: (panelWidth + setting.margin) * lineIndex
					});
				} else {
					// 対象要素を配置位置までアニメーション
					$(this).stop().animate({
						top: spotArr[lineIndex],
						left: (panelWidth + setting.margin) * lineIndex
					});
				}
				// 追加した列に対象要素の高さ分追加
				spotArr[lineIndex] += $(this).outerHeight() + setting.margin;
				compare = spotArr[lineIndex];

				parentHeight = Math.max(parentHeight, compare);

				// 親要素の高さを設定
				if(e == target.children().length - 1) {
					target.css({
						height: parentHeight + setting.margin
					});
				}
			});
		}

		panelFit('stop');
		var timer = null;
		// ページ読み込み時とリサイズ時に配置処理を実行
		$(window).on('load resize',function() {
			// リサイズ中ずっと処理させると負荷がかかるので
			// 0.2秒リサイズ処理が発生しなかったら実行
			clearTimeout(timer);
			timer = setTimeout(function() {
				panelFit('animation');
			}, 200);
		});
	}
})(jQuery);
  1. 配置する要素と親要素の横幅から、列数を決める。(20~26行目)
  2. 各列の高さを管理する配列(spotArr)を設定。(27~31行目)
  3. 各列から現在一番高さの低いものを探す。(36~41行目)
  4. 配置する列が決まったら、その配置位置までアニメーションさせる。(50~54行目)
    (アクセス時はアニメーションなしで配置のみ。 45~48行目)
  5. 配置した列に、配置した要素分の高さを追加。(56~58行目)
  6. 現在一番高差のある列を取得しておく。(60行目)
  7. 3~6を配置する要素全てに実行。
  8. 全ての配置位置が決まったら、一番高さのある列に親要素の高さを合わせる。(62~27行目)

これらの処理をページ読み込み時とリサイズ時に実行しています。
 

※2014/10/27
親要素の高さを計算して指定するように修正しました。
アクセス時のアニメーションをなくして、最初から配置されているように変更しました。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

▲PAGE TOP