高さの異なる要素を隙間なく配置するプラグイン「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);
- 配置する要素と親要素の横幅から、列数を決める。(20~26行目)
- 各列の高さを管理する配列(spotArr)を設定。(27~31行目)
- 各列から現在一番高さの低いものを探す。(36~41行目)
- 配置する列が決まったら、その配置位置までアニメーションさせる。(50~54行目)
(アクセス時はアニメーションなしで配置のみ。 45~48行目) - 配置した列に、配置した要素分の高さを追加。(56~58行目)
- 現在一番高差のある列を取得しておく。(60行目)
- 3~6を配置する要素全てに実行。
- 全ての配置位置が決まったら、一番高さのある列に親要素の高さを合わせる。(62~27行目)
これらの処理をページ読み込み時とリサイズ時に実行しています。
※2014/10/27
親要素の高さを計算して指定するように修正しました。
アクセス時のアニメーションをなくして、最初から配置されているように変更しました。
コメントが承認されるまで時間がかかります。