Friday, July 9, 2010

Visual Navigation

There are a few sites that have a navigation menu that can highlight / change when the menu's target scrolls into view (e.g. brizk design & Crush + Lovely) . I tried to generalize the script so it would work with any site and I ended making up with this jQuery plugin.


I set up a demo page here.

Download: Uncompressed | Minified | Zipped Demo | Github

I have tested this plugin in IE8, Firefox and Chrome. Please leave me feedback if you any problems with how it works or if it doesn't work in other browsers.

Setup
  • This plugin requires jQuery in order to function properly.
  • Follow the basic templates below to set this up on your site. For more details, go to the specific section.
Default Setup
  • HTML
    <div id="sidemenu">
    <ul>
    <li><a href="#home">Home</a></li>
    <li><a href="#work">Work</a></li>
    <li><a href="#blog">Blog</a></li>
    <li><a href="#projects">Projects</a></li>
    <li><a href="#about">About</a></li>
    <li><a href="#contact">Contact</a></li>
    </ul>
    </div>
    • Change the side menu id to whatever you want, just make sure you target it with the script.
    • This side menu example will work with the plugin's default settings. See the alternate example of a different layout.
  • CSS
    #sidemenu { position: fixed; top: 50px; left: 20px; background: #444; width: 120px; }
    #sidemenu ul { list-style-type: none; margin: 0; padding: 0; }
    #sidemenu li { margin: 5px; padding: 5px; width: 100px; text-align: center; }
    #sidemenu li.selected { background: #555; }
    #sidemenu a { text-decoration: none; color: #bbbbff; }
    #sidemenu a:hover { color: #fff; }
    • This CSS highly variable. Change the position, size and colors as desired.

  • Script
    $(document).ready(function(){
    $('#sidemenu').visualNav();
    });
Alternate Setup
  • HTML
    <div id="menu">
    <div class="link" title="#Home">Home</div>
    <div class="link" title="#work">Work</div>
    <div class="link" title="#blog">Blog</div>
    <div class="link" title="#projects">Projects</div>
    <div class="link" title=".about">About</div>
    <div class="link" title=".contact">Contact</div>
    </div>
    • This side menu uses divs with a title attribute. The value in this attribute can be used to target an Id or a class (which should be unique).
    • It is important to note, that this menu will not work with javascript disabled, whereas the default one will work.
  • CSS
    #menu { position: fixed; top: 50px; left: 20px; background: #444; width: 120px; }
    #menu div.link { margin: 5px; padding: 5px; width: 100px; text-align: center; }
    #menu div.selected { background: #555; }
  • Script
    $(document).ready(function(){
    $('#menu').visualNav({
    link              : 'div.link',
    targetAttr        : 'title',
    selectedAppliedTo : 'div.link'
    });
    });
Customizing / Options
This plugin has the following default options, so you will only need to include the line below in the script options if you want to change the default:
$('#sidemenu').visualNav({
link              : 'a',        // Add a link class, as necessary
targetAttr        : 'href',     // added in case you have link = "div" and attribute something like
selectedClass     : 'selected', // css class applied to menu
selectedAppliedTo : 'li',       // to only apply to the link, use "a"
topRange          : 100,        // measure from the top of the viewport to X pixels down
topMargin         : 100,        // margin above the top where the target updates the menu
bottomMargin      : 20,         // margin from the end of the page where the last menu item is used
animationTime     : 1200        // time in milliseconds
});
  • The first four options should were hopefully made clear in the examples above.
  • To modify how the menu acts, you will need to adjust the "topRange", "topMargin" and "bottomMargin" values. I made this picture to better understand what these values do for you.
  • topRange: The "topRange" is basically the area where target needs to be inside of in order for the menu to update. For example, the target (found in the link attribute) starts under the topRange. As it moves up and crosses into the topRange. The script then updates the side menu to show that the target area is in view (or inside the view port).
  • topMargin: The top edge margin (topMargin) is the area above the view port. The top edge margin is used while the page is being scrolled up - the target is above the view port and as you scroll up, the target moves down. When the target is inside the edge margin, the menu will update and point to that target.
  • bottomMargin: The bottom edge margin is the area below the view port. It is when the page is scrolled down (the contents are moving up). When the bottom of the page is inside the bottom edge margin, the menu will update with the last targeted id. This was necessary to be include in case the last section is too short and unable to reach the top range area.
  • animationTime: The animation time is the time in milliseconds that the menu will scroll to the selected section.
