├── 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 | 5 | 6 | 7 | Skeleton Screens Concept 8 | 9 | 10 | 11 | 12 |
13 |
14 | 17 | 25 |
26 |
27 | 28 |
29 |
30 |
Intro with known height
31 |
32 |
33 | 34 |
35 |
36 | Content with unknown height 37 |
38 |
39 | 40 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Skeleton Screens Concept 8 | 94 | 95 | 96 | 97 | 98 | 99 |
100 |
101 | 104 | 112 |
113 |
114 | 115 |
116 |
117 |
Intro with known height
118 |
119 |
120 | 121 |
122 |
123 | Content with unknown height 124 |
125 |
126 | 127 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Skeleton Screens Concept 2 | 3 | [![Skeleton Screens Concept example screenshot](fixtures/example.png)](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 | --------------------------------------------------------------------------------