さぁ!検索しよう!

短いコードでLightboxを作る方法です。

DEMO

HTML

<div id="wrap">
    <img src="https://www.pakutaso.com/assets_c/2015/06/HIRA86_MBAkey-thumb-1000xauto-17206.jpg">
    <img src="https://www.pakutaso.com/assets_c/2015/06/GAK88_nekokafeneko-thumb-1000xauto-16206.jpg">
    <img src="https://www.pakutaso.com/assets_c/2015/05/N879_kuchigahenojinoneko-thumb-1000xauto-14847.jpg">
    <img src="https://www.pakutaso.com/assets_c/2015/05/N825_benchinouenoshironeko-thumb-autox1000-14809.jpg">
</div>

SCSS

@mixin translate($hVal, $vVal) {
    -webkit-transform: translate($hVal, $vVal);
    transform: translate($hVal, $vVal);
}

@mixin tl($pVal, $tVal, $lVal) {
    position: $pVal;
    top: $tVal;
    left: $lVal;
}

@mixin tr($pVal, $tVal, $rVal) {
    position: $pVal;
    top: $tVal;
    right: $rVal;
}

%inactive {
    opacity: 0;
    visibility: hidden;
}

* {
    box-sizing: border-box;
}

body {
    background: #333;
}

#wrap {
    a {
        background: #ccc;
        border: 5px solid #fff;
        display: block;
        float: left;
        overflow: hidden;
        position: relative;
        padding-bottom: 40%;
        width: 50%;
        @media (min-width: 800px) {
            padding-bottom: 15%;
            width: 25%;
        }
    }
    img {
        display: block;
        max-height: 200%;
        @include tl(absolute, 0, 0);
        width: 100%;
    }
}

#overlay {
    @extend %inactive;
    background: #000;
    height: 100%;
    @include tl(fixed, 0, 0);
    transition: 0.5s;
    width: 100%;
    z-index: 1000;
    &.active {
        opacity: 0.6;
        visibility: visible;
    }
}

#large {
    @extend %inactive;
    background: #ccc;
    height: 50vw;
    overflow: hidden;
    @include tl(fixed, 50%, 50%);
    @include translate(-50%, -50%);
    transition: 0.5s;
    width: 50%;
    z-index: 2000;
    &.active {
        opacity: 1;
        visibility: visible;
    }
    img {
        @extend %inactive;
        @include tl(absolute, 50%, 50%);
        @include translate(-50%, -50%);
        transition: 0.5s;
        width: 100%;
        &.active {
            opacity: 1;
            visibility: visible;
        }
    }
    @media (min-width: 800px) {
        height: 400px;
        width: 500px;
    }
}

#close {
    background: #333;
    color: #fff;
    cursor: pointer;
    height: 8vw;
    line-height: 8vw;
    @include tr(absolute, 0, 0);
    text-align: center;
    width: 8vw;
    z-index: 4000;
    @media (min-width: 800px) {
        line-height: 44px;
        height: 44px;
        width: 44px;
    }
}

#pager {
    height: 8vw;
    list-style: none;
    margin: 0;
    padding: 0;
    @include tl(absolute, 50%, 0);
    @include translate(0, -50%);
    width: 100%;
    z-index: 4000;
    @media (min-width: 800px) {
        height: 44px;
    }
}

.prev,
.next {
    background: #333;
    color: #fff;
    cursor: pointer;
    height: 8vw;
    line-height: 8vw;
    position: absolute;
    top: 0;
    text-align: center;
    width: 8vw;
    z-index: 5000;
    @media (min-width: 800px) {
        height: 44px;
        line-height: 44px;
        width: 44px;
    }
}

.prev {
    left: 0;
}

.next {
    right: 0;
}

予め非表示

オーバーレイ#overlay、拡大画像の親要素#large、拡大画像#large imgは予め非表示にしておきます。

#overlay,
#large,
#large img {
    opacity: 0;
    visibility: hidden;
}

.activeクラスで表示

#overlay#large#large img.activeクラスが追加されると、それぞれ表示されます。

#overlay.active {
    opacity: 0.6;
    visibility: visible;
}

