Затухание в фоновом изображении после загрузки (без jquery) при использовании медиа-запросов для замены изображений для разных размеров экрана

Я читал всю ночь и, похоже, не мог прийти к какому-то конкретному ответу на то, что лучший способ сделать это. Эти две вещи, которые, как я знаю, работают, - это

Для замирания изображения при загрузке:

Используйте обертку изображений и тег <img> следующим образом:

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

и css выглядит как

.imageWrapper {
  opacity: 0
}

.loaded {
  opacity: 1
}

а затем в файле js что-то вроде

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

Для загрузки другого изображения на основе размера экрана

@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');
  }
}

Моя проблема

Я могу делать обе эти вещи по отдельности (затухание в изображении при загрузке, изменение фонового изображения, когда браузер обнаруживает меньший размер экрана), но я не могу найти решение, которое включает и. Мне нужно иметь возможность указывать другое изображение для разных размеров экрана, а также иметь возможность обнаруживать, когда загружается это изображение и исчезать.

Есть ли хороший способ сделать это?

Мое решение:

В результате я использовал вариант guest271314 для загрузки правильных изображений. Это работает со всей последней версией каждого браузера и очень легко реализуется.

Во-первых, у меня есть встроенный script, расположенный прямо под моим открывающим тегом <body>, так что, если мой браузер медленно загружает мой js файл, он может в любое время загрузить изображения.

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

а затем у меня есть тег <picture>, например:

<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>

и мой sass выглядит так:

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

.backgroundContainer
  width: 100%
  height: 100%

.backgroundImage
  opacity: 0

.loaded
  opacity: 1
  animation: fadeIn 3s

И это позволяет браузеру (независимо от скорости) ждать, пока изображение с правильным размером будет загружено, а затем затушевывает его поверх 3s, с надежным возвратом, используя тег <img> для старых браузеров.

Ответ 1

изменить # 2: обновленную скрипту прогресса: https://jsfiddle.net/c5hy0g8r/11

Проблема по-прежнему заключается в том, что при медленных сетевых условиях использование css Свойство content будет по-прежнему загружаться в куски, как обычно делают изображения. обычный метод onload = "imageLoaded (this)" не будет работать на img или изображение, содержимое которого генерируется css-содержимым: url ('img.jpg') свойство.

Вы можете использовать элемент <picture>, имеющий один или несколько элементов <source> с атрибутом srcset, установленным для источника изображения, который должен отображаться в <img>, когда соответствующий media, установленный в действительный список медиа-запросов, соответствует среде.

В onload событии элемента <img> установите родительский элемент opacity в 0; используйте requestAnimationFrame() для анимации opacity элемента от 0 до 1.

<!DOCTYPE html>
<html>

<head>
  <style>
    .imageWrapper {
      opacity: 0;
    }
  </style>
</head>

<body>

  <picture class="imageWrapper">
    <source srcset="http://lorempixel.com/50/50/technics" media="(min-width: 0px) and (max-width:150px)">
    <source srcset="http://lorempixel.com/50/50/city" media="(min-width: 151px) and (max-width: 300px)">
    <source srcset="http://lorempixel.com/50/50/nature" media="(min-width: 301px) and (max-width:450px)">
    <source srcset="http://lorempixel.com/50/50/sports" media="(min-width: 451px) and (max-width:600px)">
    <source srcset="http://lorempixel.com/50/50/animals" media="(min-width: 601px)">
    <img width="50px" height="50px" onload="imageLoaded(this)" src="null" alt="">
  </picture>
  <figcaption></figcaption>
    <script>
    const num = 1/60;
    var fx = null;
    var caption = document.querySelector("figcaption");
    var imageLoaded = (img) => {
      caption.innerHTML = "";
      cancelAnimationFrame(fx);
      var n = 0;
      var imgWrapper = img.parentNode;
      imgWrapper.style.opacity = 0;
      fx = requestAnimationFrame(function animate() {
        console.log(n);
        if (n < 1) {
          n += num;
          imgWrapper.style.opacity = n;
          fx = requestAnimationFrame(animate);
        } else {
          caption.innerHTML = img.currentSrc.slice(img.currentSrc.lastIndexOf("/") + 1);
          console.log("complete");
        }
      })
    }
  </script>
</body>
</html>

plnkr http://plnkr.co/edit/RWSc6J3kUUJPUZsrpagi?p=preview

Ответ 2

В основном я должен уметь исчезать в background-image, когда он загружает или может изменить тег <img> src, прежде чем он загрузит в зависимости от размера экрана, или сделать что-то, что включает в себя как эти вещи, используя метод, о котором я не знаю.

Вы можете использовать свойство css content со значением, установленным в функцию url(), имеющей URL-адрес изображения для отображения или изменить отображаемый источник изображения; css animation, @keyframes исчезает в background-image при загрузке исходного изображения.

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

Ответ 3

Вы должны использовать анимацию css3 для этой цели.

@-webkit-keyframes fadeIn {
            0% {opacity: 0;}
            100% {opacity: 1;}
         }

         @keyframes fadeIn {
            0% {opacity: 0;}
            100% {opacity: 1;}
         }

         .fadeIn {
            -webkit-animation-name: fadeIn;
            animation-name: fadeIn;
         }

Ответ 4

Я бы просто загрузил все изображения в свою разметку и назначил классы для медиа-запросов:

<div class="imageWrapper">
    <img class="small" src="img_small.jpg" onload="imageLoaded(this)">
    <img class="med" src="img_med.jpg" onload="imageLoaded(this)">
    <img class="large" src="img_large.jpg" onload="imageLoaded(this)">
</div>

Затем используйте ваши медиа-запросы, чтобы скрыть их по мере необходимости:

@media screen only and (min-device-width: 0) and (max-device-width: 450px) {
  .imageWrapper .large, .imageWrapper .medium { display: none; }
}

@media screen only and (min-device-width: 451px) and (max-device-width: 1024px) {
  .imageWrapper .large, .imageWrapper .small { display: none; }
}

@media screen only and (min-device-width: 1025px) {
  .imageWrapper .small, .imageWrapper .medium { display: none; }
}