Parallax Scrolling Sprites with Rellax JS

Parallax bubble sprites for WordPress

In this tutorial we’re going to use the Rellax JS parallax scrolling library to create the effect of rising bubbles as parallax sprites. It’s purely decorative – just for a bit of fun. Although we’re using simple CSS bubbles, you can easily add your own shapes, and control which posts will have the effect applied.

importantMake sure you’re using a custom child theme so you can edit functions.php

Thanks to Richard for the idea for the tutorial 👍

Parallax Sprites

Scaffold the Code

Let’s jump straight in. Go in to your child theme, create a new file called wpt-parallax-sprites.php and paste the following into it:

<?php

/**
 * WP Tutorials : Parallax Sprites (WPTPLX)
 *
 * https://wp-tutorials.tech/add-functionality/parallax-scrolling-sprites-with-rellax-js/
 */

defined('WPINC') || die();

const WPTPLX_RELLAX_VERSION = '1.12.1';
const WPTPLX_META_ENABLE_PARALLAX = '_parallax_sprites';
const WPTPLX_DEFAULT_SPRITE_COUNT = 150;
const WPTPLX_CONTAINER_CLASS = 'wptplx-sprite';
const WPTPLX_ROOT_CONTAINER_SELECTOR = 'body'; // #content

/**
 * Enqueue the front-end assets for WP Tutorials Parallax Sprites.
 */
function wptplx_wp_enqueue_scripts() {
	if (!is_singular()) {
		// The user is not trying to view a single content item.
	} elseif (!filter_var(get_post_meta(get_the_ID(), WPTPLX_META_ENABLE_PARALLAX, true), FILTER_VALIDATE_BOOLEAN)) {
		// The _parallax_sprites post meta is not TRUE for this post/page.
	} else {
		$theme_version = wp_get_theme()->get('Version');
		$base_uri = get_stylesheet_directory_uri();

		// You can download Rellax JS from here:
		// https://github.com/dixonandmoe/rellax
		wp_enqueue_script(
			'rellax',
			$base_uri . '/wpt-parallax-sprites/rellax.min.js',
			null,
			WPTPLX_RELLAX_VERSION
		);

		// This is our main JavaScript code.
		wp_enqueue_script(
			'wpt-parallax-sprites',
			$base_uri . '/wpt-parallax-sprites/parallax-sprites.js',
			array('rellax'),
			$theme_version
		);

		// We pass some data to our front-end JavaScript code in the wptplxData
		// object.
		wp_localize_script(
			'wpt-parallax-sprites',
			'wptplxData', // << You can access this object in the browser.
			array(
				'rootContainerSelector' => WPTPLX_ROOT_CONTAINER_SELECTOR,
				'spriteClasses' => wptplx_get_sprite_classes(),
				'containerClass' => WPTPLX_CONTAINER_CLASS,
				'spriteCount' => WPTPLX_DEFAULT_SPRITE_COUNT,
			)
		);

		// The styles for our sprites.
		wp_enqueue_style(
			'wpt-parallax-sprites',
			$base_uri . '/wpt-parallax-sprites/parallax-sprites.css',
			null,
			$theme_version
		);
	}
}
add_action('wp_enqueue_scripts', 'wptplx_wp_enqueue_scripts');

/**
 * This should return an array of CSS class names to apply to our sprites.
 * Each sprite will have the "wptplx-sprite" class and one of the following
 * random classes.
 */
function wptplx_get_sprite_classes() {
	global $wptplx_sprite_classes;

	if (is_null($wptplx_sprite_classes)) {
		$wptplx_sprite_classes = array(
			'sprite-bubble-one',
			'sprite-bubble-two',
			'sprite-bubble-three',
			'sprite-bubble-four',
			'sprite-diamond-one',
			'sprite-diamond-two',
			'sprite-diamond-three',
			'sprite-diamond-four',
			// Add your won custom sprite CSS classes here...
			// ...
		);
	}

	return $wptplx_sprite_classes;
}

This PHP code really only needs to decide which pages/posts should have parallax sprites enabled, then enqueue the JavaScript & CSS assets when needed. In wptplx_wp_enqueue_scripts() you’ll see that we use get_post_meta() to check if there is a true/yes in the current post’s _parallax_sprites post meta. If you’re not familiar with the standard PHP function filter_var(), you should check it out – it’s really useful for testing “yes”, “no”, “true”, “false” for boolean equivalence.

