basicScroll
Standalone parallax scrolling for mobile and desktop with CSS variables.
basicScroll allows you to change CSS variables depending on the scroll position. Use the variables directly in your CSS to animate whatever you want. Highly inspired by skrollr and Reactive Animations with CSS Variables.
Contents
Demos
Features
- Zero dependencies
- CommonJS and AMD support
- Simple JS API
- Insane performance
- Support for mobile and desktop
Requirements
basicScroll depends on the following browser features and APIs:
Some of these APIs are capable of being polyfilled in older browsers. Check the linked resources above to determine if you must polyfill to achieve your desired level of browser support.
Setup
We recommend to install basicScroll using Bower or npm.
bower install basicScroll
npm install basicscroll
Include the JS file at the end of your body
tag…
<script src="dist/basicScroll.min.js"></script>
…or skip the JS file and use basicScroll as a module:
const basicScroll = require('basicScroll')
Usage
This demo shows how to to change the opacity of an element when the user scrolls. The element starts to fade as soon as the top of the element reaches the bottom of the viewport. A opacity of .99
is reached when the middle of the element is in the middle of the viewport.
Tip: Animating from .01
to .99
avoids the repaints that normally occur when the element changes from fully transparent to translucent and from translucent to fully visible.
const instance = basicScroll.create({
elem : document.querySelector('.element'),
from : 'top-bottom',
to : 'middle-middle',
props : {
'--opacity': {
from : '.01',
to : '.99'
}
}
})
instance.start()
.element {
opacity: var(--opacity);
will-change: opacity;
}
API
.create(html, opts)
Creates a new basicScroll instance.
Be sure to assign your instance to a variable. Using your instance, you can…
- …start and stop the animation.
- …check if the instance is active.
- …get the current props.
Examples:
const instance = basicScroll.create({
from : '0',
to : '100px',
props : {
'--opacity': {
from : '0',
to : '1'
}
}
})
const instance = basicScroll.create({
elem : document.querySelector('.element'),
from : 'top-bottom',
to : 'bottom-top',
props : {
'--translateY': {
from : '0',
to : '100%',
timing : 'elasticOut'
}
}
})
const instance = basicScroll.create({
elem : document.querySelector('.element'),
from : 'top-middle',
to : 'bottom-middle',
inside : (instance, percentage) => {
console.log('viewport is inside from and to')
},
outside : (instance, percentage) => {
console.log('viewport is outside from and to')
}
})
Parameters:
data
{Object}
An object of data.
Returns:
{Object}
The created instance.
Instance API
Each basicScroll instance has a handful of handy functions. Below are all of them along with a short description.
.start()
Starts to animate the instance. basicScroll will track the scroll position and adjust the props of the instance accordingly. An update will be performed only when the scroll position has changed.
Example:
instance.start()
.stop()
Stops to animate the instance. All props of the instance will keep their last value.
Example:
instance.stop()
.update()
Triggers an update of an instance, even when the instance is currently stopped.
Example:
instance.update()
Returns:
{Array}
New props. An array of objects, each with a key and value.
.calculate()
Converts the start and stop position of the instance to absolute values. basicScroll relies on those values to start and stop the animation at the right position. It runs the calculation once during the instance creation. .calculate()
should be called when elements have altered their position or when the size of the site/viewport has changed.
Example:
instance.calculate()
.isActive()
Returns true
when the instance is started and false
when the instance is stopped.
Example:
instance.isActive()
Returns:
.getData()
Returns calculated data. More or less a parsed version of the data used for the instance creation. The data might change when calling the calculate function.
Example:
instance.getData()
Returns:
Data
The data object can include the following properties:
{
elem: null,
from : null,
to : null,
inside : (instance, percentage) => {},
outside : (instance, percentage) => {},
props: {
'--name': {
from : null,
to : null,
timing: 'ease',
direct: false
}
}
}
DOM Element/Node
Type: Node
Default: null
Optional: true
A DOM Element/Node.
The position and size of the element will be used to convert the start and stop position to absolute values. How else is basicScroll supposed to know when to start and stop an animation with relative values?
You can skip the property when using absolute values.
Example:
{
elem: document.querySelector('.element')
}
Start and stop position
Type: Integer|String
Default: null
Optional: false
basicScroll starts to animate the props when the scroll position is above from
and below to
. Absolute and relative values are allowed. Relative values require a DOM Element/Node.
Examples:
{
from : '0px',
to : '100px',
}
{
from : 'top-middle',
to : 'bottom-middle',
}
Callback functions
Type: Function
Default: () => {}
Optional: true
Both callbacks receive the current instance and a percentage:
- < 0% percent = Scroll position is below
from
- = 0% percent = Scroll position is
from
- = 100% percent = Scroll position is
to
-
100% percent = Scroll position is above from
Example:
{
inside : (instance, percentage) => {},
outside : (instance, percentage) => {},
}
Props
Type: Object
Default: {}
Optional: true
Values to animate when the scroll position changes.
Each prop of the object represents a CSS property or CSS Custom Property (CSS variables). Custom CSS properties always start with two dashes. A prop with the name --name
is accessible with var(--name)
in CSS.
More about CSS custom properties.
Example:
{
props: {
'--one-variable': { },
'--another-variable': { }
}
}
Start and end values
Type: Integer|String
Default: null
Optional: false
Works with all kinds of units. basicScroll uses the unit of to
when from
has no unit.
Examples:
'--name': {
from : '0',
to : '100px',
}
'--name': {
from : '50%',
to : '100%',
}
'--name': {
from : '0',
to : '1turn',
}
Animation timing
Type: String|Function
Default: linear
Optional: true
A known timing or a custom function. 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 timings a value less than 0 or greater than 1 is just fine.
Known timings: backInOut
, backIn
, backOut
, bounceInOut
, bounceIn
, bounceOut
, circInOut
, circIn
, circOut
, cubicInOut
, cubicIn
, cubicOut
, elasticInOut
, elasticIn
, elasticOut
, expoInOut
, expoIn
, expoOut
, linear
, quadInOut
, quadIn
, quadOut
, quartInOut
, quartIn
, quartOut
, quintInOut
, quintIn
, quintOut
, sineInOut
, sineIn
, sineOut
Examples:
'--name': {
timing: 'circInOut'
}
'--name': {
timing: (t) => t * t
}
Direct mode
Type: Boolean
Default: false
Optional: true
basicScroll applies all props globally by default. This way you can use variables everywhere in your CSS, even when the instance tracks just one element. Set direct
to true
to apply styles directly to the DOM Element/Node. Setting direct
to true
also allows you to animate CSS properties, not just CSS variables.
Examples:
<html style="--name: 0;">
<div class="element"></div>
</html>
<html>
<div class="element" style="--name: 0;"></div>
</html>
Tips
- Only animate
transform
and opacity
and use will-change
to hint browsers about the kind of changes. This way the browser can setup appropriate optimizations ahead of time before the element is actually changed. - Keep the amount of instances low. More instances means more checks, calculations and style changes.
- Don't animate everything at once and don't animate too many properties. Browsers don't like this.
- Smooth animations by adding a short transition to the element:
transform: translateY(var(--ty)); transition: transform .1s
. - basicScroll applies all props globally by default. Try to reuse variables across elements instead of creating more instances.