В этом уроке мы с вами рассмотрим как правильно оформить картинки, которые еще не подгрузились.
Для чего это вообще надо
Итак, предположим, что вы сверстали страницу и отдали заказчику. Вот тут-то суровая реальность и вносит свои коррективы. Пока вы тестировали все локально - сайт летал, как только выложили на сервер - начались проблемы. Сервер может быть перегружен, картинки могут много весить и не загружаться сразу (например, один мой клиент взял и засунул в слайд здоровенные картинки в png-24 формате. Весила каждая из них 1-2 мегабайта и было их 4-5 штук. Так что считайте сами:D) и пр. В результате, мы можем наблюдать как на нашем сайте медленно и печально грузятся зображения. Сначала появляется верхняя часть, потом середина и вот наконец-то загружено все. Разумеется клиенту это не нравится и он требует устранения этого ляпа.
Пути решения
Вот, что нас может спасти:
- прелоадер
- загрузчик изображений
Прелоадер в моем случае отпадал, ибо его еще надо было дизайнерить, оставалось либо найти загрузчик, либо писать его самому. Покопавшись в интернете, я нашел подходящую кандидатуру. Им оказался imagesLoaded, написанный на jquery. Начнем с HTML кода:
<div id="demo">
<div class="buttons">
<button id="add">Add images</button>
<button id="reset">Reset</button>
</div>
<div id="status">
<progress max="7" value="0"></progress>
</div>
<div id="image-container"></div>
</div>
Здесь блок с id="image-container"
- контейнер, где будут выводиться наши изображения (допустим, мы получаем их список через ajax-запрос, после чего, динамически вставляем на страницу). Кнопки с id="add"
и id="reset"
- кнопки, с помощью которых мы будем добавлять картинки и удалять их. Теперь подключим необходимые скрипты, добавив сразу же после этого кода:
<script src="jquery.min.js"></script>
<script src="imagesloaded.pkgd.min.js"></script>
Настало время заняться украшательством, ибо код без стилей - время на ветер. Добавте следующие стили между открывающим и закрывающим тегом head.
<style>
#image-container img {
max-height: 140px;
}
li {
height: 140px;
min-width: 100px;
display: block;
float: left;
list-style: none;
margin: 0 5px 5px 0;
background-color: black;
background-position: center center;
background-repeat: no-repeat;
}
/* анимация появления картинок */
li img,
#status {
-webkit-transition: opacity 0.4s;
-moz-transition: opacity 0.4s;
-ms-transition: opacity 0.4s;
transition: opacity 0.4s;
}
/* спиннер загрузки */
li.is-loading {
background-color: black;
background-image: url('loading.gif');
}
/* иконка не загруженног изображения */
li.is-broken {
background-image: url('broken.png');
background-color: #be3730;
width: 120px;
}
/* прячем незагруженные картинки */
li.is-loading img,
li.is-broken img {
opacity: 0;
}
.buttons { margin-bottom: 1.0em; }
button {
font-size: 18px;
padding: 0.4em 0.8em;
font-family: sans-serif;
}
#status {
opacity: 0;
position: fixed;
right: 20px;
top: 20px;
background: hsla( 0, 0%, 0%, 0.8);
padding: 20px;
border-radius: 10px;
z-index: 2; /* чтобы не перекрывался */
}
</style>
Ура, наши мучения практически позади. Нам лишь осталось написать простенький скриптик, чтобы наш пример заработал. Давайте сделаем это. Вставьте этот код после тегов <script>
и посмотрите, что у нас вышло!
<script>
( function( window ) {
'use strict';
var $progress, $status;
var supportsProgress;
var loadedImageCount, imageCount;
$( function() {
var $demo = $('#demo');
var $container = $demo.find('#image-container');
$status = $demo.find('#status');
$progress = $demo.find('progress');
supportsProgress = $progress[0] &&
// IE не поддерживает тег <progress>
$progress[0].toString().indexOf('Unknown') === -1;
$('#add').click( function() {
// добавляем новое изображение
var items = getItems();
$container.prepend( $(items) );
// вызываем ImagesLoaded
$container.imagesLoaded()
.progress( onProgress )
.always( onAlways );
// обнуляем счетчик загрузки
imageCount = $container.find('img').length;
resetProgress();
updateProgress( 0 );
});
// очищаем контейнер с изображениями
$('#reset').click( function() {
$container.empty();
});
});
// ----- ----- //
// получаем строку со всеми изображениями
function getItems() {
var items = '';
for ( var i = 0; i < 7; i++ ) {
items += getImageItem();
}
return items;
}
// получаем строку в формате <li> с тегом <img> в нем
function getImageItem() {
var item = '<li class="is-loading">';
var size = Math.random() * 3 + 1;
var width = Math.random() * 110 + 100;
width = Math.round( width * size );
var height = Math.round( 140 * size );
var rando = Math.ceil( Math.random() * 1000 );
// Вычисляем случайное число от 0 до 1000 и
// добавляем его к src чтобы избежать кеширования
var src = rando < 100 ? 'http://foo/broken-' + rando + '.jpg' :
// воспользуемся сайтом lorempixel для загрузки больших картинок
'http://lorempixel.com/' + width + '/' + height + '/' + '?' + rando;
item += '<img src="' + src + '" /></li>';
return item;
}
// ----- ----- //
function resetProgress() {
$status.css({ opacity: 1 });
loadedImageCount = 0;
if ( supportsProgress ) {
$progress.attr( 'max', imageCount );
}
}
function updateProgress( value ) {
if ( supportsProgress ) {
$progress.attr( 'value', value );
} else {
// если тег progress не поддерживается
$status.text( value + ' / ' + imageCount );
}
}
//запускается после каждого загруженного элемента
function onProgress( imgLoad, image ) {
// изменить класс, если изображение загружается/отсутствует
var $item = $( image.img ).parent();
$item.removeClass('is-loading');
if ( !image.isLoaded ) {
$item.addClass('is-broken');
}
// обновить данные прогресс-бара
loadedImageCount++;
updateProgress( loadedImageCount );
}
// скрыть статус когда все загружено
function onAlways() {
$status.css({ opacity: 0 });
}
})( window );
</script>
Альтернативный вариант
Не знаю почему, но когда я стал внедрять этот скрипт jquery загрузки изображений в проект, у меня возникла резкая антипатия к нему. 6 килобайт в сжатом виде - что-то как-то много, учитавая, что мы ничего толком не делаем. Поэтому я решил написать свой скрипт, непосредственно под свою задачу. HTML код у меня был таким:
<ul class="list_game" id="list_game">
<li>
<a href="" class="figure" data-image="img/story.jpg"></a>
<header>Игры на 5 минут</header>
<p>Утиные истории</p>
</li>
<li>
<a href="" class="figure" data-image="img/bob.jpg"></a>
<header>Игры на 5 минут</header>
<p>Спанч боб</p>
</li>
<li>
<a href="" class="figure" data-image="img/beauty.jpg"></a>
<header>Игры на 5 минут</header>
<p>Красавица и Чудовище</p>
</li>
<li>
<a href="" class="figure pop" data-image="img/mulan.jpg"></a>
<header>Игры на 5 минут</header>
<p>Мулан</p>
</li>
<li>
<a href="" class="figure new" data-image="img/princess.jpg"></a>
<header>Игры на 5 минут</header>
<p>Принцессы</p>
</li>
<li>
<a href="" class="figure" data-image="img/lilo.jpg"></a>
<header>Игры на 5 минут</header>
<p>Лило и Стич</p>
</li>
<li>
<a href="" class="figure pop" data-image="img/avatar.jpg"></a>
<header>Игры на 5 минут</header>
<p>Аватар</p>
</li>
<li>
<a href="" class="figure" data-image="img/dragon.jpg"></a>
<header>Игры на 5 минут</header>
<p>Приручить дракона</p>
</li>
<li>
<a href="" class="figure pop" data-image="img/alladin.jpg"></a>
<header>Игры на 5 минут</header>
<p>Алладин</p>
</li>
<li>
<a href="" class="figure new" data-image="img/mermaid.jpg"></a>
<header>Игры на 5 минут</header>
<p>Русалочка</p>
</li>
<li>
<a href="" class="figure" data-image="img/avia.jpg"></a>
<header>Игры на 5 минут</header>
<p>Самолеты: огонь и вода</p>
</li>
</ul>
Как видите, первоначально у нас нет никаких изображений. Мы будем определать путь к картинкам из атрибута data-image
и, как только они загрузятся, вставлять их как фоновое изображение. Все просто, осталось только научить этому браузер. Делается это так:
$("#list_game a.figure").each(function(){
var _this=$(this);
var imageA = new Image();
imageA.src = _this.attr("data-image");
imageA.onload=function() {
_this.css("background-image","url('"+imageA.src+"')");
}
});
Результат работы этого скрипта вы можете увидеть на странице jquery загрузка изображений. Смотрите, выбирайте и внедряйте).