Лого www.SiteHere.ru

Оптимизация загрузки Яндекс.Карты на сайте — загрузка Яндекс.Карты при наведении

Оптимизируя скорость загрузки сайта на разных проектах, когда дело доходит до Яндекс.Карт, то здесь приходится искать непростые решения, чтобы загрузка карты не мешала загрузке HTML структуры. В этой статье я хочу поделиться с вами таким способом загрузки Яндекс.Карт, когда Яндекс.Карта загружается только при наведении, что значительно увеличивает скорость загрузки сайта и уменьшает количество запросов от карт Яндекса.

Видео, кстати, также очень сильно влияет на скорость загрузки. Поэтому рекомендую следующую статью, где вы узнаете о том, как сделать загрузку видео по клику:

Многие могут вспомнить GIF файлы, ведь они также очень большого размера. Чтобы их оптимизировать, лучше их также загружать только при клике. То есть, если человек хочет посмотреть полную GIF-анимацию, то он кликает на Play и смотрит, иначе не нужно тратить трафик пользователя на загрузку всего содержимого GIF файлов. Этот способ оптимизированной загрузки файлов описан в следующей статье:

Почему лучше всего загружать при наведении?

Чтобы не писать много текста, лучше всего показать на конкретных цифрах.

Вот все запросы от Яндекса, где карта загружается сразу после загрузки страницы (когда вы создали карту с помощью конструктора карт):

Обычный способ загрузки карт с помощью конструктора

Смотреть пример

Итог: 9 внешних скриптов и 44 изображения.

А вот количество запросов от Яндекса, когда мы загружаем только API карт Яндекса, а саму загрузку откладываем когда уже наведем:

Загрузка API Яндекс.Карт

Смотреть пример

Итог: 4 внешних скрипта и 5 изображений. Уже лучше, но ведь можно еще 😉 !

Ну и последний (наш оптимизированный пример) список запросов от Яндекса, когда даже API карт Яндекса загружаются после наведения:

Загрузка Яндекс.Карт только при наведении

Смотреть пример

Вот так лучше. Сейчас не загружается ни один лишний файл до тех пор, пока мы не наведем на саму карту.

Все загружаемые файлы можно отследить на вкладке Network (Сеть) в инструментах разработчика браузера Google Chrome. Но в Firefox есть аналогичный инструмент и вы можете проанализировать все запросы с помощью этого браузера.

К сожалению, реализация не такая простая, как кажется на первый взгляд… Все дело в том, что у Яндекс.Карт на данный момент нет callback-а о том, что карта загрузилась полностью. Но, как вы знаете, если тщательно искать, то проблему наверняка можно решить. И решение нашлось, но обо всем по порядку…

Как сделать оптимизированную загрузку Яндекс.Карт?

Как сделать загрузку Яндекс.Карты при наведении

Первым делом нам необходимо подключить библиотеку jQuery (можно и без нее), затем прописать стили для блока с картой, для индикатора загрузки, а после заставить это все работать в нужное время и в нужном месте. Чтобы разложить все по полочкам, будем все делать по этапам, а если останутся вопросы, то вы всегда сможете задать их ниже в комментариях.

1 этап. Подключаем необходимые скрипты

Из сторонних скриптов здесь только библиотека jQuery — скачать jQuery.

Подключаем перед закрывающим тегом </body>:

HTML КОД
1
<script src="js/jquery.min.js"></script>

2 этап. Разметка для карты

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

HTML КОД
1
2
3
4
<div class="ymap-container">
    <div class="loader loader-default"></div>
    <div id="map-yandex"></div>
</div><!-- .ymap-container -->

Ничего сложного в данной структуре нет:

  • Блок с классом ymap-container — служит как "обертка" для блока с индикатором загрузки и блока с картой.
  • Блок с классами loader и loader-default — это наш индикатор загрузки.
  • Блок с идентификатором map-yandex — здесь появится карта Яндекса, когда мы наведем на "блок-обертку".

