Menu Search
Jump to the content X X
Smashing Conf Barcelona

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

How I Built The One Page Scroll Plugin

Scrolling effects have been around in web design for years now, and while many plugins are available to choose from, only a few have the simplicity and light weight that most developers and designers are looking for. Most plugins I’ve seen try to do too many things, which makes it difficult for designers and developers to integrate them in their projects.

Further reading on Smashing: Link

Not long ago, Apple introduced the iPhone 5S, which was accompanied by a presentation website6 on which visitors were guided down sections of a page and whose messaging was reduced to one key function per section. I found this to be a great way to present a product, minimizing the risk of visitors accidentally scrolling past key information.

I set out to find a plugin that does just this. To my surprise, I didn’t find a simple solution to integrate in my current projects. That is when One Page Scroll was born.

What Is One Page Scroll? Link

One Page Scroll is a jQuery plugin that enables you to create a single-scroll layout for a group of sections on a page with minimal markup.

I will explain how I built this plugin, right from its inception through to planning, testing and finally putting the code out there for free.

Note: Before building this plugin, I was aware of the controversy over “scroll-hijacking,” whereby a website overrides the native scrolling behavior of the browser to create its own interaction, which confuses some visitors. One Page Scroll would inevitably go against this principle, so I decided to come up with ways to ease the frustration. One good thing about the plugin is that developers may set a fallback that reverts scrolling from its “hijacked” state to its native behavior for certain screen sizes. This way, developers can maintain the high performance and quality of their websites on low-power devices, such as smartphones and tablets. Other than that, you can also control the length of the animation that takes the visitor from one section to the next, thus allowing you to avoid the slow transition seen on Apple’s iPhone 5S website7.

What Is Its Purpose? Link

As mentioned, most of the plugins that I found offer way too many unnecessary features, making them difficult to integrate. The purpose of this plugin is to solve this issue. The plugin had to:

  • be simple to use,
  • be easy to integrate,
  • require minimal markup,
  • do one thing well (i.e. scroll a page the way the iPhone 5S website does).

1. To The Drawing Board Link

I started by visualizing the plugin as a whole. It should enable visitors to scroll through each section of the page individually. To do that, I needed a way to disable the browser’s default scrolling behavior, while stacking each section in order and moving the page manually when the scrolling is triggered.

Visualize either in your mind or in sketches.8
Visualize either in your mind or in sketches. (View large version9)

After that, I broke the concept down into small tasks, trying to come up with a solution to each task in my mind. Here is a list of the functions and tasks that I came up with:

  1. Prepare the layout and position the sections.
    Disable the browser’s default scrolling behavior with CSS by applying overflow: hidden to the body tag. Position each section in sequence, while calculating and attaching all of the necessary information and classes.
  2. Set the manual scrolling trigger.
    Detect the scrolling trigger using jQuery, and then determine the direction, and then move the layout using CSS.
  3. Add features.
    Add responsiveness, looping, mobile swipe support, pagination, etc.
  4. Test across browsers.
    Make sure the plugin runs fine in all modern browsers (Chrome, Safari, Firefox, Internet Explorer 10) and on the most popular operating systems (Windows, Mac OS X, iOS and Android 4.0+).
  5. Open-source the plugin.
    Create a new repository, structuring it and writing instructions on how to use the plugin.
  6. Widen support.
    Explore other ways to increase support of the plugin.

2. Building The Foundation Link

Now that I had visualized the whole concept, I began to build the plugin with this template:

