Fading Banner Component

I am in the process of rebuilding my old RW Classic website https://www.esquireprint.com/ in Elements and you will see I have created a very particular banner style that cycles through three subtly different images.

I have used this style of banner on many other sites I’ve built which are full width design x450px deep. The number of images which fade transition can vary from 2, 3, 4 or even 5 different images but it always ends and stays on the final composed banner image.

Can someone explain to me how I can replicate this banner design in Elements…

We don’t have a component to mimic exactly what you’re doing there, but maybe you could change the design a little bit…

Perhaps use a container with a background image, and use the Reveal component to fade/animate in the text over the top, this could look pretty nice!

Let me know if you need more help setting something like this up :slight_smile:

(If you really want to match this exactly, you’d 100% be able to re-build this using a custom component, but it would require some coding).

Hi @dan thanks for your reply.

I have the URL here for the new site built in Elements…

As you can see, the banner requires me to hover over the graphic to make the company name appear. I would actually like it to automatically cycle through the three images I have fading from one to another before it finishes on the final banner image.

Because I love this style of banner and have used it so many times in the past, I am 100% determined to create the banner in the same way as I have done in Classic.

Please let me know what code I need to inject into the site to make this happen?

David

David here’s some code I was playing with - from Tailwind. Drop this into a custom HTMl and see if you like start, you can customise to your requirements. It’s just a play from me a non coder, who’s learning custom components at the moment. If you dont like it I won’t mind at all as I’m only learning and playing.

<div class="w-screen h-screen flex flex-col justify-center items-center bg-black dark:bg-white animate-dimlight space-y-8">
  <h1 class="relative w-full xl:text-9xl md:text-8xl text-5xl sm:tracking-[17px] tracking-[10px] uppercase text-center leading-[0.70em] outline-none box-reflect">
    ESQUIREPRINT
  </h1>
  <h2 class="relative w-full xl:text-7xl md:text-8xl text-5xl sm:tracking-[17px] tracking-[10px] uppercase text-center leading-[0.70em] outline-none box-reflect space-y-250">
    PRINT  WEB  PHOTO
  </h2>
</div>

</div>

<script src="https://cdn.tailwindcss.com">
</script>

<script>
  tailwind.config = {
    darkMode: 'class',
    theme: {
      extend: {
        keyframes: {
          dimlight: {
            '0%, 18%, 20%, 50.1%, 60%, 65.1%, 80%, 90.1%, 92%': {
              color: '#0e3742',
              boxShadow: 'none',
            },
            '18.1%, 20.1%, 30%, 50%, 60.1%, 65%, 80.1%, 90%, 92.1%, 100%': {
              color: '#fff',
              textShadow: '0 0 10px #03bcf4',
            },
          },
        },
        animation: {
          dimlight: 'dimlight 10s infinite',
        },
      },
    },
    plugins: [
      function({
        addUtilities
      }) {
        addUtilities({
          '.box-reflect': {
            '-webkit-box-reflect': 'below 1px linear-gradient(transparent, #0004)',
          },
        });
      },
    ],
  }
</script>

Here’s another one for you - once again modified from a Tailwind project

<div class="w-full mx-auto h-screen [perspective:1000px] bg-[radial-gradient(rgb(5,_221,_245),_rgb(6,_150,_253))]">
  <div class="relative sm:h-[250px] sm:w-[250px] xs:h-[150px] xs:w-[150px] mx-auto top-1/2 transform -translate-y-1/2 [transform-style:preserve-3d] animate-roll">
    <div class="box sm:[transform:translateZ(125px)] xs:[transform:translateZ(75px)]">ESQUIREPRINT</div>
    <div class="box sm:[transform:translateZ(-125px)] xs:[transform:translateZ(-75px)]">PHOTO</div>
    <div class="box sm:right-[125px] xs:right-[75px] [transform:rotateY(-90deg)]">WEB</div>
    <div class="box sm:left-[125px] xs:left-[75px] [transform:rotateY(90deg)]">PRINT</div>
    <div class="box sm:bottom-[125px] xs:bottom-[75px] [transform:rotateX(90deg)]">PHOTO</div>
    <div class="box sm:top-[125px] xs:top-[75px] [transform:rotateX(-90deg)]">SERVICE</div>
  </div>
</div>

<script src="https://cdn.tailwindcss.com">
</script>

<script>
  tailwind.config = {
  darkMode: 'class',
  theme: {
    screens: {
      xs: '320px',
      sm: '480px',
      md: '768px',
      lg: '976px',
      xl: '1440px',
    },
    extend: {
      keyframes: {
        roll: {
          '0%': { transform: 'rotateX(45deg) rotateY(-45deg)'},
          '25%': { transform: 'rotateX(-45deg) rotateY(-45deg)'},
          '50%': { transform: 'rotateX(45deg) rotateY(45deg)'},
          '75%': { transform: 'rotateX(-45deg) rotateY(45deg)'},
          '100%': { transform: 'rotateX(45deg) rotateY(-45deg)'}
        }
      },
      animation: {
        roll: 'roll 5s infinite',
      }
    }
  }
}
</script>

