Home > Blockchain >  Javascript - Background Image Transition
Javascript - Background Image Transition

Time:12-09

I am trying to get my background "jumbotron" to change images. It works, however, I would like to add a transition to the image background as it is pretty rough. I was hoping to do it in the internal script or javascript however neither appears to be working. Is there any way to achieve this I've been trying to figure it out for a few hours and I can not find any guides online for it that makes sense to me.

I really appreciate any help you can provide!

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/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>

<body>

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

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

</body>

</html>

CodePudding user response:

Are you trying to build carousel or the images in the background should load on page reload

CodePudding user response:

If you want a transition between two background images, I suggest using ::before and ::after pseudo-elements with background images, and then change the opacity on one of them.

I think it's easier if I showed the changes in steps. This code below have the same behavior as your code, where I only set --background-image.

I should point out that you should never ever use float and position: absolute unless you know what you're doing, because it just messes up the page flow. I updated (removed) the CSS accordingly. Also, Bootstrap is just the worst because you will end up trying to override anything Boostrap tries to implement, just like your CSS code did in your snippet.

var i = 0;
var images = [];
var TWELVE_SECONDS = 12000;

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() {
  let nextImage = i   % images.length;
  document.getElementById('jumbotron').style.setProperty('--background-image', `url(${images[nextImage]}`);

  setTimeout(changePicture, TWELVE_SECONDS);
}

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

#jumbotron::before,
#jumbotron::after {
  content: '';
  
  position: absolute;
  inset: 0px; /* top: 0; bottom: 0; left: 0; right: 0; */
  
  background-image: var(--foreground-image);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat !important;
  z-index: -1;
}

#jumbotron::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.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>

<body>

  <div id="jumbotron" >
    <div  slot="float: right;">
      <h3>Welcome!</h3>
      <p>Lorem ipsum dolor sit amet</p>
    </div>
  </div>

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

</body>

</html>

So if I expand on this code above, I will set the old visible image as a foreground image (in ::before), and then set it's opacity to 0 to fade out to the new image set in the background image (in ::after).

I also set the animation speed in code, so it's easier to just change one value rather than having to jump around between CSS and javascript if you want to change certain values.

As a bonus, I added preloading of the next image as well. You don't want to transition into an image that haven't been loaded.

var i = 0;
var images = [];
var preloadedImage = new Image();
var TWELVE_SECONDS = 12000;
var TWO_SECONDS = 2000;

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() {
  let jumbotronEl = document.getElementById('jumbotron');
  let oldImage = (i-1) % images.length;
  let currentImage = i   % images.length;
  let upcomingImage = i % images.length;

  if (preloadedImage.src) {
    jumbotronEl.style.setProperty('--foreground-image', `url(${images[oldImage]}`);
    jumbotronEl.style.setProperty('--background-image', `url(${images[currentImage]}`);
    jumbotronEl.style.setProperty('--opacity-animation-duration', TWO_SECONDS   'ms');
    toggleForegroundFade();
    
    setTimeout(toggleForegroundFade, TWO_SECONDS);
  } else {
    jumbotronEl.style.setProperty('--background-image', `url(${images[currentImage]}`);
  }

  setTimeout(() => { 
    preloadedImage.src = images[upcomingImage]
  }, TWO_SECONDS);

  setTimeout(changePicture, TWELVE_SECONDS);
}

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

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

#jumbotron.foreground-hidden::before {
  opacity: 0;
  transition: opacity var(--opacity-animation-duration);
}

#jumbotron::before,
#jumbotron::after {
  content: '';
  
  position: absolute;
  inset: 0px; /* top: 0; bottom: 0; left: 0; right: 0; */
  
  background-image: var(--foreground-image);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat !important;
  z-index: -1;
}

#jumbotron::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.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
</head>

<body>

  <div id="jumbotron" >
    <div >
      <h3>Welcome!</h3>
      <p>Lorem ipsum dolor sit amet</p>
    </div>
  </div>

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

</body>

</html>

CodePudding user response:

I did something similar using pseudo element after (or before). My implementation was in React using styled-components.

I tried to create the same using vanilla js. I hope it helps. I couldn't make it work using a gradient and can't explain why. I just added a filter which seems to work fine.

edit: I want to mention that I have used 'document.styleSheets[0].removeRule' which is marked as deprecated.

https://codesandbox.io/s/determined-ramanujan-z70egr

  • Related