Next up, in your child theme’s main folder, open functions.php and add the following couple of lines:

// WPT Parallax Sprites
require_once dirname(__FILE__) . '/wpt-parallax-sprites.php';

Create your Custom Field

Using Advanced Custom Fields (or Pods, or some other equivalent), create a custom field called “_parallax_sprites”, like this:

ACF Field for parallaax sprites
Add a custom post meta field so we can specify which posts have parallax sprites

infoFor more information on creating a custom field, see our auto-numbered-headings tutorial. There’s a nice section on how to create a field using ACF.

When you’ve created the custom field, edit the post/page where you want parallax sprites and check the “_parallax_sprites” option.

Asset Files

There’s a bit more we need to do to finish scaffolding the project. In your custom child theme, create a new folder called “wpt-parallax-sprites”. Go into the folder and create two empty files, called “parallax-sprites.css” and “parallax-sprites.js”. We’ll populate the files later.

Finally, download the Rellax JS library file from the CDN and save it to your computer:

https://cdn.jsdelivr.net/gh/dixonandmoe/rellax@master/rellax.min.js

Copy the file into your child theme’s “wpt-parallax-sprites” folder so you end up with three files in there.

That’s the prep work done. Now we can start work on the JavaScript… getting it working in the browser.

Assets for the parallax sprites tutorial
Parallax sprites tutorial assets

The JavaScript Core

For our core functionality, open “wpt-parallax-sprites/parallax-sprites.js” and paste the following into it:

/**
 * WP Tutorials : Parallax Sprites (WPTPLX)
 *
 * https://wp-tutorials.tech/add-functionality/parallax-scrolling-sprites-with-rellax-js/
 */
document.addEventListener('DOMContentLoaded', function() {
	'use strict';

	// Uncomment this for diagnostics
	// console.log('WPT Parallax Sprites : load');

	if (typeof wptplxData === 'undefined') {
		console.log('ERROR: Missing the wptplxData object');
	} else if (typeof Rellax === 'undefined') {
		console.log('ERROR: Missing the Rellax library');
	} else {
		// Uncomment this for diagnostics
		// console.log('WPT Parallax Sprites : init');

		var spriteClassCount = wptplxData.spriteClasses.length;

		var rootContainer = null;
		if (wptplxData.rootContainerSelector) {
			rootContainer = document.querySelector(wptplxData.rootContainerSelector);
		}

		// Fallback to using document.body as the root container.
		if (!rootContainer) {
			rootContainer = document.body;
		}

		var maxWidth = rootContainer.clientWidth;
		var maxHeight = rootContainer.clientHeight;

		// Exclude the sprites from the last 40% of the page.
		maxHeight = maxHeight * 0.60;

		var spriteIndex = 0;
		while (spriteIndex < wptplxData.spriteCount) {
			// Create the sprite's element, its container element and add the
			// sprite as a child of the container.
			const spriteContainer = document.createElement('div');
			const sprite = document.createElement('div');
			spriteContainer.append(sprite);

			spriteContainer.classList.add(wptplxData.containerClass);

			const left = Math.floor(Math.random() * maxWidth);
			const top = Math.floor(Math.random() * maxHeight);
			var speed = Math.floor(Math.random() * 9) - 4;

			spriteContainer.style.left = `${left}px`;
			spriteContainer.style.top = `${top}px`;
			spriteContainer.setAttribute('data-rellax-speed', speed);

			// Choose a random sprite class and add set it as our sprite's
			// CSS class.
			var spriteClassIndex = Math.floor(Math.random() * spriteClassCount);
			var spriteClass = wptplxData.spriteClasses[spriteClassIndex];
			sprite.classList.add(spriteClass);

			// Add the sprite's container (and sprite) to our root container
			// (which is probably document.body)
			rootContainer.append(spriteContainer);

			++spriteIndex;
		}

		// If we've created any sprites, we can initialise Rellax now. We don't
		// just pass the class name of the sprite containers, we need to put a
		// dot before it, because it's a selector.
		if (spriteIndex > 0) {
			wptplxData.rellax = new Rellax(`.${wptplxData.containerClass}`);
		}
	}
});