!function($) {

   var defaults = {
      sectionContainer: "section",

   $.fn.onepage_scroll = function(options) {
      var settings = $.extend({}, defaults, options);


The template starts off with a !function($) { … }($) module, which provides local scoping to the global variable for jQuery. The purpose of this function is to reduce the overhead for the jQuery lookup ($) and prevent conflicts with other JavaScript libraries.

The defaults variable at the top holds the default options for the plugin. So, if you don’t define any options, it will fallback to these values.

The $.fn.onepage_scroll function is the main function that initiates everything. Don’t forget to replace onepage_scroll with your own function name if you are creating your own.

Disabling the scrolling behavior can be done easily by adding overflow: hidden to the body tag via CSS through a plugin-specific class name. Coming up with a plugin-specific class naming convention is important to avoid conflicts with existing CSS styles. I usually go with an abbreviation of the plugin’s name, followed by a hyphen and a descriptive word: for example, .onepage-wrapper.

Now that all of the fundamentals are laid out properly, let’s build the first function.

3. Prepare The Layout And Position The Sections Link

Let’s get to the most interesting part: working out the calculation and instantly dropping all of my effort later in the process. I thought I needed to position each section in sequence by looping through each one and then positioning them, so that they do not overlap with each other. Here’s the snippet I came up with:

var sections = $(settings.sectionContainer);
var topPos = 0;

$.each(sections, function(i) {
      position: "absolute",
      top: topPos + "%"
   }).addClass("ops-section").attr("data-index", i+1);
   topPos = topPos + 100;

This snippet loops through each presented selector (sectionContainer is defined in the defaults variable), applies position: absolute and assigns each one with the correct top position that it needs to align properly.

The top position is stored in the topPos variable. The initial value is 0 and increases as it loops through each one. To make each section a full page and stack up correctly, all I had to do was set the height of each section to 100% and increase the topPos variable by 100 every time it loops through a section. Now, each section should stack up correctly, while only the first section is visible to visitors.

This might seem easy, but it took me a couple of hours to implement and to see how reliable it is, only to realize in the next step that I did not need any of this at all.

4. Manual Trigger And Page Transformation Link

You might think that the next step would be to move each section to its new position when the scrolling is triggered — I thought so, too. As it turns out, there is a better solution. Instead of moving every single section every time the user scrolls, which would require another loop through and another calculation, I wrapped all of the sections in one container and used CSS3’s translate3d to move the whole wrapper up and down. Because translate3d supports percentage-based values, we can use our previous top position calculation to move each section into the viewport without having to recalculate it. Another benefit is that this gives you control over the timing and easing settings of your animation.

As you may have noticed, this solution makes the positioning snippet illustrated in the previous step unnecessary because the wrapper that we’ve introduced makes each section stack up correctly without any extra styling required.

The first solution you come up with is not always the most efficient, so make sure to leave time for experimentation.10
The first solution you come up with is not always the most efficient, so make sure to leave time for experimentation. (View large version11)

Now, all we have to do is detect the direction of the user’s scrolling and move the wrapper accordingly. Here’s the code to detect the scrolling direction:

function init_scroll(event, delta) {
   var deltaOfInterest = delta,
   timeNow = new Date().getTime(),
   quietPeriod = 500;
   // Cancel scroll if currently animating or within quiet period
   if(timeNow - lastAnimation < quietPeriod + settings.animationTime) {

   if (deltaOfInterest < 0) {
   } else {
   lastAnimation = timeNow;

$(document).bind('mousewheel DOMMouseScroll', function(event) {
   var delta = event.originalEvent.wheelDelta || -event.originalEvent.detail;
   init_scroll(event, delta);

In the snippet above, first I bind a function to the mousewheel event (or DOMMouseScroll for Firefox), so that I can intercept the scrolling data to determine the direction of the scrolling. By binding my own init_scroll function in these events, I’m able to pass the available wheelData to init_scroll and detect the direction.

In a perfect world, all I would have to do to detect and move each section is retrieve the delta from the wheelData variable, use the value to determine the direction and perform the transformation. That, however, is not possible. When you are dealing with a sequencing animation, you must create a fail-safe to prevent the trigger from doubling, which would cause the animation to overlap. We can use setInterval to sort this problem out by calling each animation individually, with its own time set apart to create a sequence. But for precision and reliability, setInterval falls short because each browser handles it differently. For example, in Chrome and Firefox, setInterval is throttled in inactive tabs, causing the callbacks not to be called in time. In the end, I decided to turn to a timestamp.

var timeNow = new Date().getTime(),
quietPeriod = 500;
if(timeNow - lastAnimation < quietPeriod + settings.animationTime) {
lastAnimation = timeNow;

In the snippet above (extracted from the previous one), you can see that I have assigned the current timestamp to the timeNow variable before the detection, so that it can check whether the previous animation has performed for longer than 500 milliseconds. If the previous animation has performed for less than 500 milliseconds, then the condition would prevent the transformation from overlapping the ongoing animation. By using a timestamp, instead of setInterval, we can detect the timing more accurately because the timestamp relies on the global data.

if (deltaOfInterest < 0) {
} else {

The moveUp and moveDown are functions that change all attributes of the layout to reflect the current state of the website. Data such as the current index, the name of the current section’s class and so on are added in these functions. Each of these functions will call the final transform method to move the next section into the viewport.

$.fn.transformPage = function(settings, pos, index) {
      "-webkit-transform": ( settings.direction == 'horizontal' ) ? "translate3d(" + pos + "%, 0, 0)" : "translate3d(0, " + pos + "%, 0)",
      "-webkit-transition": "all " + settings.animationTime + "ms " + settings.easing,
      "-moz-transform": ( settings.direction == 'horizontal' ) ? "translate3d(" + pos + "%, 0, 0)" : "translate3d(0, " + pos + "%, 0)",
      "-moz-transition": "all " + settings.animationTime + "ms " + settings.easing,
      "-ms-transform": ( settings.direction == 'horizontal' ) ? "translate3d(" + pos + "%, 0, 0)" : "translate3d(0, " + pos + "%, 0)",
      "-ms-transition": "all " + settings.animationTime + "ms " + settings.easing,
      "transform": ( settings.direction == 'horizontal' ) ? "translate3d(" + pos + "%, 0, 0)" : "translate3d(0, " + pos + "%, 0)",
      "transition": "all " + settings.animationTime + "ms " + settings.easing

Above is the transform method that handles the movement of each section. As you can see, I’ve used the CSS3 transformation to handle all of the manipulation with JavaScript. The reason I did this in JavaScript, rather than in a separate style sheet, is to allow developers to configure the behavior of the plugin — mainly the animation’s timing and easing — through their own function calls, without having to go into a separate style sheet and dig for the settings. Another reason is that the animation requires a dynamic value to determine the percentage of the transition, which can only be calculated in JavaScript by counting the number of sections.

5. Additional Features Link

I was reluctant to add features at first, but having gotten so much great feedback from the GitHub community, I decided to improve the plugin bit by bit. I released version 1.2.1, which adds a bunch of callbacks and loops and, hardest of all, responsiveness.

In the beginning, I didn’t focus on building a mobile-first plugin (which I still regret today). Rather, I used a simple solution (thanks to Eike Send12 for his swipe events) to detect and convert swipe data into usable delta data, in order to use it on my init_scroll function. That doesn’t always yield the best result in mobile browsers, such as custom Android browsers, so I ended up implementing a fallback option that lets the plugin fall back to its native scrolling behavior when the browser reaches a certain width. Here’s the script that does that:

var defaults = {
   responsiveFallback: false

function responsive() {
   if ($(window).width() < settings.responsiveFallback) {
      $(document).unbind('mousewheel DOMMouseScroll');
      el.swipeEvents().unbind("swipeDown swipeUp");
   } else {
      if($("body").hasClass("disabled-onepage-scroll")) {
         $("html, body, .wrapper").animate({ scrollTop: 0 }, "fast");

      el.swipeEvents().bind("swipeDown",  function(event) {
         if (!$("body").hasClass("disabled-onepage-scroll")) event.preventDefault();
      }).bind("swipeUp", function(event){
         if (!$("body").hasClass("disabled-onepage-scroll")) event.preventDefault();

      $(document).bind('mousewheel DOMMouseScroll', function(event) {
         var delta = event.originalEvent.wheelDelta || -event.originalEvent.detail;
         init_scroll(event, delta);

First, I’ve defined a default variable to activate this fallback. The responsiveFallback is used to determine when the plugin should trigger the fallback.

The snippet above will detect the browser’s width to determine whether the responsive function should run. If the width reaches the value defined in responsiveFallback, then the function will unbind all of the events, such as swiping and scrolling, return the user to the top of the page to prepare for realignment of each section, and then reenable the browser’s default scrolling behavior so that the user can swipe through the page as usual. If the width exceeds the value defined, then the plugin checks for a class of disabled-onepage-scroll to determine whether it has already been initialized; if it hasn’t, then it is reinitialized again.

The solution is not ideal, but it gives the option for designers and developers to choose how to handle their websites on mobile, rather than forcing them to abandon mobile.

6. Cross-Browser Testing Link

Testing is an essential part of the development process, and before you can release a plugin, you must make sure that it runs well on the majority of machines out there. Chrome is my go-to browser, and I always start developing in it. It has many benefits as one’s main development browser, but your personal preference might vary. For me, Chrome has a more efficient inspection tool. Also, when I get a plugin to work in Chrome, I know that it will probably also work in Safari and Opera as well.

I mainly use my Macbook Air to develop plugins, but I also have a PC at home to check across platforms. When I get a plugin to work in Chrome, then I’ll test manually in Safari, Opera and (lastly) Firefox on Mac OS X, followed by Chrome, Firefox and Internet Explorer (IE) 10 on Windows.

The reason I test only these browsers is that the majority of users are on them. I could have tested IE 9 and even IE 8, but that would have prevented me from releasing the plugin in time with the launch of the iPhone 5S website.

This is generally not a good practice, and I’ll avoid doing it in future. But the good thing about making the plugin open-source is that other developers can help patch it after its release. After all, the purpose of an open-source project is not to create the perfect product, but to create a jumping-off point for other developers to extend the project to be whatever they want it to be.

Don’t forget to test on mobile devices before launching your plugin.13
Don’t forget to test on mobile devices before launching your plugin. (View large version14)

To ease the pain of cross-browser testing, every time I complete a plugin, I’ll create a demo page to show all of the features of the plugin, and then I’ll upload it to my website and test it, before sharing the plugin on GitHub. This is important because it enables you to see how the plugin performs in a real server environment and to squash any bugs that you might not be able to replicate locally. Once the demo page is up and running on my website, I’ll take the opportunity to test the plugin on other devices, such as phones and tablets.

With these tests, you will have covered the vast majority of browsers out there and prepared the plugin for the real world.

7. Open-Sourcing Your Plugin Link

When you think the plugin is ready, the final step is to share it on GitHub. To do this, create an account on GitHub, set up Git15 and create a new repository16. Once that is done, clone the repository to your local machine. This should generate a folder with your plugin’s name on your local machine. Copy the plugin to the newly created folder and structure your repository.

Repository Structure Link

How you structure your repository is all up to you. Here’s how I do it:

  • The demo folder consists of working demos, with all required resources.
  • The minified and normal versions of the plugin are in the root folder.
  • The CSS and sample resources, such as images (if the plugin requires it), are in the root folder.
  • The readme file is in the root directory of the generated folder.

Readme Structure Link

Another important step is to write clear instructions for the open-source community. Usually, all of my instructions are in a readme file, but if yours require a more complex structure, you could go with a wiki page on GitHub. Here is how I structure my readme:

  1. Introduction
    I explained the purpose of the plugin, accompanied by an image and a link to the demo.
  2. Requirements and compatibility
    Put this up front so that developers can see right away whether they’ll want to use the plugin.
  3. Basic usage
    This section consists of step-by-step instructions, from including the jQuery library to adding the HTML markup to calling the function. This section also explains the options available for developers to play with.
  4. Advanced usage
    This section contains more complex instructions, such as any public methods and callbacks and any other information that developers would find useful.
  5. Other resources
    This section consists of links to the tutorial, credits, etc.

8. Widening Support Link

This plugin doesn’t really need the jQuery library to do what it does, but because of the pressure to open-source it in time for the iPhone 5S website, I decided to take a shortcut and rely on jQuery.

To make amends, and exclusively for Smashing Magazine’s readers, I have rebuilt One Page Scroll using pure JavaScript (a Zepto version is also available). With the pure JavaScript version, you no longer need to include jQuery. The plugin works right out of the box.

Pure JavaScript And Zepto Version Link

Rebuilding the Plugin in Pure JavaScript Link

The process of building support for libraries can seem daunting at first, but it’s much easier than you might think. The most difficult part of building a plugin is getting the math right. Because I had already done that for this one, transforming the jQuery plugin into a pure JavaScript one was just a few hours of work.

Because the plugin relies heavily on CSS3 animation, all I had to do was replace the jQuery-specific methods with identical JavaScript methods. Also, I took the opportunity to reorganize the JavaScript into the following standard structure:

  • Default variables
    This is essentially the same as the jQuery version, in which I defined all of the variables, including the default variables for options to be used by other functions.
  • Initialize function
    This function is used for preparing and positioning the layout and for the initialization that is executed when the onePageScroll function is called. All of the snippets that assign class names, data attributes and positioning styles and that bind all keyboard inputs reside here.
  • Private methods
    The private method section contains all of the methods that will be called internally by the plugin. Methods such as the swipe events, page transformation, responsive fallback and scroll detection reside here.
  • Public methods
    This section contains all of the methods that can be called manually by developers. Methods such as moveDown(), moveUp() and moveTo() reside here.
  • Utility methods
    This section contains all of the helpers that replicate a jQuery function to speed up development time and slim down the JavaScript’s file size. Helpers such as Object.extend, which replicates the jQuery.extend function, reside here.

I ran into some annoyances, such as when I had to write a method just to add or remove a class name, or when I had to use document.querySelector instead of the simple $. But all of that contributes to a better, more structured plugin, which benefits everyone in the end.

Rebuilding the Plugin in Zepto Link

The reason why I decided to support Zepto, despite the fact that it only supports modern browsers (IE 10 and above), is that it gives developers a more efficient and lightweight alternative to jQuery version 2.0 and above, with a more versatile API. Zepto’s file size (around 20 KB) is considerably lower than jQuery 2.0’s (around 80 KB), which makes a big difference in page-loading speed. Because websites are being accessed more on smartphones, Zepto might be a better alternative to jQuery.

Rebuilding a jQuery plugin with Zepto is a much easier task because Zepto is similar to jQuery in its approach to the API, yet faster and more lightweight. Most of the script is identical to the jQuery version except for the animation part. Because Zepto’s $.fn.animate() supports CSS3 animation and the animationEnd callback right off the bat, I can take out this ugly snippet:

   "-webkit-transform": "translate3d(0, " + pos + "%, 0)",
   "-webkit-transition": "-webkit-transform " + settings.animationTime + "ms " + settings.easing,
   "-moz-transform": "translate3d(0, " + pos + "%, 0)",
   "-moz-transition": "-moz-transform " + settings.animationTime + "ms " + settings.easing,
   "-ms-transform": "translate3d(0, " + pos + "%, 0)",
   "-ms-transition": "-ms-transform " + settings.animationTime + "ms " + settings.easing,
   "transform": "translate3d(0, " + pos + "%, 0)",
   "transition": "transform " + settings.animationTime + "ms " + settings.easing
$(this).one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(e) {
   if (typeof settings.afterMove == 'function') settings.afterMove(index, next_el);

And I’ve replaced it with this:

      translate3d: "0, " + pos + "%, 0"
   }, settings.animationTime, settings.easing, function() {
      if (typeof settings.afterMove == 'function') settings.afterMove(index, next_el);

With Zepto, you can animate with CSS3 without having to define all of the CSS styles or bind the callback yourself. Zepto handles all of that for you through the familiar $.fn.animate() method, which works similar to the $.fn.animate() method in jQuery but with CSS3 support.

Why Go Through All the Trouble? Link

Because jQuery has become many people’s go-to library, it has also become increasingly complex and clunky and at times performs poorly. By providing versions for other platforms, you will increase the reach of your plugin.

Going back to the foundation will also help you to build a better, more compliant plugin for the future. jQuery and other libraries are very forgiving of minor structural problems, like missing commas and $(element) — the kinds of things that have made me a little lazy and could compromise the quality of my plugins. Without all of these shortcuts in pure JavaScript, I was more aware of what’s going on in my plugin, which methods are affecting performance and what exactly I can do to optimize performance.

Even though JavaScript libraries such as jQuery have made our lives easier, using one might not be the most efficient way to accomplish your goal. Some plugins are better off without them.

Conclusion Link

There you have it, the process I went through to build One Page Scroll. I made many mistakes and learned from them along the way. If I were to develop this plugin today, I would focus more on mobile-first and would add more comments to the code so that other people would be able to extend the plugin more easily.

Without the support of design and development communities such as GitHub, StackOverflow and, of course, Smashing Magazine, I wouldn’t have been able to create this plugin in such a short time. These communities have given me so much in the past few years. That is why One Page Scroll and all of my other plugins19 are open-source and available for free. That’s the best way I know how to give back to such an awesome community.

I hope you’ve found this article useful. If you are working on a plugin of your own or have a question or suggestion, please feel free to let us know in the comments below.

Resources Link

(al, il, ml)

Footnotes Link

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24

↑ Back to top Tweet itShare on Facebook

Pete Rojwongsuriya is a Bangkok-based entrepreneur, freelance UI designer, and a Rails developer. He is passionate about design, startups, and travel. He is the founder of Travelistly, BucketListly, and The Pete Design. He also blogs regularly at BucketListly Blog and give away free open source plugins on Github.

  1. 1

    This looks cool. If I could suggest an improvement — make the space-bar work for paging down. That’s how many people scroll down on desktops/laptops.

    • 2

      Thank you for the suggestion Klark. That’s a great idea. I’ll see what I can do to add that in the next release.

      If you don’t mind, feel free to add your suggestion on the Github repo ( :)

      I have to start clearing the issues up at some point. :/

    • 3

      Hey Klark. Good news! I just added the support for space bar key in the new version 1.3.1! Let me know if that works for you. :)

    • 4

      I highly doubt that “many” people use the spacebar for scrolling.

      • 5

        Ha! I love that you’ve got 18 downvotes on this. I agree with you, but also think that “many” of the people reading an article about a one page scroll plugin, probably do use spacebar to scroll, even though the majority of users of the web don’t.

        One thing I hate is when I’m watching something on Youtube and want to pause it and I automatically tap spacebar twice (because it’s what I’m used to doing in other video players) and it scrolls me down to the comments while the video is still playing. I understand why it does it, but it’s something I still do often.

    • 6

      I would recommend you to use fullPage.js for that. It is much more complete in that regard. (space bar, shift + space bar, arrows, pageUp, pageDown)

  2. 7

    Lorenzo Pieri

    August 25, 2014 3:21 pm

    For your interest, it appears that APPLE doesn’t give a single f*** about users with JS disabled. It is true, they only amount to a 1% (even less) of the world internet population, but still, it would have been so simple to just add a few more lines to make it better for all users. Something like:

    $(window).ready(function( ){
    //rest of the script to make it look good.

    Possibily even smaller bit of code:

    $(..)… (fn(){
    //rest of the script to make it look good.

    Just saying.

  3. 10

    nice work!

  4. 12

    Great work Pete just downloaded it to have a fiddle under the bonnet myself and will let you know if I come up with something new not that it needs it

  5. 14

    Very nice plugin, Pete! Keep up the good work and thanks for sharing your process when it comes to developing something like this.

  6. 16

    I can’t image any other pupose for this than photo pages like a tumblr blog. This practise turns a website into hell if—like in most cases—the images don’t have the same hight. The elements jump and make other elements farther down jumping, the scrolling freezes. On a computer which scrolls through large Lightroom catalogs smootly. Just think what happens on normal computers.

    • 17

      I use a similar library to this on my site/blog

      Not really for a real purpose, it was just kinda interesting.

    • 18

      As mentioned in the intro, the plugin is great for when you want to show case your product while focusing on a single feature per slide, like what the iPhone 5S website did.

      I wouldn’t recommend using this plugin if you want something more complex. This plugin is just a faster way to create a simple presentation website. :)

  7. 19

    Very cool. What versions of IE does this NOT work in though? I work for a corporate website and we have to support IE8 still :(

  8. 24

    Great work!

    • 25

      Thank you Kay! Can’t wait to see what you will come up with using the plugin. :)

  9. 26

    Great plugin. Wish I bumped into this one before I used FullPage.js….

    • 27

      Haha, Thank you for the comment man. FullPage.js is also a capable plugin with lots of options. Mine is a little minimal. :)

      • 28

        Yeah, it is, but eg making a external nav also reflect slide changes (horizontal) and some other customisation turn out to be really painful (multiple callbacks being the result and more).
        Will maybe have to drop fullpage after about 16 hrs customization – i get nowhere near to where i want to go with fullpage.

        That’s the reason i arrived here, looking for alternatives, stable but easier to customize without having to wonder what now is triggered – or not triggered. FP’s really cool if you use it as.

        • 29

          A bit confusing, my comment. eg instead of “(multiple callbacks being the result and more)” i meant “(you have to deal with the multiple callbacks and more)”.
          Nevertheless i restarted my investigations on fullpage after having read your (this) howto 2 times in full. I am returining to it right now for another read as it really is extremely comprehensive.
          One more thank.
          And, yes, fp is no all-in-one solution, it’s a particular way of doing something the itunes site did. One (me) should’t forget.

  10. 30

    Thanks for the in-depth explanation! I really like how you showed your whole thought process from the beginning to re-iterating over the whole project.

    • 31

      No problem Petyr! That’s what I was aiming for when writing this article. :) Glad you like it.

  11. 32

    What a coincidence! I was looking for a onepage scrolling plugin yesterday. Today I’m checking my feeds and you just wrote something about it. ;-)

    I love the plugin, thank you for sharing it with us! The only thing I’m not sure about is the scrolling behaviour. (I checked the demo site before i’ve read this article.) Say I want to scroll back to the top real fast. The first time it felt wrong/random to me because it sometimes scrolled and sometimes not. Now I know it’s because of the timestamp and it makes absolutely sense from a technical point of view. But if you really want so scroll to the top real fast, it’s pretty annoying. Just wondering if there would be a solution for that?

    • 33

      Thank you for the comment Tommy! That’s a valid point. We do provide several ways for users to jump to the top faster. There’s a public method you can used $(“.main”).moveTo(1); which will let you jump to the top programatically. A sample use case would be a jump to top button using this public method.

      You can also fallback to using the pagination.

      I hope this helps. :)

  12. 34

    What’s the name of that paper you used in preparing your sketch?

  13. 37

    Scrolling Plugs are very good for blogs, but unfortunately *if you use ajax to request content on the fly on when the user scrolls down; because the tec uses a client side script to display content, the page will not do very well in Google indexing as the full page will not be requested by the Google Bot.

  14. 38

    Patrick Whitty-Clarke

    August 26, 2014 11:21 pm

    Hi Pete,

    Thanks for taking the time to explain in detail how you created the plugin.

    I was wondering, have you ever had a request for a 1:1 touch movement implementation of your plugin? What I mean is, on a touch device, if I touch and drag down part of the way up or down on the page, the “next page/section” scroll event is delayed until I release my finger. So, if I decide to change direction mid-swipe, as long as I start going up after having gone down (or vice versa), the section will not jump but will revert back to the original position. RoyalSlider does this and I think it just makes the whole UI feel a lot more responsive / nice.

    I hope you understand what I mean, I have yet to find a full page / one page site script that does this, or has it as an option.

    • 39

      Yes, that is something I am currently looking into. Although, this might require an overhaul so it will be a while. :) Thank you for the suggestion and the example.

  15. 40

    Like most scrolling fx it does not work well on an iPad. Nice all-CSS based full-height section alternative here:

  16. 41

    Hi, I’m a big fan of the plugin but I felt (this was a month or so back so it may be all sorted now) that the mobile support was lacking somewhat and didn’t work “out of the box” so to speak, and the mobile support was the main reason for wanting to use this plugin as others lacked this feature.

    Therefore I also wrote my own scroller plugin which I added in some other features such as nth body classes which I wanted for my own site. Fan of your work and I keep a keen eye on your repos!

  17. 43 did a good job with their “scroll-jacking” home page. There’s a lot of companies that could benefit from forced section scrolling… Not just “tumblr” as Helen mentions above. Think about the many companies that want to showcase all the products they offer and also rotate hierarchy.

  18. 44

    Denis Leblanc

    August 28, 2014 6:32 am

    This is really nice!!

    Though, if I can add 2 bits. I don’t like how it scrolls back to the top on the demo when you hit the bottom. It should just stop. Also, when scrolling up I’d rather have the default scroll instead of the hijacked version. Are these options in the plugin?

    Thanks so much. Looking forward to testing it out.

    • 45

      You can stop the loop my toggling the loop option to false when calling the function. Although, there’s no plan to add the native scroll on scroll up yet. :)

  19. 46

    Michael Bromley

    August 29, 2014 11:15 am

    Hi Pete,

    I came across this from a link on Twitter. Interestingly, I just (literally yesterday) finished work on a project that does something similar to this, but with a bit more complex, with scope for customization and crazy effects – you might be interested in checking out the demo:

    Then I discovered this page and it was quite fascinating how you explain many of the same thought processes that I went through when building my thing.

    I also checked out the GitHub repo and there are a few cool ideas that I might take inspiration from. Well done!

  20. 47

    Dyah 苏达曼

    August 29, 2014 3:27 pm

    Hello Pete peachanan!
    I’ve just came across your plugin today.
    Unfortunately I found a problem. I tried embedding an .swf in my web page. When I scroll down to the section where the .swf is, it doesn’t show anything, plain black. But when I scroll up/bottom then come back to the section of the .swf file, the .swf starts working.
    Do you think it has anything to do with uncompatibility between the .swf and your plugin?
    Thank you in advance!

  21. 48

    Hi Pete,

    Thank you for your effort, this is a great plugin and helped me a lot in a freelance project (

    I have some suggestion:
    – You can add an option for updating url with hash or pushState. This would help me a lot
    – You can add section titles to pagination dots like tooltip

    Thank you again!

  22. 49

    Bummer, demo doesn’t work on my Android 4.0 sp :-( but looking forward to viewing later on my laptop.

  23. 50

    Hi Pete, the demo doesn’t work the same as the web page.

    When I scale the browser window down, the pagination dots vanish and the “one-page” mechanism stops working.

    Any ideas?

  24. 51

    question , on apples iphone5 one page they have that fade out fade in when you skip like an element . could u do it here ?

  25. 52


    I’m looking at using this plugin in place of fullpage.js. Will you bother applying any fixes to the self contained js version or will just the jQuery version be maintained? I’d prefer to take the library free option as I’m getting back up to speed with js again after a 10 year lapse and am trying to avoid leaning on jQuery, at least until I’m up to speed with basic js stuff. And the js version is leaner and meaner, of course…

  26. 53

    Thank you for good tutorial, I use for

  27. 54

    Great blog. The points are very useful for me. Keep sharing.

  28. 55

    A solid and very well built plugin. I’ve been toying around with creating this from scratch but this plugin does a far better job! Thanks alot.

  29. 56

    I can use $.delay inside beforeMove callback?

  30. 57

    After a long time, I have read this type of blog, and I like reading this a lot. The points are very informative for me. Thanks a lot for sharing.

  31. 58

    Is it possible to disable the scroll back to the top feature? I would like it to now scroll to the top once the the bottom is reached.

  32. 59

    Thanks you for this!
    The fallback feature is great, but it also unhook the links I have made from MoveUp och MoveDown.
    Is it possible to only fallback the scroll and swipe events, and leave the links working?

  33. 60

    Florence Bell

    January 30, 2015 6:35 am

    A solid and very well built plugin. I’ve been toying around with creating this from scratch but this plugin does a far better job! Thanks alot.

  34. 61

    Works perfect. Thanks for sharing your solution with us.
    I just started to work on a site and used your plugin today. Everything works fine, but is it possible to link directly to a section? For example in a menu or when coming from an external link? Thanks for your support!

  35. 62

    Is there a tutorial to help me install this on a wordpress site and how to set-up the screens so they are all contained within the browser?


  36. 63

    I have view the source and still don’t know why anything in your code about the window.location.hash doesn’t work!!
    Is there any problem with the updateURL parameter??

    No matter I used it true or false, when I click the pagination, my browsew still show the “#1#2#3..” and add it to window history .. <= nothing happened when I click back page doesn't refresh!! (.. I think that may call bug..)

    Is there something wrong??

  37. 64

    Vikas Singh Gusain

    April 20, 2015 9:25 am

    Hi my name is Vikas Singh and I design website on wordpress for This One Page Scroll Plugin is awesome and I use it for own website.

    Thanks for sharing this kind plugin….

  38. 65

    Florence Bell

    April 24, 2015 8:16 am

    Nice and a very useful points are included in this blog. Thanks a lot for sharing.

  39. 66

    Why assume that Users want to scroll endlessly?

    Some people want to see only related content on one page – not a random selection, going on for ever.

    Long pages mean that, half way down, the User can’t remember how far away that interesting item is.
    By contrast pagination / links creates certainty.

    Also, long pages often (mostly?) the lose important navigation tools across the top.

    Personally I steer away from pages with excessive scrolling.

  40. 67

    Can you direct me to a tutorial in which i can easily use this in a wordpress website ?

    Im a newbie . please help me if you can


↑ Back to top