Seamless Scrolling: Fixing That Annoying Shopify Announcement Banner Flash
Hey store owners! You know that little detail that can drive you absolutely nuts? For many, it's the announcement banner at the top of their Shopify store. Specifically, that jarring "flash" or "jump" when an infinitely scrolling marquee banner reaches its end and resets. It's a common headache, and recently, our community tackled it head-on in a discussion that brought out some fantastic insights and solutions.
Our friend Paul222 kicked off the conversation, asking why his custom scrolling banner would flash every time it completed a loop. He shared his code, which aimed for a seamless loop but instead hit a snag, showing a brief black space before restarting. He was particularly impressed by how sites like ravemoreberlin.com managed a perfectly smooth, endless scroll without any hiccups. Let's break down what the experts and fellow merchants had to say, and how you can banish that flash for good.
Understanding the Flash: Why It Happens
Before diving into fixes, it's good to understand the root cause. As NKCreativeSoulutions and others pointed out, the problem typically occurs when the animation reaches its 100% point and resets to 0%. If the content isn't duplicated enough times, or if the animation's endpoint doesn't perfectly align with the start of an identical content segment, you get that awkward empty space or a noticeable jump. It's like a video loop that isn't quite seamless.
PaulNewton, another community member, even raised a broader point about marquees and slideshows. He suggested they can be "MASSIVE user annoyances" and encourage "inperformant behaviors." While that's a valid consideration for user experience and site speed, if you've decided a scrolling banner is right for your brand, let's make sure it at least works flawlessly!
The Core Solution: Duplicating Content for a Seamless Loop
The consensus among the experts is that to achieve a truly endless, smooth scroll without a flash, you need to ensure there's always more content flowing in from the right before the animation resets. This is often done by duplicating your announcement content multiple times. The key is to shift the animation by exactly one full 'set' of your duplicated content. This way, when the animation resets, it's effectively jumping to a pixel-identical position, making the loop invisible to the user.
Tim_tairli confirmed that even sites like ravemoreberlin.com use this method, often by outputting 10 copies of the original announcements. The magic lies in how the animation is applied.
Method 1: Liquid-Based Duplication (Simpler for Many)
Asif_ShopiDevs offered a direct Liquid-based solution that many store owners will find straightforward. This method involves looping your announcement blocks multiple times directly in your Liquid code and adjusting the CSS animation to match.
Here's how to implement Asif_ShopiDevs's solution:
- Navigate to your theme code: In your Shopify admin, go to Online Store > Themes. Find your current theme, click Actions > Edit code.
- Locate your custom banner file: Paul222 mentioned his code was in
sections/custom-scrolling-banner.liquid. You'll likely have a similar file for your custom announcement bar. - Replace your existing code (or the relevant section) with this updated version:
{%- if template.name != 'product' -%}
{% assign ic %}
{%- endif -%}
{% schema %}
{
"name": "Scrolling Announcement",
"settings": [
{
"type": "range",
"id": "speed",
"min": 20,
"max": 200,
"step": 5,
"unit": "s",
"label": "Scrolling Speed",
"default": 60
},
{
"type": "color",
"id": "bg_color",
"label": "Background Color",
"default": "#000000"
},
{
"type": "color",
"id": "text_color",
"label": "Text Color",
"default": "#ffffff"
}
],
"blocks": [
{
"type": "announcement",
"name": "Announcement",
"settings": [
{
"type": "text",
"id": "text",
"label": "Text",
"default": "Welcome"
}
]
}
],
"presets": [
{
"name": "Scrolling Announcement"
}
]
}
{% endschema %}
What's happening here? Asif_ShopiDevs changed the original code to loop the announcement content 10 times ({% for i in (1..10) %}). Crucially, the CSS @keyframes marquee now animates to transform: translateX(-10%);. This means each full "set" of your announcements makes up 10% of the total width. Shifting by -10% moves it exactly one full set forward, and when it resets, it's visually the same as if it continued, eliminating the flash.
Method 2: JavaScript-Based Dynamic Duplication (More Flexible)
Ajaycodewiz and Tim_tairli suggested a more dynamic approach using JavaScript. This is great for responsiveness across different screen sizes and if your announcement content length can vary. Ajay's solution uses JavaScript to measure the content and viewport widths, then clones the content as many times as needed to ensure a seamless loop.
Here's how to implement Ajaycodewiz's solution:
- Navigate to your theme code: As before, Online Store > Themes > Actions > Edit code.
- Locate your custom banner file: Find your
sections/custom-scrolling-banner.liquidor similar file. - Replace your existing code (or the relevant section) with this JavaScript-enhanced version:
{%- if template.name != 'product' -%}
{%- endif -%}
{% schema %}
{
"name": "Scrolling Announcement",
"settings": [
{ "type": "range", "id": "speed", "min": 20, "max": 200, "step": 5, "unit": "s", "label": "Scrolling Speed", "default": 60 },
{ "type": "color", "id": "bg_color", "label": "Background Color", "default": "#000000" },
{ "type": "color", "id": "text_color", "label": "Text Color", "default": "#ffffff" }
],
"blocks": [
{ "type": "announcement", "name": "Announcement", "settings": [{ "type": "text", "id": "text", "label": "Text", "default": "Welcome" }] }
],
"presets": [{ "name": "Scrolling Announcement" }]
}
{% endschema %}
Ajay also provided a video demonstrating this in action, showing a smooth, flash-free scroll:
https://drive.google.com/file/d/1NNHF6xXGmlr8lUFB71Tdhnnc9YPMkNZV/view?usp=sharing

The JavaScript dynamically figures out how many copies of your announcement text are needed to fill the screen and then some. It sets a CSS variable --marquee-shift to precisely the width of one copy. This ensures that when the animation ends and restarts, it's shifting by exactly one full segment of your content, making the loop completely seamless. It also uses ResizeObserver to recalculate if the screen size changes, which is super smart!

Other Considerations from the Discussion
translate3dvs.translateX: NKCreativeSoulutions suggested tryingtranslate3dinstead oftranslateXto force GPU acceleration. While this can sometimes improve animation smoothness, it won't fix the underlying issue of content not being long enough for a seamless loop on its own, as Paul222 found out.- Simple Duplication: A "simpler" workaround mentioned was to just duplicate the string in the announcement bar itself a few times. While this can visually extend the content, it's not a true seamless loop and might still have a subtle jump, especially if users pay close attention. The dynamic or 10x Liquid duplication is much more robust.
So, there you have it! The community came through with some truly great solutions for that pesky flashing announcement banner. Whether you go with the Liquid-based 10x duplication or the more dynamic JavaScript approach, you now have the tools to achieve that professional, seamless scroll your customers deserve. It's all about making sure there's always an identical segment of content ready to roll in when the animation resets. Happy customizing!