How to Make an Animated Hero Section With Elementor

Table of Contents

Creating an eye-catching hero section for your website can be a game-changer in grabbing user attention. In this tutorial, we’ll guide you through the process of designing a dynamic hero section using Elementor and GSAP, without requiring any additional plugins. Follow along to elevate your web design skills!

Introduction

In this video tutorial, we demonstrate how to build a sleek, animated hero section using Elementor’s editor and GSAP (GreenSock Animation Platform). This method is simple, efficient, and highly customizable. By the end, you’ll have a responsive and visually appealing hero section ready to showcase your content.

Steps to Create the Hero Section

Setting Up the Containers

  1. Open the Elementor editor panel and create a new page.
  2. Add three containers to the page:
    • Main Wrapper: Assign the CSS class mdw-rotating-image-effect to this container.
    • Image Wrapper: Nest this container inside the Main Wrapper and assign the class mdw-rotating-images.
    • Text Wrapper: Also nest this container inside the Main Wrapper and assign the class mdw-rotating-image-content.

Configuring the Image Wrapper

  1. Set the height of the Image Wrapper container to 100vh to make it span the full viewport height.
  2. Add your images to the Image Wrapper and style them:
    • Border: 1px solid (choose a subtle color).
    • Width: 90px.
    • Height: 130px.
  3. Center the images within the container by setting its alignment to center.
  4. Use position: absolute for precise placement and remove any default margins or paddings.
  5. Duplicate the images as needed to create the desired effect.

Styling the Text Wrapper

  1. Add heading elements to the Text Wrapper for your content.
  2. Style the headings as desired. For example, use spans to create variations in font size or color.
  3. Set the width of the Text Wrapper container to 30% and align its position using absolute positioning.
  4. Make necessary adjustments for a polished look.

Adding GSAP Animation

  1. Insert an HTML element into the Main Wrapper container.
  2. Paste the GSAP code into the HTML element. This code will animate the images and text as desired.
  3. Assign the appropriate CSS classes to ensure the animations target the correct elements.
  4. Test the animations in the Elementor preview to confirm they work as expected.

Making the Section Responsive

  1. Adjust the image sizes and layout for different screen sizes using custom media queries in your CSS.
  2. Ensure the animation scales smoothly on mobile and tablet views by tweaking the GSAP parameters.

Advanced Customization

  • To disable the flip animation, add the class no-flip to the Main Wrapper container (mdw-rotating-image-effect).
  • For a larger image radius, use the class radius-[value]. For example, radius-300 will set a larger corner radius compared to the default radius-90.
  • Customize the animation duration and easing functions in the GSAP script for unique effects.
Extra CSS classes for Elementor animated hero section tutorial.
Here are the additional CSS classes used in this tutorial to create smooth animations for the hero section in Elementor.

Conclusion

This dynamic hero section design using Elementor and GSAP is perfect for showcasing your skills or enhancing your website’s aesthetic appeal. The steps are straightforward and allow for endless customization to suit your brand’s style.

If you found this tutorial helpful, please subscribe to my channel and leave a comment with your thoughts. Let me know if you’d like more tutorials like this in the future. Happy designing!


All the required code snippets and resources are available in the video description or on my website. Check them out to get started!

CSS Class

Main container Class : mdw-rotating-image-effectImage Wrapper Container Class : mdw-rotating-imagesContent Wrapper Container Class : mdw-rotating-image-content

JavaScript Code

