【jQuery】プラグインを使わずにモーダルを作ってみる

【jQuery】プラグインを使わずにモーダルを作ってみる
プラグインを使わずにモーダルってできますか?
ふむふむ、やってみましょうー

プラグインを使わないモーダルのサンプル

スマホでも問題ない。
IEでも問題ない。
完成ですー。

See the Pen 【jQuery】プラグインを使わずにモーダルを作ってみる by 125naroom (@125naroom) on CodePen.

HTMLとCSSとjQueryはこちら

HTML

<div class="s_section gutter">
  <a href="#modal-a" data-modal-org-target="#modal-a" class="_a">モーダルへ</a>
</div>
 
<div class="a-modal-org" role="dialog" id="modal-a">
  <div class="a-modal-org__inner">
    <div class="a-modal-org__inner2">
      <div class="a-modal-org__inner3">
        <div class="a-modal-org__body">
          <div class="a-modal-org__scroll gutter">
            ここに内容
          </div>
        </div>
      </div>
      <div class="a-modal-org__close"><a class="a-modal-org__btn" href="#"><span class="a-modal-org__btn-inner"></span><span class="a-display-off">閉じる</span></a></div>
    </div>
  </div>
</div>
<div class="a-modal-org-overlay" tabindex="0"></div>

CSS

/*=========
project - modal-org
=========*/
 
.a-modal-org {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 190002;
}
.a-modal-org__inner {
    display: flex;
    align-items: center;
    margin: 0 auto;
    height: 100%;
}
@media print, screen and (min-width: 737px) {
    .a-modal-org__inner {
        width: 80vw;
        max-width: 900px;
    }
}
@media screen and (max-width: 736px) {
    .a-modal-org__inner {
        width: 85vw;
    }
}
.a-modal-org__inner2 {
    position: relative;
    width: 100%;
}
.a-modal-org__inner3 {
    background-color: #ffffff;
}
@media print, screen and (min-width: 769px) {
    .a-modal-org__inner3 {
        max-height: 80vh;
        border-radius: 12px;
        border: 1.5rem solid #fff;
    }
}
@media print, screen and (max-width: 768px) {
    .a-modal-org__inner3 {
        max-height: 70vh;
        border-radius: 6px;
        border: 1.125rem solid #fff;
    }
}
.a-modal-org__body {
    position: relative;
    overflow: hidden;
    box-sizing: border-box;
}
.a-modal-org__scroll.is-scroll {
    overflow-y: scroll;
}
@media print, screen and (min-width: 769px) {
    .a-modal-org__scroll.is-scroll {
        padding-right: 0.5rem;
    }
}
.a-modal-org__close {
    position: absolute;
    top: 0;
    right: 0;
    transform: translate(50%, -50%);
}
.a-modal-org__btn {
    box-sizing: border-box;
    background-color: #333333;
    border-radius: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
}
.a-modal-org__btn-inner {
    display: inline-block;
    box-sizing: border-box;
    width: 20px;
    height: 20px;
    position: relative;
}
.a-modal-org__btn-inner::before, .a-modal-org__btn-inner::after {
    position: absolute;
    content: "";
    margin: auto;
    box-sizing: border-box;
    vertical-align: middle;
}
.a-modal-org__btn-inner::before {
    border-top: 2px solid #ffffff;
    width: 20px;
    height: 0;
    top: 0;
    bottom: 0;
    left: 0;
    transform: rotate(45deg);
}
.a-modal-org__btn-inner::after {
    border-left: 2px solid #ffffff;
    width: 0;
    height: 20px;
    top: 0;
    bottom: 0;
    left: 9px;
    transform: rotate(45deg);
}
 
/*=========
utility - display-off
=========*/
 
.a-display-off {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    border: 0;
    overflow: hidden;
    padding: 0;
    clip: rect(0, 0, 0, 0);
}
 
/*=========
layout - a-modal-org-overlay
=========*/
 
.a-modal-org-overlay {
    display: none;
    z-index: 190001;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    background-color: rgba(0, 0, 0, 0.7);
}

jQuery