Known Problems / Bugs / Suggestions
  • The menu will not select (or highlight) the item above the last item if they are both very short. For example, if your browser shows three sections while at the bottom of the page. The third to last may have shown for a brief time just before the bottom of the page reached the bottom edge margin. The menu would then skip directly to the last menu item. This is one reason why the bottom margin value is kept a low number (20 pixels by default).
  • If you click on a menu item, the page contents will automatically scroll to that section and update the browser url with that target. But if you manually scroll the page using the scroll bar or mouse, the web page url will not update with the current position. This was done on purpose, because if the script changes the location, the page will jump to that target automatically. This wouldn't look good if you are quickly scrolling through the page as it would make the movement jittery.
  • To make suggestions or report any bugs please email me at wowmotty at g mail dot com.

17 comments:

  1. Updated to version 2.0... using a new algorithm to determine if the blocks are in the view port.

    ReplyDelete
  2. Hi, great navigation tool. Just wondering how you would make it work for a horizontal scrolling page?
    Thanks in advance!

    ReplyDelete
  3. Hi loui83!

    I have a version in the works that will have both horizontal and vertical scrolling... but I won't be able to release it for another week or so.

    ReplyDelete
  4. Hi, very nice plugin!

    I am also curious about when the horizontal version is coming.
    How about one that can move both vertical and horizontal?

    I have seen some similar thing here; http://www.appelsiini.net/projects/viewport/3x2.html
    But i read somewhere that this will not work in some browsers.

    thanks anyway for a nice plugin.

    O

    ReplyDelete
  5. Hi Info! Get the latest version on Github which works with vertical, horizontal or both page layouts. :)

    ReplyDelete
  6. Thanks Mottie, i have downloaded it and will give it a try.
    Looks good :)

    ReplyDelete
  7. Hi,
    how do I add an external link to the menu?

    ReplyDelete
  8. @jo: Use one of the available methods to control the navigation.

    ReplyDelete
  9. Hi again,
    sorry but the link didn't make much sense to me! If I am using the horizontal menu.. e.g I have five internal links and one in this menu linking to an external blog. How can I get it to open in a new window?

    ReplyDelete
  10. Opps! Sorry I misread your question. Basically you can just add a class to each menu link, then use the "link" option to target that class name. Here is a demo.

    ReplyDelete
  11. Hi, tried to use this with a horizontal menu (188px height) that is fixed on the top of the screen , what I need to do is to scroll the section linked in the menu and positioned it just below the menu instead behind and In can´t do it. please help me.

    Thanks in advance

    ReplyDelete
  12. Hi @Charlie Hdez!

    Try this demo, maybe it will help guide you. Basically I added top padding to the ".content" to keep it below the menu.

    ReplyDelete
  13. Hey man, great plugin, only one problem i had, it doesn't really have a callback functionality. So i added my own, here is the updated code. please feel free to use or distribute my changes.

    http://pastebin.com/j74HR60m

    ReplyDelete
    Replies
    1. Thanks! I'll include this in the next update, whenever I have some time to work on it!... you can follow the progress by checking on the issue (enhancement really) I opened at my github repository for this plugin.

      Delete
  14. Hi Mottie,

    I'm having a really good time implementing the visual navigation plugin. Thanks for sharing it.

    Question. Can the scrolling animation speed be changed depending on the distance being the elements scrolled? Currently the 'animationTime' option works great, but some of my content is pretty long and having several different animation speeds would really spruce things up.

    My aim is to have at least 5-6 different animation speeds based on as many different distances, all included in the options of the plugin so they can be tweaked for each implementation. Something like... 'scrollTime1: - scrollTime6:', and 'scrollDistance1: - scrollDistance6:'.

    Thanks for the great work.

    ReplyDelete
    Replies
    1. Hiya!

      Sorry for not responding earlier, but to modify the timing it would require some core code modification. I'll look into adding something that calculates the distance it needs to move, then change the time accordingly. Maybe set it to time/pixels (completely guessing here, but something like 100ms/100pixels)? I opened a repository issue to remind myself to add this... now if I just had some free time =/

      Delete