高さの異なる要素を隙間なく配置するプラグイン「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
親要素の高さを計算して指定するように修正しました。
アクセス時のアニメーションをなくして、最初から配置されているように変更しました。
コメントが承認されるまで時間がかかります。