maesblog

複数の要素の高さを行ごとに揃えるJavaScript関数の実装方法

Webサイトのレイアウトを調整する際に、「要素の高さを揃える」と見栄えが格段に良くなります。また最近流行りのカード型レイアウトでデザインをする際にも、要素の高さを揃えたくなるケースが出てきたりします。この手のJavaScriptやjQueryのライブラリやプラグインは数多く存在していると思いますが、そうしたものに頼らずとも意外と簡単に実装できたりします。今回は自分の手で実装する方法について書いてみます。

サンプル

.div1
.p1

テキストテキストテキストテキストテキストテキスト

.p2

テキストテキストテキストテキストテキストテキストテキストテキスト

.div1
.p1

テキスト

.p2

テキストテキストテキスト

.div1
.p1

テキストテキストテキストテキスト

.p2

テキストテキストテキストテキストテキストテキストテキストテキストテキスト

.div1
.p1

テキストテキスト

.p2

テキストテキストテキストテキスト

.div1
.p1

テキストテキストテキストテキストテキストテキストテキスト

.p2

テキストテキストテキスト

.div1
.p1

テキストテキストテキストテキスト

.p2

テキストテキストテキストテキストテキストテキスト

JavaScriptコード

function equalBoxHeight(elm, num) {
    var elm = jQuery(elm);

    elm.each(function (i) {
        var height;
        var $this = jQuery(this);

        if (i === 0 || i % num === 0) {
            height = $this.height();

            for (var n = i + 1; n <= i + num - 1; n++) {
                if (height < elm.eq(n).height()) {
                    height = elm.eq(n).height();
                }
            }

            for (var n = i; n <= i + num - 1; n++) {
                elm.eq(n).css("height", height + "px");
            }
        }
    });
}

equalBoxHeight(".p1", 3);
equalBoxHeight(".p2", 3);

サンプルのソースコードはjsdo.itで確認可能です。

実装方法

関数化する前の処理の部分から説明していきます。

上記サンプルの高さを揃える前の状態が以下の画像となります。配列の添字に合わせて、番号を0から振っています。それから高さもわかりやすくするために、それぞれ「10」、「20」、「30」としました。以下の画像を元に説明していきます。

equal_box_height

1. 高さを揃えたい要素を取得してループさせる

今回は「p1」と値をつけたclass属性を持った要素の高さを揃えていきます。「elm」変数に、jQueryを使ってclass属性「p1」の要素を代入し、jQueryのeachメソッドでループ処理させます。

