Transitioning the Background Image is a common design technique

After spending hours trying to figure out how to make my background "jumbotron" change images smoothly with a transition, I am still stuck. I have tried both internal scripts and JavaScript, but nothing seems to work. Is there any way to achieve this without the rough transition effect? I've searched online for guides, but none of them make sense to me.

var i = 0;
var images = [];
var slideTime = 12000; // 12 seconds

images[0] = 'https://i.pinimg.com/736x/ba/92/7f/ba927ff34cd961ce2c184d47e8ead9f6.jpg';
images[1] = 'https://thumbs.dreamstime.com/b/portrait-funny-cat-fly-his-nose-portrait-funny-cat-fly-his-nose-isolated-white-background-125606127.jpg';
images[2] = 'https://mymodernmet.com/wp/wp-content/uploads/2022/11/masayuki-oki-cat-street-photography-19.jpeg';

function changePicture() {
  document.getElementById('jumbotron').style.transition = "all 4s";
  document.getElementById('jumbotron').style.backgroundImage = "linear-gradient(to right bottom, #0d146f, transparent)," + "url(" + images[i] + ")";

  if (i < images.length - 1) {
    i++;
  } else {
    i = 0;
  }
  setTimeout(changePicture, slideTime);
}

window.onload = changePicture;
#jumbotron {
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat !important;
  height: 100vh;
  -webkit-transition: background-image 2s ease-in-out;
  transition: background-image 2s ease-in-out;
}

.center h3 {
  margin: 0;
  position: absolute;
  top: 40%;
  left: 20%;
  transform: translate(-50%, -180%);
}

.center p {
  margin: 0;
  position: absolute;
  top: 40%;
  left: 20%;
  transform: translate(-50%, -50%);
}
<html lang="en">

<head>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>

<body>

  <div id="jumbotron" class="text-white text-center" style="">
    <div class="center" slot="float: right;">
      <h3>Welcome!</h3>
      <p>Lorem ipsum dolor sit amet</p>
    </div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

</body>

</html>

Answer №1

I successfully achieved a seamless transition by applying a linear gradient background to the jumbotron and utilizing an absolutely positioned child element with a transition effect on opacity. The key is to fade out the background, change the image, and then fade it back in.

var i = 0;
var images = [];
var slideTime = 12000; // 12 seconds

images[0] = 'https://i.pinimg.com/736x/ba/92/7f/ba927ff34cd961ce2c184d47e8ead9f6.jpg';
images[1] = 'https://thumbs.dreamstime.com/b/portrait-funny-cat-fly-his-nose-portrait-funny-cat-fly-his-nose-isolated-white-background-125606127.jpg';
images[2] = 'https://mymodernmet.com/wp/wp-content/uploads/2022/11/masayuki-oki-cat-street-photography-19.jpeg';
const bg = document.querySelector('#jumbotron .bgi')

function changePicture() {
  bg.classList.add('fade')
  setTimeout(() => {
    bg.style.backgroundImage = "linear-gradient(to right bottom, #0d146f, transparent)," + "url(" + images[i] + ")";
    bg.classList.remove('fade')
  }, 2000)

  if (i < images.length - 1) {
    i++;
  } else {
    i = 0;
  }
  setTimeout(changePicture, slideTime);
}

window.onload = changePicture;
#jumbotron {
  position: relative;
  height: 100vh;
  background-image: linear-gradient(to right bottom, #0d146f, transparent);
}

#jumbotron .bgi {
  content: "";
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat !important;
  -webkit-transition: all 2s ease-in-out;
  transition: all 2s ease-in-out;
  position: absolute;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
}

#jumbtron .bgi.fade {
  opacity: 0;
}

.center h3 {
  margin: 0;
  position: absolute;
  top: 40%;
  left: 20%;
  transform: translate(-50%, -180%);
}

.center p {
  margin: 0;
  position: absolute;
  top: 40%;
  left: 20%;
  transform: translate(-50%, -50%);
}
<html lang="en">

<head>
  <link href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="74161b1b00070006150434415a445a46">[email protected]</a>/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>

<body>

  <div id="jumbotron" class="text-white text-center" style="">
    <div class="bgi"></div>
    <div class="center" slot="float: right;">
      <h3>Welcome!</h3>
      <p>Lorem ipsum dolor sit amet</p>
    </div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="13717c7c67606761726353263d233d21">[email protected]</a>/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>

</body>

</html>

Answer №2

I utilized a similar approach by utilizing pseudo elements after (or before). I specifically implemented this in React using styled-components.

Now, I have attempted to achieve the same outcome using vanilla JavaScript. Hopefully, it proves to be beneficial.

Explore the code here

