意外と簡単!モーダルウィンドウをプラグインなしで作る

意外と簡単!モーダルウィンドウをプラグインなしで作る

モーダルウィンドウを実装するjQueryプラグインはたくさんありますが、わざわざプラグインを使わなくても、意外と簡単にモーダルウィンドウを実装することができます。自分で実装できれば、仕組みを理解しているのでカスタマイズやメンテもしやすいのが最大のメリットです。

また、モーダルウィンドウのメリットやデメリットにも触れつつ、サンプルで確認しながらプラグインなしで作っていきます!

モーダルウィンドウとは?

素材サイトなどを見ているとよく出てくる、会員登録を促す画像やボタンが全画面にオーバーレイして表示されるやつです。

モーダルウィンドウが表示されると、閉じるか、指定の動作を完了するまで他の操作ができないところが特徴で、この点がメリットでもあり、デメリットでもあります。

主な用途は下記になります。

ローディング

ローディングが必要なコンテンツを表示する際に、ローディング中であることを伝えるために使います。

アラートやエラーメッセージ

重要な操作を行う前の確認メッセージや、ユーザーに操作ミスなどを通知するために使います。

広告や画像、動画などのコンテンツをオーバーレイ表示する

前述のとおり、会員登録を促すウィンドウで使用されます。また、Lightboxのように画像や動画のサムネイルをクリックして、大きく表示したい場合にも使われます。

メリット

ユーザーに見せたい情報だけを見せることができます。また、モーダルウィンドウを閉じない限りは表示されるので、行動を制限することができます。

デメリット

メリットがそのままデメリットになります。画面全体を覆い、閉じるまで他の作業ができないというのは、ユーザビリティ上よくありません。

特にユーザーがストレスを感じるのは、ページがロードされると自動で表示されるモーダルウィンドウの広告です。これは正直、何度も続くとイラッとします。

結論

メリット・デメリット踏まえた上での私の結論ですが、クリックしてユーザーの意思で表示させるなら、メリットだけを活かせますので、私はありだと思っています。実際かなりの頻度で使っています。

使い方としては、最近は背景動画を埋め込むことが非常に多くなりましたが、背景動画はミュートで埋め込み、音ありのバージョンをボタンクリックでポップアップさせるためによく使います。

実践で使えるものではありませんが、こんなのですよというサンプルです。

サンプル

前置きが長くなりましたが、まずはベースのサンプルを見てみてください。

モーダルウィンドウの基本

ではベースのコードを見ていきたいと思います。割愛していますが、「head」内でjQueryを読み込んでいますのでそちらも忘れずに。

HTML

<body>
    <div class="content">
        <a class="js-modal-open" href="">クリックでモーダルを表示</a>
    </div>
    <div class="modal js-modal">
        <div class="modal__bg js-modal-close"></div>
        <div class="modal__content">
            <p>ここにモーダルウィンドウで表示したいコンテンツを入れます。モーダルウィンドウを閉じる場合は下の「閉じる」をクリックするか、背景の黒い部分をクリックしても閉じることができます。</p>
            <a class="js-modal-close" href="">閉じる</a>
        </div><!--modal__inner-->
    </div><!--modal-->
</body>

3行目

a要素「js-modal-open」をクリックしたらモーダルウィンドウが表示されるように、この後のjQueryで処理していきます。

5行目

「modal」がモーダルウィンドウ全体の部分になります。

6行目

モーダルウィンドウを表示している時に背景をクリックしてもモーダルウィンドウを閉じられるように、クリック用の空の背景要素として「modal__bg」を「modal」の中に入れています。

7行目

「modal__content」の中にモーダルウィンドウで表示したいコンテンツを入れます。

クラス名の頭に「js-」と付けているものがありますが、こちらはこの後のjQueryで操作するクラスになります。
こうしておくことで、後で見た時や、他の人が見てもすぐにjQueryで操作しているということがわかります。

CSS

*{
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}
.content{
    margin: 0 auto;
    padding: 40px;
}
.modal{
    display: none;
    height: 100vh;
    position: fixed;
    top: 0;
    width: 100%;
}
.modal__bg{
    background: rgba(0,0,0,0.8);
    height: 100vh;
    position: absolute;
    width: 100%;
}
.modal__content{
    background: #fff;
    left: 50%;
    padding: 40px;
    position: absolute;
    top: 50%;
    transform: translate(-50%,-50%);
    width: 60%;
}

