Modal

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

CSSに関しては一部CSSライブラリを採用しているので併用してください。

他のライブラリでも使用する汎用型のモーダル表示関数

  • 横サイズ
  • アクションボタン
  • 縦長テスト

使い方

下記関数で実行する。

modalOpen('表示要素','スワイプ設定','body用クラス','アクションボタンクラス','サイズ指定');

例)modalOpen(hoge,'swip','demo',['download','window'],'500');

  • 第一引数:モーダルの中で表示する要素の引数を指定。
  • 第二引数:スワイプイベントに使用するクラス名を指定する。+-null-+ +-swip-+
  • 第三引数:なんのモーダルを表示しているか判別するためのクラスをbodyに追加。
  • 第四引数:追加するアクションボタン用のクラス名を指定。追加したボタンのイベントは別途必要。
  • 第五引数:モーダルのサイズ指定。
    画面幅:+-fill-+
    内容幅:+-hug-+
    固定幅:直接サイズを記述。数字のみ。

アクションボタンは*-i class="ico-mui"-*のHTMLが追加されるので、指定したクラス名を使ってアイコンのCSSも別途必要です。

  • CSS
  • Script
#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: 10px;
    background: var(--bg-paper);
    box-shadow: var(--shadow);
    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%;
    color: inherit;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: .2s;
  }
  .modalMod-action-btn:hover {background: var(--hover);}
  .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: var(--bg-overlay);
    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%;}
  }
var modal_frag = false;
  //モーダル設置
  function modalOpen(obj,swip,cl,act,size){
    $bd.append('
'); $('.modalMod-body').append(obj); let $modalMod = $('#modalMod'); let $modalModSec = $('.modalMod-sec'); let $modalModBody = $('.modalMod-body'); //スワイプタイプ追加 if(swip !== ''){$modalModSec.addClass(swip);} //bodyにclass追加 if(cl !== ''){ $bd.addClass(cl); $rt.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); } //実行・表示 if(modal_frag != true){noscroll();} $modalMod.fadeIn(200).css('display','flex'); //スクロールバー追加 let secHeight = $modalModSec.height() let objHeight = $modalModBody.children().height(); if(objHeight > secHeight){ $modalMod.addClass('scrl'); if($win.width() > 769){ let scrollerHeight = parseInt(secHeight * secHeight / objHeight); $modalMod.addClass('scrl'); $modalModBody.wrap('
    '); $modalModSec.append('
    '); $('.modalMod-scrollbar-btn').height(scrollerHeight + 'px'); let scrollerTrack = secHeight - scrollerHeight; $('.modalMod-scroller').on('scroll', function(){ let 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(); if(modal_frag != true){noscroll();} modal_frag = true; setTimeout(function(){ $('#modalMod').remove(); if($rt.data('dellClass') !== ''){ $bd.removeClass($rt.data('dellClass')); } 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');