var elm = $(".p1");
elm.each(function (i) {

}

2. それぞれの行に指定するデフォルトの高さを指定する

まずheight変数を用意してデフォルトの高さを指定します。デフォルトの高さは行の一番左にある要素の高さにします。今回は1行に3つの要素があるので、添字が0か、または3で割り切れる数字のものが対象の要素となります。

if (i === 0 || i % 3 === 0) {
    var height = $(this).height();
}

今回の例では、1行目が添字「0」の要素の高さ「30」2行目が添字「3」の要素の高さ「10」がそれぞれのデフォルトの高さとなります。

3. 行ごとにループ処理させて、それぞれの高さを比較、一番大きい値の高さを取得する

デフォルトの高さ指定した変数heightを、同じ行にある他の要素の高さと比較して、大きい値のものがあればその値に置き換えていきます。

1行目には[要素0(高さ30)、要素1(高さ10)、要素2(高さ20)]の3つの要素があります。考え方としては、「要素0」の高さがデフォルトの高さとなっているので、2番目の要素「1(高さ10)」から、最後の要素「2(高さ20)」まで1つずつ高さを比較して、デフォルトの高さ「30」より大きいものがあれば、その値を変数heightに代入して置き換えていくということになります。2行目も同様です。

if (height < elm.eq(n).height()) {
    height = elm.eq(n).height();
}

1行目には[0、1、2]、2行目には[3、4、5]の3つの要素があります。それぞれの行の2番目の要素「i + 1」からループ処理を始めて、最後の要素「i + 3 - 1」の時に終わらせます。それぞれ行の最初の要素の時にループ処理を実行させたいので、ステップ2の条件分岐の中に処理を書きます。

if (i === 0 || i % 3 === 0) {
    var height = $(this).height();

    for (var n = i + 1; n <= i + 3 - 1; n++) {
        if (height < elm.eq(n).height()) {
            height = elm.eq(n).height();
        }
    }
}

今回の例では、以下のようになります。

1行目
heightの値が「30」。2番目の要素[1]の高さは「10」⇒heightはそのまま。3番目の要素[2]の高さは「20」⇒heightはそのまま。

2行目
heightの値が「10」。2番目の要素[4]の高さは「30」⇒heightは「30」に置き換わる。3番目の要素[5]の高さは「20」⇒heightはそのまま。

つまり、最終的にheightの高さは、1行目⇒「30」、2行目⇒「30」

4. 取得した行の高さの最大値をそれぞれの要素に指定する

こちらもステップ3と同様にループ処理を使って、ステップ3で取得した高さの最大値をそれぞれの要素に指定していきます。ループ処理はそれぞれの行の最初の要素「i」から始めて、最後の要素「i + 3 - 1」の時に終わらせます。それぞれ行の最初の要素の時にループ処理を実行させたいので、ステップ2の条件分岐の中に処理を書きます。

if (i === 0 || i % 3 === 0) {
    for (var n = i; n <= i + num - 1; n++) {
        elm.eq(n).css("height", height + "px");
    }
}

5. まとめると

1〜4をまとめると以下のようなコードになります。

// 変数elmにclass属性「p1」の要素を代入
var elm = $(".p1");

// 変数elmに対してjQueryのeachメソッドでループ処理
elm.each(function (i) {

    // 添字が0か、または3で割り切れる数字のときに処理を実行
    if (i === 0 || i % 3 === 0) {

        // デフォルトの高さを変数heightに指定
        var height = $(this).height();

        // 行の2番目の要素から処理を始めて、最後の要素で終わらせる
        for (var n = i + 1; n <= i + 3 - 1; n++) {

            // デフォルト値より高さが大きい場合
            if (height < elm.eq(n).height()) {

                // heightの値を置き換える
                height = elm.eq(n).height();
            }
        }

        // 行の最初の要素から処理を始めて、最後の要素で終わらせる
        for (var n = i; n <= i + 3 - 1; n++) {

            // 取得した高さの最大値をそれぞれの要素に指定
            elm.eq(n).css("height", height + "px");
        }
    }
});

6. 関数にして汎用的に使えるようにする

上記のコードを汎用的に使えるように関数にしてみます。関数の引数に「高さを揃えたい要素のclass属性値」と、「1行の中にある要素数」を指定するようにすると、以下のようなコードとなります。

function equalBoxHeight(elm, num) {
    var elm = $(elm);

    elm.each(function (i) {
        var height;
        var $this = $(this);

        if (i === 0 || i % num === 0) {
            height = $this.height();

            for (var n = i + 1; n <= i + num - 1; n++) {
                if (height < elm.eq(n).height()) {
                    height = elm.eq(n).height();
                }
            }

            for (var n = i; n <= i + num - 1; n++) {
                elm.eq(n).css("height", height + "px");
            }
        }
    });
}

以下のようにして関数を実行します。

equalBoxHeight(".p1", 3);
equalBoxHeight(".p2", 3);

.forEach()メソッドを使って書くと、すっきり書くことができます。

[[".p1", 3], [".p2", 3]].forEach(function (a) {
    equalBoxHeight(a[0], a[1]);
});

Underscore.jsを使って書く場合は以下のようになります。

<script src="underscore.js"></script>

<script>
_.each([[".p1", 3], [".p2", 3]], function (a) {
    equalBoxHeight(a[0], a[1]);
});
</script>

関連記事

コメント

  • 必須

コメント