Drawer Menu

画面端に表示するドロワーメニュー。

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

表示位置、サイズ指定、一時・常時の3つの設定が可能です。

  • DEMO
  • 規定サイズ
  • 内容物サイズ
  • 指定サイズ
  • 常時表示

xs

xm

xl

fit

120px

persistent

使い方

トリガーとなる要素に+-.drawer-btn-+クラスと、表示指定用の+-data-+属性を追加。

  • [data-drawer_position] 表示位置を記述。
    +-top-+ +-bottom-+ +-left-+ +-right-+
  • [data-drawer_type] 一時・常時の指定を記述。
    一時表示:+-temporary-+、常時表示:+-persistent-+
  • [data-drawer_size]に表示サイズを記述。
    規定サイズ:+-xs-+ +-xm-+ +-xl-+
    内容物サイズ:+-fit-+
    指定サイズ:直接サイズを記述。+-~px-+ +-~%-+

規定サイズは下記の指定です。

top bottom left right
xs height: 30%; height: 30%; width: 20%; width: 20%;
xm height: 60%; height: 60%; width: 50%; width: 50%;
xl height: 90%; height: 90%; width: 80%; width: 80%;
fit height:fit-content; height:fit-content; width:fit-content; width:fit-content;
  • HTML
  • CSS
  • Script
<button 
    class="drawer-btn"
    data-drawer_position="表示位置"
    data-drawer_size="サイズ指定"
    data-drawer_type="一時・常時"
  ></button>
#drawerMod {position: relative;}
  .drawer-sec {
    margin: auto;
    background: var(--bg-paper);
    box-shadow: var(--shadow);
    box-sizing: border-box;
    position: fixed;
    z-index: 10001;
    transition: 0.25s;
  }
  /*size*/
  .top.xs .drawer-sec ,
  .bottom.xs .drawer-sec {
    width: 100%;
    height: 30%;
  }
  .top.xm .drawer-sec ,
  .bottom.xm .drawer-sec {
    width: 100%;
    height: 60%;
  }
  .top.xl .drawer-sec ,
  .bottom.xl .drawer-sec {
    width: 100%;
    height: 90%;
  }
  .top.fit .drawer-sec ,
  .bottom.fit .drawer-sec {
    width: 100%;
    height: fit-content;
  }
  
  .left.xs .drawer-sec ,
  .right.xs .drawer-sec {
    width: 20%;
    height: 100%;
    top: 0;
  }
  .left.xm .drawer-sec ,
  .right.xm .drawer-sec {
    width: 50%;
    height: 100%;
    top: 0;
  }
  .left.xl .drawer-sec ,
  .right.xl .drawer-sec {
    width: 80%;
    height: 100%;
    top: 0;
  }
  .left.fit .drawer-sec ,
  .right.fit .drawer-sec {
    width: fit-content;
    height: 100%;
    top: 0;
  }
  
  /*position*/
  .top .drawer-sec {
    top: 0;
    transform: translateY(-100%);
    border-radius: 0 0 10px 10px;
  }
  .bottom .drawer-sec {
    bottom: 0;
    transform: translateY(100%);
    border-radius: 10px 10px 0 0;
  }
  .left .drawer-sec {
    left: 0;
    transform: translateX(-100%);
  }
  .right .drawer-sec {
    right: 0;
    transform: translateX(100%);
  }
  .drawer-sec.transY {transform: translateY(0)}
  .drawer-sec.transX {transform: translateX(0)}
  
  .drawer-set {
    width: 100%;
    height: 100%;
    overflow: auto;
    scrollbar-width: none;
  }
  
  .drawer-slider-bar ,
  .drawer-slider-bar-btn {
    width: 6px;
    border-radius: 16px;
  }
  .drawer-slider-bar {
    height: 100%;
    position: absolute;
    right: 8px;
    transform: scale(.98);
    display: none;
  }
  .drawer-slider-bar-btn {
    height: 40%;
    background: var(--txt-secondary);
  }
  
  .drawer-close {
    width: 40px;
    height: 40px;
    border-radius: 50px;
    color: var(--bg-paper);
    position: absolute;
    right: 8px;
    z-index: 1;
  }
  .top .drawer-close {top: calc(100% + 8px);}
  .bottom .drawer-close {
    bottom: calc(100% + 8px);
    transform: rotate(180deg);
  }
  .left .drawer-close {
    top: 8px;
    left: calc(100% + 8px);
    transform: rotate(270deg);
  }
  .right .drawer-close {
    top: 8px;
    right: calc(100% + 8px);
    transform: rotate(90deg);
  }
  .drawer-close:hover {background: var(--bg-overlay);}
  
  /* persistent */
  #root.drawer {
    width: 100%;
    height: 100vh;
    overflow: auto;
    transition: .25s;
  }
  .persistent .drawer-set {
    border-top: 1px solid var(--line-main);
    scrollbar-width: auto;
    scrollbar-gutter: stable;
  }
  .persistent .drawer-close {
    min-width: 40px;
    min-height: 40px;
    margin: 8px;
    color: var(--txt-primary);
    position: static;
  }
  .persistent .drawer-close:hover {background: var(--hover);}
  
  .persistent.top .drawer-close,
  .persistent.bottom .drawer-close ,
  .persistent.left .drawer-close {margin-left: auto;}
  .persistent.top .drawer-sec {
    display: flex;
    flex-direction: column;
  }
  .persistent.top .drawer-set {order: 1;}
  .persistent.top .drawer-close {order: 2;}