3 этап. Стили для блока с картой, а также для индикатора загрузки

Сейчас нам необходимо прописать стили для индикатора загрузки, а также для блока, где появится карта.

Индикатор загрузки, безусловно, играет очень важную роль. Иначе может возникнуть следующая ситуация: пользователь навел на блок, но ничего не происходит. Если у посетителя интернет-соединение слабенькое, то загрузка может затянуться, а если он не будет понимать того, что процесс идет, то решит, что карта просто не работает.

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

Итак, вот стили для блока с картой:

CSS КОД
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* &#34;Блок-обертка&#34;, где мы задаем фоновое изображение скриншотом как на карте */
.ymap-container {
  position: relative;
  margin: 3em 0 2em 0;
  overflow: hidden;
  cursor: pointer;
  background: url('../img/yandex-before-load.png') #ffffff no-repeat;
  background-position: center center;
  background-size: cover;
  box-shadow: 0 0 2em  0 rgba(0,0,0,.2);
}
 
/* Блок, в котором появится Яндекс.Карта */
#map-yandex {
  position: relative;
  z-index: 7;
  width: 100%;
  height: 20em;
  cursor: pointer;
  background-color: transparent;
}

Остались стили только для индикатора загрузки:

CSS КОД
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/* Индикатор загрузки, который показывается до загрузки карты */
.loader {
  position: absolute;
  z-index: 15;
  top: -100%;
  left: 0;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  overflow: hidden;
  color: #000000;
  transition: opacity .7s ease;
  opacity: 0;
  background-color: rgba(0,0,0,.55);
}
 
.loader:after,
.loader:before {
  box-sizing: border-box;
}
 
.loader.is-active {
  top: 0;
  opacity: 1;
}
 
.loader-default:after {
  position: absolute;
  top: calc(50% - 24px);
  left: calc(50% - 24px);
  width: 48px;
  height: 48px;
  content: '';
  animation: rotation 1s linear infinite;
  border: solid 8px #ffffff;
  border-left-color: transparent;
  border-radius: 50%;
}
 
@keyframes rotation {
  from {
    transform: rotate(0);
  }
  to {
    transform: rotate(359deg);
  }
}
 
@keyframes blink {
  from {
    opacity: .5;
  }
  to {
    opacity: 1;
  }
}

Здесь я выложил пример, где нет префиксов, чтобы код не был громоздким.

4 этап. Заставляем все вместе работать (JS)

Чтобы много не расписывать, опишу лишь процесс: когда пользователь наводит на карту, появляется индикатор загрузки (в это время загружается API Яндекса, а после сама карта), как только карта была загружена, то индикатор загрузки пропадает:

JAVASCRIPT КОД
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//Переменная для включения/отключения индикатора загрузки
var spinner = $('.ymap-container').children('.loader');
//Переменная для определения была ли хоть раз загружена Яндекс.Карта (чтобы избежать повторной загрузки при наведении)
var check_if_load = false;
//Необходимые переменные для того, чтобы задать координаты на Яндекс.Карте
var myMapTemp, myPlacemarkTemp;
 
//Функция создания карты сайта и затем вставки ее в блок с идентификатором &#34;map-yandex&#34;
function init () {
  var myMapTemp = new ymaps.Map("map-yandex", {
    center: [55.730138, 37.594238], // координаты центра на карте
    zoom: 7, // коэффициент приближения карты
    controls: ['zoomControl', 'fullscreenControl'] // выбираем только те функции, которые необходимы при использовании
  });
  var myPlacemarkTemp = new ymaps.GeoObject({
    geometry: {
        type: "Point",
        coordinates: [55.730138, 37.594238] // координаты, где будет размещаться флажок на карте
    }
  });
  myMapTemp.geoObjects.add(myPlacemarkTemp); // помещаем флажок на карту
 
  // Получаем первый экземпляр коллекции слоев, потом первый слой коллекции
  var layer = myMapTemp.layers.get(0).get(0);
 
  // Решение по callback-у для определения полной загрузки карты
  waitForTilesLoad(layer).then(function() {
    // Скрываем индикатор загрузки после полной загрузки карты
    spinner.removeClass('is-active');
  });
}
 
