Conf42 JavaScript 2023 - Online

Skeleton Mammoth - or how I've been solving the problem of reusable Skeleton Loaders

Video size:

Abstract

After investigating the topic of skeleton loaders in details, I’ve decided to create by myself a very simple, flexible, reusable, customizable solution. In this speech, I will describe the process and approach of creating this solution and turning it into a library, as well as the difficulties.

Summary

  • Alexander Tskochenka is the creator of the skeleton Mammoth open source CSS library. He will talk about how he solved the problem of reusable skeleton loaders.
  • A skeleton loader is a user interface design pattern used to enhance the user experience during content loading in web and mobile applications. There are several alternatives to using skeletons, looking ahead and answering whether they are really alternatives.
  • Skeletons must be versatile and reusable. They must be lightweight and free from third party dependencies. Since every project and every case can be very different, my skeleton needed to be able to be configurable. For demo purposes I will use react and take some base card markup.
  • Using an attribute selection, we match elements that have an explicitly specified attribute and its values. This allow us to apply different style depending on the given attribute values. Most of the animation settings could be overridden with the same approach. Advanced usage each project and case is unique.
  • I have created a library called skeleton mammoth. It starts a GitHub repository. You can introduce new users to the library by sharing information about its unending platform. I warmly welcome new contributors and any suggestions for improvement.

Transcript

