Study in Poland
Study in Poland
Content Placeholders: A Way to Style Waiting Time
Content Placeholders ?
A while ago, the great and (not always) glorious Facebook introduced content placeholders that appear to users while the page content is still being loaded, yielding a fantastic user experience. It's not always possible to load content as fast as we would want to, but at least, we can make the wait time more pleasant with this solution. There are already some interesting resources about this question :
A Cloud Cannon article that deconstructs the facebook placeholder process and comes up with a CSS only solution.
A vanilla js library named Placeloadjs that does the trick for you. You can create shapes (with some limitations though) that will behave like the placeholders seen on Facebook.
Then, some parts of the gradient box are masked by adding a bunch of little divs that give this impression of a fake schematic layout. Look at the image below, the original author included borders so you can see all the divs that are involved in the process :
HTML:
<div class="container">
<div class="placeload">
<div class="header">
<div class="img loads"></div>
<div class="header-content">
<div class="content-shape loads"></div>
<div class="content-shape loads"></div>
</div>
</div>
<div class="image-placeholder loads"></div>
<div class="placeholder-footer">
<div class="footer-block">
<div class="content-shape loads"></div>
<div class="content-shape loads"></div>
</div>
</div>
</div>
</div>
CSS:
$background: #f6f7f8;
$grey-nuance-lighter: #eeeeee;
$grey-nuance-darker: #dddddd;
$fade-grey: #e8e8e8;
body {
box-sizing: border-box;
width: 100%;
height: 100%;
background: $fade-grey;
position: relative;
overflow: hidden;
}
.container {
width: 800px;
margin: 0 auto;
min-height: 100vh;
position: relative;
.placeload {
background: #fff;
max-width: 500px;
margin: 0 auto;
width: 100%;
padding: 20px;
border: 1px solid $fade-grey;
border-radius: 3px;
position: relative;
margin-top: 30%;
transform: translateY(-50%);
.header {
display: flex;
justify-content: flex-start;
align-items: center;
.img {
width: 50px;
min-width: 50px;
height: 50px;
border-radius: 50%;
}
.header-content {
margin-left: 20px;
width: 100%;
.content-shape {
height: 8px;
margin-bottom: 8px;
&:first-child {
width: 80%;
}
&:nth-child(2) {
width: 60%;
}
}
}
}
.image-placeholder {
width: 100%;
margin-top: 20px;
height: 250px;
}
.placeholder-footer {
position: relative;
margin-top: 20px;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.footer-block {
width: 100%;
height: 100%;
min-height: 20px;
.content-shape {
height: 8px;
margin-bottom: 8px;
&:first-child {
width: 32%;
}
&:nth-child(2) {
width: 24%;
}
}
}
}
}
}
.loads {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-name: placeload;
animation-name: placeload;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
background: $background;
background: $grey-nuance-lighter;
background: -webkit-gradient(
linear,
left top,
right top,
color-stop(8%, $grey-nuance-lighter),
color-stop(18%, $grey-nuance-darker),
color-stop(33%, $grey-nuance-lighter)
);
background: -webkit-linear-gradient(
left,
#eeeeee 8%,
#dddddd 18%,
#eeeeee 33%
);
background: linear-gradient(to right, $grey-nuance-lighter 8%, $grey-nuance-darker 18%, $grey-nuance-lighter 33%);
-webkit-background-size: 800px 104px;
background-size: 1200px 104px;
position: relative;
}
@-webkit-keyframes placeload{
0% {
background-position: -468px 0;
}
100% {
background-position: 468px 0;
}
}
@keyframes placeload {
0% {
background-position: -468px 0;
}
100% {
background-position: 468px 0;
}
}
Example:
By now, you've probably seen some examples of skeleton screens in your daily browsing without even noticing. For example - Facebook shows users gray circles and lines to represent the contents of a post in their timeline.
First, let's create the base structure. In this example, the placeholder is supposed to represent a text area. We'll use BEM (Base - Element - Modifier) naming for our classes.
<div class="text-input__loading">
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
<div class="text-input__loading--line"></div>
</div>
Each line should be about the same height as our text. We can use CSS animation to create a pulsating effect.
&--line {
height: 10px;
margin: 10px;
animation: pulse 1s infinite ease-in-out;
}
Next, let's define how our pulse animation should work. We can modify the opacity of the background color using rgba to provide an opacity between 0.0 and 1.0.
@keyframes pulse {
0% {
background-color: rgba(165, 165, 165, 0.1);
}
50% {
background-color: rgba(165, 165, 165, 0.3);
}
100% {
background-color: rgba(165, 165, 165, 0.1);
}
}
We also want to vary the width of each loading line. Let's create a Sass mixin to apply the given content to each nth-child in a list.
@mixin nth-children($points...) {
@each $point in $points {
&:nth-child(#{$point}) {
@content;
}
}
}
e can use the newly created mixin to change the width of all 10 children div elements.
@include nth-children(1, 5, 9) {
width: 150px;
}
@include nth-children(2, 6, 10) {
width: 250px;
}
@include nth-children(3, 7) {
width: 50px;
}
@include nth-children(4, 8) {
width: 100px;
}
Final Result:
Write Your Reviews