<div id="drawer">
  <div class="button">
    <div class="line"></div>
    <div class="line"></div>
    <div class="line"></div>
  </div>
  <div class="close-area"></div>
</div>
<div id="drawer-menu">
  メニュー
</div>
#drawer .button {
    padding: 7px;
    position: fixed;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-shadow: 2px 2px 4px #444;
    box-shadow: 2px 2px 4px #444;
    width: 32px;
    height: 32px;
    -webkit-box-pack: justify;
    -ms-flex-pack: justify;
    justify-content: space-between;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    top: 10px;
    left: 23px;
    z-index: 1;
    color: #fff;
    background-color: #999;
    cursor: pointer;
}

#drawer .button:hover {
    background-color: #ddd;
}

#drawer .button .line {
    height: 4px;
    background-color: #fff;
}

#drawer .button:hover .line {
    background-color: #666;
}

#drawer .close-area {
    position: fixed;
    width: 100vw;
    height: 100vh;
    top: 0;
    left: 0;
    opacity: 0;
    visibility: hidden;
    -webkit-transition: opacity .2s,visibility .2s;
    transition: opacity .2s,visibility .2s;
    z-index: 2;
}

#drawer .close-area.active {
    visibility: visible;
    opacity: .5;
    background-color: #363b3f;
}

#drawer-menu {
    position: fixed;
    left: -100%;
    min-width: 280px;
    height: 100vh;
    background-color: #fefefe;
    transition: left .3s ease-in;
    z-index: 3;
}

#drawer-menu.active {
    left: 0;
    -webkit-transition: right .5s cubic-bezier(0,.8,.6,1);
    transition: left .5s cubic-bezier(0,.8,.6,1);
}
function DrawerEventRegisterer() {
    let _isOpening = false;

    function _register() {
        const BUTTON = document.querySelector( '#drawer .button' );
        if ( BUTTON === null ) return;
      
        const CLOSE_AREA = document.querySelector( '#drawer .close-area' );
        if ( CLOSE_AREA === null ) return;

        const MENU = document.getElementById( 'drawer-menu' );
        if ( MENU === null ) return;
      
        const ACTIVE_CLASS_NAME = 'active';

        const onOpen = function() {
            _isOpening = true;

            BUTTON      .addClass( ACTIVE_CLASS_NAME );
            CLOSE_AREA  .addClass( ACTIVE_CLASS_NAME );
            MENU        .addClass( ACTIVE_CLASS_NAME );
        };

        const onClose = function() {
            _isOpening = false;

            BUTTON      .removeClass( ACTIVE_CLASS_NAME );
            CLOSE_AREA  .removeClass( ACTIVE_CLASS_NAME );
            MENU        .removeClass( ACTIVE_CLASS_NAME );
        };

        _registerPushedEvents( BUTTON, CLOSE_AREA, onOpen, onClose );
        _registerResizedEvent( BUTTON, onClose );
    }

    function _registerPushedEvents( button, closeArea, onOpen, onClose ) {
        const onPushedButton    = function() { if ( !_isOpening ) onOpen();  };
        const onPushedCloseArea = function() { if (  _isOpening ) onClose(); };

        button      .registerOnPushed( onPushedButton       );
        closeArea   .registerOnPushed( onPushedCloseArea    );
    }

    function _registerResizedEvent( button, onCompleted ) {
        const onResized = function() {
            if ( !_isOpening ) return;
          
            const DISPLAY = button.getStylesheetValue( 'display' );
            if ( DISPLAY !== 'none' ) return;
            
            onCompleted();
        };

        window.registerOnResized( onResized );
    }

    return {
        register: _register,
    };
};

Element.prototype.addClass = function( name ) {
    this.classList.add( name );
};

Element.prototype.removeClass = function( name ) {
    this.classList.remove( name );
};

Element.prototype.getStylesheetValue = function( propertyName ) {
    const STYLE = window.getComputedStyle( this );
    const VALUE = STYLE .getPropertyValue( propertyName );

    return VALUE;
};

Element.prototype.registerOnPushed = function( onPushed ) {
    if ( isSmartPhoneOrTablet() ) {
        let     isTouching  = false;
        const   OPTION      = canUsePassive() ? { passive: true } : false;

        const onTouched = function() {
            if ( !isTouching ) return;

            onPushed();
            isTouching = false;
        };

        this.addEventListener( 'touchstart' , function() { isTouching = true;  }, OPTION );
        this.addEventListener( 'touchmove'  , function() { isTouching = false; }, OPTION );
        this.addEventListener( 'touchend'   , onTouched                         , OPTION );
    }
    else {
        this.addEventListener( 'click', onPushed );      
    }
};

function isSmartPhoneOrTablet() {
    const isContaining = function( search ) {
        return navigator.userAgent.indexOf( search ) !== -1;
    };

    const IS_SMART_PHONE_OR_TABLET = 
        isContaining( 'iPhone' )    || 
        isContaining( 'iPod' )      || 
        isContaining( 'Android' )   ||
        isContaining( 'iPad' )
    ;

    return IS_SMART_PHONE_OR_TABLET;
}

function canUsePassive() {
    let canUsePassive = false;
    
    const PROPERTY  = { get: function() { canUsePassive = true; } };
    const OPTIONS   = Object.defineProperty( {}, 'passive', PROPERTY );

    window.addEventListener( 'dummy', null, OPTIONS );

    return canUsePassive;
}

Window.prototype.registerOnResized = function( onResized ) {
    const INTERVAL          = 300;
    const observingEvent    = createObservingEvent( INTERVAL, null, null, onResized );
  
    window.addEventListener( 'resize', observingEvent );
};

function createObservingEvent( interval, onStarted, onExecuting, onEnded ) {
    let intervalID  = null;
    let isExecuting = false;

    const onElapsed = function() {
        if ( !isExecuting ) {
            clearInterval( intervalID );
            intervalID = null;

            if ( onEnded !== null ) onEnded();
            return;
        }

        if ( onExecuting !== null ) onExecuting();
        isExecuting = false;
    };

    const onExecute = function() {
        isExecuting = true;

        if ( intervalID !== null ) return;

        if ( onStarted !== null ) onStarted();
        intervalID = setInterval( onElapsed, interval );
    };

    return onExecute;
};

const DRAWER_EVENT_REGISTERER = new DrawerEventRegisterer;
DRAWER_EVENT_REGISTERER.register();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.