Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fade in background-image once it loads (no jquery) while still using media queries to replace images for different screen sizes

I've been reading all night and can't seem to come to any sort of concrete answer on what the best way to do this is. The two things that I know do work are these—

For fading in an image when it loads:

Use an image wrapper and an <img> tag like this:

<div class="imageWrapper">
    <img src="img.jpg" alt="" onload="imageLoaded(this)">
</div>

and the css looks like

.imageWrapper {
  opacity: 0
}

.loaded {
  opacity: 1
}

and then have in your js file something like

var imageLoaded = (img) => {
    var imgWrapper = img.parentNode;
    imgWrapper.className += ' loaded';
}

For loading a different image based on screen size

@media screen only and (min-device-width: 0) and (max-device-width: 450px) {
  .backgroundImage {
    background: url('small_background_image.jpg');
  }
}

@media screen only and (min-device-width: 451px) and (max-device-width: 1024px) {
  .backgroundImage {
    background: url('medium_background_image.jpg');
  }
}

@media screen only and (min-device-width: 1025px) {
  .backgroundImage {
    background: url('large_background_image.jpg');
  }
}

My Problem

I can do both of these things separately (fade in an image when it is loaded, change a background-image when the browser detects a smaller screen size), but I can't seem to find a solution that incorporates both. I need to be able to specify a different image for different screen sizes, and also be able to detect when that image is loaded and fade it in.

Is there a good way to do this?

My solution:

I ended up using a variation of guest271314's answer in order to load the correct images. This works on all latest version of each browser and is very easily implemented.

First, I have an inline script placed right underneath my opening <body> tag so that if my browser is slow with loading my js file it can load the images right away anyways.

<body>
    <script>
        function imageLoaded(img) {
            if ((" " + img.className + " ").indexOf(" "+'loaded'+" ") > -1 ) {
            return true;
            } else {
                img.className += ' loaded';
            }
        }
    </script>

and then I have my <picture> tag like so:

<picture class="backgroundContainer">
    <source srcset="img-1024.jpg" media="(min-width: 0px) and (max-width:1024px)">
    <source srcset="img-1920.jpg" media="(min-width: 1025px) and (max-width: 1920px)">
    <source srcset="img-2560.jpg" media="(min-width: 1921px)">
    <img class="backgroundImage" onload="imageLoaded(this)" src="img-1920.jpg" alt="">
</picture>

and my sass looks like this:

@keyframes fadeIn
  0%
    opacity: 0
  100%
    opacity: 1

.backgroundContainer
  width: 100%
  height: 100%

.backgroundImage
  opacity: 0

.loaded
  opacity: 1
  animation: fadeIn 3s

And this allows the browser (regardless of speed) to wait until the correctly-sized image is done loading, and then fades it in over 3s, with a safe fallback using the <img> tag for older browsers.

like image 474
shan Avatar asked Sep 27 '16 05:09

shan


1 Answers

I basically need to be able to fade in a background-image when it loads, or be able to change an <img> tag's src before it loads depending on screen size, or do something that incorporates both of these things using a method I'm unaware of.

You can use css content property with value set to url() function having URL of image to display, or change displayed image source; css animation, @keyframes to fade in background-image when the source image loads.

html

<picture class="backgroundImage"></picture>

css

.backgroundImage {
  opacity: 0; /* set `opacity` to `0` */
  width: 50px;
  width: 50px;
  content: url(http://lorempixel.com/50/50/technics); /* set intial image */
  animation-name: fadein;
  animation-iteration-count: 1;
  animation-duration: 2500ms;
  animation-fill-mode: both;
}

@keyframes fadein {
  to {
    opacity: 1; /* fade in image */
  }
}
/* set media queries */
@media screen only and (min-device-width: 0) and (max-device-width: 450px) {
  .backgroundImage {
    opacity: 0; /* set `opacity` to `0` */
    content: url(http://lorempixel.com/50/50/cats); /* set image */
    animation-name: first;
  }
  @keyframes first {
    to {
      opacity: 1; /* fade in image */
    }
  }
}

@media screen only and (min-device-width: 451px) and (max-device-width: 1024px) {
  .backgroundImage {
    opacity: 0; /* set `opacity` to `0` */
    content: url(http://lorempixel.com/50/50/city); /* set image */
    animation-name: second;
  }
  @keyframes second {
    to {
      opacity: 1; /* fade in image */
    }
  }
}

@media screen only and (min-device-width: 1025px) {
  .backgroundImage {
    opacity: 0; /* set `opacity` to `0` */
    content: url(http://lorempixel.com/50/50/sports); /* set image */
    animation-name: third;
  }
  @keyframes third {
    to {
      opacity: 1; /* fade in image */
    }
  }
}

jsfiddle https://jsfiddle.net/yayd5Lma/3

like image 93
guest271314 Avatar answered Sep 18 '22 17:09

guest271314