$(function(){
 
    // ============
    // a処理を一旦リセット
    // ============
    $('a[data-modal-org-target]').off('click');
 
    // ============
    // U a-modal-org
    // ============
    if($('.a-modal-org').length){
        var overlay = $('.a-modal-org-overlay');
 
        $('[data-modal-org-target]').each(function (){
            var modalTarget = $($(this).attr('data-modal-org-target'));
            var modalTargetinner3 = modalTarget.find('.a-modal-org__inner3');
            var modalTargetHead = modalTarget.find('.a-modal-org__head');
            var modalTargetBody = modalTarget.find('.a-modal-org__body');
            var modalTargetFoot = modalTarget.find('.a-modal-org__foot');
            var modalTargetScroll = modalTarget.find('.a-modal-org__scroll');
            var modalTargetBtn = modalTarget.find('.a-modal-org__btn');
 
            if(modalTarget){
 
                $(this).on('click',function(){
                    modal_org_open();
                    if(overlay){
                        overlay.on('click focusin',function(){
                            modal_org_close();
                            return false;
                        });
                    }
                    return false;
                });
 
                modalTarget.on('click',function(){
                    modal_org_close();
                });
                modalTargetinner3.on('click',function(){
                    event.stopPropagation();
                });
                modalTargetBtn.on('click',function(){
                    modal_org_close();
                    return false;
                });
 
            }
 
            // モーダルの高さ監視
            function modal_org_height(){
                if (modalTarget.is(':visible')) {
                    modalTargetBody.css("max-height", "none");
                    modalTargetScroll.removeClass('is-scroll').css("max-height", "none");
                    var outerHeight = modalTargetinner3.innerHeight();
                    if(modalTargetHead.length) outerHeight = outerHeight - modalTargetHead.outerHeight();
                    if(modalTargetFoot.length) outerHeight = outerHeight - modalTargetFoot.outerHeight();
                    modalTargetBody.css("max-height", outerHeight);
                    var scrollHeight = Math.floor(modalTargetScroll.outerHeight());
                    if(outerHeight < scrollHeight){
                        modalTargetScroll.addClass('is-scroll').css("max-height", outerHeight);
                    }
                }
            }
            $(window).on('resize',function(){
                modal_org_height();
            });
 
            function modal_org_open(){
                scroll_lock();
                // モーダルチェック
                modalTarget.css('opacity','0').show();
                modalTargetScroll.scrollTop(0);
                modal_org_height();
                modalTarget.hide().css('opacity','1');
                // モーダル表示
                modalTarget.fadeIn(600, function(){
                    $(this).attr('aria-expanded', 'true');
                });
                modalTarget.attr('tabindex',1).focus().attr('tabindex','');
                // if(overlay) overlay.fadeIn(200);
                if(overlay) a_modal_org_overlay(true, 200);         // a-modal-org-overlay用
            }
            function modal_org_close(){
                scroll_lock_off();
                modalTarget.attr('aria-expanded', 'false').fadeOut();
                // if(overlay) overlay.off().fadeOut();
                if(overlay) a_modal_org_overlay(false, 'fast');         // a-modal-org-overlay用
            }
 
        });
    }
 
    // ============
    // U scroll_lock
    // ============
    var uA = navigator.userAgent;
    var os = osCh();                                //iOS,ipadOS,Android,Mac,Win
    function osCh(){
        if (uA.indexOf('iPhone') > -1 || uA.indexOf('iPod') > -1 || uA.indexOf('iPad') > -1) return "iOS";
        if (uA.indexOf('Android') > -1) return "Android";
        if (uA.indexOf("Mac") != -1 && !('ontouchend' in document)) return "Mac";
        if (uA.indexOf("Mac") != -1 && 'ontouchend' in document) return "ipadOS";           // safari only
        if (uA.indexOf("Win") != -1) return "Win";
        return "unknown";
    }
    var scrollPosition;
    function scroll_lock(){
        if( os == "iOS" || os == "ipadOS" ){
            scrollPosition = $(window).scrollTop();
            $('body').addClass('is-scroll-lock').css({'top': -scrollPosition});
        }else{
            var clientWidth = $(window).innerWidth();
            var noScrollBarWidth = $(window).outerWidth();
            $('body').css({'overflow': 'hidden'});
            diff = noScrollBarWidth - clientWidth;
            if(diff > 0){
                $('body').css({'padding-right': diff + 'px'});
                // if(headerFixedItem && $('[data-header-fixed="true"]').length) headerFixedItem.css({'padding-right': diff + 'px'});
            };
        }
    }
    function scroll_lock_off(){
        if( os == "iOS" || os == "ipadOS" ){
            $('body').removeClass('is-scroll-lock').css({'top': 0});
            window.scrollTo( 0 , scrollPosition );
        }else{
            $('body').css({'overflow': 'auto'});
            $('body').css({'padding-right': '0'});
            // if(headerFixedItem) headerFixedItem.css({'padding-right': 0});
        }
    }
 
    // ============
    // U a-modal-org-overlay
    // ============
    function a_modal_org_overlay(flag,speed){
        var overlay = $('.a-modal-org-overlay');
        if(overlay.length){
            if(flag){
                overlay.stop().fadeIn(speed);
            }else{
                overlay.stop().off().fadeOut(speed);
            }
        }
    }
 
});