At its core, my method involves adding and removing a CSS rule (pseudo element before) to execute a transition on background-size. I consciously opted against using opacity as I believed that the original question pertained to transitioning background images. However, after exploring alternative solutions, I find them aesthetically more pleasing as they eliminate the need to modify CSS rules directly.

const images = [];
const slideTime = 2000; // To keep the demo brief with only 2 seconds of wait time
let i = 0;

images[0] =
  "https://i.pinimg.com/736x/ba/92/7f/ba927ff34cd961ce2c184d47e8ead9f6.jpg";
images[1] =
  "https://thumbs.dreamstime.com/b/portrait-funny-cat-fly-his-nose-portrait-funny-cat-fly-his-nose-isolated-white-background-125606127.jpg";
images[2] =
  "https://mymodernmet.com/wp/wp-content/uploads/2022/11/masayuki-oki-cat-street-photography-19.jpeg";

function changePicture() {
  document.styleSheets[0].insertRule(
    `#jumbotron::before { position: absolute; content: ''; top:0; left:0;width: 100%; height: 100%; background-image: url("${images[i]}"); background-size: cover; transition: all 1s ease; transform-origin: 0% 50%; }`,
    document.styleSheets[0].cssRules.length - 1
  );
}

function run() {
  i++;
  if (i === 3) {
    i = 0;
  }
}

function removeRule() {
  setTimeout(() => {
    document.styleSheets[0].deleteRule(
      document.styleSheets[0].cssRules.length - 1
    );
  }, slideTime);
}

window.onload = () => {
  setInterval(() => {
    run();
    changePicture();
    removeRule();
  }, slideTime);
};
#jumbotron {
  height: 100vh;
  position: relative;
}

#jumbotron::before {
  position: absolute;
  content: "";
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-image: url("https://i.pinimg.com/736x/ba/92/7f/ba927ff34cd961ce2c184d47e8ead9f6.jpg");
  background-size: cover;
  transition: all 1s ease;
  transform-origin: 0% 50%;
}

#jumbotron::after {
  content: "";
  inset: 0;
  position: absolute;
  background-image: linear-gradient(to right bottom, #0d146f, transparent);
}

.center h3 {
  margin: 0;
  position: absolute;
  top: 40%;
  left: 20%;
  transform: translate(-50%, -180%);
}

.center p {
  margin: 0;
  position: absolute;
  top: 40%;
  left: 20%;
  transform: translate(-50%, -50%);
}
<html lang="en">
  <head>
    <link rel="stylesheet" href="./styles.css" />
    <link
      href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bad8d5d5cec9cec8dbcafa8f948a9488">[email protected]</a>/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
      crossorigin="anonymous"
    />
  </head>

  <body>
    <div id="jumbotron" class="text-white text-center">
      <div class="center" slot="float: right;">
        <h3>Welcome!</h3>
        <p>Lorem ipsum dolor sit amet</p>
      </div>
    </div>
    <script
      src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0c6e6363787f787e6d7c4c39223c223e">[email protected]</a>/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
      crossorigin="anonymous"
    ></script>
    <script src="./script.js"></script>
  </body>
</html>

Upon executing the snippet, there might be a slight flicker when the images load for the first time, although this issue should not persist on codesandbox (refer to the link above).

Answer №3

To achieve a smooth transition between two background images, my recommendation is to utilize the ::before and ::after pseudo-elements with background images. By adjusting the opacity on one of these elements, you can create the desired effect seamlessly.

For clarity, let me showcase the step-by-step modifications. The code snippet presented below mirrors the behavior of your original code, focusing solely on defining the --background-image.

I want to emphasize the importance of avoiding the use of float and position: absolute unless you possess a thorough understanding of their impact on page flow. Following this principle, I have made adjustments in the CSS to eliminate those properties. Additionally, dealing with Bootstrap can be challenging as it often necessitates overriding default styles, much like how your CSS conflicted with Boostrap's implementation in the supplied snippet.

var index = 0;
var imageList = [];
var ANIMATION_DURATION = 8000;

imageList[0] = 'https://example.com/image1.jpg';
imageList[1] = 'https://example.com/image2.jpg';
imageList[2] = 'https://example.com/image3.jpg';

function switchImage() {
  let nextIndex = index++ % imageList.length;
  document.getElementById('hero-section').style.setProperty('--background-image', `url(${imageList[nextIndex]}`);

  setTimeout(switchImage, ANIMATION_DURATION);
}

window.onload = switchImage;
#hero-section {
  --foreground-img: '';
  --background-image: '';

  position: relative;
  height: 100vh;
  background-image: linear-gradient(to right bottom, #0d146f, transparent);
}

#hero-section::before,
#hero-section::after {
  content: '';

  position: absolute;
  inset: 0px; 

  background-image: var(--foreground-img);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat !important;
  z-index: -1;
}

#hero-section::after {
  background-image: var(--background-image);
  z-index: -2;
}

.center {
  display: inline-block;
  position: relative;
  margin-top: 10%;
  margin-left: 20%;
  text-align: center;
}
<html lang="en">

<head>
  <link href="https://cdn.example.com/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-exampleHashValue" crossorigin="anonymous">
</head>

<body>

  <div id="hero-section" class="text-white">
    <div class="center" slot="float: right;">
      <h3>Welcome!</h3>
      <p>Lorem ipsum dolor sit amet</p>
    </div>
  </div>

  <script src="https://cdn.example.com/js/bootstrap.bundle.min.js" integrity="sha384-exampleHashValue" crossorigin="anonymous"></script>

</body>

</html>

Expanding upon the previous code fragment, I've arranged for the outgoing visible image to act as the foreground image (::before) while gradually fading out to reveal the new background image set at the back (::after).

Furthermore, I have included animation speed configurations directly in the code for straightforward adjustment, eliminating the need to juggle values across multiple files if customization is required.

As an additional enhancement, preloading of subsequent images has been integrated. This ensures a smooth transition without transitioning to unloaded images.

var index = 0;
var imageList = [];
var nextImage = new Image();
var ANIMATION_DURATION = 8000;
var FADE_SPEED = 1500;

imageList[0] = 'https://example.com/image1.jpg';
imageList[1] = 'https://example.com/image2.jpg';
imageList[2] = 'https://example.com/image3.jpg';

function switchImage() {
  let heroSectionEl = document.getElementById('hero-section');
  let currentImg = (index-1) % imageList.length;
  let currIndex = index++ % imageList.length;
  let nextIndex = index % imageList.length;

  if (nextImage.src) {
    heroSectionEl.style.setProperty('--foreground-img', `url(${imageList[currentImg]}`);
    heroSectionEl.style.setProperty('--background-image', `url(${imageList[currIndex]}`);
    heroSectionEl.style.setProperty('--fade-speed', FADE_SPEED + 'ms');
    toggleForegroundFade();

    setTimeout(toggleForegroundFade, FADE_SPEED);
  } else {
    heroSectionEl.style.setProperty('--background-image', `url(${imageList[currIndex]}`);
  }

  setTimeout(() => { 
    nextImage.src = imageList[nextIndex];
  }, FADE_SPEED);

  setTimeout(switchImage, ANIMATION_DURATION);
}

function toggleForegroundFade() {
  document.getElementById('hero-section').classList.toggle('foreground-hidden');
}

window.onload = switchImage;
#hero-section {
  --foreground-img: '';
  --background-image: '';
  --fade-speed: '';

  position: relative;
  height: 100vh;
  background-image: linear-gradient(to right bottom, #0d146f, transparent);
}

#hero-section.foreground-hidden::before {
  opacity: 0;
  transition: opacity var(--fade-speed);
}

#hero-section::before,
#hero-section::after {
  content: '';

  position: absolute;
  inset: 0px;

  background-image: var(--foreground-img);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat !important;
  z-index: -1;
}

#hero-section::after {
  background-image: var(--background-image);
  z-index: -2;
}

.center {
  display: inline-block;
  position: relative;
  margin-top: 10%;
  margin-left: 20%;
  text-align: center;
}
<html lang="en">

<head>
  <link href="https://cdn.example.com/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-exampleHashValue" crossorigin="anonymous">
</head>

<body>

  <div id="hero-section" class="text-white foreground-hidden">
    <div class="center">
      <h3>Welcome!</h3>
      <p>Lorem ipsum dolor sit amet</p>
    </div>
  </div>

  <script src="https://cdn.example.com/js/bootstrap.bundle.min.js" integrity="sha384-exampleHashValue" crossorigin="anonymous"></script>

</body>

</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I retrieve the span html element without using a class with ajax?

Trying to work with Ajax syntax for the first time, I have this HTML code. <div class="select2-container select2" id="s2id_ServiceID-2-1" style="width: 100%;"> <a href="javascript:void(0)" onclick="return false;" class="select2-choice" tabind ...

If the template variable is empty, the nesting HTML element should be hidden

Check out my awesome template: <li><a href="/{{ user_data.room2 }}" id="room2">/{{ user_data.room2 }}</a></li> <li><a href="/{{ user_data.room3 }}" id="room3">/{{ user_data.room3 }}</a></li> < ...

Organize object properties based on shared values using JavaScript

Check out the JavaScript code snippet below by visiting this fiddle. var name = ["Ted", "Sarah", "Nancy", "Ted", "Sarah", "Nancy"]; var prodID = [111, 222, 222, 222, 222, 222]; var prodName = ["milk", "juice", "juice", "juice", "juice", "juice ...

Protect your website's ajax-generated content from being indexed by search engines with these strategies

Recently, Google made an update allowing its crawler to index ajax-generated content on web pages by following specific guidelines. However, my requirement is to ensure that no search engine can crawl my ajax-generated content. So, my question is: What ...

Having trouble with JQuery's .prop function not unchecking a checkbox?

I have been experimenting with different solutions in order to uncheck a checkbox when another checkbox is checked. Unfortunately, none of the methods I've tried seem to be working effectively... Currently, my code looks like this: $("#chkBox1").cli ...

How can I utilize jQuery to create a remove button that deletes individual div elements one at a time?

<div class= "button"> <button id="More" type="submit">Click here to add more Parameters</button> <button id="Remove" type="submit">Click here to Remove Parameters</button> </div> <script> var count = 2; ...

Explore the comparison feature with jQuery's combobox

I am attempting to compare values from an array with values in a combobox using jQuery, but I am encountering difficulties. My array is structured like this: (value 1, value 2,...) names separated by commas (Example: john smith, peter pan). On the other h ...

Adding inline SVGs to a Nuxt 3 Vite project: A step-by-step guide

Hey there, I've been struggling with importing inline SVGs into my Nuxt3 Vite project. Any advice would be greatly appreciated. I discovered that using <img src="~/assets/images/icons/push-icon-chatops.svg" /> works, but I actually ne ...

Encountering an issue with html2canvas: receiving an error message stating "object

To print the div using Javascript, I encountered an issue with the generated barcode not appearing in the printed page. This led me to use the html2canvas approach to 'render' the div before printing it out. Here is the code snippet: HTML: < ...

What prevents variables defined in outer blocks from being accessed by nested describe() blocks?

In my real code, I encountered a problem that I wanted to demonstrate with a simple example. The code below functions properly. I defined a variable in the root describe() block that can be accessed in the it() blocks of nested describe()s. describe(&apo ...

Executing a JavaScript function when a column in a Fusion Chart is clicked

I have two div elements in HTML and I would like to have div2 load when div1 is clicked. Additionally, whenever div2 loads, a back button should also appear to return to div1. Is there a way to achieve this using HTML? <td background="images/bgTd.gif ...

Is there a way to replicate input data from one website onto a totally separate platform?

I am currently working on a hotel website using the user-friendly WYSIWYG site builder, Wix (yes, I know, don't judge). Like all hotel websites, we need a form for customers to enter their details for reservations and other purposes. However, there&a ...

How do I disable scrolling while the animation is running in CSS?

Is there a way to disable scrolling while animating in CSS without using overflow:hidden on the body tag? ...

A guide to setting up checkbox input in Vue 3 so that it toggles between checked and unchecked states when an

I'm in the process of creating a div container that will contain both an image and a checkbox input element. The checkbox input has a click handler that passes a value to a function, as well as a :value binding which sends the value to an array named ...

Error encountered in AngularJS when utilizing the Flickr API with the parameter "nojsoncallback=1": Unexpected token Syntax

My AngularJS application is trying to access the Flickr API. I need the data in RAW JSON format without any function wrapper, following the guidelines provided in the documentation by using &nojsoncallback=1. However, I keep encountering a console er ...

"Even rows are the only ones being highlighted on the table

I created a table that dynamically highlights all odd rows. To achieve this, I implemented a method to identify the row number and then apply the alt class to those specific rows. In order to highlight the rows on hover, I added a simple :hover selector ...

The technique for accessing nested key-value pairs in a JSON object within an Angular application

After receiving the response from the backend, I have retrieved a nested hash map structure where one hash map is nested within another: hmap.put(l,hmaps); //hmap within hmap When returning the response to the frontend, I am using the ResponseEntity meth ...

Are there any class options that offer a wider width than modal-lg?

I am currently using vue.js along with Bootstrap. Within my modal dive, I am looking for a class that will help me increase the width of the modal div, As you can see from the image below, my modal div looks like this. I plan on adding 12 more tabs, whic ...

Comprehending the Syntax of the ExtJS Framework

I have recently inherited a project utilizing Sencha's ExtJS framework without any handover or documentation. As I navigate through the code, I find myself trying to decipher certain syntax and exploring resources tailored for newcomers to this specif ...

Can CSS be used to generate these shadows?

Check out this image I made showcasing a board with an elongated shadow cast behind it. The intention is to emulate the look of the board leaning against a wall, resulting in a triangular shadow on either side. I'm curious if it's achievable to ...