This transcript was autogenerated. To make changes, submit a PR.
You. Hi all, I am glad to welcome everyone to this wonderful meeting. In today's talk, I will tell you about how I have solve the problem of reusable skeleton loaders and turn it into my own open source CSS library, skeleton mammoth before starting my speech, I want to introduce myself with a couple of facts. My name is Alexander Tskochenka. I have about five years of experience in it sphere in total, author of technical and scientific articles, hackathons, referring conferences, speaker and of course creator of the skeleton Mammoth open source CSS library. So let's get started. There are a lot of great articles on the Internet devoted to skeleton loaders covering their types, cases and needs for their use. After investigating this topic in detail, I came to the conclusion that each example already made solution is unique and good on its own way, but in most cases they are suitable for a specific scenario rather than for universal use. For many scenarios, these prompted me to create my own reusable and customizable solutions that would suit most use cases and what are skeleton loaders? A skeleton loader, also known as a skeleton screen or content placeholder, is a user interface design pattern used to enhance the user experience during content loading in web and mobile applications. When data is being fetched or processed in the background, instead of displaying a blank connective screen, a skeleton loader mimics page layout by providing users with a visual cue of what to expect, reducing perceived loading times and mitigation. Potential frustration many well known large websites use curtain loaders and here are some examples. These are examples of skeletons used on YouTube on the left side and LinkedIn on the right side. But why do we have to use skeleton loaders at all? Good question. In an attempt to answer this question briefly, I have outlined several main reasons for using skeleton loaders. But if you investigate this question separately, you can get a lot more information for yourself. And the first one is improve user experience. Skeleton loaders enhance the user experience by providing visual feedback and reducing the perception of content. Loading delays another one is reduced bounce rate. Yes, skeleton loaders can prevent users from leaving the page due to the loading delays. Another one is smooth transitions. They create smoother transition between different sites of a page or application and one more it's focus attention, unlike other alternative skeleton loaders attract the user attention to progress rather than waiting time. And here's the problems of mostly existing skeletons. Taking into account that there are a lot of examples of creating your own skeleton loaders or libraries that did it for you, there are still number of concerns with them. And here's its list limited customization many exited in skeletons have limited customization options. It leads to a mismatch of the actual content design and skeleton style. Another one is empowerment user support. Although their purpose is to provide a visual representation, most of them are not adapted to users with visual impairments or those who use screen readers. Another one is versatility and visibility. Most approaches to creating skeletons offer either creating a shallow copy of a component's placeholders, resulting in many and many similar copies, or essentially changing the structure of existing components. Both of the approaches require a lot of additional code and assets. One more maintenance complexity. As a website evolve and content changes, keeping skeleton loaders up to date can become a maintenance burden and another one bind to a specific framework library. Often, ready made solutions are either only stacked for certain frameworks such as react js or Vue js, or they are parts of a larger library. So, for example, if you only want to use skeleton from a popular libraries like MUI, you still need to install its core files or component of that library to use only one skeleton from there. Alternatives there are several alternatives to using skeletons, looking ahead and answering whether they are really alternatives. My answer is no, rather than yes. If we talk about correct usage, then the skeleton is one of the best solutions. But still, let's consider a couple of alternatives along with their pros and cons. And first of them is spinner. Spinner is a common alternative to skeleton loaders. They consist of animated icons that rotate continuously, providing a visual cue that the content is loading. You can see it on the slide. To the pros of spinners I can say its simplicity simple implementations that often requires only a few lines of code or using predesigned libraries. And of course it's a universal understanding. Spinners are widely recognized across different platforms and applications, ensuring that users understand that content is loading. To the columns of spinner I could attribute limited information. Spinners do not provide any context about the content is being loaders overlap the entire page almost of it, not individual elements. It gives the feeling of loading not individual elements of the page, but the entire site as a whole. So spinners are integral part of interfaces, but they are not exactly suitable for replacing skeletons. Another one is a progress bar. A progress bar is a visual element that indicates the completion status of a task or process. It provides a linear representation, typically with a field portion that grows gradually. The process of progress bar I could attribute precise feedback that provides accurate and precise feedback on the completion status of a task. Its time estimation progress bar can give user estimate of remaining time required for completion and its multipurpose progress bar can be used in various contexts and scenarios, making them a versatile component in web and application development. But for the cons of the spin progress bars, I could say it's lack of context. In some cases, progress bars might not provide sufficient context about the actual task approaches they represent and implementation complexity. Creating progress bar with accurate representation and smooth animations can be complex, especially when dealing with varying tasks, durations and responsiveness. Process bar are more suitable for scenarios showing the progress of a file, upload or quantity of progress. They are often used at the top of the pages to show the progress of an entire page loading. However, they cannot serve as an equivalent replacement for the skeleton because they are intended for other purposes and another one is absence of any visual yeah, not having any loaders or placeholders is also an alternative, and in some cases this will be a better solution than using unsuitable elements, the main and probably the only process that you don't need additional time and resources spent on implementations. But here come the obvious cons, a less attractive design for your site, and the perception of slower loading time. Creating versatile and reusable skeleton after I had gained enough knowledge of what skeletons are, when to use them and approaches to their development, I tried to determine for myself what my final result should be. These are the key requirements that I wanted to have present and my final result. So first, it's versatile and reusable. There are a lot of examples over the Internet with overcomplicated approaches where you have to create a separate skeleton for every component you want to have them on. In my cases, I want it to be something singular that can be reused for most cases and not stick to any JavaScript framework like react of you. The second one is configuration flexibility. Since every project and every case can be very different, my skeleton needed to be able to be configurable. Another one is future reach. Yeah, it's just a simple skeleton, but in addition to the standard set of features, I wanted to fill it with support for additional useful and necessary features. And last but not least, lightweight and dependencies free, lightweight and as free as possible from other third party dependencies. All of these expectations and investigations led me to the fact that my future skeleton had to be written in pure CSS without any JavaScript and third party dependencies. This makes it possible to be lightweight and dependencies free. The main idea that it inherits layouts of components it applied to and customize them with their own styles over time for development purposes, I have rewritten CSS syntax to SCSS. This made it possible to decompose the code for smaller logical parts, make it more concise and reusable, but the end result to the end compiled result is still pure CSS without any dependencies. Base card as a basic example and for demo purposes I will use react and take some base card markup to show how it works, but I remind you that it's not tied to any of the frameworks. Here is a card markup example that has its own styles and doesn't know about the existence of skeletons yet. It's just an ordinary card with an image and two text fields. You can see it's a parent class card in the parent div and some child divs with the card image wrapper and card body with title and subtitle. In order for the skeleton to become active, it's only necessary to apply the parent class SM loading to the card itself and the child classes smitem primary or smitem secondary to those elements on which we want to see the skeleton so the updated result will look like this. Let me break it down and explain in a few moments. On the first line of code, I apply a same loading class depending on the condition. If the status of the datastate datastat is equal to loading, then the class will be applied. Otherwise, no, the same loading class should only be set or present while your data is loading. It's kind of a feature to turn on or turn off the skeleton. So only when at present, child elements with the presence of appropriate classes smitem primary and the same item secondary will display the skeleton. Lines two, seven and eight of the code contain classes to show the skeleton on these elements. So only three classes will make this skeleton to work. Root variables colors let's take a little look under the hood and if you can clearly see what's shown on this slide, that's okay. The main idea is to show how everything works for usability as well as an advanced usage of the skeleton, which I will discuss later. The main style values are variables paste in the CSS root pseudoclass. This particular slide shows that every color value is placed inside the variable inside the CSS root pseudoclass. You can see it here. The same for animations. All values for animation management are in variables placed inside the root CSS pseudoclass. It's like duration, time and function, et cetera. Base styles this slide depict the base style that don't relate to any color scheme or configuration. The main idea in my approach is that the solution should be reusable and does not have to be customized separately for each component. As stated earlier, parent class sm loading is used to activate the skeleton loader style. You can see it here. The semitetem primary and smitem secondary classes override an element style and display the skeleton. In this way. The layout styles and dimensions of elements in our case it's base card component, are persisted and inherited by the skeleton loaders. So you don't need to specify width or height of the skeleton. It's inherited by the base components. In our case it's base card. Additionally, I would like to say that with this approach we guarantee that all child elements of the smitem primary class or smitem secondary are hidden and at least have a non creating space character. You can see it here. So if we have, let's say some empty div that doesn't have a content, but we have applied the smitem primary or secondary class, it will be shown in any way and rendered. If an element contains no content at all, the symbol ensures that the element is displayed and rendered. There is also a part that is responsible for users of screen readers and let them know that the content is in the process of loading. You can see it in the middle of the slide. The main idea of these basic styles is to hide all unnecessary visual elements such as borders, placeholders, et cetera, so you can apply your own skeleton styles structure here is a visual representation of what the base card components looks like. You can see like say our imaginary website and our base card component. The card has a class same loading to turn on the skeleton. So this card itself has class card and SM loading class. The elements on which the skeleton is displayed have corresponding classes, smitem primary and SM item secondary. Here you can see this image of the card with Smitem primary class and two fields with smitem secondary like title and subtitle advanced features in addition to the main functionality, it's good to have additional features to satisfy as many users needs as possible and cover as many use cases as possible. And first feature is color scheme with the CSS media feature prefers color scheme I have implemented automatic support of the light and dark themes. Depending on the user settings, it will be applied automatically. Of course it's possible to set it manually. I'll talk about it later in the documentation. In the presentation. Another one is reduced motion by default. In the skeleton I decided to make animation enabled, but there are cases when developers or users would prefer not to have it, and if for the former this may be dictated by design and requirements, then for the latter, it may be due to the vestibular motion disorders. For this, the CSS media feature prefers reduced motion comes to the rescue. Whenever a user had these settings enabled, let's say on their laptop. On any other device, the animation will be disabled and configuration. At this stage the main styles are over and the skeleton can be considered ready. But I was haunted by the thought that I should be able to configure all of the above. What if I want to turn off the animation? What if I want to always have a dark theme? Since it's not possible for CSS to receive any values as arguments like JavaScript functions do, the addition of JavaScript was excluded, at least at this stage, because it will completely break the main concept of being as simple as possible. But still, we can implement something similar to arguments if you know their values in advance. And here that data attributes came to error eight. With their help, we can check for the presence of the value we need in the attribute and apply the desired style. That's simple. For example, if you want to explicitly set the animation theme and the varsity settings, you need to make a JSON object as shown on the top code snippet. You can see it here. It's still our base card with some variable config that's wrapped in the JSON stringify method, and we set predefined fields like animation type, theme, and opacity. Next, pipe this object to the custom attribute data SM config on the same layer as the SM loading class shown on the lower code snippet. And that's all. Here's what it looks like in the compiled CSS when a user sets only a theme configuration. Thus, using an attribute selection, we match elements that have an explicitly specified attribute and its values. This allow us to apply different style depending on the given attribute values. Advanced usage each project and case is unique, and it's impossible to predict and make everything versatile. Yeah, especially when it comes to colors. That is why, as I said earlier, most of the values are placed in variables in CSS root pseudoclass. If you want to adjust the default styles, just overwrite appropriate variables in your own CSS file inside the root CSS pseudoclass. So, for example, if you want to change the color of the primary item with the class smitem primary, you only need to override the corresponding variable, and that's all the same for animations. Most of the animation settings, like their duration, time functions, et cetera, could be overridden with the same approach. In this way, it gives us the full freedom of action in terms of customization, of course. To make the work easier and clearer, I made a well described documentation section that contains all the variables available for overriding and usage examples and moving from theory to practice. Let's take a look at a demo using a tinched result and its capabilities. Here's what a working skeleton for card components looks like. The quality of the picture may not be very good since this is a GIF animation converted from a video file, but anyway, once the data has loaded, the skeleton disappears and you display the loaded content to the user. At the same time, you can develop transitions between the skeleton and the content yourself for a smooth flow. As you can see on this slide how it smoothly transitioned. This slide showed support for the dark color scheme, which, as I said, is either turned on automatically in the absence of explicitly specified settings, or is set up using a configuration object. For the demo purposes, it's using configuration object and sets up manually so I can switch the skeleton theme and website theme to the dark and light themes animations out of the box there's support for different animations as well as the ability to turn it off so you can see on the slide different types of animations. We can turn it off by pressing none. We can set wave animations from left to right, wave reverse from right to left, and pulse animation. It's like blinking and opacity. This slide showed the ability to set the opacity of the skeleton. This is done because standard colors may not always suit your design, but in order to adjude them to your design, you just need to play with the opacity property without having to completely override the colors. So let's wrap it up. After I had studied the topic of skeleton loaders for a long time, their varieties, usage and approaches to development, I managed to collect the sense of useful information and turn it into a final product. Having collected best practices, improved them and combined them into a single entity. I have created a library called skeleton mammoth. I believe that I managed to achieve my goals and create a pretty good library with all of the advantages described in this presentation. I hope that this library is able to benefit people when using it, or provide new knowledge and experience as a starting point to create something of their own. If you find my speech useful and would like to show your support, there's a simple way to do so. And first of them, it starts a GitHub repository. This helps to increase its visibility and lets others know that the library has a strong user base and of course spreads the world. You can introduce new users to the library by sharing information about its unending platform, such as writing about in a blog post, mentioning social media, or discuss in relevant developer communities. It's very crucial for me to receive feedback on my library and I warmly welcome new contributors and any suggestions for improvement. Thank you for your attention. By scanning this QR code, you will find useful links such as my LinkedIn, Instagram, a link to the library itself, and slide and presentation text. Wish you all the best.
...

Aleksandr Tkachenko

Senior Software Engineer @ Playtech

Aleksandr Tkachenko's LinkedIn account Aleksandr Tkachenko's twitter account



Awesome tech events for

Priority access to all content

Video hallway track

Community chat

Exclusive promotions and giveaways