#large.active,
#large img.active {
    opacity: 1;
    visibility: visible;
}

JavaScript

$(function() {
    var $wrap = $('#wrap');
    $wrap.before('<div id="overlay"></div><div id="large"></div>');
    var $overlay = $('#overlay');
    var $large = $('#large');
    $large.append('<ul id="pager"><li class="prev"><</li><li class="next">></li></ul><div id="close">☓</div>');
    var imgLen = $wrap.find('img').length;
    var $pager = $('#pager');
    var max;
    var current;
    var imgSrc;
    var $img;
    var $clone;

    $wrap.find('img').each(function() {
        imgSrc = $(this).attr('src');
        $img = $(this).wrap('<a></a>').closest('a').attr('href', imgSrc);
        max = imgLen - 1;
        $img.each(function() {
            $clone = $(this).clone();
            $large.append($clone);
            $(this).click(function(e) {
                e.preventDefault();
                current = $(this).index();
                $overlay.addClass('active');
                $large.find('img').eq(current).addClass('active');
                $large.addClass('active');
            });
        });
    });

    $pager.children().click(function() {
        if ($(this).hasClass('prev')) {
            move(current - 1);
        } else {
            move(current + 1);
        }
    });

    function move(index) {
        if (index < 0) {
            index = max;
        }
        if (index > max) {
            index = 0;
        }
        $large.find('img').removeClass('active');
        $large.find('img').eq(index).addClass('active');
        current = index;
    }

    $overlay.click(function() {
        $(this).removeClass('active');
        $large.removeClass('active');
        $large.find('img').removeClass('active');
    });

    $('#close').click(function() {
        $large.removeClass('active');
        $large.find('img').removeClass('active');
        $overlay.removeClass('active');
    });
});

変数

各変数の役割は以下の通りです。

変数名 説明
$wrap #wrap
$overlay #overlay
$large #large
$imgLen #wrap内にあるimgの総数
$pager #pager
max 画像のインデックスの最大
current 現在の画像のインデックス
imgSrc 画像のsrc
$img #wrap内にあるimgを、href="imgSrc"を追加したaタグで囲ったimg
$clone $imgを複製したもの

#wrapの前にオーバーレイと拡大画像の親要素を生成

.beforeで、#wrapの前に、オーバーレイ’#overlayと拡大した画像の親要素#large`を生成しています。

$wrap.before('<div id="overlay"></div><div id="large"></div>');

生成後のHTMLは以下の通りです。

<div id="overlay">
</div>
<div id="large">
</div>
<div id="wrap">
</div>

#large内にページャーと閉じるボタンを生成

.appendメソッドで、#large内に#pager#closeを生成しています。

$large.append('<ul id="pager"><li class="prev"><</li><li class="next">></li></ul><div id="close">☓</div>');

生成後のHTMLは以下の通りです。

<div id="large">
    <ul id="pager">
        <li class="prev"><</li>
        <li class="next">></li>
    </ul>
    <div id="close">☓</div>
</div>

#wrap内のimgに対する処理

#wrap img.each()メソッド実行すると、#wrap内のimgに対してそれぞれ順番に処理を行ないます。

