Samuli Natri
Nov. 30, 2016
Updated: Dec. 03, 2016
By Samuli NatriNov. 30, 2016
(Updated: Dec. 03, 2016)

How To Create Parallax Effects (Drupal 8 Tutorial) (Article + Video)

In this tutorial you will learn how to make basic parallax effects in Drupal 8 using ScrollMagic ( and GSAP ( libraries.

I chose ScrollMagic because it seems to be more active and robust than many of the other solutions out there. Also you can do all kinds of animations, pins and scrolling effects, not just parallax effects.

Fluid Container

I’m using Bootstrap subtheme in this tutorial. Here’s how to install it:

  • Change the main container class to .container-fluid in your theme settings (admin/appearance/settings/yourtheme):

This will make our layout fluid so the parallax sections stretch from edge to edge.

Custom Blocks

  • Go to admin/structure/block/block-content/types and create a new block type called Parallax
  • Go to block/add and create two Parallax blocks:

  • Go to admin/structure/block and place the blocks in the content region:

  • Place also some Basic Blocks around the Parallax blocks:

  • Organize the blocks like this:

Now you should see something like this in the frontpage:

Template For a Custom Block Type

  • Turn on debug mode:

Easiest way to disable caching and turn on debugging is to use Drupal Console:

drupal site:mode dev

Or you can do it manually:

Add this in themes/YOURTHEME/YOURTHEME.theme:

 * Implements hook_theme_suggestions_HOOK_alter() for form templates.
 * @param array $suggestions
 * @param array $variables
function YOURTHEME_theme_suggestions_block_alter(array &$suggestions, array $variables) {
    // Block suggestions for custom block bundles.
    if (isset($variables['elements']['content']['#block_content'])) {
        array_splice($suggestions, 1, 0, 'block__bundle__' . $variables['elements']['content']['#block_content']->bundle());


This adds a theme suggestion for the Parallax block type that can be seen in the source code if you have enabled debugging:

  • Create themes/YOURTHEME/templates/block--bundle--parallax.html.twig file and add this in it:
<div class="parallax parallax--{{ elements['#id'] }}">
    <div class="parallax__bg"></div>
    <div class="parallax__content">
        <h2{{ title_attributes }}>{{ label }}</h2>
        {{ content['body']['0']['#text'] | raw}}
parallax--{{ elements['#id'] }} Adds a unique identifier so we can add background images later.
parallax__bg Will be used for the background image.
parallax__content Contains the block label and body.

You can use kint() for debugging:

drush -y en devel kint search_kint
{{  kint() }}
<div class="parallax parallax--{{ elements['#id'] }}">


// general

.main-container {
  padding: 0px;
.page-header {
  padding-bottom: 0px;

// normal sections

.block-block-content1a31ff52-7962-454d-8df9-e5a203d1e4ca {
  text-align: center;
  padding: 10em;
  font-size: 20px;
  background-color: #204d74;
  color: #fff;

// parallax sections

.parallax {
  text-align: center;
  // so we can absolute position the background
  position: relative;
  overflow: hidden;
  height: 600px;

.parallax__bg {
  position: absolute;
  width: 100%;
  height: 140%;

.parallax--parallax01 .parallax__bg {
  background: url('../images/1-darker.png');
.parallax--parallax02 .parallax__bg  {
  background: url('../images/2-darker.png');

.parallax__content {
  // center content vertically
  position: relative;
  top: 50%;
  -webkit-transform: translateY(-50%);
  -ms-transform: translateY(-50%);
  transform: translateY(-50%);
  color: #fff;
  h2 {
    margin: 0px;
    font-size: 30px;
  p {
    font-size: 20px;


ScrollMagic library:

  • Create a js folder in the themes/YOURTHEME folder
  • Download the scripts and put them in themes/YOURTHEME/js folder:
cd themes/YOURTHEME
unzip master
cp janpaepke-ScrollMagic-ae215ee/scrollmagic/minified/ScrollMagic.min.js .
cp janpaepke-ScrollMagic-ae215ee/scrollmagic/minified/plugins/animation.gsap.min.js .
cp janpaepke-ScrollMagic-ae215ee/js/lib/greensock/TweenMax.min.js .
  • Add this in
  - 'YOURTHEME/global-styling'
  •  Add this in themes/YOURTHEME/YOURTHEME.libraries.yml
      css/style.css: {}
    js/ScrollMagic.min.js: {}
    js/animation.gsap.min.js: {}
    js/TweenMax.min.js: {}
    js/main.js: {}
    - core/drupal
    - core/jquery
  • Add this in themes/YOURTHEME/js/main.js:
(function ($) {
    'use strict';
    Drupal.behaviors.myBehavior = {
        attach: function (context, settings) {

            var controller = new ScrollMagic.Controller();
            var scene1 = new ScrollMagic.Scene({
                triggerElement: '.parallax--parallax01',
                triggerHook: 1,
                duration: "100%"
            .setTween(TweenMax.from('.parallax--parallax01 .parallax__bg', 1, {y: '-40%', ease:Power0.easeNone}))

JavaScript coding standards:

  • Clear caches and you should see the effect

It is important to set the .parallax__bg height according to the tween y value. So in this line I have y as -40%:

setTween(TweenMax.from('.parallax--parallax01 .parallax__bg', 1, {y: '-40%', ease:Power0.easeNone}))

Thus I have to set:

.parallax__bg {
  height: 140%;

Note (2016.11.29) : Quick-edit module broke the effect for admin user. Disabling the module solves it temporarily.

We need a scene for each block, so you can either add another scene (just change the class name):

            var scene2 = new ScrollMagic.Scene({
                triggerElement: '.parallax--parallax02',
                triggerHook: 1,
                duration: "100%"
            .setTween(TweenMax.from('.parallax--parallax02 .parallax__bg', 1, {y: '-40%', ease:Power0.easeNone}))

Or you can make a loop:

(function ($) {
    'use strict';
    Drupal.behaviors.myBehavior = {
        attach: function (context, settings) {

            var controller = new ScrollMagic.Controller();

            var blocks = [".parallax--parallax01", ".parallax--parallax02"];

            blocks.forEach(function (block, index) {

                var $bg = $(block).find('.parallax__bg');
                var $content = $(block).find('.parallax__content');

                var tl = new TimelineMax();
                    .from($bg, 2, {y: '-40%', ease: Power0.easeNone}, 0)
                    .from($content, 1, {autoAlpha: 0, ease: Power0.easeNone}, 0.4)

                var scene = new ScrollMagic.Scene({
                    triggerElement: block,
                    triggerHook: 1,
                    duration: "100%"

TimelineMax allows you to define multiple tweens (transitions). In this case I also added a second tween for the content to fade it in:

.from($content, 1, {autoAlpha: 0, ease: Power0.easeNone}, 0.4)

See the greensock docs for more information:

Improvement ideas

Other solutions

Scrollmagic and Screensock


Great tutorial, will certainly try this soon. At the other hand I'm very interested to know how you would do that second improvement idea (injecting the classes automatically). I really hope you decide to make a follow up tutorial. Thanks anyway.

Hi and thanks!
Is it possible to do this with Paragraphs on one page instead of blocks?

I'm also interested in both injecting the images AND using paragraphs to set this up to make it easy for front-end users to use - any updates on these?

Also - I noticed both in my working parallax and your video examples that the effect seems to stop once the image gets to the top third of the page... is there a way to fix this so the effect continues the entire page height?

Add new comment