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

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.

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("mousewheel DOMMouseScroll",function(e){ //mousewheel
      if($($(this).data("mPS2idExtend").selector).length) e.preventDefault();
      $(this).trigger("scrollSection",((e.originalEvent.detail<0 || e.originalEvent.wheelDelta>0) ? 1 : -1));
    }).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));
      }
    });

  });
})(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("mousewheel DOMMouseScroll",function(e){ //mousewheel
      if($($(this).data("mPS2idExtend").selector).length) e.preventDefault();
      $(this).trigger("scrollSection",((e.originalEvent.detail<0 || e.originalEvent.wheelDelta>0) ? 1 : -1));
    }).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)]);
      }
    });

  });
})(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 code...

    //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.

 


41 Comments

Post a comment
  1. Nick
    Posted on October 18, 2017 at 05:23 Permalink

    Hey mate, curious whether what I’m trying to achieve is possible:

    1. I have the home page with various “block-like” sections going down the page.
    2. They aren’t in the menu in any way.
    3. I would like to have my mouse scrolling stop at the top of the section for a bit. Kind of a hold? Some of my sections are larger than a full page so I don’t really want to make each movement of the mousewheel go to a new section (but if that’s the only option then happy to make the changes to get it working) – I’m mostly after the snapping effect.

    Does this sound possible?

    Reply
  2. Arkadiusz
    Posted on October 7, 2017 at 16:25 Permalink

    Hello,

    Is it possible to scroll containers longer than viewport height?
    Like here in section “Options” (#options):
    https://projects.lukehaas.me/scrollify/

    Reply
    • malihu
      Posted on October 7, 2017 at 19:46 Permalink

      Hi,

      No, it’s not possible with this script.

      Reply
  3. Haripal
    Posted on September 11, 2017 at 10:06 Permalink

    Sir, i have added keyborad and mousewheel code to my website. It worked well. But when i add touch event code it stopped working. Please let me know how can i solve this.

    Reply
  4. Weisen
    Posted on August 20, 2017 at 22:00 Permalink

    Hi Malihu,

    Good Day! Will the code above work even if I don’t add the classes on the menu?

    For example I just wanted the elements on just my homepage to scroll and menu links on top lead to different pages?

    I’m using uncode theme but I don’t think they have the scroll to section functionality which your plugin can provide.

    Thank you!

    Reply
  5. Vektor
    Posted on August 6, 2017 at 03:36 Permalink

    Hi Malihu!

    I have a serious problem with this (sorry for my ignorance and english, i’m spanish designer).

    Everything works fine, but don’t work with mousewheel and i don’t understan why. Can you iluminate me please?

    Really thanks!

    Reply
    • malihu
      Posted on August 6, 2017 at 12:42 Permalink

      The js code you added is not correct. Change the lines at the start:

      jQuery(document).ready(function($){ $(window).on("load",function(){

      with:

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

      Reply
      • Vektor
        Posted on August 7, 2017 at 03:53 Permalink

        First, thanks for reply! I changed that code and still don’t work. Anything more for helping me please?

        Reply
        • malihu
          Posted on August 7, 2017 at 12:51 Permalink

          The page at vektorlab.com/testscroll/ works well for me. Did you fix the issue?

          Reply
          • Vektor
            Posted on August 7, 2017 at 12:57 Permalink

            you are right! The problem is i’m working with firefox and don’t work with firefox 54.0.1. Work in chrome and iexplore. Do you know why? Really really thanks

    • malihu
      Posted on August 7, 2017 at 13:18 Permalink

      Try removing the following classes from your links:

      __mPS2id _mPS2id-h mPS2id-clicked mPS2id-highlight mPS2id-highlight-first

      and also the following from your targets:

      _mPS2id-t mPS2id-target mPS2id-target-first mPS2id-target-last

      All the classes above are added by the plugin automatically, so you should not add them manually.

      Also, remove the code below as you already loading the jQuery library in your HTML head tag

      <!-- Google CDN jQuery with fallback to local --> <script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="js/jquery-3.1.0.min.js"><\/script>')</script>

      Reply
  6. Jaap de Wit
    Posted on July 25, 2017 at 18:44 Permalink

    Hi,

    I’ve installed the plugin and placed the custom code for scrolling to next section with mouse in the theme’s custom code section (header).
    But it’s not working. I’m using the Divi theme.

    Your older code which I found in https://wordpress.org/support/topic/scroll-with-mouse-to-id-possible/ works for some part.

    Any idea? (website is in maintenance, I can disable it for some period, let me know)

    Cheers,
    Jaap

    Reply
    • malihu
      Posted on August 6, 2017 at 12:46 Permalink

      I can’t really help unless I see your page, so let me know when you disable maintenance.

      Reply
      • Jaap
        Posted on August 29, 2017 at 09:58 Permalink

        Hi,

        Maintenance is disabled. You can check. WP plugin is enabled and I’ve placed the extended script in the header.

        Cheers,
        Jaap

        Reply
        • malihu
          Posted on August 31, 2017 at 21:17 Permalink

          It seems that all page scripts are using the defer attribute which affects when js code is executed. Try adding the custom/extended script in an external .js file and include it at the bottom of your document.

          Reply
          • Jaap
            Posted on September 8, 2017 at 09:57 Permalink

            Hi Malihu,

            Thanks for your answer. I’ve placed the script in a separate js file and am calling it from the footer.php. Still doesn’t work though. Any more ideas?

            Cheers,
            Jaap

          • Jaap
            Posted on September 14, 2017 at 13:09 Permalink

            Hi Malihu,

            Hope you have some time to check. My customer really likes this functionality and wants to have it work.
            Cheers,
            Jaap

        • malihu
          Posted on September 15, 2017 at 21:42 Permalink

          I’ve just checked it again. Try adding defer to the script (like the other scripts in your page):

          <script src="path/to/scroll.js" defer></script>

          Reply
          • Jaap
            Posted on September 17, 2017 at 11:42 Permalink

            Hi, I’ve tried adding ‘defer’ but then scrolling down is no longer possible. Only through menu items. When scrolling up it’s scrolls all the way to the top.

        • malihu
          Posted on September 17, 2017 at 16:04 Permalink

          OK first, you need to use defer

          Second, it seems that you have a duplicate of each section/link. One for desktop and one for mobile. The duplicated links are all on the same menu element with no way to identify them.

          The issue is that the script cannot work with the desktop and mobile links in the same menu element. I’m not sure if you can change this(?)

          Reply
          • Jaap
            Posted on September 18, 2017 at 11:33 Permalink

            Hi Malihu,

            I’ve managed to get it working on desktop by removing the section id’s from the mobile sections. I also need to get it working on tablet and mobile. How come it doesn’t since the mobile id’s are different from the desktop ones? Breaking my head here πŸ™‚

            Cheers,
            Jaap

          • Jaap
            Posted on September 18, 2017 at 16:22 Permalink

            Hi Malihu,

            Almost there! I managed to solve the problem with desktop/mobile. The scroll is working nog on all devices. The only thing I see is that sometimes when scrolling it skips a section. Any idea how to fix that?

            Cheers,
            Jaap

        • malihu
          Posted on September 19, 2017 at 19:08 Permalink

          Glad you solved the issue. I can’t really say why it might skip a section. Do you have a special mouse or?

          I’ve tested your page extensively with standard mouse-wheel (normal wheel notch), spin-scroll mousewheel (logitech hyper-scroll) and trackpad (2 finger gesture) and it never missed a section for me.

          Keep in mind though that if you use for instance trackpad or spin-scroll acceleration, the sections will continue to scroll untill the wheel/gesture is stopped.

          Reply
          • Jaap
            Posted on September 19, 2017 at 21:15 Permalink

            Hi Malihu,

            Thanks for your answer. I’m using an Apple magic mouse but scrolling with the trackpad also skip sections. (chrome and safari)

            I also found out that when using the script with touch events scrolling on other pages than the homepage is no longer possible on all Samsung devices.

            Removing this line: “body{ -ms-touch-action: none; touch-action: none; }” solves that issue.

            Cheers,
            Jaap

        • malihu
          Posted on September 20, 2017 at 19:16 Permalink

          If you have other pages that you want to scroll normally, you need to change the CSS to:

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

          so it applies only on homepage.

          Apple magic devices use scrolling acceleration that’s very sensitive. A section might get skipped even when you touch-swipe with minimum force. I’m guessing this is the case(?)

          Reply
  7. John
    Posted on June 24, 2017 at 14:07 Permalink

    Hi Malihu,

    Thanks for your great plugin and all your work. I’m trying to get this extension of ps2id work but with little success. Everything seems fine from my side but somehow no bullets appear and no keyboard/mouse scrolling is possible.

    Could you possibly offer a hand? The test site I’m working on is here.

    Thanks in advance.

    J.

    Reply
    • John
      Posted on June 24, 2017 at 18:09 Permalink

      John here again,

      Just a quick update. I got the scroll with mouse and keyboard to work after all. It was my mistake.

      The only two issues now are the bullet points not appearing and also a strange jump from the 1st to the 3rd section and back. The other two sections are being ignored.

      Any help will be appreciated,
      Thanks.

      Reply
      • malihu
        Posted on June 25, 2017 at 02:37 Permalink

        Hello,

        In one of your widgets (I think a section-2 link), you’ve set the class _mPS2id-h by hand. Remove it and test again the page.

        The problem comes from those next/previous widget links so first try the above to see if this fixes the issue (I’ve made a live test by removing the next/previous widget links and mousewheel works as expected without skipping sections).

        The bullets are appended in your page. You just need to style them so they appear over your content. For example:

        /* aside indicators */ #sections-bullets{ position: fixed; right: 2em; height: auto; top: 50%; transform: translateY(-50%); z-index: 99; } .section-bullet{ display: block; position: relative; width: 9px; height: 9px; border-radius: 100%; background: #fff; margin: 12px auto; opacity: .6; } .section-bullet:hover, .section-bullet.mPS2id-highlight{ opacity: 1; background: #e6842c; }

        You also have a js console error, because you’ve wrapped the js code in jQuery(document).ready(function($){ ... })(jQuery); which is not correct. The code should be wrapped in (function($){ ... })(jQuery);, exactly as shown in the post above.

        Reply
        • John
          Posted on June 28, 2017 at 19:12 Permalink

          Hi again Malihu,

          Thanks for the reply, extremely helpful.

          You were right about the unnecessary class, it’s removed. I fixed the console error also, I was prompted by the plugin I use to add scripts to form it this way. However the jumping behaviour persists. Scrolling up from section-1 leads to section-3 and scrolling down from s-3 takes me back to s-1. All other navigation is ignored. I’ve run through everything again but I don’t get it.

          By the way, the next/previous links are necessary for the designer and I can’t do without them. I knew already that the scrolling is smooth without them but I think I can’t drop them. Any other ideas would be helpful otherwise I’ll have to chose between the two.

          And thanks for the bullets too. they were there, I never thought of simply styling them.

          Thanks a million,
          John

          Reply
          • malihu
            Posted on June 29, 2017 at 05:34 Permalink

            No need to choose between the two. We’ll make it work πŸ˜‰

            Go to plugin settings and set the value of “Highlight selector(s)” option to:

            .menu-item a[href*='#']

            Save changes and test your page again.

            See also the last point in my previous comment. You have inserted the js custom script in:

            jQuery(document).ready(function($){ //custom script here... })(jQuery);

            which is not correct. You need to change it to:

            (function($){ //custom script here... })(jQuery);

            Let me know

          • John
            Posted on June 29, 2017 at 17:12 Permalink

            Hi again,

            Genius! That solved it, so cool.

            The custom js script I had corrected the previous time, just didn’t explain it well in my previous message. The new Highlight selector did the trick.

            Thanks so much M., amazing stuff.

            John

          • malihu
            Posted on June 29, 2017 at 20:25 Permalink

            Cool πŸ™‚ Glad I helped!

  8. Manuel
    Posted on May 27, 2017 at 06:32 Permalink

    How to select specifics pages for the script work in some pages and others don’t work.

    Reply
    • malihu
      Posted on May 29, 2017 at 21:44 Permalink

      If you’re using WordPress, you should insert the js script in conditional tags.

      If not, simply insert the script only in the pages you want.

      Keep in mind that in order for such scripts to work, you need specific page layout/design (like the one in the demo).

      Reply
  9. Elzbieta
    Posted on March 22, 2017 at 22:16 Permalink

    Hello.
    This script is awesome. How can I add this to my joomla on gantry framework website?

    Reply
    • malihu
      Posted on March 22, 2017 at 22:38 Permalink

      This is a standard javascript/jQuery script, so you’d add it just like any other js script in your page or template.
      I’m not familiar with gantry and I rarely work with joomla so I can’t really say how/where to add it. You should ask this on joomla/gantry forums or perhaps Google “how to add js script in joomla” for a tutorial.

      Reply
    • Elzbieta
      Posted on March 22, 2017 at 23:00 Permalink

      I just send You an email. Will You help?

      Reply
      • malihu
        Posted on March 22, 2017 at 23:22 Permalink

        Check your email πŸ™‚

        Reply
  10. z
    Posted on January 12, 2017 at 12:26 Permalink

    i was trying to do mousewheel scroll from one row to another in wordpress, im using page to id scroll plugin + i have put the Jquery script in the footer but i cannot seem to make it scroll to sections,
    can you post here the settings you have set up in the settings page on page scroll to ID and what class names should i put in the row class and row id, i have no section id and section class i can only work with row id and row class, hit me up on email (admin: edited email address)

    Reply
    • malihu
      Posted on January 12, 2017 at 15:48 Permalink

      No special settings needed. Send me your link so I can check it.

      Reply

Post a comment

Your e-mail is never published nor shared. Required fields are marked *

You may use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
You can write or copy/paste code directly in your comment using the <code> tag:
<code>code here...</code>
You may also use the data-lang attribute to determine the code language like so:
<code data-lang-html>, <code data-lang-css>, <code data-lang-js> and <code data-lang-php>

css.php