Django - The Easy Way Django - The Easy Way
Samuli Natri 2016.11.30
Samuli Natri is a software developer who enjoys programming games and web applications. He attended Helsinki University Of Technology (Computer Science) and Helsinki University (Social Sciences).

Drupal 8 - How To Create Parallax Effects

Tutorial on how to make basic parallax effects using ScrollMagic and GSAP libraries.

I chose ScrollMagic because it seems to be more active 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. Check How To Install Bootstrap Subtheme tutorial for instructions.

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

Check How To Disable Page Caching for more info.

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'] }}"> <!-- 1 -->
    <div class="parallax__bg"></div> <!-- 2 -->
    <div class="parallax__content"> <!-- 3 -->
        <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

Install Devel module and enable kint submodule. Search kint adds additional features like copy path button.

{{  kint() }}
<div class="parallax parallax--{{ elements['#id'] }}">

CSS (less)

// 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;


Check ScrollMagic library on GitHub.

Create a themes/YOURTHEME/js/ folder and download the scripts there:

cd themes/YOURTHEME
wget https://github.com/janpaepke/ScrollMagic/zipball/master
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.info.yml:

  - '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: {}

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}))

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%; // < here

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

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)

Related Links