├── assets
└── logo.png
├── fixtures
└── example.png
├── .gitignore
├── LICENSE
├── index-without-skeleton-screens.html
├── index.html
└── README.md
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dimitrinicolas/skeleton-screens-concept/HEAD/assets/logo.png
--------------------------------------------------------------------------------
/fixtures/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dimitrinicolas/skeleton-screens-concept/HEAD/fixtures/example.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log*
4 | npm-debug.log*
5 |
6 | # Coverage directory
7 | coverage
8 |
9 | # nyc test coverage
10 | .nyc_output
11 |
12 | # TS Dist directory
13 | dist
14 |
15 | # Dependency directories
16 | node_modules/
17 |
18 | # npm cache directory
19 | .npm
20 |
21 | # Eslint cache
22 | .eslintcache
23 |
24 | # Temporary files
25 | tmp
26 |
27 | # Mac files
28 | .DS_Store
29 |
30 | # SSL Certificate
31 | cert.pem
32 | key.pem
33 |
34 | # ORM config
35 | ormconfig.json
36 |
37 | # Next build
38 | .next
39 | out/
40 |
41 | # Environnement variables
42 | .env
43 | .env.development
44 | .env.staging
45 | .env.production
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Dimitri Nicolas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/index-without-skeleton-screens.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
125 |
126 |
127 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Skeleton Screens Concept
2 |
3 | [](https://dimitrinicolas.github.io/skeleton-screens-concept)
4 |
5 | I present to you a concept of implementation of Skeleton Screens in web Single Page
6 | Applications. Before thinking about using this concept in your project, make
7 | sure to read the [Known issues](#known-issues) section.
8 |
9 | The main benefit is to provide a great user experience on first page load and to
10 | decrease the First Contentful Paint time that has a role to play in Google's
11 | website evaluation, you can learn more in [Benefits](#benefits) section
12 |
13 | ## [Example](https://dimitrinicolas.github.io/skeleton-screens-concept)
14 |
15 | An example is available at the following address:
16 | [dimitrinicolas.github.io/skeleton-screens-concept](https://dimitrinicolas.github.io/skeleton-screens-concept).
17 |
18 | I made sure that the style sheet weighs at least 300 kb for the example by
19 | adding random strings inside. You can use your browser developer tools to
20 | simulate a slow internet connection.
21 |
22 | The source code is available in this repository: [index.html](index.html).
23 |
24 | ## Concept
25 |
26 | First, we load the application style sheet as a non-blocking resource using the
27 | following pattern in the HTML `head` element:
28 |
29 | ```html
30 |
31 | ```
32 |
33 | And add the stylesheet at the end of your `body` element:
34 |
35 | ```html
36 |
37 | ```
38 |
39 | Then, we add some CSS inside a `style` tag just before the non-blocking style
40 | sheet loading:
41 |
42 | ```html
43 |
44 |
45 |
46 |
68 |
69 |
70 |
71 |
72 | ```
73 |
74 | Then, we need to crush some pre-loading style by adding `display: block` to
75 | `.header__content` and `.footer` in our `style.css` file.
76 |
77 | ### Animations
78 |
79 | We could add skeleton blocks and highlighting animations in our pre-loading
80 | style using `before` and `after` pseudo-elements and CSS animations.
81 |
82 | To create a fake logo block inside the header, we can add the following style:
83 |
84 | ```css
85 | .header__wrap::before {
86 | content: "";
87 |
88 | position: absolute;
89 | top: 16px;
90 | left: 0;
91 | bottom: 16px;
92 |
93 | width: 100px;
94 |
95 | background-color: #efefef;
96 | }
97 | ```
98 |
99 | Then we can add an highlight sweeping animation using like that:
100 |
101 | ```css
102 | .header__wrap::before {
103 | /* Block style */
104 |
105 | background-image:
106 | linear-gradient(to right, transparent, rgba(255, 255, 255, 0.6) 50%, transparent 100%);
107 |
108 | background-repeat: no-repeat;
109 | background-size: 80px 100%;
110 | background-position: -80px 0;
111 |
112 | animation: sweep 1000ms ease-in-out 0s infinite;
113 | }
114 |
115 | @keyframes sweep {
116 | to {
117 | background-position: calc(100% + 80px) 0;
118 | }
119 | }
120 | ```
121 |
122 | ## Known issues
123 |
124 | When loading the application style as a non-blocking resource, any element with
125 | a `transition` CSS property will get triggered on style sheet load if its
126 | animated properties values are different from the default or from the
127 | pre-loader style.
128 |
129 | To prevent this problem to trigger transition on every property of the element,
130 | we can target the properties to animate using the `transition-duration` and
131 | `transition-property` CSS properties. You can learn more about theses on Mozilla
132 | Web documentation:
133 | [developer.mozilla.org/fr/docs/Web/CSS/transition-property](https://developer.mozilla.org/fr/docs/Web/CSS/transition-property).
134 |
135 | To totally prevent this issue we'll need to add a specific class name to the
136 | `html` tag like `.js-can-use-transitions` on style loading after a small time
137 | and use the `transition` property in our style only when this class name has
138 | been added:
139 |
140 | At the end of the `body` element:
141 |
142 | ```html
143 |
148 | ```
149 |
150 | In `style.css`:
151 |
152 | ```css
153 | .js-can-use-transitions .header {
154 | transition: background-color 300ms;
155 | }
156 | ```
157 |
158 | This solution is not ideal, the user will need to have JavaScript enabled to
159 | have CSS transitions and the time to wait before adding the class name to the
160 | `html` element depends on the user device computation performance. The 100
161 | milliseconds value is the maximum average time the browser will need to compute
162 | the style sheet.
163 |
164 | ## Benefits
165 |
166 | I did five [Google PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights) tests on each version of the same example page: [the
167 | standard one without skeleton screens and with render-blocking CSS](https://dimitrinicolas.github.io/skeleton-screens-concept/index-without-skeleton-screens.html) and [the version with this concept](https://dimitrinicolas.github.io/skeleton-screens-concept).
168 |
169 | The Mobile score and First Contentful Paint time were always the same after each
170 | test. The version with skeleton screens got a 99% mobile score with 0,8 seconds
171 | for the First Contentful Paint. The standard version got a 97% mobile score with
172 | 2,2 seconds for the First Contentful Paint.
173 |
174 | These results are not the best example because the example page has a super
175 | simple DOM and the 300 kb style sheet only contains a small amount of CSS to
176 | compute, the whole file size come from a random string in a CSS comment.
177 |
178 | I'll need to implement this concept into a real website to better understand the
179 | performance benefit.
180 |
181 | ## Use Case
182 |
183 | This approach of skeleton screens is useful for Single Page Applications with a
184 | heavy style sheet.
185 |
186 | ## Frameworks implementation
187 |
188 | I need to find solutions to use this concept with static website frameworks like
189 | [Gatsby](https://github.com/gatsbyjs/gatsby) or [Next.js](https://github.com/zeit/next.js/).
190 |
191 | ## Related
192 |
193 | - [Everything you need to know about skeleton screens (uxdesign.cc)](https://uxdesign.cc/what-you-should-know-about-skeleton-screens-a820c45a571a) - An article by [Bill Chung](http://billat.work/) about differents skeleton screens design solutions and studies of their performances on the user perception.
194 |
195 | ## License
196 |
197 | This project is licensed under the [MIT license](LICENSE).
198 |
--------------------------------------------------------------------------------