Animated Image Slide In Effect Shopify Section

Creating an eye-catching banner section for your store is a great way to capture the attention of potential customers and enhancing their shopping experience. In this blog post, we will explore how to design a dynamic banner section that features an engaging product image animation. By leveraging CSS animations and Liquid templating, you can create a visually stunning display that not only showcases your products but also adds a touch of interactivity to your online store. Whether you're a seasoned developer or just starting with Shopify, this guide will provide you with the tools and techniques needed to elevate your store's aesthetic and drive conversions.
Code: https://github.com/ndrishinski/blogs/commit/16be98059e299e72606001765be967390a6d9914
Prefer video?
Enjoy, otherwise read on!
Remove any background from images
When we add our image to this section, we want to make sure we remove any background of the product itself so there is not a big square image flying in. There are many ways to do this but if you are looking for a quick and easy way then I recommend using https://www.remove.bg/ which has served me well. Once you download your new product image with no background you are ready to code!
Creating our section
The first thing we will need to do in our duplicated theme is create a new file in the 'sections' directory. You can name it whatever you'd like, but I'm going to call it 'animated-banner.liquid'. Once our file is created we can add our CSS, HTML/Liquid, JavaScript and Schema.
Adding our styles
At the top of the file we can add the following code:
<style>
#custom-hero-animation-banner {
position: relative;
width: 100%;
height: 600px;
overflow: hidden;
background: linear-gradient(to right, {{ section.settings.background-first-color }}, {{ section.settings.background-second-color }});
display: flex;
align-items: center;
justify-content: center;
}
#custom-hero-animation-banner * {
color: {{ section.settings.text-color}};
}
#custom-hero-animation-banner .container {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
padding: 2rem;
width: 100%;
}
#custom-hero-animation-banner .content {
text-align: center;
z-index: 20;
opacity: 0;
transform: translateY(20px);
margin-top: 50px;
}
#custom-hero-animation-banner h1 {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 1rem;
}
#custom-hero-animation-banner p {
font-size: 1.25rem;
max-width: 600px;
margin: 0 auto 2rem;
}
#custom-hero-animation-banner .button {
background-color: {{ section.settings.button-color }};
color: {{ section.settings.button-text-color }};
border: none;
padding: 0.75rem 1.5rem;
font-size: 1.5rem;
font-weight: 600;
border-radius: 0.375rem;
cursor: pointer;
display: inline-flex;
align-items: center;
transition: background-color 0.3s ease;
}
#custom-hero-animation-banner .button:hover {
background-color: #f3e8ff;
}
#custom-hero-animation-banner .arrow-right {
margin-left: 0.5rem;
width: 1.25rem;
height: 1.25rem;
}
#custom-hero-animation-banner .image-container {
position: absolute;
top: 50%;
left: 100%;
transform: translate(50%, -{{ section.settings.image-height-from-top }}%);
width: 100%;
max-width: 400px;
aspect-ratio: 3 / 4;
opacity: 0;
}
#custom-hero-animation-banner #product-image {
width: 100%;
height: 100%;
object-fit: contain;
filter: drop-shadow(0 25px 25px rgba(0, 0, 0, 0.15));
}
#custom-hero-animation-banner .trust-indicator {
position: absolute;
bottom: 2rem;
left: 50%;
transform: translateX(-50%);
text-align: center;
z-index: 20;
opacity: 0;
}
#custom-hero-animation-banner .trust-indicator p {
/* font-size: 0.875rem; */
font-size: 18px;
font-weight: 600;
margin-bottom: 0.5rem;
}
#custom-hero-animation-banner .stars {
display: flex;
justify-content: center;
gap: 0.25rem;
}
#custom-hero-animation-banner .star {
width: 2.25rem;
height: 2.25rem;
color: #fbbf24;
}
@media (min-width: 768px) {
#custom-hero-animation-banner h1 {
font-size: 3.75rem;
}
#custom-hero-animation-banner p {
font-size: 1.5rem;
}
#custom-hero-animation-banner .image-container {
max-width: 500px;
}
}
@media (max-width: 767px) {
#custom-hero-animation-banner .trust-indicator p {
font-size: 15px;
margin-bottom: 0.25rem;
}
}
{% if section.settings.enable-image-movement %}
#custom-hero-animation-banner #product-image {
animation: rotate-image 1s ease-in-out infinite alternate;
}
@keyframes rotate-image {
0% {
transform: rotate(-5deg);
}
100% {
transform: rotate(5deg);
}
}
{% endif %}
There is a lot of CSS here. I'm not going to worry about talking thru all of it but just take notice of the places we are referencing our theme settings ({{ section.settings... }}. These are customizable options available in the theme editor!
Adding our HTML/Liquid
Now that we have our CSS in place, let's add our HTML below it. Again take notice of our references to our schema settings that we will create in a moment:
<div class="hero-section unique-class-name-section-hero" id="custom-hero-animation-banner">
<div class="container">
<div class="content">
<h1 id="hero-title">{{ section.settings.banner-heading }}</h1>
<p id="hero-description">
{{ section.settings.banner-subheading }}
</p>
{% if section.settings.show-cta-button %}
<button id="cta-button" class="button">
{{ section.settings.cta-text }}
</button>
{% endif %}
</div>
<div class="image-container">
<img src="{{ section.settings.main-image | image_url }}" alt="Featured Product" id="product-image" />
</div>
</div>
<div class="trust-indicator">
<p>{{ section.settings.bottom-text }}</p>
<div class="stars">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="star">
<path
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="star">
<path
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="star">
<path
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="star">
<path
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="star">
<path
d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" />
</svg>
</div>
</div>
</div>
Add our JavaScript
Now that our HTML/Liquid is in place, it's time to add our JavaScript for our animation and functionality! Right below the HTML code we pasted above, we can add this:
<script> document.addEventListener("DOMContentLoaded", () => { const imageContainer = document.querySelector(".image-container"); const content = document.querySelector(".content"); const trustIndicator = document.querySelector(".trust-indicator"); {% if section.settings.show-cta-button and section.settings.cta-button-link %} document.querySelector('#cta-button').addEventListener('click', function() { window.location.href = 'products/{{ section.settings.cta-button-link }}' }) {% endif %} // Slide in the image setTimeout(() => { imageContainer.style.transition = "opacity 1s ease, left 1s ease"; imageContainer.style.opacity = "1"; imageContainer.style.left = "50%"; imageContainer.style.transform = "translate(-50%, -{{ section.settings.image-height-from-top }}%)"; }, 100); // Fade in and rise up the content setTimeout(() => { content.style.transition = "opacity 0.5s ease, transform 0.5s ease"; content.style.opacity = "1"; content.style.transform = "translateY(0)"; }, 1000); // Fade in the trust indicator setTimeout(() => { trustIndicator.style.transition = "opacity 0.8s ease"; trustIndicator.style.opacity = "1"; }, 1500); // Stagger the text animations const textElements = [ document.getElementById("hero-title"), document.getElementById("hero-description"), // document.getElementById("cta-button"), ]; textElements.forEach((element, index) => { setTimeout(() => { element.style.transition = "opacity 0.5s ease, transform 0.5s ease"; element.style.opacity = "1"; element.style.transform = "translateY(0)"; }, 1000 + index * 200); }); }); </script>
Adding our Schema Settings
Now we can finally add our schema settings which will enable us to add this section from the theme editor, as well as give us advanced customizable options for the section! At the bottom of the file paste:
{% schema %}
{
"name": "Banner-Slide-In",
"settings": [
{
"type": "image_picker",
"id": "main-image",
"label": "Main Product Image"
},
{
"type": "text",
"id": "banner-heading",
"label": "Banner Heading",
"default": "Discover Your Perfect Style"
},
{
"type": "text",
"id": "banner-subheading",
"label": "Banner Sub Heading",
"default": "Elevate your wardrobe with our curated collection of trendsetting fashion."
},
{
"type": "text",
"id": "cta-text",
"label": "CTA Button Text",
"default": "Shop Now"
},
{
"type": "color",
"id": "background-first-color",
"label": "BG 1st Color",
"default": "#7e22ce"
},
{
"type": "color",
"id": "background-second-color",
"label": "BG 2nd Color",
"default": "#4338ca"
},
{
"type": "color",
"id": "text-color",
"label": "Text Color",
"default": "#fff"
},
{
"type": "color",
"id": "button-text-color",
"label": "Button Text Color",
"default": "#7e22ce"
},
{
"type": "color",
"id": "button-color",
"label": "Button Background Color",
"default": "#fff"
},
{
"type": "checkbox",
"id": "show-cta-button",
"default": false,
"label": "Show CTA Button"
},
{
"type": "range",
"default": 40,
"min": 0,
"max": 100,
"label": "Image height from top",
"step": 1,
"id": "image-height-from-top"
},
{
"type": "text",
"default": "Trusted by over 1 million customers",
"label": "Bottom Text",
"id": "bottom-text"
},
{
"type": "product",
"id": "cta-button-link",
"label": "Product Link"
},
{
"type": "checkbox",
"default": true,
"label": "Enable image movement",
"id": "enable-image-movement"
}
],
"presets": [
{
"name": "Banner-Slide-In"
}
]
}
{% endschema %}
Now we should be able to find this section in our Theme Editor and add our Image and other customizations we want to make!
Conclusion

I hope that you have enjoyed this tutorial and found it an easy addition to your store! Please subscribe to my Youtube channel for more content just like this!