EITCH DESIGN エイチ デザイン / モーダル表示

menu

モーダル表示

モーダル表示用の汎用関数

  • CODE
  • DEMO
  • 説明
  • 使い方
  • 解説

他のライブラリでも使用する汎用型のモーダル表示関数。
オプションは以下の3つ

・スマホでのスワイプ設定
・アクション用のボタン追加(デフォルトはクローズボタンのみ)
・[body]にclass追加

modalOpen('表示要素','スワイプ設定','body用class','アクションボタン追加');
(表示要素 : 要素の引数)
モーダルの中で表示する要素の引数を指定。

(スワイプ設定 : class名)
スワイプイベントに使用するclass名を指定する。
空でスワイプイベントなし、デフォルトは[swip]。

(body用class : class名)
モーダル表示状態を判別するためのclassをbodyに追加。

(アクションボタン追加 : class名)
クローズ以外のボタンを追加する場合に専用class名を指定。
追加たしたボタンのイベントは別途必要。

  • html

    copy
    none
  • css

    copy
    .noscroll {
      width: 100%;
      overflow: hidden;
      position: fixed;
      left: 0;
    }
    .noscroll #param {
      position: relative;
      filter: blur(3px);
    }
    
    #modalMod {
      display: none;
      position: relative;
      z-index: 1001;
    }
    .modalMod-sec ,
    .modalMod-bg {
      position: fixed;
      top: 0;
      left: 0;
    }
    .modalMod-sec {
      max-width: 90%;
      max-height: 90%;
      min-width: 400px;
      margin: auto;
      padding: 24px;
      border-radius: 4px;
      background: #fff;
      box-shadow: 0 3px 10px #282828;
      box-sizing: border-box;
      right: 0;
      bottom: 0;
      z-index: 1001;
    }
    .fill .modalMod-sec {
      width: 90%;
      height: 90%;
    }
    .hug .modalMod-sec {
      width: fit-content;
      height: fit-content;
    }
    .modalMod-scroller {
      height: 100%;
      margin-top: -40px;
      overflow-y: auto;
      scrollbar-width: none;
      -ms-overflow-style: none;
      -webkit-overflow-scrolling: touch;
      position: relative;
      z-index: 1003;
    }
    .modalMod-body {
      width: 100%;
      height: 100%;
      margin-top: -40px;
    }
    .modalMod-action {
      width: fit-content;
      margin-left: auto;
      border-radius: 40px;
      display: flex;
      justify-content: flex-end;
      position: sticky;
      top: 0;
      right: 0;
      z-index: 1004;
    }
    .modalMod-action-btn {
      width: 40px;
      height: 40px;
      border-radius: 50% 50%;
      background: rgba(255,255,255,0.3);
      color: inherit;
      display: flex;
      justify-content: center;
      align-items: center;
      transition: 0.2s;
    }
    .modalMod-action-btn:hover {background: rgba(0,0,0,0.1);}
    .modalMod-action-btn.close .ico-mui::before {content: '\e5cd';}
    .modalMod-scrollbar {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 24px;
      left: 0;
      z-index: 1002;
    }
    .modalMod-scrollbar-btn {
      width: 4px;
      border-radius: 4px;
      background: rgba(0,0,0,0.6);
      position: absolute;
      right: 8px;
    }
    .scrl.hug .modalMod-sec {height: 100%;}
    .scrl .modalMod-body {margin-top: 0;}
    .modalMod-bg {
      width: 100%;
      height: 100%;
      background: rgba(0,0,0,0.7);
      z-index: 1000;
    }
    
    @media screen and (max-width: 768px) {
      #modalMod {
        width: 100%;
        height: 100%;
        justify-content: center;
        align-items: center;
        position: fixed;
        top: 0;
        left: 0;
      }
      .modalMod-sec {
        min-width: 50%;
        max-height: 95%;
        padding: 8px;
        position: relative;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
      }
      .fill .modalMod-sec {height: 95%;}
    }
  • jQuery

    copy
    var modal_frag = false;
    
    //スクロール制限
    function noscroll(){
      if(modal_frag == true){return false;}
    
      if(!$('.noscroll')[0]){
        //制限
        const winScroll = $(window).scrollTop();
        $prm.css('top', -winScroll).data('scroll', winScroll);
        $bd.addClass('noscroll');
      } else {
        //解除
        $bd.removeClass('noscroll');
        $('body,html').scrollTop($('#param').data('scroll'));
        $prm.removeAttr('style').removeData('scroll');
      }
    }
    
    //モーダル設置
    function modalOpen(obj,swip,cl,act,size){
      $bd.append('
    '); $('.modalMod-body').append(obj); const $modalMod = $('#modalMod'); const $modalModSec = $('.modalMod-sec'); const $modalModBody = $('.modalMod-body'); //スワイプタイプ追加 if(swip !== ''){$modalModSec.addClass(swip);} //bodyにclass追加 if(cl !== ''){ $bd.addClass(cl); $prm.data('dellClass', cl); } //アクションボタン追加 if(act !== ''){ for(var i = 0; i < act.length; i++) { $('.modalMod-action').prepend('
  • '); } } //サイズ設定 if(size === 'fill' || size === 'hug'){ $modalMod.addClass(size); } else if($.isNumeric(size)){ $modalModSec.width(size); } //実行・表示 noscroll(); $modalMod.fadeIn().css('display','flex'); //スクロールバー追加 const secHeight = $modalModSec.height() const objHeight = $modalModBody.children().height(); if(objHeight > secHeight){ $modalMod.addClass('scrl'); if($win.width() > 769){ const scrollerHeight = parseInt(secHeight * secHeight / objHeight); $modalMod.addClass('scrl'); $modalModBody.wrap('
    '); $modalModSec.append('
    '); $('.modalMod-scrollbar-btn').height(scrollerHeight + 'px'); const scrollerTrack = secHeight - scrollerHeight; $('.modalMod-scroller').on('scroll', function(){ const offset = $(this).scrollTop() * scrollerTrack / (objHeight - secHeight); $('.modalMod-scrollbar-btn').css('transform','translateY(' + offset + 'px)'); }); } }; } //クローズトリガー $bd.on('click','.modalMod-action-btn.close , .modalMod-bg',function(){modalClose();}); //クローズアクション function modalClose(){ $('#modalMod').fadeOut(); noscroll(); modal_frag = true; if($prm.data('dellClass') !== ''){ $bd.removeClass($prm.data('dellClass')); } setTimeout(function(){ $('#modalMod').remove(); modal_frag = false; },600); } //スワイプ 縦横 var isTouch = ('ontouchstart' in window); $bd.on({ 'touchstart': function(e){ if($('#modalMod.scrl')[0]){return;} this.pageX = (isTouch ? event.changedTouches[0].pageX : e.pageX); this.pageY = (isTouch ? event.changedTouches[0].pageY : e.pageY); this.touched = true; }, 'touchmove': function(e){ if(!this.touched){return;} this.pageXm = (isTouch ? event.changedTouches[0].pageX : e.pageX); this.pageYm = (isTouch ? event.changedTouches[0].pageY : e.pageY); if(this.pageYm != 0){ var yc = this.pageYm - this.pageY + 1; var yco = yc / 160; var ycod = Math.sqrt(Math.pow(yco,2)); var opc = 1 - ycod; $('.modalMod-sec').css({ 'transform':'translateY(' + yc + 'px)', 'opacity':opc, 'transition':'none' }); nowTouch = true; } }, 'touchend': function(e){ if(!this.touched){return;} this.touched = false; this.left = this.pageX - (isTouch ? event.changedTouches[0].pageX : e.pageX); this.top = this.pageY - (isTouch ? event.changedTouches[0].pageY : e.pageY); if(this.top == 0 && this.left == 0){ modalClose(); return false; } else if(this.top > 60){ $('.modalMod-sec').css('transform','translateY(-150%)'); modalClose(); nowTouch = false; } else if(this.top < -60){ $('.modalMod-sec').css('transform','translateY(150%)'); modalClose(); nowTouch = false; } else { $('.modalMod-sec').css({ 'transform':'translateY(0)', 'opacity':'1', 'transition':'0.1s' }); } } }, '.modalMod-sec.swip');