Как сделать простой Preloader при загрузке страниц

Preloader при загрузке страниц чаще всего нужен в том случае, если необходимо, чтобы пользователь начал пользоваться сайтом только после загрузки всех ресурсов (изображения, javascript-код и так далее). Но нужно использовать его с осторожностью, так как пока все ресурсы не будут загружены, контент остаётся недоступным

Пример Preloader, который будем реализовывать в этой практической статье, можно посмотреть на видео

Этот же пример на Codepen

Или просто обновите страницу с этой статьёй - при открытии статьи, вы уже, скорей всего, заметили данный Preloader :)

Верстаем структуру

Для начала необходимо найти подходящий Preloader. Небольшой набор качественных Preloaders можно посмотреть здесь - https://tobiasahlin.com/spinkit/

По ссылке выше, выбираем наиболее подходящий Preloader и нажимаем на Source

1


В появившемся окне копируем HTML-структуру Preloader

<div class="sk-chase">
  <div class="sk-chase-dot"></div>
  <div class="sk-chase-dot"></div>
  <div class="sk-chase-dot"></div>
  <div class="sk-chase-dot"></div>
  <div class="sk-chase-dot"></div>
  <div class="sk-chase-dot"></div>
</div>


В разметке создадим блок <div class="preloader"></div> и вставляем в него скопированный HTML-код

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Preloader</title>
    <link rel="stylesheet" href="css/bootstrap-reboot.min.css"/>
    <link rel="stylesheet" href="css/main.css"/>
  </head>
  <body>

  	<!-- Изображения для фона и теста -->
    <div class="images">
      <div class="images__image"><img src="https://picsum.photos/1920/1080" alt=""/></div>
      <div class="images__image"><img src="https://picsum.photos/1920/1081" alt=""/></div>
      <div class="images__image"><img src="https://picsum.photos/1920/1082" alt=""/></div>
      <div class="images__image"><img src="https://picsum.photos/1920/1083" alt=""/></div>
      <div class="images__image"><img src="https://picsum.photos/1920/1084" alt=""/></div>
      <div class="images__image"><img src="https://picsum.photos/1920/1085" alt=""/></div>
      <div class="images__image"><img src="https://picsum.photos/1920/1086" alt=""/></div>
      <div class="images__image"><img src="https://picsum.photos/1920/1087" alt=""/></div>
    </div>

		<!-- Блок Preloader -->
    <div class="preloader">

      <!-- Добавляем готовую структуру Preloader -->
      <div class="sk-chase">
        <div class="sk-chase-dot"></div>
        <div class="sk-chase-dot"></div>
        <div class="sk-chase-dot"></div>
        <div class="sk-chase-dot"></div>
        <div class="sk-chase-dot"></div>
        <div class="sk-chase-dot"></div>
      </div>
    </div>

    <script src="js/main.js"></script>
  </body>
</html>


Добавляем стили

В том же окне, где копировали HTML-структуру Preloader, копируем CSS-стили для него

.sk-chase {
  width: 40px;
  height: 40px;
  position: relative;
  animation: sk-chase 2.5s infinite linear both;
}

.sk-chase-dot {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  animation: sk-chase-dot 2.0s infinite ease-in-out both;
}

.sk-chase-dot:before {
  content: '';
  display: block;
  width: 25%;
  height: 25%;
  background-color: #fff;
  border-radius: 100%;
  animation: sk-chase-dot-before 2.0s infinite ease-in-out both;
}

.sk-chase-dot:nth-child(1) { animation-delay: -1.1s; }
.sk-chase-dot:nth-child(2) { animation-delay: -1.0s; }
.sk-chase-dot:nth-child(3) { animation-delay: -0.9s; }
.sk-chase-dot:nth-child(4) { animation-delay: -0.8s; }
.sk-chase-dot:nth-child(5) { animation-delay: -0.7s; }
.sk-chase-dot:nth-child(6) { animation-delay: -0.6s; }
.sk-chase-dot:nth-child(1):before { animation-delay: -1.1s; }
.sk-chase-dot:nth-child(2):before { animation-delay: -1.0s; }
.sk-chase-dot:nth-child(3):before { animation-delay: -0.9s; }
.sk-chase-dot:nth-child(4):before { animation-delay: -0.8s; }
.sk-chase-dot:nth-child(5):before { animation-delay: -0.7s; }
.sk-chase-dot:nth-child(6):before { animation-delay: -0.6s; }

@keyframes sk-chase {
  100% { transform: rotate(360deg); }
}

@keyframes sk-chase-dot {
  80%, 100% { transform: rotate(360deg); }
}

@keyframes sk-chase-dot-before {
  50% {
    transform: scale(0.4);
  } 100%, 0% {
    transform: scale(1.0);
  }
}


Добавляем остальные стили

