This website uses cookies to personalise ads and to analyse traffic ok
web design

How to close mobile menu when using Page scroll to id plugin

In order to auto-close an opened mobile menu when links that scroll the page are clicked, you’ll need to add some extra javascript in your page or theme template.

This issue is not a problem that comes from “Page scroll to id”, as the plugin has no control over the mobile menu a site is using. The same problem would happen even if you were using other similar plugins or no plugin at all (e.g. the page would “jump” but the mobile menu would still be opened). This issue comes from the fact that most mobile menu scripts do not auto-close the menu, when menu links are clicked, simply because most developers forget that a link might point to an anchor within the same page.

Page scroll to id for WordPress

Page scroll to id is a fully featured WordPress plugin for creating links that scroll the page smoothly to any id within the document. The plugin replaces browser’s “jumping” behavior with a smooth scrolling animation, when links with href value containing # are clicked.
It provides all the basic tools and advanced functionality for single-page websites, in-page navigation, back-to-top links etc. with features like: adjustable scrolling animation duration and easing, link and target highlighting via ready-to-use CSS classes, vertical and/or horizontal scrolling, scrolling from/to different pages etc.

Page scroll to id with mousewheel and keyboard

Code sample which should scroll between page sections created with Page scroll to id plugin, using the mouse-wheel and keyboard arrows.

In order to scroll between page sections via mouse-wheel and/or keyboard you’d normally need custom javascript code made specifically for your site layout/markup but I’ve created a more generic script that works along Page scroll to id plugin. The script uses a special plugin class (_mPS2id-h) in order to work independently from most layouts. This class is related to plugin’s highlight feature, meaning that it should work in most cases.

Script for WordPress

“Page scroll to id” WordPress plugin version 1.6.7 or greater must be installed and activated on your site.

After you create your page(s) target sections, edit your theme’s or child-theme’s functions.php and paste the following code

/* 
---------------------------------------- 
"Page scroll to id" with mousewheel and keyboard custom script
The following requires "Page scroll to id" WordPress plugin version 1.6.7 or greater 
---------------------------------------- 
*/

//----- SETUP -----

//set the options for the mousewheel scrolling 

function ps2id_mousewheel_options($opt){
  $opts = array(
    //set the ids of pages or posts that you want the mousewheel functionality to be enabled 
    //and set the target sections URLs for each of your sections of each page
    'ps2id_mousewheel_pages'            =>  array( 
      //1st page id and its target sections URLs
      '25'    =>  array(
        //page mousewheel sections URLs (e.g. #section-1 or http://site.com/#section-1 or /page/#section-1)
        '#section-1', 
        '#section-2', 
        '#section-3', 
        '#section-4', 
        '#section-5', 
      ),
      //2nd page id and its target sections URLs
      '3'    =>  array(
        //page mousewheel sections URLs
        '#section-1', 
        '#section-2', 
        '#section-3', 
        '#section-4', 
        '#section-5', 
        '#section-6', 
        '#section-7', 
        '#section-8', 
      ),
    ),
    //Special options for the mouse-wheel smooth scrolling (these overwrite the ones in plugin settings)
    //Scroll type/easing
    'ps2id_mousewheel_scroll_easing'        =>  "easeOutQuint",
    //Scroll duration (in milliseconds)
    'ps2id_mousewheel_scroll_duration'        =>  1000,
    //Keep the current element highlighted until the next one comes into view (this is needed if the page has non-adjacent sections, i.e. when not all sections are next to one another)
    'ps2id_mousewheel_keep_highlight_until_next'  =>  true,
    //Allow only one highlighted element at a time (should be disabled when $ps2id_mousewheel_keep_highlight_until_next is set to true)
    'ps2id_mousewheel_force_single_highlight'    =>  false,
    //Append the clicked link’s hash value (e.g. #id) to browser’s URL/address bar (this should normally be disabled for better UX)
    'ps2id_mousewheel_append_hash'          =>  false
  );
  $r = (isset($opt) && !empty($opt)) ? $opts[$opt] : $opts;
    return $r;
}

//----- HTML -----

add_action('wp_footer', 'ps2id_mw_html');