11行目

モーダルウィンドウ全体をラップする「modal」は、jQueryで表示・非表示を操作するので、初期状態は「display: none」にしておきます。

12行目

モーダルウィンドウの高さをブラウザの高さと合わせるため「height: 100vh」を指定しています。

ちなみに「ボックスの高さをブラウザの高さと合わせる」テクニックは下記の記事に詳しい内容があるので、興味があれば見てみてくださいね。

13行目

「position: abusolute」ではスクロールした際にモーダルウィンドウもスクロールされて見えなくなってしまうので「position: fixed」にして、固定表示にします。

18〜21行目

先ほどHTMLのところで書いたとおり、モーダルウィンドウを閉じるための背景要素になります。こちらもブラウザの高さと幅に合わせています。

親要素の「modal」に「position: fixed」が指定されているので、こちらは「position: absolute」でオッケーです。
また、モーダルウィンドウがオーバレイしてることがわかりやすいように、背景色は「rgba」で半透明にしています。

25,27,28,29行目

モーダルウィンドウのコンテンツを画面の縦横センターに配置している部分になります。
いくつか他のサンプルも見てきましたが、jQueryでコンテンツの幅を取得してやっていたいりしていましたが、そんなことをしなくてもこの4行で画面の縦横センターに配置することができます。

センター配置の仕組み

「position: absolute」を指定した上で、「left: 50%」と「top: 50%」を指定すると、ボックスの左上が親要素の縦横センターになります。

そして、さらに「transform: translate(-50%,-50%)」とすると、「left: 50%」と「top: 50%」は親要素の幅と高さに対して50%移動しますが、「transform」は自分の幅と高さに対しての50%移動します。よって下のイメージのように画面の縦横センターに配置することができます。

こちらのテクニックは下記の記事に詳しい内容があるので、こちらも興味があればぜひ見てみてください。

jQuery

$(function(){
    $('.js-modal-open').on('click',function(){
        $('.js-modal').fadeIn();
        return false;
    });
    $('.js-modal-close').on('click',function(){
        $('.js-modal').fadeOut();
        return false;
    });
});

jQueryは簡単です。「js-modal-open」をクリックしたら「fadeIn」でモーダルウィンドウを表示し、「js-modal-close」をクリックしたら「fadeOut」で非表示にしています。 

4,8行目

a要素の場合は「return false」を書かないと、リンク要素として処理され、jQueryの処理ができないので注意しましょう。

応用編

ベースのモーダルウィンドウはそれほど難しくなかったと思います。ここからはせっかくなので、いくつか応用編をやっていきたいと思います。

応用編と言っても、対して高度なことはやらないので、ここまでできた方なら問題ないと思いますので、ぜひ最後まで見ていってください。

複数のモーダル

さて、ベースのモーダルウィンドウは1つだけだったのであれでよかったですが、表示したいモーダルが複数になるとこれまでのやり方ではダメなので、改良していきます。

まずはサンプルをご確認ください。

HTML

<body>
    <div class="content">
        <a class="js-modal-open" href="" data-target="modal01">クリックでモーダル1を表示</a><br>
        <a class="js-modal-open" href="" data-target="modal02">クリックでモーダル2を表示</a>
    </div>
    <div id="modal01" class="modal js-modal">
        <div class="modal__bg js-modal-close"></div>
        <div class="modal__content">
            <p>1つ目モーダルウィンドウです。ここにモーダルウィンドウで表示したいコンテンツを入れます。モーダルウィンドウを閉じる場合は下の「閉じる」をクリックするか、背景の黒い部分をクリックしても閉じることができます。</p>
            <a class="js-modal-close" href="">閉じる</a>
        </div><!--modal__inner-->
    </div><!--modal-->
    <div id="modal02" class="modal js-modal">
        <div class="modal__bg js-modal-close"></div>
        <div class="modal__content">
            <p>2つ目モーダルウィンドウです。ここにモーダルウィンドウで表示したいコンテンツを入れます。モーダルウィンドウを閉じる場合は下の「閉じる」をクリックするか、背景の黒い部分をクリックしても閉じることができます。</p>
            <a class="js-modal-close" href="">閉じる</a>
        </div><!--modal__inner-->
    </div><!--modal-->
</body>
3,4行目

a要素「js-modal-open」に「data-target」属性を追加しました。この値をモーダルウィンドウのID属性とリンクさせることで、どのモーダルウィンドウを開くかわかるようにしています。

