Как сделать skeleton loading
Как создать каркасные загрузчики в CSS. Skeleton loader.
Оптимизируйте восприятие времени загрузки с помощью каркасной загрузки контента
Движение играет важную роль в приложениях. Это может помочь сделать интерфейсы более выразительными и интуитивно понятными, а также предоставить ключевую информацию, такую как обратная связь, которая может направить внимание пользователя на важные части страницы.
Когда дело доходит до загрузки анимации, движение также может сыграть большую роль в улучшении восприятия. С правильным балансом скорости, направления или замедления, движение может сделать загрузку более производительной.
Как каркасные загрузчики улучшают восприятие
Хороший пример ощутимого улучшения производительности происходит в загрузчиках Skeleton. Каркасный или как его еще называют скелетный загрузчик может выполнять роль заполнителя для информации, которая все еще загружается, помогая пользователю сосредоточиться на прогрессе, а не на времени ожидания.
Это то, что мы рассмотрим в этой статье. Мы рассмотрим улучшение анимации загрузки панели мониторинга от простого загрузчика до анимации загрузки заполнителя.
Анимация
Анимация довольно простая, но очень эффективная. Мы хотим анимировать градиент слева направо. Мы также хотим убедиться, что градиент проходит через свой контейнер, чтобы исчезнуть, прежде чем появится снова.
Работая над движениями, мы обычно должны стремиться к продолжительности где-то между 300-500 мс. Что-нибудь ниже этой продолжительности, анимация становится слишком быстрой для восприятия; большее время может показаться вялым, заставляя пользователей чувствовать, что они ждут больше, чем на самом деле. Также важно отметить, что чем сложнее и больше анимация, тем медленнее она должна быть.
Мы также хотим использовать приятное смягчение движения, чтобы анимация была более естественной. Ничто в реальном мире не движется с постоянной линейной скоростью.
Чтобы полностью понять, как будет работать анимация, лучше всего объяснить ее с помощью другой анимации:
Анимация градиента
Здесь мы анимируем градиент слева направо, начиная с внешней стороны контейнера.
Написание CSS
В HTML мы будем работать только с одним элементом-заполнителем. Вот с этим:
Вся анимация будет идти внутри ::before элемента. Это псевдоэлемент, который часто используется для добавления косметики в выбранный элемент. Подумайте о псевдоэлементе как о добавленном ключевом слове к селектору, который позволяет стилизовать определенные его части. Но прежде чем заняться этим, давайте определим некоторые стили для родителя:
Давайте проанализируем этот псевдоэлементный код:
Все это должно привезти к следующей анимации:
How to Create Skeleton Loaders in CSS
Optimize your perceived performance by wireframing content
Motion plays an important role in any application. It can help you to make interfaces more expressive and intuitive, whilst also providing key information, such as feedback that can guide a user’s attention to important parts of your page.
When it comes to loading animations, motion can also play a big part in improving perceived performance. With the right balance of speed, direction, or easing, motion can make loading feel more performant.
#How Skeleton Loaders Improve Perceived Performance
A good example of perceived performance enhancement occurs in skeleton loaders. A skeleton loader can act as a placeholder for information that is still loading, helping the user focus on progress instead of wait times.
This is what we’ll look at creating in this article. We will look at improving the loading animation of a dashboard from a simple loading spinner to a placeholder loading animation, and eventually, turn:
#The Loading Animation Explained
The animation is quite simple yet very effective. We want to animate a gradient from left to right. We also want to make sure the gradient goes over its container to disappear, before starting all over again.
When thinking about motion, we should usually aim for a duration somewhere between 300–500ms. Anything below this duration, animations become too fast to perceive; anything above can feel sluggish, making users feel they are waiting more than they actually are. It’s also important to note that the more complex and larger the animation, the slower it should be. Just like larger objects in the real world move at a slower pace.
In the gif above, the animation takes over 2 seconds to complete, making the application’s performance feel laggy. Therefore, we’ll go for a shorter duration. However, because of its large dimensions, we may still end up over 500ms.
We also want to make use of a nice easing to make the animation feel more natural. Nothing in the real world moves at a constant, linear pace. To fully understand how the animation will work, the best way is to explain it through another animation:
#Animating a gradient
Here we’re animating a gradient from left to right, starting from outside of the container. To break it down:
#Writing The CSS for the Loader
From the HTML side, we will only be working with a single placeholder element. Let it be:
The whole animation will go inside a ::before element. This is a pseudo-element that is often used to add cosmetics to the selected element. Think of pseudo-element as an added keyword to a selector that lets you style specific parts of it. But before taking care of it, let’s define some styles for the parent:
#Using a pseudo-element
Let’s analyze the code of this pseudo-element:
With everything in place, this will result in the following animation:
#Summary
When dealing with subtle animations, you can see that implementing them shouldn’t be much work. Yet the user experience they provide outweighs the time and effort that goes into them.
If you also change the fixed width of the gradient to a percentage, you’ll also be able to reuse the animation on different shapes and sizes. You only need to write it once, then use it as you like.
What are your favorite animations when it comes to loading? Let us know in the comments. Thank you for reading through, happy styling. 🎨
10 Best Practices for Quickly Improving Your CSS
Building scalable and manageable stylesheets
Want to get weekly updates to your mailbox? 📬
Subscribe to our newsletter! Unsubscribe anytime.
We don’t spam. You will only receive information relevant to you.
📚 Get access to exclusive content
Want to get access to exclusive content? Support webtips to get access to tips, checklists, cheatsheets, and much more. ☕
Get access
Courses
The Complete JavaScript Course 2021: From Zero to Expert!
The modern JavaScript course for everyone! Master JavaScript with projects, challenges and theory. Many courses in one!
Dive in and learn React.js from scratch! Learn Reactjs, Hooks, Redux, React Routing, Animations, Next.js and way more!
The Complete Web Developer in 2021: Zero to Mastery
Learn to code and become a Web Developer in 2021 with HTML, CSS, Javascript, React, Node.js, Machine Learning & more!
Recommended
10 Critical Performance Optimization Steps You Should Take
Improve user experience and conversion rates
How to Secure Your API With JSON Web Tokens
A simple way of adding authorization to your Express app
How to Lazy Load Images With Intersection Observer
And save network requests and bandwidth
Newsletter
Subscribe to our newsletter! Unsubscribe anytime.
We don’t spam. You will only receive information relevant to you.
Learn in-demand tech skills in half the time
Want to get access to exclusive content? Support webtips with the price of a coffee to get access to tips, checklists, cheatsheets, and much more. ☕
Get access
Subscribe to our newsletter! Unsubscribe anytime.
We don’t spam. You will only receive information relevant to you.
🐢 Каркасные экраны: реализация в React
furry.cat
Профессионалы в области UI/UX утверждают, что важно сохранять заинтересованность пользователей, пока они ожидают загрузки контента на страницу.
Традиционно для этого в вебе использовались спиннеры и лоадеры. Это хороший подход, ведь анимированная иконка четко говорит пользователю: про вас не забыли, процесс идет. Однако в современных условиях он уже несколько устарел. Человек понимает, что происходит, но смотреть на движущиеся точки довольно скучно. Каждый оборот спиннера добавляет раздражения.
На смену лоадерам пришли «каркасные» экраны (skeleton screens), которые не просто «тянут время», но и лучше обозначают прогресс загрузки, уменьшая негативные ощущения юзера (loading-time frustration). Другими словами, создают иллюзию того, что контент вот-вот появится.
Сегодня мы будем разбираться, как их делать в React-приложениях.
Разница между интерфейсом с лоадером и каркасным экраном
Глобального погружения в основы CSS, JS или React не будет, поэтому вы можете смело читать дальше, даже если не являетесь экспертом в этих технологиях.
Что такое каркасные экраны?
Каркасный, или скелетный, экран – разновидность интерфейса, которая не содержит реального контента. Такой UI повторяет «настоящую» разметку страницы, но вместо контентных единиц – текста, изображений, карточек, блоков – показывает «заглушки», схожие с ними по форме (обычно серые линии и прямоугольники, а также их группы). Когда контент загружается и занимает свое место в макете, заглушки исчезают. Этот переход выглядит не таким резким, как переход между чистой страницей и заполненной текстом.
Другими словами, это занятый плейсхолдерами вместо реальных данных «скелет» страницы.
Так как скелетный UI напоминает настоящий, пользователь видит структуру страницы даже без контента, и у него создается впечатление, будто загрузка идет быстрее – по крайней мере, что первый этап загрузки уже прошел.
Каркасные экраны отлично сочетаются с техникой ленивой загрузки: постепенное появление элементов выглядит более естественным, когда уже ожидает их.
Другие названия техники:
Этим подходом пользуются многие сайты, в том числе порталы крупных технологических компаний: Blockchain.com, YouTube, Facebook, Medium.
Интерфейс Blockchain.com с частично подгруженным контентом. Для представления графиков также используется скелетный плейсхолдер.
Каркасный экран на сайте medium
Главная страница сайта LinkedIn в 2018 до загрузки контента
Типы каркасных экранов
Каркасные экраны бывают разными. Самые популярные – это текстовые и графические (цветные) заполнители.
Текстовые используются чаще всего, так как они максимально просты в реализации. Разработчику не нужно знать особенности реального контента, чтобы заменить его заполнителем.
Графические каркасы сложнее – они зависят от контента, который замещают, и встречаются реже.
Готовые решения
Для быстрой реализации паттерна каркасных экранов в вашем приложении можно воспользоваться готовыми решениями. Для React они, конечно, тоже есть. Рассмотрим парочку для примера.
React Placeholder
Достоинства
Недостатки
Пример
Пример создания скелетного компонента с использованием react-placeholder:
Все плейсхолдеры можно настраивать через т.н. пропсы. Например, задать цвет и размер (количество рядов текста) для текстового блока.
Больше информации вы найдете в документации модуля.
React Loading Skeleton
Достоинства
Недостатки
Пример
Пример создания скелетного компонента с использованием react-loading-skeleton:
Здесь мы импортируем основной компонент Skeleton и компонент темы SkeletonTheme из модуля.
Рассмотрим этот модуль подробнее: разработаем с его помощью скелетный экран YouTube.
Каркасные экраны в стиле YouTube
Установка React
Самый простой способ установить и настроить React в новом приложении – использовать утилиту Create React App. При этом вам почти ничего не придется делать – только набрать команду в терминале. Сначала установите модуль глобально, если вы этого еще не сделали:
Затем создайте новый проект skeleton-screens :
Когда установка завершится, перейдите в папку проекта и запустите локальный сервер:
Вы увидите приветственный экран React:
Создание интерфейса
Вместо реальных данных с YouTube мы будем использовать заранее подготовленный массив, чтобы не усложнять руководство дополнительной логикой.
Создайте файл data.js в папке src и скопируйте туда следующий код:
В этом фрагменте описаны два блока страницы – «Рекомендованное» и «Последние новости» – каждый из которых содержит несколько видео-превью.
Теперь используем эти данные для верстки интерфейса. Нам потребуется три компонента:
Создадим папку components внутри src – в ней будем размещать файлы компонентов.
Создайте файл Card.js в папке components :
Простой функциональный React-компонент, который выводит данные в шаблон.
CardList
Этот компонент сложнее, так как он имеет собственное состояние.
Пока в шаблоне не используется переменная loading, скоро мы к ней вернемся.
Стилизация
До сих пор мы только расставляли классы в верстке, но не добавляли реальные стили для них. Пора облагородить внешний вид приложения. Откройте файл App.css в папке src и замените код на следующий:
Теперь можно посмотреть как выглядит интерфейс, пока без каркасных экранов. Пару секунд, когда страница загружается, мы видим белый экран, а затем все данные появляются сразу.
Интерфейс клона YouTube без каркасных экранов
Подключение React Loading Skeleton
В React Loading Skeleton вам не нужно пошагово создавать скелетный экран, тщательно подбирая параметры типографики, отступы и прочие стили под ваш контент. Его можно поместить прямо внутрь вашего компонента вместо загружаемого контента.
У этой библиотеки есть пара полезных плюшек: легкая темизация и указание продолжительности цикла анимации.
Простая настройка темы для каркасных экранов
Продолжительность
Больше информации о настройках компонента вы можете найти в документации.
Установка пакета
Чтобы подключить библиотеку react-loading-skeleton в проект, запустите следующую команду:
Создание компонента
Теперь можно добавить каркасные экраны для видео-данных. В папке components создайте новый компонент SkeletonCard.js :
Итак, для каждого фейкового видео у нас уже есть каркас, состоящий из нескольких блоков. Пропсы height и width отвечают за размеры блока, а circle=
По умолчанию для компонента React Loading Skeleton подключена симпатичная пульсирующая анимация. При желании вы можете создать свою анимацию, мы же воспользуемся дефолтной.
Осталось только подключить каркасный экран в приложение и отображать его, пока происходит подгрузка данных. Внесите изменения в код компонента App :
Весь исходный код вы можете найти в репозитории проекта.
Наше приложение полностью готово. При открытии отображается красивый каркасный экран с пульсирующей анимацией, а в это время за кадром подгружаются данные. Как только мы их получим (на демо-примере стоит задержка в 5 секунд), то сразу выведем на страницу.
Вот так выглядит результат:
Заключение
Каркасные или скелетные экраны значительно улучшают пользовательский опыт. Они избавляют посетителей сайта от растерянности и непонимания происходящего, а также создают впечатление, будто контент уже на подходе и вот-вот его покажут.
Для создания подобного интерфейса можно использовать готовые библиотеки или реализовать его самостоятельно с помощью простых геометрических фигур и капли анимации.
Angular: Показываем скелетон страницы за три шага
Привет, меня зовут Олег. Я работаю в команде Тинькофф Бизнеса. В моей работе часто происходит ситуация, когда странице нужны данные с сервера. Пока мы запрашиваем эти данные, на странице надо что-нибудь показать.
Но тут возникает проблема: в таком случае нам придется свой чистенький и красивый компонент превращать в страшненького квазисолидного уродца с примешанной логикой для индикации загрузки. Если вы сталкивались с подобными ситуациями, эта статья поможет вам все исправить за три простых шага.
Типичный случай выглядит примерно так:
Лишние свойства у класса — для отслеживания статуса загрузки.
Подписочки-отписочки, от которых хотелось бы отказаться.
Чрезмерно усложнившийся шаблон с дополнительным локальным шаблоном и условием для индикации статуса загрузки.
Вдобавок этот обслуживающий код будет копироваться от компонента к компоненту. Уф-ф-ф, этот код явно с проблемами! Мы-то хотели просто улучшить видимую производительность, показав скелетон страницы пользователю, пока загружаются данные…
Может, получится отделить логику показа скелетона от самой страницы, поместить ее в отдельный компонент и переиспользовать? Давайте разберемся, как это можно исправить, сделав один дополнительный компонент, который будет показывать скелетон будущей страницы!
Шаг первый: определяемся, когда мы хотим показывать скелетон
Кроме проблем, описанных ранее, есть еще одна: если оставить все как есть, мы не сможем использовать гарды и резолверы, поскольку они отрабатывают до того, как компонент создается. Это значит, что мы не сможем показать скелетон, находящийся внутри страницы. К счастью, фреймворк предоставляет нам события о том, на каком этапе навигации мы сейчас находимся, и мы можем использовать это!
После некоторых размышлений я, кажется, пришел к единственному правильному выводу: показываем скелетон страницы с момента начала проверки на доступ к странице до момента завершения текущей навигации или ее отмены или ошибки в процессе навигации.
Для воплощения этого замысла нам поможет документация, где описан порядок, в котором происходят события роутера. Запишем в конструкторе компонента:
Шаг второй: получаем скелетон, соответствующий странице
Часто случается так, что у нескольких страниц одинаковое строение и, соответственно, одинаковые скелетоны. Поэтому наиболее удачным решением будет выделить скелетон страницы в отдельный компонент и переиспользовать его по необходимости. А о том, как его передавать и получать, я сейчас расскажу!
Как же нам получить скелетон, соответствующий странице, на которую происходит навигация? Очень просто. Мы положим скелетон рядом с самой страницей в конфигурации роута, вот так:
Положили, но как его достать при навигации? С этим нам опять поможет событие роутера, которое содержит информацию о странице, на которую переходит пользователь.
На первый взгляд кажется, что снимок будущего состояния роутера не содержит информации об активированной странице. Но, присмотревшись получше, можно получить нужные данные. Свойство .firstChild указывает не на первый роут в массиве роутов, а на первый активированный из них, то есть тот, на который мы переходим. Запишем в конструкторе компонента:
Шаг третий: катим в прод
Осталось только сложить первые два шага — и практически все готово. Вот код, который получился у меня, допишем его в конструктор компонента:
И добавим вот такой код в шаблон компонента:
Шаг назад: шаг, который существует вопреки
Было бы еще круче, если бы все сразу работало так, как хочется. Я столкнулся с тем, что некоторые наши роуты находятся в отдельных, ленивых модулях, которые загружаются по необходимости. Поэтому и скелетоны, связанные с этими роутами декларируются в этих модулях (инжекторах ленивых модулей), а это значит, что эти компоненты невозможно создать в корневом модуле (корневом инжекторе). Если декларировать их в корневом модуле, это будет увеличивать размер основного бандла. Это не есть хорошо.
Чтобы решить эту проблему, нам надо добраться до инжектора ленивого модуля, для этого придется залезть под капот фреймворка, посмотреть, как создаются ленивые модули и куда записывается информация об этом. К счастью, это место не менялось с 2017 года. Мы можем воспользоваться этой информаций и слегка изменить код под эти требования:
И подправим шаблон:
Я понимаю, что это решение выглядит не очень, но другого выхода я не нашел. Если есть идеи, как это сделать не залезая под капот фреймворка, не стесняйтесь — пишите комментарий!
Вывод
Теперь у нас есть чистая страница пользователя, которая содержит код только для отображения страницы пользователя, в ней нет обслуживающего кода для индикации загрузки пользователя с сервера и у которой единственная ответственность это отображать страницу пользователя. И есть отдельный, чистый скелетон этой страницы с минимальным количеством зависимостей, единственная ответственность которого — отображаться, пока загружаются данные, нужные для страницы.
Весь представленный код я собрал и выложил в небольшую библиотечку: вот тут ее можно поддержать на GitHub, а вот тут скачать из npm. Она весит ≈1,5 кб, так что можете смело добавлять в свой проект.
Skeleton Screens in Plain JavaScript
Creating a better User Experience even while your user awaits!
Loading data now days is done in browser or application itself, rather than the server.This mitigates the need of waiting for ages for the data to finally come back and load in user’s application. Despite of it however, fetching data from the browser also takes time as it is an asynchronous task, thus we some some sort of loading screen to assure the user about it.
Skeleton Screens has been around for some time lately and it is for a good reason. Having just a simple blob or a square animating with a text saying “Loading” is very boring to look at which makes users not to stay on your application for a long time. Skeleton Screens however are able to hold off the users for a longer time as they give indication of the layout in which the content will appear. This has been proven to be a better experience than using a traditional loading spinners, loaders or animated text.
Here are some examples of skeleton screen used in many web apps like Facebook, YouTube, Discord, etc.
We will also be building an application in HTML, CSS and JavaScript where we will be send an API (GitHub API) to the server, get a response back and display the content once we receive it. In doing so, while we wait for the data to load, we will display an animated skeleton screen to indicate the eventual layout in which data will be placed. This serves three purposes:
Before getting started. lets look at the final product that we will be building
Things we will be covering:
a) Creating Animated Skeleton Screen
b Displaying User Profile without reloading the page
c) Error Handling when a user is not found.
Start by creating an empty folder and opening it in VS Code. We will need three files, the HTML file for creating out layout of the page, CSS file to design the page and JavaScript file for sending request and receiving responses to then load content in our screen.
I have named these files index.html, index.css and index.js (You can name then as you want).
THE HTML
The HTML contains only the layout aspects of our application. The body of the HTML consists of a form element with a input text and a button. The another child of body element is a container that contains a division with a class of profile container containing multiple children.
2. Second child is the h2 tag to have user’s name to be embedded later
3. A profile info division that contains 3 paragraphs tad that houses a span tag which will later be embedded with follower, repository and following count.
4. Finally, an overlay division is created to be viewed if the entered username does not exist in GitHub database.
The only interesting thing in this HTML is every section that need to be updated with content, has a class of loading into it. This loading class is styled in CSS in such a way that it describes only the basic layout of the content in the card.
THE CSS
The code in CSS of the app is quite long, hence I would suggest you to come up with your own design to implement here.
We will only see the styles applied in Loading class as it is the one responsible for the skeleton effect.
The loading class here is given a background of a linear gradient along along with certain width and height. Also, the linear gradient is then animated.
Moreover, if we also need to assign certain width for certain elements in the page.
These styles are just for providing a certain width and height to the classes in HTML so that the skeleton screen looks appealing (Better UI).
THE JAVASCRIPT
The JavaScript of this project is very simple! Here is a graph showing the progression of the application
We see that the app’s initial state is a waiting state, where users needs to input a username. When a username is entered, then the app requests the server the data it needs to receive, and then displays it to screen. The time between requesting to the server and getting response back is fulfilled by the skeleton screen.
Thus, we first need to select all contents that need to be set on skeleton form. They being the wrapper division for user avatar, the username division, the span tag where we display followers, repositories and following of a certain user and finally the overlay that is shown if the entered user doesn’t exist.
We also need to select the form as we need to add the submit event listener to it so that we submit the username to server.
The next thing that we need to perform is to have an event listener to the form when we submit it.
We first need to get the username from the input field, store it in a variable, set the value inside the input field to null and have the cursor to focus on it.
Moreover, once the submit button is pressed, we need to fetch data from API. Thus, a function apiCall is called which accepts the username of user as argument.
We see that the function apiCall is not created. Lets see what we need to do in this function. The main objective of this function is to request data from the API. Hence, we make use of fetch() method in apiCall function.
First, if the Promise returned by the fetch method is fulfilled, then we receive a response which needs converted into JavaScript object before we use it in the application. Here you may think of using JSON.parse() to parse the incoming response, but that is very not true.
See, JSON.parse() is synchronous in nature, hence it runs on same thread as our main program. The response that we receive however is a Promise, thus it is asynchronous in nature. If we convert the response onto JavaScript object using JSON.parse(), we will not be getting any data as the fetching of data is done in separate thread, where the response is received as a callback. Hence, JSON.parse() cannot be used.
If we see submit any name from the form, and check in the browser, we can see that we receive the information in JavaScript object format of the user name that has been typed.
But, we still do not see what we intended to. We have to be able to update our container to display the required data and also have a running skeleton screen.
First lets work on displaying data on the screen once we fetch it. We will require a function to render data once we receive it. We will call this function once we receive the data.