How to create a Liquid Distortion Hero Slider in Divi

by | Sep 7, 2021 | 22 comments

Preview

Hey Guys! Today we’re gonna check how to create this modern hero slider using liquid distortion animations based on GSAP and PixiJS. Check it out:

Description

As you can see from the video preview, there are several animations going on here:

  • the liquid transition effect when we switch from a slide to another
  • the liquid animation when the mouse hover the image
  • the tilt effect on the Title and Subtitle when we move the move hover the image

In order to achieve all these effects, we’d need to use a lot of custom code using PixiJS and GSAP. But the good news is hmongouachon released a JavaScript library called rgbKineticSlider that will manage everything for us and make our lives definitely easier! Check out his GitHub page for more info on this awesome script.

HTML Markups

This freebie is slightly different from the other ones, as we won’t deal with the core Divi modules. Instead, we will just need to create few simple HTML markups in order to run the slider inside a Canvas created by our Javascript code, and the basic markups for our navigation arrows. Here is the HTML code that we will insert in a Code Module in Divi:

<!-- SLIDER -->
<div id="rgbKineticSlider" class="rgbKineticSlider"></div>

<!-- SLIDER NAV/ARROWS -->
<nav class="dalds__nav arrows">
    <a href="#" class="main-nav prev" data-nav="previous">Prev</a>
    <a href="#" class="main-nav next" data-nav="next">Next</a>
</nav>

Note that our slider is just composed of a div with id=”rgbKineticSlider”. This is essentially the main markup to run our slider. Basically, it’s just a container. Our script will detect that guy and append the slider inside it through a canvas. If you are not familiar with canvas and how it can be useful when drawing 2D/3D animations in our web projects, make sure to check out this documentation.

Custom CSS

There is not much to talk about here. The CSS is pretty basic. Since all the animations are controlled by our Javascript library, we’ll only need few lines to styles the navigation arrows and position our slider correctly in order to cover all the screen.

To make your life easier, we already set some CSS variables in order to style the arrow text & background color so you don’t have to dive into the code to make basic changes:

:root{
  --dalds__arrows__text-color: #fff;
  --dalds__arrows__bg-color: #000;
  --dalds__arrows__text-color--hover: #000;
  --dalds__arrows__bg-color--hover: #fff;
}

One thing I’d like to focus your attention on is the following code on lines 25 & 26:

height: 100vh; /* Fallback for browsers that do not support Custom Properties */
height: calc(var(--vh-mobile, 1vh) * 100);

Why are we using this calculation method and not just 100vh? To avoid the annoying jump on mobile phones when the bottom mobile navigation gets visible and create a glitch effect when you scroll up and down your website. You can read a really interesting article on how to set a 100vh section on mobile devices on CSS-tricks website (highly recommended!).

Here is the complete custom CSS used in this layout. Whenever you need to copy/paste it to your website, you can quickly do it by pressing the button below the code window, and it will copy all the code to your clipboard.

<style>
/*
Template: Liquid Distortion Slider
Author: Maxime Beguin
Company: Divi Agency
URL: https://divi.agency/
Version: 1.0.0
Licence: MIT
*/
  
:root{
  --dalds__arrows__text-color: #fff;
  --dalds__arrows__bg-color: #000;
  --dalds__arrows__text-color--hover: #000;
  --dalds__arrows__bg-color--hover: #fff;
}
  
/* FULLPAGE POSITIONING */
  
.rgbKineticSlider {
   display: block;
   position: relative;
   overflow: visible;
   height: 100vh; /* Fallback for browsers that do not support Custom Properties */
   height: calc(var(--vh-mobile, 1vh) * 100);
   width: 100%;
}

canvas {
   position: absolute;
   display: block;
   left: 0 !important;
   top: 0 !important;
   -webkit-transform: none !important;
   transform: none !important
}


/* NAVIGATION ARROWS */

nav.dalds__nav.arrows {
   cursor: pointer;
}