// Функция для определения полной загрузки карты (на самом деле проверяется загрузка тайлов) 
function waitForTilesLoad(layer) {
  return new ymaps.vow.Promise(function (resolve, reject) {
    var tc = getTileContainer(layer), readyAll = true;
    tc.tiles.each(function (tile, number) {
      if (!tile.isReady()) {
        readyAll = false;
      }
    });
    if (readyAll) {
      resolve();
    } else {
      tc.events.once("ready", function() {
        resolve();
      });
    }
  });
}
 
function getTileContainer(layer) {
  for (var k in layer) {
    if (layer.hasOwnProperty(k)) {
      if (
        layer[k] instanceof ymaps.layer.tileContainer.CanvasContainer
        || layer[k] instanceof ymaps.layer.tileContainer.DomContainer
      ) {
        return layer[k];
      }
    }
  }
  return null;
}
 
// Функция загрузки API Яндекс.Карт по требованию (в нашем случае при наведении)
function loadScript(url, callback){
  var script = document.createElement("script");
 
  if (script.readyState){  // IE
    script.onreadystatechange = function(){
      if (script.readyState == "loaded" ||
              script.readyState == "complete"){
        script.onreadystatechange = null;
        callback();
      }
    };
  } else {  // Другие браузеры
    script.onload = function(){
      callback();
    };
  }
 
  script.src = url;
  document.getElementsByTagName("head")[0].appendChild(script);
}
 
// Основная функция, которая проверяет когда мы навели на блок с классом &#34;ymap-container&#34;
var ymap = function() {
  $('.ymap-container').mouseenter(function(){
      if (!check_if_load) { // проверяем первый ли раз загружается Яндекс.Карта, если да, то загружаем
 
	  	// Чтобы не было повторной загрузки карты, мы изменяем значение переменной
        check_if_load = true; 
 
		// Показываем индикатор загрузки до тех пор, пока карта не загрузится
        spinner.addClass('is-active');
 
		// Загружаем API Яндекс.Карт
        loadScript("https://api-maps.yandex.ru/2.1/?lang=ru_RU&amp;loadByRequire=1", function(){
           // Как только API Яндекс.Карт загрузились, сразу формируем карту и помещаем в блок с идентификатором &#34;map-yandex&#34;
           ymaps.load(init);
        });                
      }
    }
  );  
}
 
$(function() {
 
  //Запускаем основную функцию
  ymap();
 
});

Весь код я постарался подробно прокомментировать, чтобы все было понятно, но если остались вопросы, то вы можете задать их мне в комментариях.

Скачать готовый пример вы можете по ссылке ниже:

Скачать готовый пример

Вывод

Данный способ особенно хорошо, если применять его вместе с другими способами оптимизации: запускаем Youtube видео только по клику и запускаем GIF по клику. Тогда вы точно ощутите прирост в скорости загрузки.

Если у вас появились идеи и мысли на счет того, как можно оптимизировать данный способ — не стесняйтесь, пишите в комментариях! 🙂

Успехов!

С Уважением, Юрий Немец

Оптимизация загрузки Яндекс.Карты на сайте — загрузка Яндекс.Карты при наведении 4.87/5 (97.33%) 15 голос(ов)

Понравилась статья - расскажи друзьям! :)