プラグインを使わないモーダルのサンプル(同じページに複数設置)

『data-modal-org-target』と『id』の紐付けさえ間違えなければ簡単ですねー。

See the Pen 【jQuery】プラグインを使わずにモーダルを作ってみる、複数も可能 by 125naroom (@125naroom) on CodePen.

HTMLとCSSとjQueryはこちら

HTML

<div class="s_section gutter">
  <a href="#modal-a" data-modal-org-target="#modal-a" class="_a">モーダルAへ</a>
  <a href="#modal-b" data-modal-org-target="#modal-b" class="_a">モーダルBへ</a>
  <a href="#modal-c" data-modal-org-target="#modal-c" class="_a">モーダルCへ</a>
</div>
 
<div class="a-modal-org" role="dialog" id="modal-a">
  <div class="a-modal-org__inner">
    <div class="a-modal-org__inner2">
      <div class="a-modal-org__inner3">
        <div class="a-modal-org__body">
          <div class="a-modal-org__scroll">
            モーダルAの内容
          </div>
        </div>
      </div>
      <div class="a-modal-org__close"><a class="a-modal-org__btn" href="#"><span class="a-modal-org__btn-inner"></span><span class="a-display-off">閉じる</span></a></div>
    </div>
  </div>
</div>
 
<div class="a-modal-org" role="dialog" id="modal-b">
  <div class="a-modal-org__inner">
    <div class="a-modal-org__inner2">
      <div class="a-modal-org__inner3">
        <div class="a-modal-org__body">
          <div class="a-modal-org__scroll">
            モーダルBの内容
          </div>
        </div>
      </div>
      <div class="a-modal-org__close"><a class="a-modal-org__btn" href="#"><span class="a-modal-org__btn-inner"></span><span class="a-display-off">閉じる</span></a></div>
    </div>
  </div>
</div>
 
<div class="a-modal-org" role="dialog" id="modal-c">
  <div class="a-modal-org__inner">
    <div class="a-modal-org__inner2">
      <div class="a-modal-org__inner3">
        <div class="a-modal-org__body">
          <div class="a-modal-org__scroll">
            モーダルCの内容
          </div>
        </div>
      </div>
      <div class="a-modal-org__close"><a class="a-modal-org__btn" href="#"><span class="a-modal-org__btn-inner"></span><span class="a-display-off">閉じる</span></a></div>
    </div>
  </div>
</div>
<div class="a-modal-org-overlay" tabindex="0"></div>

CSS

/*=========
project - modal-org
=========*/
 
.a-modal-org {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 190002;
}
.a-modal-org__inner {
    display: flex;
    align-items: center;
    margin: 0 auto;
    height: 100%;
}
@media print, screen and (min-width: 737px) {
    .a-modal-org__inner {
        width: 80vw;
        max-width: 900px;
    }
}
@media screen and (max-width: 736px) {
    .a-modal-org__inner {
        width: 85vw;
    }
}
.a-modal-org__inner2 {
    position: relative;
    width: 100%;
}
.a-modal-org__inner3 {
    background-color: #ffffff;
}
@media print, screen and (min-width: 769px) {
    .a-modal-org__inner3 {
        max-height: 80vh;
        border-radius: 12px;
        border: 1.5rem solid #fff;
    }
}
@media print, screen and (max-width: 768px) {
    .a-modal-org__inner3 {
        max-height: 70vh;
        border-radius: 6px;
        border: 1.125rem solid #fff;
    }
}
.a-modal-org__body {
    position: relative;
    overflow: hidden;
    box-sizing: border-box;
}
.a-modal-org__scroll.is-scroll {
    overflow-y: scroll;
}
@media print, screen and (min-width: 769px) {
    .a-modal-org__scroll.is-scroll {
        padding-right: 0.5rem;
    }
}
.a-modal-org__close {
    position: absolute;
    top: 0;
    right: 0;
    transform: translate(50%, -50%);
}
.a-modal-org__btn {
    box-sizing: border-box;
    background-color: #333333;
    border-radius: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
}
.a-modal-org__btn-inner {
    display: inline-block;
    box-sizing: border-box;
    width: 20px;
    height: 20px;
    position: relative;
}
.a-modal-org__btn-inner::before, .a-modal-org__btn-inner::after {
    position: absolute;
    content: "";
    margin: auto;
    box-sizing: border-box;
    vertical-align: middle;
}
.a-modal-org__btn-inner::before {
    border-top: 2px solid #ffffff;
    width: 20px;
    height: 0;
    top: 0;
    bottom: 0;
    left: 0;
    transform: rotate(45deg);
}
.a-modal-org__btn-inner::after {
    border-left: 2px solid #ffffff;
    width: 0;
    height: 20px;
    top: 0;
    bottom: 0;
    left: 9px;
    transform: rotate(45deg);
}
 
/*=========
utility - display-off
=========*/
 
.a-display-off {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    border: 0;
    overflow: hidden;
    padding: 0;
    clip: rect(0, 0, 0, 0);
}
 
/*=========
layout - a-modal-org-overlay
=========*/
 
.a-modal-org-overlay {
    display: none;
    z-index: 190001;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    background-color: rgba(0, 0, 0, 0.7);
}

jQuery