The code breaks down like this:

  • If wptplxData or Rellax are not defined, then…
    • report an error and don’t go any further
  • Determine our root container element. This can be document.body, or any element on your page, such as #content or #main
  • For each sprite that we need to create…
    • Choose a random sprite type (CSS class) and store it in spriteClass.
    • Create a <div class="wptplx-sprite"></div> element to act as our sprite’s container
    • Create a div for our sprite and set its CSS class to the value of spriteClass
    • Add the sprite div as a child of our sprite’s container div
    • Set a random left and top position for our sprite’s container div
    • Set a random speed for our sprite’s container div
    • Add our sprite container to the root container
  • Initialise Rellax using the .wptplx-sprite selector

The sprites are rendered as two div elements, one inside the other. The outer element is a container element – this is what Rellax controls. The inner element is our actual sprite:

<div class="wptplx-sprite" data-rellax-speed="3" style="left: 12px; top: 34px;">
	<div class="sprite-bubble-three"></div>
</div>

Before we can test the code, we need to add some CSS, so edit “wpt-parallax-sprites/parallax-sprites.css” and add this:

/**
 * WP Tutorials : Parallax Sprites (WPTPLX)
 *
 * https://wp-tutorials.tech/add-functionality/parallax-scrolling-sprites-with-rellax-js/
 */
.wptplx-sprite {
	position: absolute;
	pointer-events: none;
}

.wptplx-sprite>div {
	width: 3em;
	height: 3em;
}


/**
 * Round bubbles
 */
.wptplx-sprite .sprite-bubble-one,
.wptplx-sprite .sprite-bubble-two,
.wptplx-sprite .sprite-bubble-three,
.wptplx-sprite .sprite-bubble-four {
	border-radius: 50%;
	background-image: linear-gradient(to bottom right, white, transparent 30%);
	border: 1px solid lightblue;
}

.wptplx-sprite .sprite-bubble-one {
	border-color: lightblue;
	width: 7em;
	height: 7em;
}

.wptplx-sprite .sprite-bubble-two {
	border-color: lightgrey;
	width: 6em;
	height: 6em;
}

.wptplx-sprite .sprite-bubble-three {
	border-color: lightsteelblue;
	width: 5em;
	height: 5em;
}

.wptplx-sprite .sprite-bubble-four {
	border-color: lightcyan;
	width: 4em;
	height: 4em;
}

/**
 * Diamond bubbles
 */
.wptplx-sprite .sprite-diamond-one,
.wptplx-sprite .sprite-diamond-two,
.wptplx-sprite .sprite-diamond-three,
.wptplx-sprite .sprite-diamond-four {
	border-radius: 1em;
	background-image: linear-gradient(to right, #fff8, transparent 20%);
	border: 1px solid lightblue;
	transform: rotate(45deg);
}

.wptplx-sprite .sprite-diamond-one {
	border-color: lightblue;
	width: 7em;
	height: 7em;
}

.wptplx-sprite .sprite-diamond-two {
	border-color: lightgrey;
	width: 6em;
	height: 6em;
}

.wptplx-sprite .sprite-diamond-three {
	border-color: lightsteelblue;
	width: 5em;
	height: 5em;
}

.wptplx-sprite .sprite-diamond-four {
	border-color: lightcyan;
	width: 4em;
	height: 4em;
}

Analysis of the Logic

As with a lot of WordPress plugins/addons, we hook the wp_enqueue_scripts action to inject our CSS and JavaScript files into a page header. It’s important to pass the correct dependencies and version strings in wp_enqueue_script() and wp_enqueue_style(). Notice that when we enqueue our “wpt-parallax-sprites” scripts, we’re dependent on the “rellax” script being loaded first. Getting these dependencies correct will help your caching and asset aggregation system.

The JavaScript logic should be easy to read – it’s just a loop that puts a lot of DIVs all over the content, at random positions. And the CSS should be easy to hack into whatever shape you want too.

That’s it, really. Have fun with it 😎 👍

Like This Tutorial?

Let us know

WordPress plugins for developers

Leave a comment