13 комментариев к записи
  • Влад

    Отличная статья! Оптимизация сайта как никогда важна сегодня и если есть возможность ускорить загрузку сайта за счет карт то конечно же надо это делать. На своем сайте делюсь секретами по оптимизации блога на wordpress.

     
  • Дмитрий Ковалевский

    Интересный вариант — при наведении. Спасибо) возьму на заметку. Но сам действую немного по другому, если интересно то так:

    1. Загрузка скрипта карты только после загрузки страницы: window.onload = function() { …}); 

    2. В этот момент прелоадер на месте карты.

    3. Когда api готово узнаю через ymaps.ready(function() { …}); И в этот момент скрываю прелоадер и открываю блок с картой.

    Конечно запросов на странице сразу немало, но визуально для пользователя все происходит плавно и карта готова сразу.

     
    • Юрий Немец

      Спасибо за способ, Дмитрий! Вы предложили также хороший рабочий вариант.

       
  • Задрот

    Привет, я в js не силен, поэтому подскажи, в этом коде:

    // Функция загрузки API Яндекс.Карт по требованию (в нашем случае при наведении)
    function loadScript(url, callback){
      var script = document.createElement("script");
     
      if (script.readyState){  // IE
        script.onreadystatechange = function(){
          if (script.readyState == "loaded" ||
                  script.readyState == "complete"){
            script.onreadystatechange = null;
            callback();
          }
        };
      } else {  // Другие браузеры
        script.onload = function(){
          callback();
        };
      }
     
      script.src = url;
      document.getElementsByTagName("head")[0].appendChild(script);
    }

     

    Почему тут сначала идет проверка загружен ли скрипт, потом сразу вызывается функция колбек, в котором вызывается функция инициализации. И только в конце в действительности загружается скрипт с api? 

     

     
  • Дмитрий

    Посмотрите Ваш последний оптимизированный пример, если первый раз открыть страницу и навести курсор на карту, то после отработки индикатора загрузки появляется карта. Но если мы обновим эту же страницу в браузере и повторно наведем курсор на поле карты, то появившийся индикатор загрузки крутится бесконечно. Как подкорректировать код, чтобы индикатор исчезал при повторных перезагрузках страницы?

     
    • Юрий Немец

      Добрый день, Дмитрий!

      Напишите, пожалуйста, что у вас за браузер и какая версия, так как проверил в следующих браузерах и такой ошибки не обнаружил:

      1) Firefox 50.1.0 — корректно работает

      2) Google Chrome 55.0.2883.87 — корректно работает

      3) Opera 42.0.2393.137 — корректно работает

      4) Safari 5.1.4 — корректно работает

       
      • Сергей

        Добрый день, такая же проблема, как и у Дмитрия. При повторных перезагрузках страницы появившийся индикатор загрузки крутится бесконечно (но не всегда, и только в Firefox, в остальных браузерах все работает корректно, даже в IE11). Проверял на разных компьютерах, такой же результат. А так метод очень понравился .Спасибо.

         
      • Дмитрий

        Юрий спасибо за Ваш ответ, проблема в firefox 50.1.0, проверьте именно первый раз карта грузится корректно, но если на этой же странице не уходя с неё, сделать перезагрузку через "Обновить текущую страницу" и повторно навести курсор на поле с картой, то прелоадер уходит в бесконечность, причем если чуть изменить размер окна браузера (уменьшая его курсором например), то прелоадер сразу пропадает.

        На смартфоне в firefox 51.0b15 все ок.

         
  • Дмитрий

    На данный момент ушел от этой проблемы путем удаления дива с прелоадером, соответственно сейчас не виден процесс загрузки карты визуально, но она хотя бы в итоге грузится через пару секунд.

     
    • Юрий Немец

      Дмитрий, добрый день! А понимает ли сейчас посетитель с медленным интернетом, что карта загружается, и это не просто изображение?

       
      • Дмитрий

        Трудно сказать, надеюсь что медленного интернета практически нет. Юрий Вы не могли бы подсказать вариант, чтобы изначально была ссылка например (посмотреть на карте) и по клику на ней уже открывался div соответственно с подгрузкой всех скриптов, т.е. вместо варианта наведения на карту сделать ссылку. Готов оплатить данную доработку, напишите на 20cent@mail.ru

         
  • Key-Bo

    а потом появился async

     
  • Андрей

    Увы, но ни один из примеров не будет работать на мобильных устройствах. Более правильно будет загружать либо при определении, что элемент попал в видимую часть экрана, либо просто при прокрутке.

     

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *