5 | {% endblock %}
6 |
7 | {% block og %}
8 |
9 |
10 |
11 | {% endblock %}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "speed-patterns",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "npx @11ty/eleventy --serve",
8 | "build": "npx @11ty/eleventy"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/AlexanderChernyshev/speed-patterns.git"
13 | },
14 | "keywords": [],
15 | "author": "",
16 | "license": "ISC",
17 | "bugs": {
18 | "url": "https://github.com/AlexanderChernyshev/speed-patterns/issues"
19 | },
20 | "homepage": "https://github.com/AlexanderChernyshev/speed-patterns#readme",
21 | "dependencies": {
22 | "@11ty/eleventy": "^1.0.0",
23 | "markdown-it": "^14.1.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.eleventy.js:
--------------------------------------------------------------------------------
1 | const markdownIt = require("markdown-it");
2 |
3 | module.exports = function (eleventyConfig) {
4 | // Set custom directories for input, output, includes, and data
5 | eleventyConfig.addPassthroughCopy("src/style.css");
6 | eleventyConfig.addPassthroughCopy("src/assets/**");
7 | eleventyConfig.setFrontMatterParsingOptions({
8 | excerpt: true,
9 | // Optional, default is "---"
10 | excerpt_separator: "",
11 | });
12 |
13 | // add `order` front matter to each pattern to sort them (lower values firts)
14 | eleventyConfig.addCollection("orderedPatterns", function (collectionApi) {
15 | return collectionApi.getFilteredByTag("pattern").sort(function (a, b) {
16 | return a.data.order - b.data.order;
17 | });
18 | });
19 |
20 | eleventyConfig.addFilter("md", function (content = "") {
21 | return markdownIt({ html: true }).render(content);
22 | });
23 |
24 | return {
25 | dir: {
26 | input: "src",
27 | includes: "_includes",
28 | data: "_data",
29 | output: "_site",
30 | },
31 | };
32 | };
33 |
--------------------------------------------------------------------------------
/src/assets/speed_patterns_burger_menu.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Speed Patterns
2 | A collection of design patterns for fast web sites published on http://www.speedpatterns.com/
3 |
4 | The goal of this project is to collect **product / UX / visual design patterns for creating fast web sites** and intended to help product managers, web designers and front-end developers plan speedy experiences from project inception or help articulate the improvements when performance issues are identified later down the road.
5 |
6 | We concentrate on describing user experience challenges and solutions, but also provide technical details on how to understand if pattern is being followed and identify potential issues.
7 |
8 | High level technical solution might also be provided, but linking to outside technical resources and industry articles is encouraged as we strive to define stable long-term patterns rooted in user psychology and web fundamentals and not on specific solutions that vary too much based on technology stacks and latest developments in browser technology.
9 |
10 | # Contributing
11 | Project is open for everybody to contribute. Please help us cover as many use-cases and known solutions to speed design problems as possible.
12 | See [Contributing Guide](https://github.com/Speed-Patterns/speed-patterns/tree/master/CONTRIBUTING.md) to see how you can help.
13 |
--------------------------------------------------------------------------------
/src/index.njk:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layout.njk
3 | title: Speed Patterns
4 | id: homepage
5 | ---
6 |
Speed is a major contributor to user experience on modern web sites.
7 |
8 |
It is important to pay attention not only to technologies that said experiences are build with, but to the way they are designed as well.
9 |
10 |
Proper speed design is a collaboration between product managers, UI designers and developers as all the aspects of the page composition must be balanced to achieve fast experience that is useful for end-users and deliver on the goals set by creators of the site.
11 |
12 |
Below is the list of common speed design problems and their design solutions. We try not to concentrate on specific technical implementations or specific types of sites so it can be used in any context.
13 |
14 | {% for post in collections.orderedPatterns %}
15 |
16 |
17 |
18 |
38 |
--------------------------------------------------------------------------------
/src/patterns/immutable_layout.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: article.njk
3 | title: Immutable Layout
4 | tags: pattern
5 | thumbnail: /assets/pushy_ads.gif
6 | og_image: /assets/immutable_layout_og_image.jpg
7 | order: 2
8 | ---
9 |
10 | A common problem on web sites that use ads or other 3rd party display elements (widgets), but also manifests in regular websites is change in layout as page loads.
11 |
12 | This is particularly noticeable by users when they start scrolling down the page and element at the top of the page (e.g. ad banner or carousel image that finally loaded) suddenly changes it's height pushing content down.
13 |
14 |
15 |
16 |
17 | Pushy ad
18 |
19 |
20 |
21 | ## Solution
22 |
23 | Instead of shifting the layout, always set the expected size of the available space.
24 |
25 |
26 | Expected ad
27 |
28 |
29 |
30 | Use CSS to set height/width of the container when loading element into it and for images, simply specify width and height directly on a tag so layout engine doesn't have to wait for image bytes to come back from the network to determine its pixel dimensions.
31 |
32 | ```html
33 |
34 | ```
35 |
36 | [Cumulative Layout Shift (CLS)](https://web.dev/articles/cls) is a visual stability metric as part of Core Web Vitals.
37 |
38 | [Good CLS score](https://web.dev/articles/cls#what-is-a-good-cls-score) is under **0.1** at **75%ile** of your users meaning that under 10% of the screen should shift during the page load.
39 |
--------------------------------------------------------------------------------
/src/assets/no_spinners.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/patterns/fast_start.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: article.njk
3 | title: Fast Start
4 | tags: pattern
5 | thumbnail: /assets/slow_paint_filmstrip.png
6 | og_image: /assets/fast_start_og_image.jpg
7 | order: 1
8 | ---
9 |
10 | Before user can start the experience, there is an inevitable delay as user's browser goes away from previous view to the current view.
11 |
12 |
13 |
14 | This delay manifests itself in waiting for first piece of the UI to be painted on the screen. Usually user waits for page to show while looking at the previous page, e.g. search engine results page or another page where they performed an action that led him to the page in question.
15 |
16 | On this filmstrip, previous page is shown as white:
17 |
18 |
19 | Slow first paint filmstrip
20 |
21 |
22 |
23 | The usual cause for such delays are either a bottleneck of a first request for HTML page:
24 |
25 |
26 | Slow first request
27 |
28 |
29 |
30 | Alternatively, delay can be caused by various render-blocking assets loaded on the page, like CSS stylesheets, fonts or pure rendering delays due to time-consuming layout and painting or JavaScript compilation and execution that compete for same CPU resources:
31 |
32 |
33 | Delayed first paint
34 |
35 |
36 |
37 | ## Solution
38 |
39 | Making it a requirement to start painting quickly is critical, especially as it competes with other technical and design goals of loading large amounts of code and displaying a large number of elements on the page.
40 |
41 | [First Contentful Paint (FCP)](https://web.dev/articles/fcp) is a metric that measures how long it takes the browser to render the first piece of content from the DOM. It is a good proxy for when the main content of the page is visible to the user.
42 |
43 | [Good FCP](https://web.dev/articles/fcp#what-is-a-good-fcp-score) is considered below **1.8s** at **75%ile** of your users.
44 |
45 | Set timing SLAs during product and design discussions. Appropriately measure and build the experience to meet the requirements.
46 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | ## 1. Propose new pattern
4 | To make sure we cover as many patterns as possible to help development of fast web sites (as opposed to discovering issues too late in the game), you are encouraged to submit new patterns to the project.
5 |
6 | [Submit a new issue](https://github.com/Speed-Patterns/speed-patterns/issues/new?body=...%20describe%20the%20pattern%2C%20include%20illustrations%20...%0D%0A%0D%0A%23%23%20WebPageTest%20report%20for%20pages%20following%20and%20not%20following%20the%20pattern%3A%0D%0A%2A%20Success%3A%20http%3A%2F%2Fwww.webpagetest.org%2Fresult%2F...%0D%0A%2A%20Failure%3A%20http%3A%2F%2Fwww.webpagetest.org%2Fresult%2F...%0D%0A%0D%0A%23%23%20Existing%20blog%20posts%2C%20articles%2C%20videos%0D%0A%2A%20%0D%0A%0D%0A%23%23%20Links%20to%20successful%20implementations%0D%0A%2A&title=New+Pattern%3A+...name+of+the+pattern...&labels=New+Pattern) and describe a high level pattern to start the discussion on what is the best approach to document a pattern and gather feedback from maintainers and other members.
7 | To help others get a headstart in understanding the pattern, you can collect some of the following supporting materials:
8 | * Links to existing blog posts, articles, videos describing the issues or solutions to the problem
9 | * Links to web sites that already successfully implement the pattern
10 | * Illustrations of the problems in the form of screen grabs or videos / animated GIFs showing successes and failures to implement the pattern
11 | * Technical documentation helping identify the properly followed pattern, e.g. waterfall charts and filmstrips. Links to [WebPageTest](http://www.webpagetest.org/) test results help a lot.
12 |
13 | You can mark submissions that are in early stages of definition and need more active help using [`draft`](https://github.com/Speed-Patterns/speed-patterns/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22New+Pattern%22+label%3Adraft) label.
14 |
15 | ### License
16 | By contributing to this project, you agree that your work will be shared under [Creative Commons Attribution 4.0 International Lincense](https://creativecommons.org/licenses/by/4.0/) [](https://creativecommons.org/licenses/by/4.0/)
17 |
18 | Please help us attribute your work properly by adding your name to [CONTRIBUTORS](https://github.com/Speed-Patterns/speed-patterns/blob/master/CONTRIBUTORS.md) file
19 |
20 | ## 2. Help formulating new patterns
21 | It takes some good conversation to describe a design pattern to make sure it is well established and has legs, please help by reviewing and leaving comments on [existing submissions](https://github.com/Speed-Patterns/speed-patterns/issues) and [pull requests](https://github.com/Speed-Patterns/speed-patterns/pulls).
22 |
23 | ## 3. Add new pattern page
24 | When it is clear that the pattern is well established and you collected feedback from other members and maintainers, create a new pattern file in [`/_patterns/`](https://github.com/Speed-Patterns/speed-patterns/tree/master/_patterns) folder and supporting assets in [`/assets/`](https://github.com/Speed-Patterns/speed-patterns/tree/master/assets) folder and open a pull request.
25 | Please include a link to existing pattern issues to help maintainers get context of the previous conversation.
26 |
27 | ## 4. Celebrate and share
28 | Patterns and best practices are only good if the are followed.
29 |
30 | Start by adopting them and celebrating them in your development and share them with your collegues and wider public.
31 |
32 | Don't forget to celebrate the accomplishments with a healthy party or better yet, a meetup!
33 |
--------------------------------------------------------------------------------
/src/assets/no_spinners_animated.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --header-color: #fff8eb;
3 | }
4 |
5 | .logo {
6 | margin-right: 0.5em;
7 | }
8 |
9 | .textimagepair {
10 | display: flex;
11 | flex-direction: row;
12 | gap: 1em;
13 | padding: 2rem;
14 | background-color: #fff4de;
15 | }
16 |
17 | @media screen and (max-width: 110em) {
18 |
19 | .textimagepair {
20 | flex-direction: column;
21 | }
22 |
23 | .textimagepair video {
24 | margin-left: auto;
25 | margin-right: auto;
26 | }
27 |
28 | }
29 |
30 | .callout {
31 | background-color: rgb(255, 241, 185);
32 | border: solid 0.1em rgb(255, 223, 96);
33 | border-left-width: 1em;
34 | padding: 1.5em;
35 | border-radius: 5px;
36 | }
37 |
38 | header span {
39 | display: flex;
40 | align-items: center;
41 | }
42 |
43 | .githublink {
44 | margin-left: 0.5em;
45 | }
46 |
47 | .speed-pattern {
48 | margin-top: 1em;
49 | }
50 |
51 | .speed-pattern h2 {
52 | margin-top: 0;
53 | background-color: #f0e6d3;
54 | border-radius: 0.5em;
55 | padding: 0.5em;
56 | }
57 |
58 | .contributing {
59 | background-color: #f0e6d3;
60 | padding: 1em;
61 | margin-top: 2em;
62 | }
63 |
64 | .contributing h2 {
65 | margin-top: 0;
66 | }
67 |
68 | .burger {
69 | margin-left: 0.5em;
70 | }
71 |
72 | body {
73 | margin: 0;
74 | background-color: white;
75 | display: grid;
76 | gap: 0;
77 | font-size: calc(15px + 0.390625vw);
78 | }
79 |
80 | nav {
81 | padding: 1em;
82 | background-color: #f0e6d3;
83 | }
84 |
85 | nav ul {
86 | list-style: none;
87 | padding: 0;
88 | font-size: 1.2em;
89 | }
90 |
91 | nav li {
92 | margin-bottom: 0.6em;
93 | }
94 |
95 | .mobile-hidden {
96 | display: none;
97 | }
98 |
99 | header {
100 | display: flex;
101 | align-items: center;
102 | background-color: #2D3866;
103 | padding: 1em;
104 | font-size: 2em;
105 | font-family: Arial, Helvetica, sans-serif;
106 | font-weight: bold;
107 | text-transform: uppercase;
108 | justify-content: space-between;
109 | }
110 |
111 | header a {
112 | color: var(--header-color);
113 | text-decoration: none;
114 | }
115 |
116 | header a:visited {
117 | color: var(--header-color);
118 | }
119 |
120 | a {
121 | color: #4F63B3;
122 | }
123 |
124 | a:visited {
125 | color: #2D3866;
126 | }
127 |
128 | main {
129 | padding: 1em 3em 2em 3em;
130 | }
131 |
132 | .sidebar {
133 | padding: 1em;
134 | background-color: #f0e6d3;
135 | }
136 |
137 | .home-link {
138 | font-weight: bolder;
139 | }
140 |
141 | #homepage .speed-pattern img {
142 | max-width: 100%;
143 | max-height: 10em;
144 | }
145 |
146 | pre {
147 | text-wrap: pretty;
148 | }
149 |
150 | @media screen and (min-width: 75em) {
151 |
152 | .mobile-hidden {
153 | display: block;
154 | }
155 |
156 | html {
157 | height: 100%;
158 | }
159 |
160 | body {
161 | grid-template-columns: 1fr 5fr 18em;
162 | grid-template-rows: auto 1fr;
163 | height: 100%;
164 | }
165 |
166 | #homepage {
167 | grid-template-columns: 0 6fr 18em;
168 | grid-template-rows: auto 1fr;
169 | height: 100%;
170 | }
171 |
172 | header {
173 | grid-row: 1/2;
174 | grid-column: 1/4;
175 | }
176 |
177 | .sidebar {
178 | grid-row: 2/3;
179 | grid-column: 3/4;
180 | }
181 |
182 | main {
183 | grid-row: 2/3;
184 | grid-column: 2/3;
185 | }
186 |
187 | nav {
188 | grid-row: 2/3;
189 | grid-column: 1/2;
190 | }
191 |
192 | #homepage nav {
193 | display: none;
194 | }
195 |
196 | .burger {
197 | display: none;
198 | }
199 |
200 | }
--------------------------------------------------------------------------------
/src/assets/octocat_github_link_image_white_sized.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
35 |
--------------------------------------------------------------------------------
/src/_includes/layout.njk:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ title }}
9 |
10 |
11 | {% block og %}
12 |
13 |
14 |
15 | {% endblock %}
16 |
17 |
18 |
19 |
20 |
21 |
22 | Speed Patterns
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
40 |
41 |
57 |
58 |
59 | {% block title %}{% endblock %}
60 | {{ content | safe }}
61 |
62 |
63 |
118 |
119 |
--------------------------------------------------------------------------------
/src/patterns/skeletal_designs.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: article.njk
3 | title: Skeletal Designs
4 | tags: pattern
5 | thumbnail: /assets/skeletal_design_perception_time_diagram.svg
6 | og_image: /assets/skeletal_designs_og_image.png
7 | order: 3
8 | ---
9 |
10 | Technique introduced by Luke Wroblewsky and used by many sites, including Facebook's and LinkedIn's newsfeeds can be utilized to indicate progress and provide visual cue to what user should expect reducing cognitive load and user's frustration.
11 |
12 |
13 |
14 | ## In-Progress State
15 |
16 | This technique allows the _in-progress state_ of the page to be helpful to user-experience, rather than a hinderance.
17 |
18 | Defining the in-progress state should be a delibarate part of the design process.
19 |
20 | ## Why this is needed
21 |
22 |
23 |
24 |
25 |
This solves the problem of the empty screen: instead of having to wait for data to show up, the user can see visual cues and information about the page's content before the actual data has arrived.
26 |
27 |
These cues can be multiple things:
28 |
29 |
30 |
known headers and titles for sections of the document
31 |
field names ex: price, amount of items
32 |
the visual layout of the page
33 |
zones for different content on the page
34 |
35 |
36 |
Why are zones important?
37 | They allow users to do a first pass and understand the structure of the page ahead of time, which allows for easier navigation of the data once the page has fully loaded.
38 |
39 |
40 |
41 |
44 |
45 |
46 |
47 | This helps reduce cognitive load for users, which reduces the stress of taking in the site. By having the zones establish their dimensions and purpose at the beginning of the loading process, and the final content filing in to that structure, the strain of the user to take in the whole is spread out over the loading time and thus reduced. As opposed to having to first wait and receive no information, and then being hit by a large amount of information and struggling to get your bearings when you would want to start navigating already.
48 |
49 | ### Reduced Perception Time
50 |
51 | It is not just about the technical aspects of loading the page. With this method we reduce the perception time of the user. Without this technique, the user is unable to prepare for navigating the page, and when it finally loads all at once they must spend more time parsing it before they can use it. Whereas with this technique, the user can be prepared to navigate the page once fully loaded, and needs less time to get their bearings and start using the page.
52 |
53 |
54 |
55 | Diagram showing dirstribution of perception over loading time
56 |
57 |
58 | ## Things to avoid
59 |
60 |
61 |
62 | It is critical to avoid layout shift once content loads. You want to make sure that the zones the users see before the page loads match the final layout. Otherwise users would have to make another pass to readjust to the page structure, defeating the purpose of having the zones during loading, and nullifying the advantages this would provide, namely the user having a map of navigation of the page.
63 |
64 |
65 | Cumulative Layout Shift (CLS) metric that is part of Core Web Vitals is a measure of layout shift and is useful for tracking it for both skeletal designs and during regular page load.
66 |
80 | Unfortunately, it became common practice to use a simple to build but not good solution of pulsating gray boxes which occupy the space of the page but do not always set the exact dimensions of the layout.
81 |
82 | In some cases the exact dimesnions are in fact unknown, but in many cases we can know the layout up-front. As such, designers should analyze the content of the page to set dimensions that are known, instead of defaulting to generic solutions or placeholders.
83 |
84 | One common exception to this are social media feeds, where we cannot know what _type_ of content will be in the feed.
85 |
86 | This unfortunate technique was popularized by the need to solve this issue on social networks, which then became taken as standard practice when it should have remained an exception.
87 |
88 |
89 |
90 |
93 |
94 |
95 |
96 | An alternative solution to the gray boxes in this particular case might be to progressively load content without having any skeleton structure. This will show the progress of the page loading by the content appearing on the screen in order, and will not require additional cognitive load to redo the users understanding of the page structure.
97 |
98 | ### Do not delay content!
99 |
100 | Needless to say, that skeleton design should only be used when it is necessary to wait for additional content and there is not technical solution for loading the data faster.
101 |
102 | DO NOT artificially create this multi-step process.
103 |
104 | Spend time investigating technical solutions to load content faster. Only use skeletal designs if there is no alternative.
105 |
106 | ## Examples and Solutions
107 |
108 | Designers and Engineers need to spend time thinking of the in-progress state of the page.
109 |
110 | Using different backround color for zones when using skeletal design loading is a good way to establish zones and their purpose when nothing else, such as textual labels or actual content, is known ahead of time about them.
111 |
112 | In particular, this is useful for spaces that will be occupied by images, as image resources inherently take time to load over the network.
113 |
114 | ## Resources
115 |
116 | - [Mobile Design Details: Avoid The Spinner](https://www.lukew.com/ff/entry.asp?1797) by [Luke Wroblewsky](https://lukew.com/)
117 |
--------------------------------------------------------------------------------
/src/assets/skeletal_design_perception_time_diagram.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------