nav.dalds__nav.arrows a {
   position: absolute;
   top: 47.5vh;
   z-index: 1;
   padding: 20px;
   -webkit-transition: .3s all ease;
   -o-transition: .3s all ease;
   transition: .3s all ease;
   background-color: var(--dalds__arrows__bg-color);
   color: var(--dalds__arrows__text-color);
   border-radius: 50%;
   display: -webkit-box;
   display: -ms-flexbox;
   display: flex;
   -webkit-box-align: center;
   align-items: center;
   -webkit-box-pack: center;
   justify-content: center;
   height: 70px;
   width: 70px;
   cursor: pointer;
}

nav.dalds__nav.arrows a:hover {
   background-color: var(--dalds__arrows__bg-color--hover);
   color: var(--dalds__arrows__text-color--hover);
}

nav.dalds__nav.arrows a.next {
   right: 10vw;
}

nav.dalds__nav.arrows a.prev {
   left: 10vw;
}


/* RESPONSIVE SETTINGS */

@media screen and (max-width: 980px) {
   nav.dalds__nav.arrows a {
      top: unset;
      bottom: 10vh;
   }
   canvas {
      z-index: -1;
   }
}
</style>

Custom JavaScript

Here is where all the magic happens! Let’s separate this tutorial into 3 sections:

  • Set our constants with Images and Titles/Subtitles
  • Calculate the viewport height on mobile
  • Configure the Liquid Slider

Set our constants with Images and Titles/Subtitles

In order to set our content correctly, we will need to add them inside a constant that is recognized by our JavaScript. Sounds difficult? Don’t fear it, it’s pretty straightforward! The only thing we’ll have to do is modifying the following code:

  // IMAGES SETTINGS
  const images = [
    "YOUR_IMAGE_URL-1.jpg",
    "YOUR_IMAGE_URL-2.jpg",
    "YOUR_IMAGE_URL-3.jpg",
    "YOUR_IMAGE_URL-4.jpg",
    "YOUR_IMAGE_URL-5.jpg",
    "YOUR_IMAGE_URL-6.jpg"
  ];

  // CONTENT SETTING
  const texts = [
    ["TITLE-1", "SUBTITLE-1"],
    ["TITLE-2", "SUBTITLE-2"],
    ["TITLE-3", "SUBTITLE-3"],
    ["TITLE-4", "SUBTITLE-4"],
    ["TITLE-5", "SUBTITLE-5"],
    ["TITLE-6", "SUBTITLE-6"],
  ];

Just replace the image URLs with the ones you want to use. Do the same with titles and subtitles.

Now make sure to download the following images on your computer: displace-circle.png and map-9.jpeg. Upload them to your own media library and copy the generated URLs.

Once done, open the JS Module Code again, go to lines 58 & 59 and replace the URLs with the ones copied above:

// SETTINGS
// displacement images sources
backgroundDisplacementSprite: 'YOUR_PATH/map-9.jpeg', // slide displacement image 
cursorDisplacementSprite: 'YOUR_PATH/displace-circle.png', // cursor displacement image

And you are all set: save your page and check the frontend, you should see your content inside the slider. Easy peasy!

Calculate the viewport height on mobile

As mentioned in the CSS section, we need to correctly calculate the viewport height to avoid the annoying “jump” that happens on mobile due to the navigation bar of our mobile browsers. In order to do this we’ll apply the following code:

// RESPONSIVE FULLHEIGHT ON MOBILE BROWSERS
  let vw = window.innerWidth;
  let vh = window.innerHeight * 0.01;
  document.documentElement.style.setProperty('--vh-mobile', `${vh}px`);  
  window.addEventListener('resize', () => {
    if(window.innerWidth !== vw){
      let vh = window.innerHeight * 0.01;
      document.documentElement.style.setProperty('--vh-mobile', `${vh}px`);
      vw = window.innerWidth;
    };
  });

Basically, we are storing the innerWidth and innerHeight of the window inside the vw and vh variables. Then we create a CSS variable called –vh-mobile that will be used by our CSS code to calculate the correct viewport height. To make it responsive, we’ll add an eventListener when the browser is resizing (only on window innerWidth changes) and recalculate the viewport height if needed. And that’s it!

Configure the Liquid Slider

First of all, we need to initialize our script and assign our content to it:

// INIT SLIDER
  rgbKineticSlider = new rgbKineticSlider({
    // images and content sources
    slideImages: images,
    itemsTitles: texts,

Then, we need to configure all the settings. The rgbKineticSlider library has a ton of settings, and I won’t describe each option since I’ve added all the comments from the official documentation inside the code itself. If you like the actual animation, you can keep the settings as it is now. But if you are curious to see all the possibilities that this library offers, I’d encourage you to play with the settings as follow:

  • change the value from FALSE to TRUE (and vice versa) to see what happen in the frontend.
  • Decrease and increase each value to see the resulted animation.
  • Double check the // text settings section in order to make your titles and subtitles responsive on mobile devices.

When you find the perfect setting, you are done!

Here is the complete custom JavaScript used. Again, if you just want to copy/paste the code, feel free to use your Copy to Clipboard button below the code window.

<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.7.1/gsap.min.js"  crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/gh/hmongouachon/rgbKineticSlider/js/libs/pixi.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi-filters/1.0.8/filters.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/gh/hmongouachon/rgbKineticSlider/js/rgbKineticSlider.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
  // IMAGES SETTINGS
  const images = [
    "https://divi.agency/wp-content/uploads/2021/08/pexels-matheus-bertelli-573294.jpg",
    "https://divi.agency/wp-content/uploads/2021/08/pexels-janko-ferlic-687501.jpg",
    "https://divi.agency/wp-content/uploads/2021/08/pexels-oluwatoyin-adedokun-3723625.jpg",
    "https://divi.agency/wp-content/uploads/2021/08/pexels-mariana-montrazi-7366424.jpg",
    "https://divi.agency/wp-content/uploads/2021/08/pexels-yasin-gundogdu-2644735.jpg",
    "https://divi.agency/wp-content/uploads/2021/08/pexels-kei-scampa-3823741.jpg"
  ];

  // CONTENT SETTING
  const texts = [
    ["Design", "Beautiful things."],
    ["Passion", "For my work."],
    ["Art", "My oxygen."],
    ["Dedication", "Until reaching satisfaction."],
    ["Accountability", "Yesterday, today and tomorrow."],
    ["Inspiration", "Stand out from the crowd."],
  ];
</script>
<script>
/*
Template: Liquid Distortion Slider
Author: Maxime Beguin
Company: Divi Agency
URL: https://divi.agency/
Version: 1.0.0
Licence: MIT
*/
jQuery(document).ready(function($){
  // RESPONSIVE FULLHEIGHT ON MOBILE BROWSERS
  let vw = window.innerWidth;
  let vh = window.innerHeight * 0.01;
  document.documentElement.style.setProperty('--vh-mobile', `${vh}px`);  
  window.addEventListener('resize', () => {
    if(window.innerWidth !== vw){
      let vh = window.innerHeight * 0.01;
      document.documentElement.style.setProperty('--vh-mobile', `${vh}px`);
      vw = window.innerWidth;
    };
  });

  // INIT SLIDER
  rgbKineticSlider = new rgbKineticSlider({
    // images and content sources
    slideImages: images,
    itemsTitles: texts,

    // SETTINGS
    // displacement images sources
    backgroundDisplacementSprite: '/wp-content/uploads/2021/08/map-9.jpeg', // slide displacement image 
    cursorDisplacementSprite: '/wp-content/uploads/2021/08/displace-circle.png', // cursor displacement image

    // cursor displacement effect 
    cursorImgEffect : true, // enable cursor effect
    cursorTextEffect : false, // enable cursor text effect
    cursorScaleIntensity : 0.65, // cursor effect intensity
    cursorMomentum : 0.14, // lower is slower

    // swipe 
    swipe: true, // enable swipe
    swipeDistance : window.innerWidth * 0.4, // swipe distance - ex : 580
    swipeScaleIntensity: 2, // scale intensity during swipping

    // slide transition
    slideTransitionDuration : 1, // transition duration
    transitionScaleIntensity : 30, // scale intensity during transition
    transitionScaleAmplitude : 160, // scale amplitude during transition

    // regular navigation
    nav: true, // enable navigation
    navElement: '.dalds__nav.arrows .main-nav', // set nav class


    // image rgb effect
    imagesRgbEffect : false, // enable img rgb effect
    imagesRgbIntensity : 0.9, // set img rgb intensity
    navImagesRgbIntensity : 80, // set img rgb intensity for regular nav 

    // texts settings
    textsDisplay : true, // show title
    textsSubTitleDisplay : true, // show subtitles
    textsTiltEffect : true, // enable text tilt
    googleFonts : ['Playfair Display:700', 'Roboto:400'], // select google font to use
    buttonMode : false, // enable button mode for title
    textsRgbEffect : false, // enable text rgb effect
    textsRgbIntensity : 0.03, // set text rgb intensity
    navTextsRgbIntensity : 15, // set text rgb intensity for regular nav

    textTitleColor : 'white', // title color
    textTitleSize : 125, // title size
    mobileTextTitleSize : 80, // title size
    textTitleLetterspacing : 3, // title letterspacing

    textSubTitleColor : 'white', // subtitle color ex : 0x000000
    textSubTitleSize : 21, // subtitle size
    mobileTextSubTitleSize : 21, // mobile subtitle size
    textSubTitleLetterspacing : 2, // subtitle letter spacing
    textSubTitleOffsetTop : 80, // subtitle offset top
    mobileTextSubTitleOffsetTop : 60, // mobile subtitle offset top
  });
});
</script>

Additional Notes

Since we can’t run custom codes inside the Visual Builder view, the settings (including images, content, etc…) won’t reflect in our backend. To avoid having a blank section, we used a static background image that applies to the Visual Builder view only. You can easily change it by modifying line 99 of our CSS:

.et-fb-root-ancestor .et-db #et-boc .et-l div.et_pb_section.dalds__section {
   background-image: url(https://divi.agency/wp-content/uploads/2021/08/pexels-matheus-bertelli-573294.jpg) !important;
}

Change logs

v1.0.0 (07/09/2021):

  • Initial public release

Final Thoughts

This type of slider is certainly not a good fit for “traditional” websites. But if you’re looking after adding a creative touch to a modern and “artistic” project, then this liquid slider could be the perfect match. While it’s based on custom codes – and barely uses the core Divi modules – it’s still quite easy and fun to set up, even for JavaScript beginners.

Well guys and gals, I hope you liked this freebie and learned something new today that will add value to your next Divi project! Let me know what you think in the comments below!

Wanna share some love? You are more than welcome to leave a review on my Facebook page!

Maxime Beguin

Maxime Beguin

Founder & CEO of Divi Agency

My journey as a self-taught Full Stack Developer started in 2011. Back in the days, I was mainly building HTML/CSS websites using Notepad++ and Joomla (tears of nostalgy…). I started using WordPress a few years later while I was learning PHP and JavaScript, and decided to completely embrace the Divi Community. I’m now the CEO of Divi Agency – a white label agency based In Bologna (Italy) 100% focused on helping other agencies and freelancers growing their Divi Business – but I still try to dedicate time to help people in the various Divi groups on Facebook and to write free tutorials on this blog.

For agencies

Looking for a White Label partner?

We’re happy to work with other agency owners, from freelancers looking to diversify income, to any companies looking to outsource workflow. We love connecting with like-minded individuals and collaborating to exceed client expectations together.

Suscribe to our Newsletter

22 Comments

    • Maxime Beguin

      Hi Matej,

      You could try the following steps:

      – add HTTPS to your website.
      – Change the image URLs to your own images as described in the YT video and the article above.
      – Download the following images and upload them into your media library: https://divi.agency/wp-content/uploads/2021/08/map-9.jpeg and https://divi.agency//wp-content/uploads/2021/08/displace-circle.png
      – Then open the JS Code module, and inside the section // displacement images sources insert the URLs of the images above (from your own media library)

      I edited the article above and explained these steps in detail.

      Please let me know if it solves the issue.

      Reply
      • Matej

        Hi again,

        I didi what you said, added HTTPS so my website, changed the image URLs and downloaded the files and uploaded them through my media library and added them in the JS Code module inside the section you mentioned.

        I still don’t see the text or the images.

        Reply
        • Maxime Beguin

          From your code, I can see you replaced just 1 image in the const images = […]. You need to replace them all.
          Also just before the image settings, I can see you replaced the scripts with the img URLs. You need to keep the scripts src as they are.

          Reply
          • Matej

            I just made the necessary changes as you said for it to work, but it still doesn’t display any images or text.

          • Maxime Beguin

            I keep seeing this error on the console log: “Uncaught (in promise) TypeError: h.Deferred is not a constructor” generated by the imagesloaded script. Are you deferring JavaScript files somehow? Maybe in the performance tab inside the Divi options? Or through a cache plugin like WP Rocket?

  1. Nick

    I also got an error “Uncaught (in promise) TypeError: h.Deferred is not a constructor” Edited everything in Divi. On one site gives out this error, on another is not present

    Reply
    • Maxime Beguin

      Hey Nick, are you deferring the JavaScript/jQuery files somehow? It looks like an issue with a speed optimization setting…

      Reply
  2. Ahmed Ramadan

    i uploaded the Jason File, the image shows in the builder view and when i go out it changes to a Black screen

    Reply
    • Maxime Beguin

      Hey Ahmed, if you followed all the steps described in the tutorial and the YouTube video, it may be due to some conflict with other scripts or your optimisation settings. Could you please share a link where you get this black screen?

      Reply
  3. RiOo

    Does the file still works with the latest Divi Update? because i get a black screen once i install the file.
    https://ahmedramadan.club/

    Reply
    • Maxime Beguin

      Hey RiOo, the demo is running on the last version of Divi (v4.12.1) and it works smoothly. I can’t see the slider running on the page you shared. Could you share the page where it’s running?

      Reply
        • Maxime Beguin

          There are several issues on your sites. Please make sure to watch the whole video and read the tutorial to apply the necessary changes to your code. Are you deferring jQuery in the speed optimization settings of divi or using a caching plugin? If you do, try to disable it and let me know if it changes anything.

          Reply
  4. Joe

    Amazing! Thank u for your work!

    Reply
    • Maxime Beguin

      Thanks Joe, really appreciate it!

      Reply
  5. Younes

    First of all, Big thanks to you for your amazing work.

    However it seems that i get the same black screen error and my console is spitting this : “Uncaught (in promise) TypeError: h.Deferred is not a constructor” again and again…

    Did some of the previous one having the same issue managed to fix ? Or do you have a solution for me please ?

    Reply
    • Younes

      Okay, my bad i found the issue.

      For the ones that will come after me : Divi -> theme options -> desactivate ” Defer jQuery And jQuery Migrate”

      runs like a charm \o/

      Thanks again

      Reply
  6. abdurrahman

    hello, thank you very much for your work. i uploaded the json file and i closed divi js deffering. file works but thats not the same animation in my case. not liquid transition. can you help me please? my website is https://limon.tk

    Reply
    • Maxime Beguin

      Hey abdurrahman,

      if you want to defer your files, my advice is to copy all the scripts inside your Child Theme and properly enqueue them with the correct dependencies. You need to be sure that the init file isn’t running before the libraries have been fully loaded on the site. Fortunately, WordPress can natively handle it through the wp_enqueue_script() function: https://developer.wordpress.org/reference/functions/wp_enqueue_script/.

      Good luck!

      Reply
  7. Zach

    Thank you for creating this. Is there not a way to change the background color of the entire canvas to something other than black?

    Reply

Submit a Comment

Your email address will not be published. Required fields are marked *

More Freebies

Adding a subtle animation to your menu can increase the curiosity of your visitors and the overall user experience. This tutorial will show you how to create a fullwidth menu using the trendy circular reveal animation.

GSAP has been extremely popular in the last years to create awesome animations on both website and mobile apps environments. Now is the perfect time to fully integrate it into your next Divi projects as a good alternative to popups.

“How can I add a simple filter on my Divi website?” is a recurring question on the Divi Facebook groups. Well, today we’re going to implement that without using any plugin – just by using the default Divi modules, a bit of custom codes, and the Isotope JS library.