6,13行目

前述のとおり、どのモーダルウィンドウかわかるようにID属性を追加しました。

CSS

CSSは変化なしです。

jQuery

$(function(){
    $('.js-modal-open').each(function(){
        $(this).on('click',function(){
            var target = $(this).data('target');
            var modal = document.getElementById(target);
            $(modal).fadeIn();
            return false;
        });
    });
    $('.js-modal-close').on('click',function(){
        $('.js-modal').fadeOut();
        return false;
    }); 
});

jQueryはモーダルウィンドウを開く処理の方だけ変更しました。 

2行目

「js-modal-open」が複数になったので、「each」メソッドの中で「this」を使うことで、どの「js-modal-open」がクリックされたかわかるようにします。

4行目

そして「data」メソッドで、クリックした「js-modal-open」の「data-target」属性を取得し、変数「target」に代入しています。

5行目

「data-target」の値はモーダルウィンドウのID属性とリンクさせているので、「document.getElementById(target)」とすることで、モーダルウィンドウが複数あっても表示したいものだけ取得することができます。

では改めてサンプルです。

これで複数のモーダルウィンドウがあっても、data-target属性とID属性が正しくリンクできていれば問題なく表示できます。

スクロール位置を元に戻す

モーダルウィンドウを表示している最中にスクロールしてしまった場合、表示した位置と閉じた時の位置が違うと、ユーザーが戸惑う可能性があります。ですので、モーダルウィンドウを閉じたら、表示したスクロールの位置に戻すようにしたいと思います。

ではまたサンプルを

モーダルウィンドウを表示したままスクロールして閉じても、開いた時のスクロール位置に戻ります。

HTML

<body>
    <div class="content">
        <a class="js-modal-open" href="" data-target="modal01">クリックでモーダル1を表示</a><br>
        <a class="js-modal-open" href="" data-target="modal02">クリックでモーダル2を表示</a><br>
        <br>
        <div class="box">box1</div>
        <div class="box">box2</div>     
        <div class="box">box3</div>
        <div class="box">box4</div>
        <div class="box">box5</div>
    </div>
    <div id="modal01" class="modal js-modal">
        <div class="modal__bg js-modal-close"></div>
        <div class="modal__content">
            <p>1つ目モーダルウィンドウです。ここにモーダルウィンドウで表示したいコンテンツを入れます。モーダルウィンドウを閉じる場合は下の「閉じる」をクリックするか、背景の黒い部分をクリックしても閉じることができます。</p>
            <a class="js-modal-close" href="">閉じる</a>
        </div><!--modal__inner-->
    </div><!--modal-->
    <div id="modal02" class="modal js-modal">
        <div class="modal__bg js-modal-close"></div>
        <div class="modal__content">
            <p>2つ目モーダルウィンドウです。ここにモーダルウィンドウで表示したいコンテンツを入れます。モーダルウィンドウを閉じる場合は下の「閉じる」をクリックするか、背景の黒い部分をクリックしても閉じることができます。</p>
            <a class="js-modal-close" href="">閉じる</a>
        </div><!--modal__inner-->
    </div><!--modal-->
</body>

サンプル2にスクロールができるように「box」を追加しただけです。 

CSS

*{
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}
.content{
    margin: 0 auto;
    padding: 40px;
}
.box{
    background: #eee;
    height: 200px;
    margin-bottom: 100px;
}
.modal{
    display: none;
    height: 100vh;
    position: fixed;
    top: 0;
    width: 100%;
}
.modal__bg{
    background: rgba(0,0,0,0.8);
    height: 100vh;
    position: absolute;
    width: 100%;
}
.modal__content{
    background: #fff;
    left: 50%;
    padding: 40px;
    position: absolute;
    top: 50%;
    transform: translate(-50%,-50%);
    width: 60%;
}

同じく「box」のスタイルが増えただけです。

jQuery

$(function(){
    var winScrollTop;
    $('.js-modal-open').each(function(){
        $(this).on('click',function(){
            //スクロール位置を取得
            winScrollTop = $(window).scrollTop();
            var target = $(this).data('target');
            var modal = document.getElementById(target);
            $(modal).fadeIn();
            return false;
        });
    });
    $('.js-modal-close').on('click',function(){
        $('.js-modal').fadeOut();
        $('body,html').stop().animate({scrollTop:winScrollTop}, 100);
        return false;
    }); 
});