body {
  background: #121212;
}
.images {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 32px;
  gap: 32px;
  padding: 32px;
}
.images__image {
  border-radius: 8px;
  overflow: hidden;
}
.images__image img {
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
  display: block;
}

/* Стили для основного блока Preloader */
.preloader {

  /* Фиксируем блок на всю ширину и высоту окна, чтобы перекрывать все остальные элементы */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  z-index: 9999;

  /* Центрируем анимацию Preloader */
  display: flex;
  align-items: center;
  justify-content: center;

  /* При загрузке страницы, Preloader сразу отображается */
  opacity: 1;
  visibility: visible;

  /* Добавляем затемнение */
  background: rgba(18,18,18,0.64);

  /* Добавляем плавный переход */
  transition: opacity 1s, visibility 0s 0s;
}

/* Класс для скрытия Preloader */
.preloader_hidden {
  visibility: hidden;
  opacity: 0;
  transition: opacity 1s, visibility 0s 1s;
}

/* Скопированый код анимации Preloader */
.sk-chase {
  width: 128px;
  height: 128px;
  position: relative;
  -webkit-animation: sk-chase 2.5s infinite linear both;
  animation: sk-chase 2.5s infinite linear both;
}
.sk-chase-dot {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  -webkit-animation: sk-chase-dot 2s infinite ease-in-out both;
  animation: sk-chase-dot 2s infinite ease-in-out both;
}
.sk-chase-dot:before {
  content: '';
  display: block;
  width: 25%;
  height: 25%;
  background-color: #3626a7;
  border-radius: 100%;
  -webkit-animation: sk-chase-dot-before 2s infinite ease-in-out both;
  animation: sk-chase-dot-before 2s infinite ease-in-out both;
}
.sk-chase-dot:nth-child(1) {
  -webkit-animation-delay: -1.1s;
  animation-delay: -1.1s;
}
.sk-chase-dot:nth-child(2) {
  -webkit-animation-delay: -1s;
  animation-delay: -1s;
}
.sk-chase-dot:nth-child(3) {
  -webkit-animation-delay: -0.9s;
  animation-delay: -0.9s;
}
.sk-chase-dot:nth-child(4) {
  -webkit-animation-delay: -0.8s;
  animation-delay: -0.8s;
}
.sk-chase-dot:nth-child(5) {
  -webkit-animation-delay: -0.7s;
  animation-delay: -0.7s;
}
.sk-chase-dot:nth-child(6) {
  -webkit-animation-delay: -0.6s;
  animation-delay: -0.6s;
}
.sk-chase-dot:nth-child(1):before {
  -webkit-animation-delay: -1.1s;
  animation-delay: -1.1s;
}
.sk-chase-dot:nth-child(2):before {
  -webkit-animation-delay: -1s;
  animation-delay: -1s;
}
.sk-chase-dot:nth-child(3):before {
  -webkit-animation-delay: -0.9s;
  animation-delay: -0.9s;
}
.sk-chase-dot:nth-child(4):before {
  -webkit-animation-delay: -0.8s;
  animation-delay: -0.8s;
}
.sk-chase-dot:nth-child(5):before {
  -webkit-animation-delay: -0.7s;
  animation-delay: -0.7s;
}
.sk-chase-dot:nth-child(6):before {
  -webkit-animation-delay: -0.6s;
  animation-delay: -0.6s;
}
@-webkit-keyframes sk-chase {
  100% {
    transform: rotate(360deg);
  }
}
@keyframes sk-chase {
  100% {
    transform: rotate(360deg);
  }
}
@-webkit-keyframes sk-chase-dot {
  80%, 100% {
    transform: rotate(360deg);
  }
}
@keyframes sk-chase-dot {
  80%, 100% {
    transform: rotate(360deg);
  }
}
@-webkit-keyframes sk-chase-dot-before {
  50% {
    transform: scale(0.4);
  }
  100%, 0% {
    transform: scale(1);
  }
}
@keyframes sk-chase-dot-before {
  50% {
    transform: scale(0.4);
  }
  100%, 0% {
    transform: scale(1);
  }
}


Пишем логику на JavaScript

Логика максимально простая - определяем, когда все ресурсы страницы будут загружены, ищем блок Preloader и добавляем ему класс для скрытия

window.addEventListener('load', () => { /* Страница загружена, включая все ресурсы */
  const preloader = document.querySelector('.preloader') /* находим блок Preloader */
  preloader.classList.add('preloader_hidden') /* добавляем ему класс для скрытия */
})


Итоги

Конечно, Preloader можно добавлять не только на событие загрузки страницы. Preloader часто добавляют также при AJAX-запросах в отдельных компонентах, не блокируя остальную часть сайта. Но об этом в другой раз :)

Буду рад, если статья оказалась полезной

Спасибо за ваше внимание и уделённое время!