data-anchor-target="#foo"
>
will have it's keyframes tiggered by the position of the
#foo element
. Any CSS selector can be used, i.e
data-anchor-target=".bar:not(.bacon) ~ span > a[href]"
Note: If you need to support IE 7, then you may only use IDs as anchor-target
s, i.e. #foo
. The IE plugin maps querySelector
to getElementById
.
Here's an infographic for better understanding of anchors (click to open PDF):
Important: All those values will be calculated up-front and transformed to absolute
mode. So if either the element's box height changes (height, padding, border) or the elements position within the document, you probably need to call refresh()
(see documentation in JavaScript section below). Window resizing is handled by skrollr.
Percentage offsets
All offsets shown above are given in absolute pixel values, e.g. data-300
for 300px
from the top or data-13-top-bottom
for a 13px
offset to the top-bottom
anchor. As of skrollr 0.6.13
you can also have offsets as percentages of the viewport by appending a p
to the number. For example data-75p
for when you scrolled down 75%
of the viewport or data-10p-center
to have a 10%
offset from the center
anchor.
Hash navigation
Check out the skrollr-menu plugin.
Working with constants
I was lying to you. The syntax for absolute mode is not data-[offset]-[anchor]
and for relative mode it's not data-[offset]-(viewport-anchor)-[element-anchor]
. In both cases, offset
can be preceded by a constant which can be passed to the init
method. The name of the constant needs to be preceded with an underscore.
Example:
skrollr.init({
constants: {
foobar: 1337
}
});
Valid characters for a constant are [a-z0-9_]
.
Dynamic constants
Starting with skrollr 0.6.19
the word "constants" doesn't quite fit anymore, but who cares.
You can now use functions and percentages as constants. They are automatically evaluated when the window is resized or if you call refresh
.
skrollr.init({
constants: {
foo: function() {
//Note: you can access the skrollr instance with `this` for things like `this.relativeToAbsolute`
return Math.random() * 100;//trolololol
},
vh: '100p'
}
});
CSS classes
skrollr will add a skrollr
class to the HTML
element when calling init
and will remove a no-skrollr
class if present. Additionally, it will add a skrollr-desktop
or skrollr-mobile
class depending on which it detects. This allows fallback CSS rules to create a good user experience on unsupported devices or when JavaScript or skrollr are disabled.
All elements under skrollr's control (elements with appropriate data-attributes) will get the skrollable
class. In addition, we add either the skrollable-before
, skrollable-between
or skrollable-after
class, depending on whether the current scroll position is before, between or after the first/last (smallest/largest) keyframe of an element.
Animating attributes
Starting with skrollr 0.6.24 you can also animate attribute and not just style properties. This is especially a big thing because in the SVG world many properties are implemented as attributes and not in CSS. Animating an attribute couldn't be simplier, just prefix the property with an @
symbol!
Note: as always, skrollr doesn't do any magic. It doesn't understand what a polygon or points are. It's only interpolating numbers, that's it. So make sure you have the same number of numbers in your keyframes (8 in this case).
Filling missing values
Imagine the following animation
One could expect left
to have a value of 25%
at keyframe 200
. That is not the case. By design, skrollr only interpolates values between key frames which are direct neighbors. What actually happens is that skrollr internally fills out all holes once from left and then from right. So the above is equivalent to
Preventing interpolation
The reason why skrollr is so lightweight and powerful is because it literally interpolates every number it can find. If you want to prevent some side effect, you can suppress interpolation for a specific value by prepending an exclamation point.
Example:
Note: The values for both keyframes (if they contain a number) need to be prefixed if you want to avoid skrollr throwing an exception at you!
Limitations
There are some limitations of skrollr you should be aware of.
- All numeric values have to have the same unit, even
0
needs a unit. It's not possible to animate from 5%
to 100px
. skrollr won't complain, but results are undefined.
- Animations between values which are composed of multiple numeric values like
margin:0 0 0 0;
are only possible for the same number of values. margin:0px 0px 0px 0px;
to margin:0px 100px 50px 3px;
is fine, but not margin:10px;
to margin:5px 10px;
.
- Animations between CSS transforms only work when they use the same functions in same order. From
rotate(0deg) scale(1)
to rotate(1000deg) scale(5)
is fine.
- Color animations don't support named values like "red" or hex values like "#ff0000". Instead, you have to use
rgb()
, rgba()
, hsl()
and hsla()
. Don't worry, there's a skrollr plugin for IE < 9 to support hsl()
(without "a"!) and to fall rgba back to rgb.
- Color animations only work for same color functions.
hsl()
to hsl()
or hsla()
is fine, but not rgb()
to hsl()
. Which makes sense, because animating from the same colors in rgb space and in hsl space results in different animations (hsl gives you the nice rainbow stuff).
But feel free to send in a pull request to fix any of them. Just keep in mind that keeping skrollr as lightweight as possible has high priority.
JavaScript
On the JavaScript part there's not much to do (you can, if you want to!). So if you only know CSS and HTML, perfect.
skrollr.init([options])
All there is to do is to call skrollr.init([options]);
which returns an instance of the singleton skrollr class. Subsequent calls to init()
will just return the same skrollr instance again.
Possible options for init()
are
smoothScrolling=true
Smooth scrolling smoothens your animations. When you scroll down 50 pixels, the animations will transition instead of jumping to the new position.
The global setting can be overridden per element by setting data-smooth-scrolling
to on
or off
.
smoothScrollingDuration=200
The number of milliseconds the animations run after the scroll position changed the last time.
constants={}
An object containing integers as values. The keys can contain [a-z0-9_]
. They do not need a leading underscore.
Example: data-_myconst-200
and skrollr.init({constants: {myconst: 300}})
result in data-500
.
scale=1
By default, skrollr uses the largest key frame and makes document height + viewport height this high, thus the max possible scroll top offset. If your animation runs too fast or too slow, just adjust the scale value.
scale
only affects keyframes in absolute mode.
When forceHeight
is set to false, scale
is ignored.
scale
affects constants
as well.
scale
does only affect key frames in absolute mode, e.g. data-500
but not data-top
.
forceHeight=true
true
: Make sure the document is high enough that all key frames fit inside. Example: You use data-1000
, but the content only makes the document 500px high. skrollr will ensure that you can scroll down the whole 1000px. Or if you use relative mode, e.g. data-top-bottom
, skrollr will make sure the bottom of the element can actually reach the top of the viewport.
false
: Don't manipulate the document and just keep the natural scrollbar.
mobileCheck=function() {...}
This option allows you to pass a function to skrollr overwriting the check for mobile devices. The function should return true
when mobile scrolling should be used and false
if not.
The default looks like this
function() {
return (/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera);
}
mobileDeceleration=0.004
The amount of deceleration for momentum scrolling on mobile devices. This options tells skrollr how fast or slow you want the scrolling to stop after the user lifted his finger.
Set it to 1
to disable momentum scrolling.
skrollrBody='skrollr-body'
This option allows you to override the default id-selector used for supporting mobile browsers. It might come in handy when the element in question already has a assigned id or if you would like to define more then one skrollrBody depending on preceding JavaScript-logic.
edgeStrategy='set'
This option specifies how to handle animations when the scroll position is outside the range on the keyframes (i.e. before the first or after the last keyframe).
One of three options are possible
-
set
(default): When before/after the first/last keyframe, apply the styles of the first/last keyframe to the element.
-
ease
: Same as set, but the values will be transformed using the given easing function.
-
reset
: When before/after the first/last keyframe, apply the styles which the element had before skrollr did anything. This means resetting the class attribute as well as removing all styles which have been applied to the style
property. This means the element won't have any skrollable-*
CSS classes.
Example:
Given the following element with two keyframes
and the following easing function which always returns 0.5
(I know it's pointless, but it's just an example. A real world example would be an easing function that represents a curve and starts somewhere between 0
and 1
, but not at 1
)
function(p) {
return 0.5;
}
and imagine the scrollbar is at 237
, which is below the first keyframe which is at 1000
.
-
set
will result in
which is plain data-1000
.
-
ease
will result in
which is 0.5 * data-1000
.
-
reset
will result in
which is what the element originally had. Note how top
is missing.
beforerender
A listener function that gets called each time right before we render everything. The function will be passed an object with the following properties:
{
curTop: 10, //the current scroll top offset
lastTop: 0, //the top value of last time
maxTop: 100, //the max value you can scroll to. curTop/maxTop will give you the current progress.
direction: 'down' //either up or down
}
Returning false
will prevent rendering.
render
A listener function that gets called right after we finished rendering everything. The function will be passed with the same parameters as beforerender
.
Example
skrollr.init({
render: function(data) {
//Log the current scroll position.
console.log(data.curTop);
}
});
keyframe
Experimental
In order to receive keyframe
events from an element, add the data-emit-events
attribute to the element. The keyframe function will be called with three arguments
- The
element
that passed the keyframe.
- The
name
of the keyframe, camel-cased (see example).
- The
direction
the user is scrolling.
Example:
Some content
skrollr.init({
keyframe: function(element, name, direction) {
//name will be one of data500, dataTopBottom, data_offsetCenter
}
});
Note: this is experimental, expect the API to change! Originally I wanted to emit the events right on the element, so you could do this
//Wouldn't this be nice?
document.querySelector('#foo').addEventListener('skrollr.dataTopBottom.up', function() {
//#foo just passed the data-top-bottom keyframe while scrolling up
}, false)
but IE.
easing
An object defining new easing functions or overwriting existing ones. Easing functions get just one argument, which is a value between 0 and 1 (the percentage of how much of the animation is done). The function should return a value between 0 and 1 as well, but for some easings a value less than 0 or greater than 1 is just fine.
An easing function basically transforms the timeline for an animation. When the animation should be 50% done, you can transform it to be 90% done or whatever your function does.
Example:
skrollr.init({
easing: {
//This easing will sure drive you crazy
wtf: Math.random,
inverted: function(p) {
return 1 - p;
}
}
});
You can now use the easing functions like any other.
skrollr ships with some built in functions:
- linear: The default. Doesn't need to be specified.
- quadratic: To the power of two. So 50% looks like 25%.
- cubic: To the power of three. So 50% looks like 12.5%
- begin/end: They always return 0 or 1 respectively. No animation.
- swing: Slow at the beginning and accelerates at the end. So 25% -> 14.6%, 50% -> 50%, 75% -> 85.3%
- sqrt: Square root. Starts fast, slows down at the end.
- outCubic
- bounce: Bounces like a ball. See https://www.desmos.com/calculator/tbr20s8vd2 for a graphical representation.
Custom easing
- Use this generator
- Insert the given polynomial coeficients instead of t, t2, t3, t4 and t5
t5*(p*p*p*p*p) + t4*(p*p*p*p) + t3*(p*p*p) + t2*(p*p) + t*p
Example shown with the values for easeOutElasticBig
easeOutElasticBig: function(p) {
return 56*(p*p*p*p*p) - 175*(p*p*p*p) + 200*(p*p*p) - 100*(p*p) + 20*p;
}
skrollr.get()
Returns the skrollr instance if init()
has been called before or undefined
.
Public API
Calling init()
returns an instance of skrollr which exposes a public api.
refresh([elements])
Reparses all given elements
. You can pass a single element or an array-like element (Array, NodeList or jQuery object)
Useful when
- Elements in
relative
mode change and need to be updated.
- Data-attributes are manipulated dynamically.
- New elements are added to the DOM and should be controlled by skrollr.
When no elements
are given, all elements in the document will be parsed again. In fact, when calling skrollr.init()
skrollr uses refresh()
without parameters internally.
Time consuming operations, should not be called on every rendering.
relativeToAbsolute(element, viewportAnchor, elementAnchor)
Returns an integer which represents the absolute scroll position which correlates to the relative anchor.
element
must be a DOM element.
viewportAnchor
and elementAnchor
must be one of top
, center
or bottom
Example:
var offset = s.relativeToAbsolute(document.getElementById('foo'), 'top', 'bottom');
//offset contains the scroll position at which #foo's bottom is at the top of the viewport.
//If you now use setScrollTop(offset) or animateTo(offset) #foo's bottom will be perfectly aligned with the top of the viewport. Yay.
getScrollTop()
Returns the current scroll offset in pixels. Normalizes different browser quirks and handles mobile scrolling.
getMaxScrollTop()
Returns the number of pixels that can be scrolled down in total. If forceHeight
is true, that's usually the largest keyframe. Otherwise it's the height of the document minus the viewport height.
setScrollTop(top[, force = false])
Sets the top offset using window.scrollTo(0, top)
on desktop or updating the internal state in case of mobile scrolling.
When force
is set to true
, skrollr will jump to the new position without any kind of transition. By default, the global smoothScrolling
setting applies.
isMobile()
Returns if skrollr runs in mobile mode (see also mobileCheck
option).
animateTo(top[, options])
Animates the scroll position from current position to top
. Possible options
are
duration
How long the animation should run in milliseconds. The default is 1000
or one second.
easing
The name of an easing function. The same functions can be used as for property animations. Default is linear
.
done
A function to be called after the animation finished. When you pass a top
value, which is the same as the current, then the function will be called immediately. The function gets a boolean argument interrupted
which indicates if the animation was interrupted by stopAnimateTo
or finished to the end.
stopAnimateTo()
Stops the animation and calls the done
callback passing true
as interrupted
arguments.
isAnimatingTo()
Returns if an animation caused by animateTo is running.
on(name, fn)
Set a listener function for one of the events described in the options section (beforerender, render, keyframe). Only one listener can be attached at a given time. This method overwrites the current listener, if any.
off(name)
Removes the listener for the given event.
destroy()
Destroys skrollr. All class
and style
attributes will be set to the values they had before.
Changelog
See HISTORY.md.