function ps2id_mw_html(){
?>
  <?php if(class_exists('malihuPageScroll2id')) : ?>
    <?php
    $pages_arr = ps2id_mw_get_pages();
    $page_id = get_queried_object_id();
    $sections_arr = in_array($page_id, $pages_arr) ? ps2id_mousewheel_options('ps2id_mousewheel_pages')[$page_id] : null;
    ?>
    <?php if(is_single( $pages_arr ) || is_page( $pages_arr )) : ?>
      <?php if(!is_null($sections_arr)) : ?>
        <div id="ps2id-mw-sections-bullets">
          <?php 
          foreach($sections_arr as $section){
            ?>
              <a href="<?php echo $section; ?>" class="ps2id-mw-section-bullet"></a>
            <?php
          }
          ?>
        </div>
      <?php endif; ?>
      <style>
        body{ -ms-touch-action: none; touch-action: none; } /* optional for touch/pointer events */

        /* aside bullets section */
        #ps2id-mw-sections-bullets{
          position: fixed;
          right: 2em;
          height: auto;
          top: 50%;
          transform: translateY(-50%);
          z-index: 2;
        }

        /* aside bullets */
        .ps2id-mw-section-bullet{
          display: block;
          position: relative;
          width: 1.5em;
          height: 1.5em;
          border-radius: 100%;
          margin: 0 auto;
          opacity: .6;
        }

        .ps2id-mw-section-bullet::before{
          content: "";
          display: block;
          position: absolute;
          top: 0;
          right: 0;
          bottom: 0;
          left: 0;
          margin: .4em;
          border-radius: 100%;
          border: 1px solid;
        }

        .ps2id-mw-section-bullet:hover, 
        .ps2id-mw-section-bullet.mPS2id-highlight:not(.mPS2id-highlight-first):not(.mPS2id-highlight-last), 
        .ps2id-mw-section-bullet.mPS2id-highlight-first{
          opacity: 1;
        }
      </style>
    <?php endif; ?>
  <?php endif; ?>
<?php
};

//----- Javascript -----

add_action( 'wp_enqueue_scripts', 'ps2id_special_params', 1 );

function ps2id_special_params(){
  if(class_exists('malihuPageScroll2id')){
    $pages_arr = ps2id_mw_get_pages();
    if(is_single( $pages_arr ) || is_page( $pages_arr )) : 
      wp_register_script( 'page-scroll-to-id-mw-js-init', '', array(), '0.0.1', false );
      wp_enqueue_script( 'page-scroll-to-id-mw-js-init' );
      wp_add_inline_script( 'page-scroll-to-id-mw-js-init', 'window.ps2id_special_params={
        highlightSelector: ".ps2id-mw-section-bullet", //mouse-wheel script highlight selector
        scrollEasing: "'.ps2id_mousewheel_options('ps2id_mousewheel_scroll_easing').'", //set a more fitting scroll easing for mousewheel smooth scrolling
        scrollSpeed: '.ps2id_mousewheel_options('ps2id_mousewheel_scroll_duration').', //set a more fitting scrolling duration for mousewheel smooth scrolling
        keepHighlightUntilNext: "'.json_encode(ps2id_mousewheel_options('ps2id_mousewheel_keep_highlight_until_next')).'", //this is needed if the page has non-adjacent sections (i.e. when not all sections are next to one another)
        forceSingleHighlight: "'.json_encode(ps2id_mousewheel_options('ps2id_mousewheel_force_single_highlight')).'", //should be disabled when keepHighlightUntilNext is enabled
        appendHash: "'.json_encode(ps2id_mousewheel_options('ps2id_mousewheel_append_hash')).'" //should normally be disabled for better UX
      };');
    endif;
  }
}

add_action( 'wp_enqueue_scripts', 'ps2id_mw_js', 99 );