<style>
[class^='mdw-rotating-image-effect'] .elementor-widget-image,
[class*='mdw-rotating-image-effect'] .elementor-widget-image{
    transition: none !important;
}
[class^='mdw-rotating-image-effect'] .mdw-rotating-images,
[class*='mdw-rotating-image-effect'] .mdw-rotating-images{
    perspective: 1000px;
    transition: none !important;
}
[class^='mdw-rotating-image-effect'] .elementor-widget-image img,
[class*='mdw-rotating-image-effect'] .elementor-widget-image img,
[class^='mdw-rotating-image-effect'] .elementor-widget-image a,
[class*='mdw-rotating-image-effect'] .elementor-widget-image a{
    max-width: unset;
}
[class^='mdw-rotating-image-effect'] .mdw-rotating-image-content,
[class*='mdw-rotating-image-effect'] .mdw-rotating-image-content,
[class^='mdw-rotating-image-effect'] .mdw-rotating-images,
[class*='mdw-rotating-image-effect'] .mdw-rotating-images{
    opacity: 0;
}
[class^='mdw-rotating-image-effect'].init .mdw-rotating-image-content,
[class*='mdw-rotating-image-effect'].init .mdw-rotating-image-content,
[class^='mdw-rotating-image-effect'].init .mdw-rotating-images,
[class*='mdw-rotating-image-effect'].init .mdw-rotating-images,
html.elementor-html .mdw-rotating-image-content,
html.elementor-html .mdw-rotating-images{
    opacity: 1;
}
</style>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script>
if(!MDWNonce112){
var MDWNonce112 = true;
(function($){
let selector = '[class^="mdw-rotating-image-effect"], [class*="mdw-rotating-image-effect"]',
    options = [],
    isImageLoad = [],
    isWindowLoaded = false,
    isAnimated = [],
    windowHeight,
    bottomView,
    topView

function imageStackEntrance($this, i){
    var breakPoint = '768px',
    media = gsap.matchMedia()
    media.add({
        isDesktop: `(min-width: ${breakPoint})`,
        isMobile: `(max-width: ${breakPoint})`,
    },
    (context) => {
    var { isDesktop } = context.conditions,
        imageContainer = $this.find('.mdw-rotating-images'),
        content = $this.find('.mdw-rotating-image-content'),
        images = $this.find('.elementor-widget-image'),
        imageHeight = images.eq(0).height(),
        count = images.length,
        sliceAngle = (2*Math.PI)/count,
        radius1 = options[i].initRadius + imageHeight/2,
        radius2 = isDesktop ? options[i].radiusDesktop : options[i].radiusMobile,
        cardFlip = options[i].flipCard
        
        radius2 -= options[i].initRadius
    
    $this.addClass('init')    
    
    gsap
    .timeline()
    .from(images, {
        y: $this.find('.mdw-rotating-images').height()/2 + imageHeight * 1.5,
        rotateX: -180,
        stagger: 0.1,
        duration: 0.5,
        opacity: 0.8,
        scale: 3,
    })
    .set(images, {
        transformOrigin: `center ${radius1 + imageHeight/2}px`,
    })
    .set(imageContainer,{
        transformStyle: 'preserve-3d',
    })
    .to(images,{
        y: -radius1,
        duration: 0.5,
        ease: 'power1.out',
    })
    .to(images,{
        rotation: (index) => index*360/count,
        rotateY: 15,
        duration: 1,
        ease: 'power1.out',
    }, '<')
    .to(images,{
        rotation: (index) => (index+1) * (360 / count),
        x: (index) => radius2*Math.sin((180-(index+1)*360/count)*Math.PI/180),
        y: (index) => radius2*Math.cos((180-(index+1)*360/count)*Math.PI/180) - radius1
    })
    .to(images, {
        rotateY: 180,
        duration: 1,
    }, '<')
    .from(content, {
        opacity: 0,
        filter: 'blur(60px)',
        duration: 1,
    }, '<')
    .to(images, {
        repeat: -1,
        duration: 2,
        onRepeat: () => {
        if(cardFlip){
            gsap.to(images[Math.floor(Math.random() * count)], {
                rotateY: '+=180',
            });
        }},
    })
    .to(imageContainer, {
        rotation: 360,
        duration: 20,
        repeat: -1,
        ease: 'none',
    }, '<-=2')
    })
}

function triggerAnimation(e){
    if(e && e.type=='load') isWindowLoaded = true
    if(!isWindowLoaded) return
    $(selector).each(function(i){
        var $this = $(this),
        offset = $this[0].getBoundingClientRect(),
        offsetTop = offset.top,
        offsetBottom = offset.bottom
        if(offsetTop < bottomView && offsetBottom > topView && !isAnimated[i] && isImageLoad[i] && isWindowLoaded){
            isAnimated[i] = true
            imageStackEntrance($this, i)
        }
    })
}

function getValues(){
    $(selector).each(function(i){
        let $this = $(this)
            
        className = $this.attr('class'),
        classNameIndex = className.indexOf('mdw-rotating-image-effect'),
        shortClass = className.substring(classNameIndex, className.indexOf(' ',classNameIndex)),
        values = shortClass.split('-')
        
        options[i] = {
            initRadius: 50,
            radiusDesktop : 170,
            radiusMobile: 90,
            flipCard: true
        }
        
        values.forEach(function(value, index){
            if(value =='initradius' && values[index+1] && !isNaN(values[index+1])){ options[i].initRadius = parseFloat(values[index+1]) 
            }
            if(value =='radius' && values[index+1] && !isNaN(values[index+1])){ options[i].radiusDesktop = parseFloat(values[index+1]) 
            }
            if(value =='mobileradius' && values[index+1] && !isNaN(values[index+1])){ options[i].radiusMobile = parseFloat(values[index+1]) 
            }
            if(value =='noflip'){ options[i].flipCard = false }
        })
    })
}

function init(){
    $(selector).each(function(i){
        isAnimated[i] = false
        isImageLoad[i] = false
        
        var imageCount = 0,
        img = $(this).find('.mdw-rotating-images img')
        
        img.each(function(){
            
            $(this).on('load', function() {
                imageCount++
                if(imageCount == img.length){
                    isImageLoad[i] = true
                    triggerAnimation()
                }
            })
            if(this.complete){
                $(this).trigger('load')
            }
        })
        getValues()
    })
}

function setValues(){
    windowHeight = $(window).height()
    bottomView = (windowHeight / 100) * 50
    topView = (windowHeight / 100) * 50
}

$(document).ready(init)
$(window).on('load resize', setValues)
$(window).on('load scroll', triggerAnimation)

})(jQuery)
}
</script>

Related Tutorials