$(function(){
 
    // ============
    // a処理を一旦リセット
    // ============
    $('a[data-modal-org-target]').off('click');
 
    // ============
    // U a-modal-org
    // ============
    if($('.a-modal-org').length){
        var overlay = $('.a-modal-org-overlay');
 
        $('[data-modal-org-target]').each(function (){
            var modalTarget = $($(this).attr('data-modal-org-target'));
            var modalTargetinner3 = modalTarget.find('.a-modal-org__inner3');
            var modalTargetHead = modalTarget.find('.a-modal-org__head');
            var modalTargetBody = modalTarget.find('.a-modal-org__body');
            var modalTargetFoot = modalTarget.find('.a-modal-org__foot');
            var modalTargetScroll = modalTarget.find('.a-modal-org__scroll');
            var modalTargetBtn = modalTarget.find('.a-modal-org__btn');
 
            if(modalTarget){
 
                $(this).on('click',function(){
                    modal_org_open();
                    if(overlay){
                        overlay.on('click focusin',function(){
                            modal_org_close();
                            return false;
                        });
                    }
                    return false;
                });
 
                modalTarget.on('click',function(){
                    modal_org_close();
                });
                modalTargetinner3.on('click',function(){
                    event.stopPropagation();
                });
                modalTargetBtn.on('click',function(){
                    modal_org_close();
                    return false;
                });
 
            }
 
            // モーダルの高さ監視
            function modal_org_height(){
                if (modalTarget.is(':visible')) {
                    modalTargetBody.css("max-height", "none");
                    modalTargetScroll.removeClass('is-scroll').css("max-height", "none");
                    var outerHeight = modalTargetinner3.innerHeight();
                    if(modalTargetHead.length) outerHeight = outerHeight - modalTargetHead.outerHeight();
                    if(modalTargetFoot.length) outerHeight = outerHeight - modalTargetFoot.outerHeight();
                    modalTargetBody.css("max-height", outerHeight);
                    var scrollHeight = Math.floor(modalTargetScroll.outerHeight());
                    if(outerHeight < scrollHeight){
                        modalTargetScroll.addClass('is-scroll').css("max-height", outerHeight);
                    }
                }
            }
            $(window).on('resize',function(){
                modal_org_height();
            });
 
            function modal_org_open(){
                scroll_lock();
                // モーダルチェック
                modalTarget.css('opacity','0').show();
                modalTargetScroll.scrollTop(0);
                modal_org_height();
                modalTarget.hide().css('opacity','1');
                // モーダル表示
                modalTarget.fadeIn(600, function(){
                    $(this).attr('aria-expanded', 'true');
                });
                modalTarget.attr('tabindex',1).focus().attr('tabindex','');
                // if(overlay) overlay.fadeIn(200);
                if(overlay) a_modal_org_overlay(true, 200);         // a-modal-org-overlay用
            }
            function modal_org_close(){
                scroll_lock_off();
                modalTarget.attr('aria-expanded', 'false').fadeOut();
                // if(overlay) overlay.off().fadeOut();
                if(overlay) a_modal_org_overlay(false, 'fast');         // a-modal-org-overlay用
            }
 
        });
    }
 
    // ============
    // U scroll_lock
    // ============
    var uA = navigator.userAgent;
    var os = osCh();                                //iOS,ipadOS,Android,Mac,Win
    function osCh(){
        if (uA.indexOf('iPhone') > -1 || uA.indexOf('iPod') > -1 || uA.indexOf('iPad') > -1) return "iOS";
        if (uA.indexOf('Android') > -1) return "Android";
        if (uA.indexOf("Mac") != -1 && !('ontouchend' in document)) return "Mac";
        if (uA.indexOf("Mac") != -1 && 'ontouchend' in document) return "ipadOS";           // safari only
        if (uA.indexOf("Win") != -1) return "Win";
        return "unknown";
    }
    var scrollPosition;
    function scroll_lock(){
        if( os == "iOS" || os == "ipadOS" ){
            scrollPosition = $(window).scrollTop();
            $('body').addClass('is-scroll-lock').css({'top': -scrollPosition});
        }else{
            var clientWidth = $(window).innerWidth();
            var noScrollBarWidth = $(window).outerWidth();
            $('body').css({'overflow': 'hidden'});
            diff = noScrollBarWidth - clientWidth;
            if(diff > 0){
                $('body').css({'padding-right': diff + 'px'});
                // if(headerFixedItem && $('[data-header-fixed="true"]').length) headerFixedItem.css({'padding-right': diff + 'px'});
            };
        }
    }
    function scroll_lock_off(){
        if( os == "iOS" || os == "ipadOS" ){
            $('body').removeClass('is-scroll-lock').css({'top': 0});
            window.scrollTo( 0 , scrollPosition );
        }else{
            $('body').css({'overflow': 'auto'});
            $('body').css({'padding-right': '0'});
            // if(headerFixedItem) headerFixedItem.css({'padding-right': 0});
        }
    }
 
    // ============
    // U a-modal-org-overlay
    // ============
    function a_modal_org_overlay(flag,speed){
        var overlay = $('.a-modal-org-overlay');
        if(overlay.length){
            if(flag){
                overlay.stop().fadeIn(speed);
            }else{
                overlay.stop().off().fadeOut(speed);
            }
        }
    }
 
});

メモ

jQueryのことで何かわからないことがあればjQueryの日本語リファレンスサイトがあるので一度チェックしてみるといろいろ解決できたりしますよ。

さいごに

わー、これこれー
デバイス対応が難しかったですねー

関連記事

Author

デザコト

あ、いいな、と思うWebデザインを紹介しています。デザインの参考に。やさしいデザインが多いです。Webデザインギャラリー『デザインのこと - Web design gallery』を運営しています。

Googleさんの
おすすめ

4

/

19

2024

Googleさんの
おすすめ

4

/

19

2024

デザインの記事

メリット
  • 2024.04.19New
  • メリット
  • 国内、海外のウェブデザイン、パソコン・タブレット・スマートフォンでも見やすいレスポンシブ対応の「あ、いいな」と思うウェブデザインを集めています。
  • デザインのこと – Web design gallery
5年経った無印良品窓の家
【jQuery】 ローディング、実装サンプル集