#wrap内のimgに対する処理の流れは以下の通りです。

  1. $(this).attr('src');とすることで、#wrap内にあるimgsrcを取得しています。更に取得したsrcimgSrcに代入しています。
    imgSrc = $(this).attr('src');
    
  2. #wrap内のimg.wrap()メソッドを実行し、それぞれaタグで囲います。続けて、#wrap内のimg.closest()メソッドと.attr()メソッドを実行すると、closest()メソッドで直近の祖先要素つまり先程囲ったaタグが.attr()メソッドの対象となります。
    なので、.attr('href', imgSrc)とすることで、aタグにリンク先をimgSrcとしたhrefが追加されます。

    $img = $(this).wrap('<a></a>').closest('a').attr('href', imgSrc);  
    

    よって、HTMLは以下のように変化します。

    <div id="wrap">
        <a href="https://www.pakutaso.com/assets_c/2015/06/HIRA86_MBAkey-thumb-1000xauto-17206.jpg"><img src="https://www.pakutaso.com/assets_c/2015/06/HIRA86_MBAkey-thumb-1000xauto-17206.jpg">
        </a>
        <a href="https://www.pakutaso.com/assets_c/2015/06/GAK88_nekokafeneko-thumb-1000xauto-16206.jpg"><img src="https://www.pakutaso.com/assets_c/2015/06/GAK88_nekokafeneko-thumb-1000xauto-16206.jpg"></a>
        <a href="https://www.pakutaso.com/assets_c/2015/05/N879_kuchigahenojinoneko-thumb-1000xauto-14847.jpg"><img src="https://www.pakutaso.com/assets_c/2015/05/N879_kuchigahenojinoneko-thumb-1000xauto-14847.jpg"></a>
        <a href="https://www.pakutaso.com/assets_c/2015/05/N825_benchinouenoshironeko-thumb-autox1000-14809.jpg"><img src="https://www.pakutaso.com/assets_c/2015/05/N825_benchinouenoshironeko-thumb-autox1000-14809.jpg"></a>
    </div>
    
  3. インデックスindex()は0から始まるので、#wrap内のimgの総数から1を引いた値が、インデックスの最大となります。
    max = imgLen - 1;
    

$imgに対する処理

.each()メソッドによる$imgに対する処理の流れは以下の通りです。

  1. $imgの複製を$cloneに代入します。
    $clone = $(this).clone();
    
  2. 1.を#large内に移動します。
    large.append($clone);
    
  3. $imgをクリックすると、クリックされた$imgとして$imgのインデックス(何番目の$imgか)がcurrentに代入されます。
    current = $(this).index();
    
  4. #overlayが表示されます。
    $overlay.addClass('active');
    
  5. #large内に存在するcurrentと同じインデックスのimgのみを表示させます。
    $large.find('img').eq(current).addClass('active');
    
  6. #largeとその中に存在する#pager#closeが表示されます。
    $large.addClass('active');
    

move関数

move関数はページャーがクリックされたときに実行される関数です。処理内容は以下の通りです。

  1. 引数には左方向への移動先を意味するcurrent-1か、右方向への移動先を意味するcurrent+1が渡されます。引数に渡された値が0より小さい、つまり左方向の移動先に画像がなければ、indexmaxを代入し、最後のインデックスの画像に移動します。
    if (index < 0) {
        index = max;
    }
    
  2. 引数に渡された値が’max’より大きい、つまり右方向の移動先に画像がなければindex0を代入し、先頭のインデックスの画像に移動します。
    if (index > max) {
        index = 0;
    }
    
  3. #large内のimgを一度非表示(リセット)にします。
    $large.find('img').removeClass('active');
    
  4. 1.か2.によって変更されたindexの#large内にあるimg`を表示させます。

    $large.find(‘img’).eq(index).addClass(‘active’);

  5. 1.か2.によって変更されたindexを現在のインデックスcurrentとします。

    current = index;

ページャーをクリック

#pager内の.prev.nextがクリックされると、move関数が実行されます。、左右の画像に切り替わります。

.prevがクリックされると一つ左の画像へ移動するので、move関数には現在のインデックスcurrentから1を引いた値を渡します。

if ($(this).hasClass('prev')) {
    move(current - 1);
}

.nextがクリックされると一つ右の画像へ移動するので、move関数には現在のインデックスcurrentに1を足した値を渡します。

else {
    move(current + 1);
}

オーバーレイをクリック

$overlayがクリックされたときの処理内容は以下の通りです。

  1. 自身を非表示にします。

    $(this).removeClass(‘active’);

  2. #largeを非表示にします。

    $large.removeClass(‘active’);

  3. #large imgを非表示にします。

    $large.find(‘img’).removeClass(‘active’);

閉じるボタンをクリック

#closeがクリックされたときの処理内容は以下の通りです。

  1. #largeを非表示にします。

    $large.removeClass(‘active’);

  2. #large imgを非表示にします。

    $large.find(‘img’).removeClass(‘active’);

  3. #overlayを非表示にします。

    $overlay.removeClass(‘active’);


以上で、【jQuery】ページャー付きのLightboxを作る方法を終わります。