<div id="page-top-button">ページトップへ</div>

<div>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
  <p>aaaaaaaaaaaaaa</p>
  <p>bbbbbbbbbbbbbb</p>
  <p>cccccccccccccc</p>
</div>
#page-top-button {
  position: fixed;
  top: 10px;
  left: 23px;
  color: #fff;
  background-color: #999;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  padding: 5px 20px;
  box-shadow: 2px 2px 4px #444;
  -webkit-box-shadow: 2px 2px 4px #444;
}

#page-top-button:hover {
  color: #666;
  background-color: #ddd;
}
function PageTopButtonEventRegisterer() {
    const _SCROLLER = new Scroller( document.documentElement, 70, 15 );
  
    function _register() {
        const PAGE_TOP_BUTTON = document.getElementById( 'page-top-button' );
        if ( PAGE_TOP_BUTTON === null ) return;

        const onPushed = function() {
            _SCROLLER.scrollByPosition( 0 );
        };

        PAGE_TOP_BUTTON.registerOnPushed( onPushed );
    }

    return {
        register: _register,
    };
}

function Scroller( target, speed, interval ) {
    const   _MAX_POSITION   = target.scrollHeight - target.clientHeight;
    let     _timeoutId      = null;

    function _scrollByPosition( position ) {
        if ( _timeoutId !== null ) return;

        let currentPosition = target.scrollTop;
        if ( position > _MAX_POSITION ) position = _MAX_POSITION;
        
        const   DIRECTION   = position < currentPosition ? -1 : 1;
        const   MOVEMENT    = speed * DIRECTION;

        const onScroll = function() {
            currentPosition += MOVEMENT;

            const IS_COMPLETED =
                ( DIRECTION ===  1 && currentPosition >= position ) ||
                ( DIRECTION === -1 && currentPosition <= position )
            ;

            if ( IS_COMPLETED ) {
                target.scrollTop = position;
                _timeoutId = null;

                return;
            }

            target.scrollTop = currentPosition;
            _timeoutId = setTimeout( onScroll, interval );
        };

        onScroll();
    };

    function _scrollByElement( element ) {
        const POSITION = element.offsetTop;

        _scrollByPosition( POSITION );
    }

    return {
        scrollByPosition: _scrollByPosition,
        scrollByElement : _scrollByElement,
    };
};

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;
}

const PAGE_TOP_BUTTON_EVENT_REGISTERER = new PageTopButtonEventRegisterer;
PAGE_TOP_BUTTON_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.