Hi Paul,

Thank you so much for producing these banners in Tailwind they look really cool. As a non-coder I can really see there is nothing to be scared of, I just have to get my hands dirty!

Would you be able to help me recreate the banner I have on my live website… esquireprint.com as I really want to replicate that.

So there are three banner images fading from…

Esquire-Print-Home-Banner-1.jpg
to
Esquire-Print-Home-Banner-2.jpg
to
Esquire-Print-Home-Banner-3.jpg

Then it stays on Banner-3 permanently until you refresh the page.

How would I be able to do that?

David

Try asking @elementsbot to help with this as well.

Absolutely, this is 100% my jam! David, you want a banner in Elements that cycles through three images with a fade transition, and then permanently stays on the last one until refresh. That’s a classic “timed image slider but freeze after last image” trick!

Here’s how you can build this in Elements with zero fear (and just a sprinkle of easy code):


Step 1: Use the Custom Component

Add an HTML Component (or Custom Component) to your banner area.


Step 2: Paste This Code (Replace Image Names!)

<div id="ep-banner" class="relative w-full h-[450px] overflow-hidden">
  <img src="/images/Esquire-Print-Home-Banner-1.jpg" class="ep-banner-img absolute w-full h-full object-cover opacity-100 transition-opacity duration-700" />
  <img src="/images/Esquire-Print-Home-Banner-2.jpg" class="ep-banner-img absolute w-full h-full object-cover opacity-0 transition-opacity duration-700" />
  <img src="/images/Esquire-Print-Home-Banner-3.jpg" class="ep-banner-img absolute w-full h-full object-cover opacity-0 transition-opacity duration-700" />
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
  const images = document.querySelectorAll('#ep-banner .ep-banner-img');
  const showTimes = [2000, 2000, 0]; // time to show each image (ms)
  let current = 0;

  function showNext() {
    // Hide all
    images.forEach((img, i) => img.style.opacity = (i === current ? '1' : '0'));
    if (current < images.length - 1) {
      setTimeout(() => {
        current++;
        showNext();
      }, showTimes[current]);
    }
    // else: stays on last image!
  }

  showNext();
});
</script>

What this does:

  • Each image will fade in, then fade to the next, until the last one, which stays.
  • Banner is always 450px deep (per your style), and full-width.
  • Swaps images every 2 seconds—you can change showTimes for different speeds.

What to edit:

  • Replace /images/Esquire-Print-Home-Banner-1.jpg with your real file paths.
  • Use Theme settings for sizing if you want, but this code is ready as-is!

:man_mage: No extra libraries, just pure HTML, Tailwind classes, and a vanilla JavaScript sprinkle!


If you want to get extra-fancy and drop in text overlays, buttons, etc. just pop those inside the <div> and style as normal.

Need a version that works with Alpine.js or want to make it even slicker? Just say the word—I have variations for days.


Let me know if this works in Elements, or if you want a Marketplace Component for this (so you never have to see code again :smirking_face:).

You got this, David! And welcome to the “I can code a little” club.:sparkles:


You can always @elementsbot for nerdy (but gentle) code help.

Bonus: This is a perfect showcase for why Elements is so much more flexible than Classic!

Robin got there before me! Try my chatty bots code mad see if it works, if not tell him what’s not working and he’ll help.

I see your getting on well with CMS did you finish the “cookie component” in CMS are you happy to share? Have a look at my two animations above and please comment as I am play/learning a few animations at moment.TIA

Aloha Paul,

Yes, I have converted it to using the CMS, and it is so much cleaner now. I’m in the process of cleaning up the DevPack for the system, and then I’ll be happy to share it. By moving it to the CMS, I got rid of 3/4 of the settings, which made it a lot cleaner.

Of course, there are a couple of things that you have to pay attention to when setting it up, but once you understand the basic concept, it works great.

BTW, this is more of a Privacy Consent system as opposed to a full-blown cookie consent system.

The other thing it now does is that all the information for the entire system is encoded in the privacy policy MD file, so with the one file, you get not only the policy but also all of the text for the two modals that are involved.

UPDATE: The only thing missing that would make it easier to use would be to allow the user to pick the policy MD file and then have the custom component hook up the various “items” in the system to that file. This makes it easier on the user as they would not have to go through and hook up the items manually. But I’ll need some help from @ben on how to make that happen, or if it is even possible. I already have a property in the component to handle this but it is not currently hooked up.

2 Likes

