Если вы в последнее время заходили в интернет, то, скорее всего, видели красивую анимацию загрузки, которая заполняет страницу, прежде чем элегантно подгрузится ее содержимое.
Некоторые социальные гиганты, такие как Facebook, даже используют этот подход для улучшения загрузки страниц. Как мы можем добиться такого же результата с помощью одного только простого CSS?
Мы создадим анимацию загрузки с помощью CSS-класса, который вы можете применить практически к любому элементу (в пределах разумного).
Анимация загрузкиЛишь с одним CSS можно добиться высокой гибкости, изящности приложения и в то же время простоты.
Хотя сниппет довольно мал и вы можете просто скопировать и вставить его, я расскажу о том, что в нем происходит, и приведу пример его динамического использования при загрузке данных.
Просто хотите сниппет?Пожалуйста: CSS Loading Animation.
Нужно ли мне знать, как анимировать, для прочтения этого руководства?Нет! Мы подробно рассмотрим, что именно вам нужно сделать. На самом деле анимация здесь относительно проста, так что давайте приступим к делу!
В этой первой части сосредоточимся на том, чтобы собрать анимацию загрузки в одно целое и увидеть ее на статическом HTML-сайте. Цель состоит в том, чтобы пошагово создать настоящий сниппет. Мы будем использовать здесь только HTML и CSS.
Для начала нам понадобится небольшой образец контента страницы. Здесь действительно нет никаких ограничений, вы можете создать его с помощью базового HTML и CSS или добавить в свое приложение Create React!
Для этого руководства я собираюсь использовать HTML и CSS с несколькими примерами контента, которые позволят нам увидеть наш сниппет в действии.
Для начала создайте новый HTML-файл. Заполните его чем-нибудь, что даст возможность поиграться с анимацией. Я воспользуюсь сайтом fillerama со строчками из моего любимого сериала “Футурама”!
Статическая веб-страница HTML-CSS с контентом, взятым с fillerama.ioЕсли вы собираетесь следовать моему примеру, то вот как выглядит мой проект:
my-css-loading-animation-static
- index.html
- main.css
Отслеживайте через коммит!
В качестве основы давайте создадим новый CSS-класс. В наш CSS-файл добавим:
.loading {
background: #eceff1;
}
Теперь, когда у нас есть такой класс, давайте добавим его к нескольким или ко всем элементам на нашей странице. Я добавил его к нескольким абзацам, заголовкам и спискам.
<p class="loading">For example...
Статическая веб-страница HTML-CSS с серым фоном для контента
Это дает нам основной фон, но мы, вероятно, хотели бы скрыть имеющийся текст. Во время загрузки у нас этого текста еще не будет, поэтому, скорее всего, мы захотим использовать заполняющий текст или фиксированную высоту. В любом случае, мы можем изменить цвет на прозрачный:
.loading {
color: transparent;
background: #eceff1;
}
Статическая веб-страница HTML-CSS с серым фоном и прозрачным цветом для контента
Независимо от того, применяете ли вы класс к элементу списка верхнего уровня (<ol>
или <ul>
) или к отдельному пункту в списке (<li>
), всё выглядит как один большой блок. Если мы добавим небольшой отступ в нижнюю часть для всех элементов списка, то увидим, что они отображаются по-разному:
li {
margin-bottom: .5em;
}
Разница в стиле между применением к верхнему уровню списка или к пунктам в списке
И вот теперь всё начинает складываться воедино, но пока что выглядит скорее, как поле для заполнения. Так что давайте анимируем то, что у нас есть, для создания эффекта загрузки.
Прежде чем действительно анимировать класс, нам нужно, чтобы было, что анимировать. Поэтому давайте добавим к классу .loading
градиент:
.loading {
color: transparent;
background: linear-gradient(100deg, #eceff1 30%, #f6f7f8 50%, #eceff1 70%);
}
Это означает, что нам нужен линейный градиент с наклоном в 100 градусов, где мы начинаем с #eceff1 и переходим к #f6f7f8 на 30% и обратно к #eceff1 на 70%;
Тонкий градиентный фон, который похож на бликЕго трудно заметить поначалу: без движения он может выглядеть, как обычный блик на экране компьютера. Если хотите увидеть его, то прежде чем идти дальше, не стесняйтесь поиграть с цветами, обозначенными выше.
Теперь, когда есть основа для анимации, нам сначала нужно создать правило ключевых кадров:
@keyframes loading {
0% {
background-position: 100% 50%;
}
100% {
background-position: 0 50%;
}
}
Это правило меняет положение фона от начальных 100% до 0% по оси X.
Воспользовавшись этим правилом, мы можем добавить свойство анимации к классу .loading
:
.loading {
color: transparent;
background: linear-gradient(100deg, #eceff1 30%, #f6f7f8 50%, #eceff1 70%);
animation: loading 1.2s ease-in-out infinite;
}
Строчка animation устанавливает ключевой кадр loading
, говорит ему продолжаться в течение 1,2 секунд, устанавливает функцию синхронизации как ease-in-out
, чтобы все выглядело плавно, и с помощью infinite
указывает повторять это в бесконечном цикле.
Как вы, возможно, заметили, после сохранения этих параметров ничего по-прежнему не происходит. Причина в том, что мы устанавливаем градиент от одного конца элемента DOM до другого, так что нам некуда двигаться!
Давайте попробуем установить background-size
для класса .loading
.
.loading {
color: transparent;
background: linear-gradient(100deg, #eceff1 30%, #f6f7f8 50%, #eceff1 70%);
background-size: 400%;
animation: loading 1.2s ease-in-out infinite;
}
Теперь, поскольку наш фон расширяется за пределы выбранного элемента DOM (эта расширенная часть вам не видна), у него есть некоторое пространство для анимации, и вот она!
Наша анимация загрузки!Отслеживайте через коммит!
Теперь, когда в нашем распоряжении есть анимация загрузки, давайте задействуем ее в базовом примере, где имитируется состояние загрузки.
Хитрость с фактическим использованием здесь в том, что, как правило, у нас нет в доступе контента, поэтому в большинстве случаев приходится его подделывать.
Чтобы показать, как это можно сделать, создадим простое приложение React с Next.js.
Шаг 1. Создаем пример приложения React с Next.jsПерейдите в каталог, где вы хотите создать свой новый проект, и введите в командной строке следующее:
yarn create next-app
# или
npm init next-app
Вам будет предложено выбрать некоторые параметры, в частности имя, определяющее каталог, в котором создается проект, и тип проекта. Я использую my-css-loading-animation-dynamic
и “Default Starter App”.
После установки перейдите в ваш новый каталог и запустите сервер разработки:
cd [каталог]
yarn dev
# или
npm run dev
Запуск сервера разработки с Next.JS
Следом давайте заменим содержимое в файле pages/index.js
. Я собираюсь извлечь содержимое страницы из предыдущего примера, но мы создадим его аналогично тому, как если бы ожидали, что оно будет исходить от API. Во-первых, давайте добавим контент (content
) в качестве объекта над оператором return
:
const content = {
header: `So, how 'bout them Knicks?`,
intro: `What are their names? I'm Santa Claus! This opera's as lousy as it is brilliant! Your lyrics lack subtlety. You can't just have your characters announce how they feel. That makes me feel angry! Good news, everyone! I've taught the toaster to feel love!`,
list: [
`Yes! In your face, Gandhi!`,
`So I really am important? How I feel when I'm drunk is correct?`,
`Who are those horrible orange men?`
]
}
Чтобы отобразить этот контент, давайте произведем следующую замену внутри <main>
:
<main>
<h1>{ content.header }</h1>
<p>{ content.intro }</p>
<ul>
{ content.list.map((item, i) => {
return (
<li key={i}>{ item }</li>
)
})}
</ul>
</main>
А что касается стилей, вы можете скопировать и вставить всё из файла main.css
из Части 1 в тэг <style>
в нижней части индексной страницы. Это даст нам следующее:
С этим мы должны вернуться к точке, аналогичной той, на которой закончили в Части 1. Но сейчас мы еще не используем никакую анимацию загрузки.
Отслеживайте через коммит!
Пример, с которым мы работаем, довольно прост. Вы увидите, что всё будет предварительно сгенерировано статически, но это помогает нам создать реалистичную демонстрацию, с помощью которой можно протестировать анимацию загрузки.
Чтобы подделать состояние загрузки, мы используем useState
из React, useEffect
и старомодный setTimeout
, чтобы предзагрузить некоторый “загружаемый” контент, а после того, как setTimeout
завершится, нам нужно заменить его на реальный контент страницы. Тем временем, благодаря отдельному экземпляру useState
, мы будем знать, что находимся в состоянии загрузки.
В первую очередь нам нужно импортировать зависимости. В начало файла pages/index.js
добавьте:
import { useState, useEffect } from 'react';
Над объектом content
давайте добавим некоторое состояние:
const [loadingState, updateLoadingState] = useState(true);
const [contentState, updateContentState] = useState({})
А внутри содержимого мы теперь можем обновить экземпляры, чтобы использовать это состояние:
<h1>{ contentState.header }</h1>
<p>{ contentState.intro }</p>
<ul>
{ contentState.list.map((item, i) => {
return (
<li key={i}>{ item }</li>
)
})}
</ul>
После того, как вы сохраните и загрузите страницу в таком виде, сразу же заметите, что мы получаем ошибку, потому что свойство list
не существует в нашем contentState
. Так что сначала надо исправить это:
{ Array.isArray(contentState.list) && contentState.list.map((item, i) => {
return (
<li key={i}>{ item }</li>
)
})}
Затем давайте добавим setTimeout
внутри хука useEffect
, чтобы имитировать загрузку наших данных. Добавьте под объектом content
следующее:
useEffect(() => {
setTimeout(() => {
updateContentState(content);
updateLoadingState(false)
}, 2000);
}, [])
Как только вы сохраните это и откроете браузер, то заметите, что в течение двух секунд у вас не отображается никакой контент, а затем он загружается. Так имитируется асинхронная загрузка данных.
Отслеживайте через коммит!
Теперь мы наконец-то можем добавить загрузочную анимацию. Так что используем для этого состояние загрузки, которое мы настроили с помощью useState
, и если контент загружается, будем добавлять класс .loading
в элементы.
Прежде чем приступить, вместо того, чтобы по отдельности добавлять этот класс к каждому элементу DOM, было бы более разумно осуществлять это с помощью CSS и добавления класса к родительскому элементу. Так мы и сделаем.
Во-первых, обновим класс .loading
, чтобы он указывал на наши элементы:
.loading h1,
.loading p,
.loading li {
color: transparent;
background: linear-gradient(100deg, #eceff1 30%, #f6f7f8 50%, #eceff1 70%);
background-size: 400%;
animation: loading 1.2s ease-in-out infinite;
}
Затем мы можем динамически добавить класс к тэгу <main>
:
<main className={loadingState ? 'loading' : ''}>
Примечание: если вы используете Sass, то можете управлять стилями загрузки, расширяя класс .loading
на экземпляры, которые хотите использовать, или создавать поля для заполнения и расширять уже их!
И если вы обновите страницу, то заметите, что в течение двух первых секунд это все еще просто пустая страница!
Проблема в том, что когда мы загружаем контент, внутри тэгов у нас нет ничего, чему свойство line-height
наших элементов могло бы назначить какую-то высоту:
Но мы можем исправить это! Поскольку класс .loading
устанавливает текст прозрачным, мы можем просто добавить слово Loading
(“Загружается…”) для каждого фрагмента содержимого страницы:
const [contentState, updateContentState] = useState({
header: 'Loading',
intro: 'Loading',
list: [
'Loading',
'Loading',
'Loading'
]
})
Примечание: мы не можем использовать здесь пустое пространство, потому что это само по себе не даст нам высоту при рендеринге DOM.
И как только вы сохраните и перезагрузите страницу, первые две секунды будут отображать состояние загрузки, которое соответствует контенту!
Анимация загрузки HTML & CSSОтслеживайте через коммит!
Эту технику можно использовать довольно широко. Поскольку это CSS-класс, вы можете легко и просто добавлять его, куда захотите.
Если вы не поклонник установки текста “Загружается…” для состояния загрузки, другой вариант — установить фиксированную высоту. Единственная проблема здесь в том, что такой вариант требует больше обслуживания в плане подгонки CSS для соответствия тому, как будет выглядеть загружаемый контент.
Кроме того, этот способ не совершенен. Чаще всего вы не будете точно знать, сколько у вас на странице находится копий. Цель в том, чтобы притворяться и намекать, что на странице есть контент и что он в данный момент как раз загружается.
Перевод статьи : Colby Fayock How to Use Pure CSS to Create a Beautiful Loading Animation for your App
Комментарии