モーダルウィンドウを開く時にスクロール位置の取得と、閉じた時のスクロール位置を戻す処理が追加になっています。 

2行目

スクロール位置の値を入れる変数「winScrollTop」を宣言しています。

6行目

「$(window).scrollTop()」で画面のスクロール位置(数値)が取得できますので、「js-modal-open」がクリックされたら、「winScrollTop」にスクロール位置を代入します。

15行目

「js-modal-close」がクリックされたら、取得しておいたスクロール位置まで、アニメーションさせながら移動しています。これで開いた時と閉じた時が同じスクロール位置になりました。

動画をモーダルウィンドウで表示する

冒頭の方で紹介した動画をモーダルウィンドウで表示するサンプルのソースコードも記載しておきますので、色々遊んでみてください。

HTML

<body>
    <header class="site-header">
        <h1 class="site-logo"><img src="images/logo.png" alt="WEBDESIGNDAY"></h1>
        <nav class="gnav">
            <ul class="gnav__menu">
                <li class="gnav__menu__item"><a href="">About</a></li>
                <li class="gnav__menu__item"><a href="">Works</a></li>
                <li class="gnav__menu__item"><a href="">Recruit</a></li>
                <li class="gnav__menu__item"><a href="">News</a></li>
                <li class="gnav__menu__item"><a href="">Contact</a></li>
            </ul>
        </nav>
    </header>
    <div class="hero">
        <video class="hero__video" src="images/video.mp4" loop muted autoplay></video>
        <a class="modal-open js-modal-open" href="" data-target="modal01">動画を見る</a><br>
    </div>
    <div class="content">
        <div class="box">box1</div>
        <div class="box">box2</div>     
        <div class="box">box3</div>
        <div class="box">box4</div>
        <div class="box">box5</div>
    </div>
    <div id="modal01" class="modal js-modal">
        <div class="modal__bg js-modal-close"></div>
        <div class="modal__content">
            <video class="hero__video" src="images/video.mp4" loop muted autoplay></video>
            <a class="js-modal-close" href="">閉じる</a>
        </div><!--modal__inner-->
    </div><!--modal-->
</body>

CSS

*{
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}
.site-header{
    background: rgba(255,255,255,0.8);
    display: flex;
    padding:20px;
    position: fixed;
    justify-content: space-between;
    width: 100%;
}
.site-logo img{
    height: 20px;
    width: auto;
}
.gnav__menu{
    display: flex;
}
.gnav__menu__item{
    list-style: none;
    margin-left: 20px;
}
.gnav__menu__item a{
    color: #333;
    text-decoration: none;
}
.hero{
    position: relative;
}
.hero__video{
    height: auto;
    width: 100%;
}
.content{
    margin: 0 auto;
    padding: 40px;
}
.box{
    background: #eee;
    height: 200px;
    margin-bottom: 100px;
}
.modal-open{
    background: #fff;
    color: #222;
    left: 50%;
    padding: 10px 40px;
    position: absolute;
    top: 50%;transform: translate(-50%,-50%);
}
.modal{
    display: none;
    height: 100vh;
    position: fixed;
    top: 0;
    width: 100%;
}
.modal__bg{
    background: rgba(0,0,0,0.8);
    height: 100vh;
    position: absolute;
    width: 100%;
}
.modal__content{
    background: #fff;
    left: 50%;
    padding: 40px;
    position: absolute;
    top: 50%;
    transform: translate(-50%,-50%);
    width: 60%;
}

jQuery

$(function(){
    var winScrollTop;
    $('.js-modal-open').each(function(){
        $(this).on('click',function(i){
            //スクロール位置を取得
            winScrollTop = $(window).scrollTop();
             
            var target = $(this).data('target');
            var modal = document.getElementById(target);
            $(modal).fadeIn();
            return false;
        });
    });
    $('.js-modal-close').on('click',function(){
        $('.js-modal').fadeOut();
        $('body,html').stop().animate({scrollTop:winScrollTop}, 100);
        return false;
    }); 
});

サンプルで使用している動画の素材は下記のサイトでダウンロードしています。

まとめ

最後まで読んでいただいた方、お付き合いいただきありがとうございました。

モーダルウィンドウに限らずサイトにギミックを取り入れる際は、ユーザビリティも考慮して本当に必要なものを取り入れることで、ユーザーエクスペリエンスが向上するものを取り入れていきたいですね。

Category&Tag