I’m not sure if this is due to the style of banner you’re using but your pages load incredibly slowly for me - I mean painfully slow. I have a gigabit connection and typically have no issues with any sites but yours ground me to a halt. It might be worth checking performance because it’s probably not a great endorsement for a site promoting web design as one of the products. Just thought I’d mention it whilst in design/rebuild phase.

Thank you for noticing this Kim, I wonder if the slowness is the speed in which the banner is activating? I had it set to 5 seconds because I was trying to make the transition from one banner image to the next be as smooth as possible.

I have dropped this down to 2 seconds now which does make it activate quicker but the transitions are still very sharp and not as smooth as I’d like.

Can anyone help me make the transitions really smooth so it just fades from one image to the next?

Here is the custom HTML code ElementsBot gave me but when I ask for it to be made smoother the suggestions don’t really seem to work…

Just for context, if you click on the Print page in the menu bar and hover over the banner, that is how smooth I’d like the banner to be on the Home page.

I don’t want to have to hover over the banner image to reveal the logo.

Btw, one other weird anomaly I have noticed is the Contact button in the menu bar will randomly disappear if I refresh the page, what could be causing that?

Give this code a go…

<!-- Requires Tailwind + Alpine v3 -->
<div
  x-data="{
    images: [
      'https://images.unsplash.com/photo-1519681393784-d120267933ba?q=80&w=1600',
      'https://images.unsplash.com/photo-1491553895911-0055eca6402d?q=80&w=1600',
      'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1600'
    ],
    active: 0,
    start() {
      setInterval(() => {
        this.active = (this.active + 1) % this.images.length
      }, 4000) // change every 4s
    }
  }"
  x-init="start()"
  class="relative w-full aspect-[21/9] overflow-hidden"
>
  <template x-for="(img, i) in images" :key="i">
    <img
      :src="img"
      x-show="active === i"
      class="absolute inset-0 h-full w-full object-cover"
      x-transition:enter="transition-opacity duration-1000"
      x-transition:enter-start="opacity-0"
      x-transition:enter-end="opacity-100"
      x-transition:leave="transition-opacity duration-1000"
      x-transition:leave-start="opacity-100"
      x-transition:leave-end="opacity-0"
    />
  </template>
</div>

That’s really good Dan!

Can you modify the code to make the transition just a little smoother, as smooth as the banner on this site…

Maybe we can also change the duration to 3 seconds and finish on the last slide so it doesn’t loop round to the first slide again?

Okay, give this a go, it looks much better.

If you want to tweak the length of transition, just change this number transition-opacity duration-[2000ms] in the code!

<div
  x-data="{
    images: [
      'https://images.unsplash.com/photo-1519681393784-d120267933ba?q=80&w=1600',
      'https://images.unsplash.com/photo-1491553895911-0055eca6402d?q=80&w=1600',
      'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1600'
    ],
    active: 0,
    start() {
      setInterval(() => {
        this.active = (this.active + 1) % this.images.length
      }, 4000) // change every 4s
    }
  }"
  x-init="start()"
  class="relative w-full aspect-[21/9] overflow-hidden"
>
  <template x-for="(img, i) in images" :key="i">
    <img
      :src="img"
      class="absolute inset-0 h-full w-full object-cover transition-opacity duration-[2000ms] ease-in-out"
      :class="active === i ? 'opacity-100' : 'opacity-0'"
    />
  </template>
</div>

Edit: Ah-ha! just saw your message about making it 3 seconds and not looping… try this instead:

<div
  x-data="{
    images: [
      'https://images.unsplash.com/photo-1519681393784-d120267933ba?q=80&w=1600',
      'https://images.unsplash.com/photo-1491553895911-0055eca6402d?q=80&w=1600',
      'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1600'
    ],
    active: 0,
    timer: null,
    start() {
      this.timer = setInterval(() => {
        if (this.active < this.images.length - 1) {
          this.active++
        } else {
          clearInterval(this.timer) // stop on last image
        }
      }, 3000) // change every 3s
    }
  }"
  x-init="start()"
  class="relative w-full aspect-[21/9] overflow-hidden"
>
  <template x-for="(img, i) in images" :key="i">
    <img
      :src="img"
      class="absolute inset-0 h-full w-full object-cover transition-opacity duration-[3000ms] ease-in-out"
      :class="active === i ? 'opacity-100' : 'opacity-0'"
    />
  </template>
</div>
1 Like

Yes, yes, YES!

That’s it, you did it, thank you Dan!

Awesome! However, I can’t take all the credit, I did have a little AI help :stuck_out_tongue:

1 Like

Fantastic how this came about, one and all. Between the elementsbot and the humansbotnot, nice to see a body of knowledge — and a desire to help one another — continue to bring solutions Elements and its users. Stay kind!