$bd.on('click','.drawer-btn',function(){
    let $posi = $(this).data('drawer_position');
    let $type = $(this).data('drawer_type');
    let $size = $(this).data('drawer_size');
    let slide = '';
    let overlay = '';
    if($type == 'temporary'){
      slide = '
'; overlay = '
'; } if($size.match('xs|xm|xl')){ $bd.append(''); } else { let size = ''; if($posi == 'top' || $posi == 'bottom'){size = 'width:100%; height:'+$size+';'} else if($posi == 'left' || $posi == 'right'){size = 'width:'+$size+'; height:100%; top: 0;'} $bd.append(''); } $rt.toggleClass('drawerDisp'); $('.overlay').fadeIn(200); //スライドバー $('.drawer-set').scroll(function(){ let $wrap = $(this).parents('#drawerMod'); let $slide = $(this); let $barBtn = $wrap.find('.drawer-slider-bar-btn'); let disp_height = $slide.height(); // スクロールバー移動可能量(スライダー表示幅 - スライダー幅) / スクロール可能量(スライダー全幅 - スライダー表示幅) let offset = $(this).scrollTop() * (disp_height - $barBtn.height()) / ($slide.get(0).scrollHeight - disp_height); $barBtn.css('transform', 'translateY(' + offset + 'px)'); }); }); function drawerOpen(obj){ let $drawer = $('#drawerMod'); let $sec = $('.drawer-sec'); let posi = $drawer.data('position'); let trans = 'transX'; if(posi == 'top' || posi == 'bottom'){trans = 'transY';} $('.drawer-set').append(obj); $drawer.fadeIn(250); $sec.addClass(trans); if($('.drawer-set').children().height() > $sec.height()){ $('.drawer-slider-bar').show(); } if($drawer.data('type') == 'persistent'){ let ws = $win.scrollTop(); $rt.addClass('drawer').css('transition','.25s'); let scale = $sec.height(); if(posi == 'top'){ $rt.css({ 'height':'calc(100vh - '+scale+'px)', 'margin-top':scale }) if(ws>scale){console.log(0); $rt.css('transition','0s').scrollTop(ws+scale); } else { $rt.scrollTop(ws); } } else if(posi == 'bottom'){ $rt.css('height','calc(100vh - '+scale+'px)').scrollTop(ws); } else if(posi == 'left'){ $rt.css('padding-left',$sec.width()).scrollTop(ws); } else if(posi == 'right'){ $rt.css('width','calc(100% - '+$sec.width()+'px)').scrollTop(ws); } } else { noscroll(); } } function drawerClose(){ $('.drawer-sec').removeClass('transY transX'); $('.overlay').fadeOut(250); let close = function(){ $('#drawerMod').remove(); $rt.removeClass('drawer'); } if(!$('.noscroll')[0]){ let rs = $rt.scrollTop(); $rt.removeAttr('style').toggleClass('drawerDisp'); setTimeout(function(){ close(); $('body,html').scrollTop(rs); },300); } else { setTimeout(function(){ noscroll(); close(); },300); } } $bd.on('click','.overlay ,.drawer-close',function(){drawerClose();});

ドロワー内に設置するオブジェクトを渡すJSの記述も別途必要です。

$bd.on('click','トリガー',function(){
    drawerOpen(オブジェクト);
  });