function ps2id_mw_js(){
  if(class_exists('malihuPageScroll2id')){
    $pages_arr = ps2id_mw_get_pages();
    if(is_single( $pages_arr ) || is_page( $pages_arr )) : 
      if(PS2ID_MINIFIED_JS){
        $deps = array('jquery','page-scroll-to-id-mw-js-init','page-scroll-to-id-plugin-script');
      }else{
        $deps = array('jquery','page-scroll-to-id-mw-js-init','page-scroll-to-id-plugin-init-script','page-scroll-to-id-plugin-script');
      }
      wp_register_script( 'page-scroll-to-id-mw-js', '', $deps, '0.0.1', true );
      wp_enqueue_script( 'page-scroll-to-id-mw-js' );
      wp_add_inline_script( 'page-scroll-to-id-mw-js', '(function($){
        $(window).on("load",function(){
    
          var doc=$(document),
            mPS2idData=doc.data("mPS2id"),
            mPS2idExt;
    
          if(!mPS2idData){
            console.log("Error: \'Page scroll to id\' plugin not present or activated. Please run the code after plugin is loaded.");
            return;
          }

          if(!$("._mPS2id-t").length) return;
    
          doc.data("mPS2idExtend",{
            selector: "._mPS2id-h",
            currentSelector: function(){
              return this.index($(".mPS2id-highlight-first").length ? $(".mPS2id-highlight-first") : $(".mPS2id-highlight").length ? $(".mPS2id-highlight") : $(".mPS2id-wheel-init"));
            },
            target: function(){
              var curr=$(".mPS2id-target-first").length ? $(".mPS2id-target-first") : $(".mPS2id-target").length ? $(".mPS2id-target") : $(".mPS2id-clicked").length ? $("#"+$(".mPS2id-clicked").attr("href").split("#")[1]) : false;
              if(!curr.length){
                //if no current target exists, get the next and previous closest sections
                var max=999999999,
                  min=-999999999;
                $("._mPS2id-t").each(function(){
                  var pos=mPS2idData.layout==="horizontal" ? this.getBoundingClientRect().left : this.getBoundingClientRect().top;
                  if(pos < 0 && pos > min){
                    min=pos; 
                    curr=$("._mPS2id-t[data-psid-wheel-section=\'"+($(this).data("psid-wheel-section")+1)+"\']");
                  }else if(pos > 0 && pos < max){
                    max=pos; 
                    curr=$("._mPS2id-t[data-psid-wheel-section=\'"+($(this).data("psid-wheel-section")-1)+"\']");
                  }
                });
                $("._mPS2id-h[data-psid-wheel-link=\'"+curr.data("psid-wheel-section")+"\']").addClass("mPS2id-wheel-init");
              }
              return [
                $("._mPS2id-t[data-psid-wheel-section=\'"+(curr.data("psid-wheel-section")-1)+"\']"), //previous target
                curr, //current target
                $("._mPS2id-t[data-psid-wheel-section=\'"+(curr.data("psid-wheel-section")+1)+"\']"), //next target
              ];
            },
            needScroll: function(dir){
              if($("html,body").is(":animated")) return;
              if(dir > 0){ //scrolled fw
                var el=mPS2idExt.target.call()[2][0]; //next adjacent target
                if(mPS2idData.layout==="horizontal"){
                  return el ? el.getBoundingClientRect().left > (window.innerWidth || document.documentElement.clientWidth) : true; //next target is after viewport
                }else{
                  return el ? el.getBoundingClientRect().top > (window.innerHeight || document.documentElement.clientHeight) : true; //next target is below viewport
                }
              }else if(dir < 0){ //scrolled bw
                var el=mPS2idExt.target.call()[0][0]; //previous adjacent target
                if(mPS2idData.layout==="horizontal"){
                  return el ? el.getBoundingClientRect().right < 0 : true; //previous target is before viewport
                }else{
                  return el ? el.getBoundingClientRect().bottom < 0 : true; //previous target is above viewport
                }
              }
            },
            input:{
              y: null,
              x: null},
            i: null,
            time: null,
            support:{
              wheel: false
            }
          }).on("ps2id-scrollSection",function(e,dlt,i){
            var sel=$(mPS2idExt.selector);
            if(!$("html,body").is(":animated")){
              if(!i) i=mPS2idExt.currentSelector.call(sel);
              if(!(i===0 && dlt>0) && !(i===sel.length-1 && dlt<0)) sel.eq(i-dlt).trigger("click.mPS2id");
            }
          }).on("keydown",function(e){ //keyboard
            var code=e.keyCode ? e.keyCode : e.which,
              keys=$(this).data("mPS2id").layout==="horizontal" ? [37,39] : [38,40];
            if(code===keys[0] || code===keys[1]){
              if(!mPS2idExt.needScroll((code > 38 ? 1 : -1))){ //check if normal scrolling is needed to reach adjacent targets
                if($(mPS2idExt.selector).length) e.preventDefault();
                $(this).trigger("ps2id-scrollSection",(code===keys[0] ? 1 : -1));
              }
            }
          })
          //touch events (remove the following code if you don\'t want to apply the touch functionality)
          .on("pointerdown touchstart",function(e){ //touch (optional)
            var o=e.originalEvent;
            if(o.pointerType==="touch" || e.type==="touchstart"){
              var y=o.screenY || o.changedTouches[0].screenY;
              mPS2idExt.input.y=y;
              if($(this).data("mPS2id").layout==="horizontal"){
                var x=o.screenX || o.changedTouches[0].screenX;
                mPS2idExt.input.x=x;
              }
              mPS2idExt.time=o.timeStamp;
              mPS2idExt.i=mPS2idExt.currentSelector.call($(mPS2idExt.selector));
            }
          }).on("pointerup touchend",function(e){
            var o=e.originalEvent;
            if(o.pointerType==="touch" || e.type==="touchend"){
              var y=o.screenY || o.changedTouches[0].screenY,
                diff=mPS2idExt.input.y-y,
                time=o.timeStamp-mPS2idExt.time,
                i=mPS2idExt.currentSelector.call($(mPS2idExt.selector));
              if($(this).data("mPS2id").layout==="horizontal"){
                var x=o.screenX || o.changedTouches[0].screenX,
                  diff=mPS2idExt.input.x-x;
              }
              if(Math.abs(diff)<2) return;
              var _switch=function(){
                return time<200 && i===mPS2idExt.i;
              };
              var dir=diff > 0 ? 1 : -1;
              if(time < 500 && Math.abs(diff) > 50) $(this).trigger("ps2id-scrollSection",[(diff>0 && _switch() ? -1 : diff<0 && _switch() ? 1 : 0),(_switch() ? mPS2idExt.i : i)]);
            }
          })
          // -----
          .on("ps2id-wheel-init",function(){
            //script initialization
            mPS2idExt=$(this).data("mPS2idExtend");
            $("._mPS2id-t").each(function(index){
              $(this).attr("data-psid-wheel-section",index);
            });
            $("._mPS2id-h").each(function(index){
              $(this).attr("data-psid-wheel-link",index);
            });
            //vanilla js mousewheel event (https://github.com/jquery/jquery/issues/2871)
            document.addEventListener(\'wheel\', wheel, {passive: false}, false);
            document.addEventListener(\'mousewheel\', wheel, {passive: false}, false);
            document.addEventListener(\'DOMMouseScroll\', wheel, {passive: false}, false);
            function wheel(e){
              if(e.type == "wheel"){
                mPS2idExt.support.wheel = true;
              }else if(mPS2idExt.support.wheel){
                return;
              }
              if(!mPS2idExt.needScroll((mPS2idData.layout==="horizontal" ? e.deltaX : e.deltaY))){ //check if normal scrolling is needed to reach adjacent targets
                if($(mPS2idExt.selector).length) e.preventDefault();
                doc.trigger("ps2id-scrollSection",((e.detail<0 || e.wheelDelta>0 || e.deltaY < 0 || e.deltaX < 0) ? 1 : -1));
              }
            };
          }).trigger("ps2id-wheel-init");
        });
        
      })(jQuery);');
    endif;
  }
}

function ps2id_mw_get_pages(){
  //get pages ids as array
  $pages_arr = array();
  foreach(ps2id_mousewheel_options('ps2id_mousewheel_pages') as $k => $v) {
    $pages_arr[] = $k;
  }
  return $pages_arr;
}
/* ---------------------------------------- */

Edit ps2id_mousewheel_options function in the code above to setup the pages or posts that you want the mousewheel functionality to be enabled and the target sections URLs for each page. For example, the code below will enable the mousewheel functionality on the posts or pages with id 25, 148 and 3. For each post/page we add its sections URLs:

  'ps2id_mousewheel_pages'            =>  array( 
    '25'    =>  array(
      //page mousewheel sections URLs (e.g. #section-1 or http://site.com/#section-1 or /page/#section-1)
      '#section-1', 
      '#section-2', 
      '#section-3', 
      '#section-4', 
      '#section-5', 
    ),
    '148'    =>  array(
      //page mousewheel sections URLs
      '#section-1', 
      '#section-2', 
      '#section-3', 
      '#section-4', 
    ),
    '3'    =>  array(
      //page mousewheel sections URLs
      '#section-1', 
      '#section-2', 
      '#section-3', 
      '#section-4', 
      '#section-5', 
      '#section-6', 
      '#section-7', 
      '#section-8', 
    ),
  ),

Add as many pages as you want 😉

You may also want to set few specific plugin option for these pages. These options will overwrite the ones in plugin settings:

//Scroll type/easing
'ps2id_mousewheel_scroll_easing'        =>  "easeOutQuint",
//Scroll duration (in milliseconds)
'ps2id_mousewheel_scroll_duration'        =>  1000,
//Keep the current element highlighted until the next one comes into view (this is needed if the page has non-adjacent sections, i.e. when not all sections are next to one another)
'ps2id_mousewheel_keep_highlight_until_next'  =>  true,
//Allow only one highlighted element at a time (should be disabled when $ps2id_mousewheel_keep_highlight_until_next is set to true)
'ps2id_mousewheel_force_single_highlight'    =>  false,
//Append the clicked link’s hash value (e.g. #id) to browser’s URL/address bar (this should normally be disabled for better UX)
'ps2id_mousewheel_append_hash'          =>  false

Version 2.0 script

You need 3 steps in order to make this work: Add the HTML (1), set few plugin options to specific values (2) and add the custom javascript for the mousewheel (3).

1.The HTML

Add the HTML code for the bullet indicators, changing the links href/URL to your sections ids

<div id="sections-bullets">
  <a href="#section-1" class="section-bullet"></a>
  <a href="#section-2" class="section-bullet"></a>
  <a href="#section-3" class="section-bullet"></a>
  <a href="#section-4" class="section-bullet"></a>
  <a href="#section-5" class="section-bullet"></a>
  <a href="#section-6" class="section-bullet"></a>
  <a href="#section-7" class="section-bullet"></a>
</div>

2.Plugin function call and options

You need to set a few specific options in order for the mousewheel script to work properly. You mainly need to set the highlightSelector option to "#sections-bullets a" and enable keepHighlightUntilNext. You should also set the scroll easing option parameter to a value like "easeOutQuint", "easeOutQuart" etc.:

<script>
    (function($){
        $(window).on("load",function(){
            $("a[rel='m_PageScroll2id']").mPageScroll2id({
                highlightSelector: "#sections-bullets a",
                keepHighlightUntilNext: true,
                scrollEasing:"easeOutQuint",
                scrollSpeed:1200
            });
        });
    })(jQuery);
</script>

3.The script

The following script should be placed after Page scroll to id plugin files and function call.

<script>
    (function($){
      $(window).on("load",function(){
  
        var doc=$(document),
          mPS2idData=doc.data("mPS2id"),
          mPS2idExt;
  
        if(!mPS2idData){
          console.log("Error: 'Page scroll to id' plugin not present or activated. Please run the code after plugin is loaded.");
          return;
        }

        if(!$("._mPS2id-t").length) return;
  
        doc.data("mPS2idExtend",{
          selector: "._mPS2id-h",
          currentSelector: function(){
            return this.index($(".mPS2id-highlight-first").length ? $(".mPS2id-highlight-first") : $(".mPS2id-highlight").length ? $(".mPS2id-highlight") : $(".mPS2id-wheel-init"));
          },
          target: function(){
            var curr=$(".mPS2id-target-first").length ? $(".mPS2id-target-first") : $(".mPS2id-target").length ? $(".mPS2id-target") : $(".mPS2id-clicked").length ? $("#"+$(".mPS2id-clicked").attr("href").split("#")[1]) : false;
            if(!curr.length){
              //if no current target exists, get the next and previous closest sections
              var max=999999999,
                min=-999999999;
              $("._mPS2id-t").each(function(){
                var pos=mPS2idData.layout==="horizontal" ? this.getBoundingClientRect().left : this.getBoundingClientRect().top;
                if(pos < 0 && pos > min){
                  min=pos; 
                  curr=$("._mPS2id-t[data-psid-wheel-section='"+($(this).data("psid-wheel-section")+1)+"']");
                }else if(pos > 0 && pos < max){
                  max=pos; 
                  curr=$("._mPS2id-t[data-psid-wheel-section='"+($(this).data("psid-wheel-section")-1)+"']");
                }
              });
              $("._mPS2id-h[data-psid-wheel-link='"+curr.data("psid-wheel-section")+"']").addClass("mPS2id-wheel-init");
            }
            return [
              $("._mPS2id-t[data-psid-wheel-section='"+(curr.data("psid-wheel-section")-1)+"']"), //previous target
              curr, //current target
              $("._mPS2id-t[data-psid-wheel-section='"+(curr.data("psid-wheel-section")+1)+"']"), //next target
            ];
          },
          needScroll: function(dir){
            if($("html,body").is(":animated")) return;
            if(dir > 0){ //scrolled fw
              var el=mPS2idExt.target.call()[2][0]; //next adjacent target
              if(mPS2idData.layout==="horizontal"){
                return el ? el.getBoundingClientRect().left > (window.innerWidth || document.documentElement.clientWidth) : true; //next target is after viewport
              }else{
                return el ? el.getBoundingClientRect().top > (window.innerHeight || document.documentElement.clientHeight) : true; //next target is below viewport
              }
            }else if(dir < 0){ //scrolled bw
              var el=mPS2idExt.target.call()[0][0]; //previous adjacent target
              if(mPS2idData.layout==="horizontal"){
                return el ? el.getBoundingClientRect().right < 0 : true; //previous target is before viewport
              }else{
                return el ? el.getBoundingClientRect().bottom < 0 : true; //previous target is above viewport
              }
            }
          },
          input:{
            y: null,
            x: null},
          i: null,
          time: null,
          support:{
            wheel: false
          }
        }).on("ps2id-scrollSection",function(e,dlt,i){
          var sel=$(mPS2idExt.selector);
          if(!$("html,body").is(":animated")){
            if(!i) i=mPS2idExt.currentSelector.call(sel);
            if(!(i===0 && dlt>0) && !(i===sel.length-1 && dlt<0)) sel.eq(i-dlt).trigger("click.mPS2id");
          }
        }).on("keydown",function(e){ //keyboard
          var code=e.keyCode ? e.keyCode : e.which,
            keys=$(this).data("mPS2id").layout==="horizontal" ? [37,39] : [38,40];
          if(code===keys[0] || code===keys[1]){
            if(!mPS2idExt.needScroll((code > 38 ? 1 : -1))){ //check if normal scrolling is needed to reach adjacent targets
              if($(mPS2idExt.selector).length) e.preventDefault();
              $(this).trigger("ps2id-scrollSection",(code===keys[0] ? 1 : -1));
            }
          }
        })
        //touch events (remove the following code if you don't want to apply the touch functionality)
        .on("pointerdown touchstart",function(e){ //touch (optional)
          var o=e.originalEvent;
          if(o.pointerType==="touch" || e.type==="touchstart"){
            var y=o.screenY || o.changedTouches[0].screenY;
            mPS2idExt.input.y=y;
            if($(this).data("mPS2id").layout==="horizontal"){
              var x=o.screenX || o.changedTouches[0].screenX;
              mPS2idExt.input.x=x;
            }
            mPS2idExt.time=o.timeStamp;
            mPS2idExt.i=mPS2idExt.currentSelector.call($(mPS2idExt.selector));
          }
        }).on("pointerup touchend",function(e){
          var o=e.originalEvent;
          if(o.pointerType==="touch" || e.type==="touchend"){
            var y=o.screenY || o.changedTouches[0].screenY,
              diff=mPS2idExt.input.y-y,
              time=o.timeStamp-mPS2idExt.time,
              i=mPS2idExt.currentSelector.call($(mPS2idExt.selector));
            if($(this).data("mPS2id").layout==="horizontal"){
              var x=o.screenX || o.changedTouches[0].screenX,
                diff=mPS2idExt.input.x-x;
            }
            if(Math.abs(diff)<2) return;
            var _switch=function(){
              return time<200 && i===mPS2idExt.i;
            };
            var dir=diff > 0 ? 1 : -1;
            if(time < 500 && Math.abs(diff) > 50) $(this).trigger("ps2id-scrollSection",[(diff>0 && _switch() ? -1 : diff<0 && _switch() ? 1 : 0),(_switch() ? mPS2idExt.i : i)]);
          }
        })
        // -----
        .on("ps2id-wheel-init",function(){
          //script initialization
          mPS2idExt=$(this).data("mPS2idExtend");
          $("._mPS2id-t").each(function(index){
            $(this).attr("data-psid-wheel-section",index);
          });
          $("._mPS2id-h").each(function(index){
            $(this).attr("data-psid-wheel-link",index);
          });
          //vanilla js mousewheel event (https://github.com/jquery/jquery/issues/2871)
          document.addEventListener('wheel', wheel, {passive: false}, false);
          document.addEventListener('mousewheel', wheel, {passive: false}, false);
          document.addEventListener('DOMMouseScroll', wheel, {passive: false}, false);
          function wheel(e){
            if(e.type == "wheel"){
              mPS2idExt.support.wheel = true;
            }else if(mPS2idExt.support.wheel){
              return;
            }
            if(!mPS2idExt.needScroll((mPS2idData.layout==="horizontal" ? e.deltaX : e.deltaY))){ //check if normal scrolling is needed to reach adjacent targets
              if($(mPS2idExt.selector).length) e.preventDefault();
              doc.trigger("ps2id-scrollSection",((e.detail<0 || e.wheelDelta>0 || e.deltaY < 0 || e.deltaX < 0) ? 1 : -1));
            }
          };
        }).trigger("ps2id-wheel-init");
      });
      
    })(jQuery);
</script>

Version 1.0 script

The script should be placed after Page scroll to id plugin files and function call. If you’re using the WordPress version of the plugin, you should place it wherever your theme allows you to add custom javascript or directly in the footer.php template inside a script (<script>...</script>) tag after wp_footer();

The script

(function($){
  $(window).on("load",function(){

    if(!$(document).data("mPS2id")){
      console.log("Error: 'Page scroll to id' plugin not present or activated. Please run the code after plugin is loaded.");
      return;
    }

    $(document).data("mPS2idExtend",{
      selector:"._mPS2id-h",
      currentSelector:function(){
        return this.index($(".mPS2id-highlight-first").length ? $(".mPS2id-highlight-first") : $(".mPS2id-highlight"));
      },
      input:{y:null,x:null},
      i:null,
      time:null
    }).on("scrollSection",function(e,dlt,i){
      var d=$(this).data("mPS2idExtend"),
        sel=$(d.selector);
      if(!$("html,body").is(":animated")){
        if(!i) i=d.currentSelector.call(sel);
        if(!(i===0 && dlt>0) && !(i===sel.length-1 && dlt<0)) sel.eq(i-dlt).trigger("click.mPS2id");
      }
    }).on("keydown",function(e){ //keyboard
      var code=e.keyCode ? e.keyCode : e.which,
        keys=$(this).data("mPS2id").layout==="horizontal" ? [37,39] : [38,40];
      if(code===keys[0] || code===keys[1]){
        if($($(this).data("mPS2idExtend").selector).length) e.preventDefault();
        $(this).trigger("scrollSection",(code===keys[0] ? 1 : -1));
      }
    });

    //mousewheel (https://github.com/jquery/jquery/issues/2871)
    var supportsWheel=false;
    function wheel(e){
      if (e.type == "wheel") supportsWheel = true;
        else if (supportsWheel) return;
      if($($(document).data("mPS2idExtend").selector).length) e.preventDefault();
      $(document).trigger("scrollSection",((e.detail<0 || e.wheelDelta>0 || e.deltaY < 0 || e.deltaX < 0) ? 1 : -1));
    };
    document.addEventListener('wheel', wheel, {passive: false}, false);
    document.addEventListener('mousewheel', wheel, {passive: false}, false);
    document.addEventListener('DOMMouseScroll', wheel, {passive: false}, false);

  });
})(jQuery);

You can change the selector value to a more specific one if you need. This selector should be your “Page scroll to id” main navigation links, so instead of using simply selector:"._mPS2id-h" you could use for example selector:".menu-item ._mPS2id-h"

Important: Please note that you do not have to add the _mPS2id-h class to your elements. It is added automatically by the plugin. Also note that if you have additional links handled by the plugin (e.g. in addition to your menu links, you have back-to-top, next/previous section links etc. in your page), you might need to set your main (e.g. menu) links selector as the “Highlight selector(s)” in plugin settings (e.g. set the option value to .menu-item a).

The script works best when your sections have the same height (or width for horizontal layouts) as the viewport, which is something that most page layouts with this kind of functionality have.

Extending the script with touch events (optional)

If you want to have the same functionality in touch-devices, you can extend the script above like this:

(function($){
  $(window).on("load",function(){

    if(!$(document).data("mPS2id")){
      console.log("Error: 'Page scroll to id' plugin not present or activated. Please run the code after plugin is loaded.");
      return;
    }

    $(document).data("mPS2idExtend",{
      selector:"._mPS2id-h",
      currentSelector:function(){
        return this.index($(".mPS2id-highlight-first").length ? $(".mPS2id-highlight-first") : $(".mPS2id-highlight"));
      },
      input:{y:null,x:null},
      i:null,
      time:null
    }).on("scrollSection",function(e,dlt,i){
      var d=$(this).data("mPS2idExtend"),
        sel=$(d.selector);
      if(!$("html,body").is(":animated")){
        if(!i) i=d.currentSelector.call(sel);
        if(!(i===0 && dlt>0) && !(i===sel.length-1 && dlt<0)) sel.eq(i-dlt).trigger("click.mPS2id");
      }
    }).on("keydown",function(e){ //keyboard
      var code=e.keyCode ? e.keyCode : e.which,
        keys=$(this).data("mPS2id").layout==="horizontal" ? [37,39] : [38,40];
      if(code===keys[0] || code===keys[1]){
        if($($(this).data("mPS2idExtend").selector).length) e.preventDefault();
        $(this).trigger("scrollSection",(code===keys[0] ? 1 : -1));
      }
    }).on("pointerdown touchstart",function(e){ //touch (optional)
      var o=e.originalEvent,
        d=$(this).data("mPS2idExtend");
      if(o.pointerType==="touch" || e.type==="touchstart"){
        var y=o.screenY || o.changedTouches[0].screenY;
        d.input.y=y;
        if($(this).data("mPS2id").layout==="horizontal"){
          var x=o.screenX || o.changedTouches[0].screenX;
          d.input.x=x;
        }
        d.time=o.timeStamp;
        d.i=d.currentSelector.call($(d.selector));
      }
    }).on("touchmove",function(e){
      if($("html,body").is(":animated")) e.preventDefault();
    }).on("pointerup touchend",function(e){
      var o=e.originalEvent;
      if(o.pointerType==="touch" || e.type==="touchend"){
        var y=o.screenY || o.changedTouches[0].screenY,
          d=$(this).data("mPS2idExtend"),
          diff=d.input.y-y,
          time=o.timeStamp-d.time,
          i=d.currentSelector.call($(d.selector));
        if($(this).data("mPS2id").layout==="horizontal"){
          var x=o.screenX || o.changedTouches[0].screenX,
            diff=d.input.x-x;
        }
        if(Math.abs(diff)<2) return;
        var _switch=function(){
            return time<200 && i===d.i;
          };
        $(this).trigger("scrollSection",[(diff>0 && _switch() ? -1 : diff<0 && _switch() ? 1 : 0),(_switch() ? d.i : i)]);
      }
    });

    //mousewheel (https://github.com/jquery/jquery/issues/2871)
    var supportsWheel=false;
    function wheel(e){
      if (e.type == "wheel") supportsWheel = true;
        else if (supportsWheel) return;
      if($($(document).data("mPS2idExtend").selector).length) e.preventDefault();
      $(document).trigger("scrollSection",((e.detail<0 || e.wheelDelta>0 || e.deltaY < 0 || e.deltaX < 0) ? 1 : -1));
    };
    document.addEventListener('wheel', wheel, {passive: false}, false);
    document.addEventListener('mousewheel', wheel, {passive: false}, false);
    document.addEventListener('DOMMouseScroll', wheel, {passive: false}, false);

  });
})(jQuery);

You should also add the following rule to your stylesheet:

body{ -ms-touch-action: none; touch-action: none; }

Please note that using such functionality with touch devices can be (very) tricky and might not work exactly the same across all devices, browsers etc. A good way would be to keep such behavior for mouse and keyboard and let touch devices scroll the page normally.

Auto-generating aside bullet indicators (optional)

If you see the script demo, in addition to the main navigation menu, you’ll notice few bullets at the right which act as links and visual indicators of the sections. You can create those by hand or you can use a small function like this:

$("body").append("<div id='sections-bullets' />").find($(document).data("mPS2idExtend").selector).each(function(){
  $("#sections-bullets").append("<a href='"+$(this).attr("href")+"' class='section-bullet' rel='m_PageScroll2id'></a>");
});

This should be placed within the window load function:

(function($){
  $(window).on("load",function(){

    //the script above goes here...

    //still inside window load we add the function that auto-generates the bullets 
    $("body").append("<div id='sections-bullets' />").find($(document).data("mPS2idExtend").selector).each(function(){
      $("#sections-bullets").append("<a href='"+$(this).attr("href")+"' class='section-bullet' rel='m_PageScroll2id'></a>");
    });

  });
})(jQuery);

If you need help or the code customized for some specific layout let me know in the comments or contact me.

 

Page scroll to id

Page scroll to id is an easy-to-use jQuery plugin that enables animated page scrolling to specific id within the document. The plugin replaces the default browser behaviour of “jumping” to page sections when links with href value containing hash (#) are clicked, by smoothly animating the page to those sections. You can use it for simple back-to-top links or complex, single-page website navigation and features include: adjustable animation speed, advanced animation easings, vertical and/or horizontal scrolling, ready-to-use classes for links highlighting etc.

css.php