jParallax
Download
jParallax has had a major overhaul in readiness to be released as version 1.0! Layers are now freezable – the last feature I wanted to implement – and the code is more j and compact. I've been really encouraged by all the great comments, so thank you everyone! I just need you to road test the demos and tell me that it's still working in your browser, and then I'll stick a 1.0 on it.
Cheers!
What does jParallax do?
jParallax turns a selected element into a 'window', or viewport, and all its children into absolutely positioned layers that can be seen through the viewport. These layers move in response to the mouse, and, depending on their dimensions (and options for layer initialisation), they move by different amounts, in a parallaxy kind of way.
The diagram on the right illustrates what Parallax does to the html:
<ul id="parallax">
<li></li>
<li></li>
</ul>
Here's a demonstration with some images:
But that's not all that jParallax does. If the layers are made of <div>s or <li>s or any other container then content can be positioned inside those layers, and Parallax provides methods for navigating to that content in response to user events.
Demos
Using jParallax
The default behaviour of jParallax is to show the whole width of a layer in response to the mouse travelling the whole width of the parallax 'window'. When the mouse is moved to the extreme left-hand side of the parallaxed window the left-hand side of the layer meets it, and when the mouse is moved to the extreme right-hand side of the parallaxed window the right-hand side of the layer arrives at the right hand-side of the window.
The simplest way to use jParallax is to make the layers different sizes using CSS. Bigger layers move faster and thus appear closer, and unless a layer is smaller than the viewport, its edges are never seen. The Colour Drops Demo was made in exactly this way, with jParallax in its default state, and the 'speed' of the layers controlled simply by making the images different sizes. No options have been passed in.
However, we all want tweaky-tweaky. I also give you tweaky-tweaky...
Instantiation
jQuery('#parallax').jparallax(options, layer_options);
Clearly the parallaxed element(s) can be selected any way you like. For the sake of simplicity for the rest of this guide I refer to the parallaxed element as '#parallax'.
CSS
In most cases, you should set the following CSS on the parallaxed element:
#parallax
{position:relative; overflow:hidden; width:npx; height:npx;}
Children of a parallaxed element become layers, and are automatically given position:absolute; in order to start moving them around, but the parallaxed element itself needs position:relative; or position:absolute; or the layers will move relative to the document rather than the viewport. overflow:hidden; stops layers displaying outside of the bounds of the viewport, and width and height should be set to prevent the viewport collapsing.
In addition, jParallax needs to know how big layers are, and if there is anchored content inside a layer it needs to know where and how big it is. It uses jQuery's height(), width() and offset() methods to find out. However, if you experience trouble with the range of motion of a layer you should consider setting all dimensions (height, width, top and left) explicitly via CSS to make life easy for those methods.
Options default values
The following options can be passed to jParallax to set the behaviour of the mouse, default behaviour of the layers, animation settings and so on:
- mouseResponse: boolean true
- mouseport: jQuery('element') same as parallaxed element
- Enables mouse response and specifies the DOM element to track the mouse in. By default it's on, and it's the same as the viewport, the DOM element that you instantiated jParallax on. Perhaps you might want to use the whole window as the mouseport, in which case you could pass in jQuery(window).
- mouseActiveOutside: boolean false
- Enables mouse response outside the limits of the mouseport, but layers behave as if the mouse was at the edge of the mouseport.
- linkResponse: boolean true
- Enables response to "link" events triggered on the parallaxed element(s). Content containing an anchor tag, and positioned inside a layer, is pulled to the centre of the viewport when the anchor's name attribute is passed as the first value in an array via the custom "link" event. Consider the following code:
jQuery('a').click(function(){
var ref=jQuery(this).attr("href");
jQuery('#parallax').trigger("link", [ref]);
});
This says that when an anchor in the document is clicked, its html attribute will be passed as a ref to the element '#parallax' in a "link" event trigger. If there is content on one of the layers containing <a name="ref"> it will be pulled to the centre of the viewport. If not, nothing will happen.
If linked content is not being used it's a good idea to switch linkResponse to false. It will save the browser a tiny amount of overhead on plugin initialisation. This option was called "triggerResponse" up to version 0.9.9.
- linkExposesEdges: boolean false
- Sets whether linkResponse pulls the edges of layers into the viewport while attempting to display content in the centre.
- takeoverFactor: 0-1 0.68
- takeoverThresh: 0-1 0.002
-
Sets the speed and accuracy with which the layers 'catch up' with the mouse position when the mouse enters the mouseport from somewhere other from whence it has left. Technically, takeoverFactor is the decay of the approach curve per animation frame, where lower numbers are more decay (and therefore quicker), and takeoverThresh is the distance within which the layer position is considered to have arrived, as a ratio of the mouseport dimension. takeoverThresh is by default a five-hundredth of the mouseport - larger numbers may produce a noticeable 'jump' at the beginning of a new mouse movement. You shouldn't need to mess with these too much, I just stuck them in there because we all like tweaky-tweaky.
- frameDuration: milliseconds 25
-
You may want to put this up to save CPU. About 40 is acceptable (25 frames/second). I like it zippy, though. I hear Google Chrome has got timing accuracy down to 1ms! Others don't do lower than 15ms.
- xparallax: boolean true
- yparallax: boolean true
- xorigin: 'left' | 'centre', 'center', 'middle' | 'right' | 0-1 'centre'
- yorigin: 'top' | 'centre', 'center', 'middle' | 'bottom' | 0-1 'centre'
-
Sets default alignment of layers. See 'Layer Options' below for a detailed description.
- cssViewport: {name: value} {}
- cssLayers: {name: value} {position: absolute}
- Style jParallax via jQuery on instantiation. This can make sense when you start thinking about graceful degredation. I don't recommend it to start with, though.
Layer Options default values
In addition to the options above, Layer Options can be passed to each layer individually, as extra arguments:
jQuery('element').jparallax(options, layer_0_options, layer_1_options, etc.);
As an example, to give the second layer a set xtravel value, but pass no options as default:
jQuery('element').jparallax({}, {}, {xtravel: '200px'});
A layer option object can have the following parameters:
- xparallax: boolean true
- yparallax: boolean true
-
Enables motion in the x or y direction in response to the mouse.
- xtravel: 0-1 | 'n%' | 'npx' 1
- ytravel: 0-1 | 'n%' | 'npx' 1
-
When specified as a number between 0 and 1, or as a percentage string, xtravel and ytravel scale the distance a layer will travel. When specified as a pixel string they set the distance a layer will travel.
When travel is left at the default 1, the behaviour is to display the whole width of the layer over the whole range of the viewport in response to the mouse travelling the whole width of the mouseport. In other words, the left meets the left when the mouse is on the left, the centre lines up when the mouse is at the centre and the right meets the right when the mouse is at the right. Setting xtravel to, say, 0.5, or '50%' will mean half that layer's possible horizontal travel will occur over the same range of mouse motion.
Numbers outside the range 0-1 can be used, too. Negatives will cause travel in reverse direction, scaling factors greater than 1 (or '100%'), or less than -1 (or '-100%') will cause the edges of layers to be pulled into view.
- xorigin: 'left' | 'centre', 'center', 'middle' | 'right' | 0-1 'centre'
- yorigin: 'top' | 'centre', 'center', 'middle' | 'bottom' | 0-1 'centre'
-
Only meaningful when xtravel or ytravel are not 1. Determines which point of the layer lines up with which point of the viewport when the mouse is at that point in the mouseport. Got that?
Look, if origin.x is set to 'left', then when the mouse is moved to the left hand side of the mouseport the left hand side of the layer arrives at the left hand side of the viewport. If it's set to 'centre', then when the mouse is at the centre of the mouseport the centre of the layer is aligned with the centre of the viewport. Similarly with 'right'.
Numbers may also be used:
- 0 is equivalent to 'left'.
- 0.5 is equivalent to 'centre' or 'center' or 'middle'.
- 1 is equivalent to 'right'.
Numbers outside the range 0-1 may also be used, although you will start seeing the edges of layers appearing inside the viewport. And they'll travel in the opposite direction.
- width: integer undefined
- height: integer undefined
- Values for layer dimensions, normally read from css, can be overridden. This does NOT change the css, only jParallax's idea of how big a layer is. This can be very useful in cases where you want to be able to 'click through' the upper layers. Typically you make layers very small in css, but tell jParallax they are big via width and height. You prabably want overflow: visible on those layers, too.
Tips
Extra graphics
If you want to add elements to #parallax, such as overlaying curved corner images like in the above example, add them after you have instantiated jParallax in order to avoid having those elements included in the calculations.
Transparent image layers
Use jQuery iFixPng plugin, to make see-through .png images work on IE6.
Sites using jParallax
Let me know if you have a site that uses jParallax using the 'Write to me' form at the top of this page.
Version history
0.9.9
Basically version 1.0, but until I've fully tested it, it's staying 1% away.
- Code majorly refactored. It's much more j now, and a little smaller. The anim clock changed, the code got re-shuffled to make it more compact, to re-use more routines and make more use of jQuery goodness. The biggest internal change is that it now uses vector arrays instead of property objects to store data.
- Implemented events for internal control of calculation and animation, and external control of goodies like "freeze" and "link".
- Options added: cssLayers and cssViewport, for 'embedding' styles in the jParallax declaration, should you want to.
- triggerResponse is now linkResponse
- Some previously undocumented options now documented. But not all. Oh no.
0.9.1
- Fixed bug when specifying travel by %.
- Travel px or % detection has more robust Regex.
0.9
0.8.1
- Tested in Safari, Firefox 3, IE6, IE7, Google Chrome (Beta) and Opera 9.5. IE6 has trouble handling multiple jParallax instances when they are declared on one jQuery selector. Other than that, all present and correct. Declare your doctypes!
- Bug fixed in matrixSearch.
0.8
- Gracefully handles window resize.
- Begins to shoot for proper IE support.
- Positioning algorithm re-written. In fact, it can barely be called an algorithm any longer, as the positioning now relies almost solely on CSS. Whereas previously it was defined absolutely in pixels, positioning is now defined by percentage combined with variable (negative) margins, forcing the browser CSS engine to take more responsibility for re-positioning. This means that window resizing is smooth, and the Javascript has less calculating to do. However, it may be more of a CPU hog this way. Some testing will be done.
- Due to the above changes, some Options and Layer Options now mean something slightly different to their original definitions. For example, xtravel is now a ratio by default rather than a pixel definition.
- Made a minor change to the way dimensions are registered - they now use the jQuery methods width(), height() and offset(), so they should no longer need to be explicitly set via CSS (although it wouldn't hurt, if you want to be sure). This also applies to layer contents.
- Added Target Demo to demonstrate window resizing and Trigger Response, and updated arse demo to jParallax.
- Some code optimising to make it faster, but there's more that can be done in this department.
- Docs updated.
0.7 (Not released)
0.6
- Trigger response added.
- New demos added. Remote control and a crude trigger demo.
- Options simplified. They were getting a bit out of hand. Default options are now all attributes of one object, rather than nested objects as previously. (Layer Options still work the same way, one object per layer).
- Docs updated.
0.5
- Soft Takeover animation timer and mouseport detection rewritten to get rid of jerky re-entry bugs. Life is now smoother and creamier.
0.4
- Based on an idea I read somewhere on the web or possibly in the book jQuery In Action, jParallax now saves CPU by moving the layers at a maximum frameRate and not on every change of mouse co-ordinates.
- Soft Takeover animates layers to position over time on mouseport re-entry. It's a little dodgy.
0.3
- Implemented a crude Soft Takeover. It doesn't animate to position over time, just over mouse move, but it does make the mouseport entry a bit smoother.
0.2
- Fixed xtravel, ytravel and mouseport initialisation.
- Added Stalk Button demo.
0.1
- Initial port from proof of concept code. My first jQuery plugin!
- Colour drop demo.
nothing new man…
Hi Chris,
You make this stuff so simple – thanks for all your great tips and hard work! My question is can this work with multi-level navigation as well? It wouldn’t need to apply the effect the the child links, but would like to be able to have them drop down. Any tips on this is helpful.
Thanks, Larry
Larry just asked the same question that I had as well. This is a great start, but what needs to happen to support multi-level navigation?
Though I haven’t tried it myself, one thing that might work is duplicate the code for the find(“a”) hover and make one for $(“li:not(:has(ul))”). that does the default stuff (it doesn’t have a UL-child so it’s not a dropdown-able item)
And another one for $(“li:has(ul)”) that does have a ul-child. In that case move the magic line horizontally where it should be, but also move it down the height of the UL-element.
If you dont want the magic line to move diagonally (ie. shortest route) then you need to queue the animation to go horizontal first to the LI-item, and then move vertically down (position: absolute; bottom: -(2 + UL-height)px; ). And on MouseOut (callback of hover() – move vertically up and then horizontally).
I might try this next weekend, but I’m not sure I’ll remember. Feel free to see if it works out !
–
TeMc
Try looking into the dropdowns (also jQuery based):
http://css-tricks.com/simple-jquery-dropdowns/
Thanks for sharing Chris, just a little detail. Download is broken.
Once again, a sly implementation!
As always, feel free to do whatever you want with it. Preferably, use it in corporate projects and earn wheelbarrows of cash.
Yes sir!
Actually, I needed this for a commercial project as it was, and this just satisfied that need. You’re a 5-star helpful guy :)
Wow, simply effect that looks pretty good.
Just one thing, i prefer to have the magic-line li in the html markup, instead of appending it by javascript.
Its just a matter of taste and probably your way is better for seo, but as a developer i love to see exactly the markup i’ll have to work with ;)
How would you use this with Wordpress’ wp_page_menu?