{"id":18311072,"url":"https://github.com/dmitriyakkerman/wpo","last_synced_at":"2026-02-22T12:42:51.708Z","repository":{"id":144074479,"uuid":"350059754","full_name":"dmitriyakkerman/wpo","owner":"dmitriyakkerman","description":null,"archived":false,"fork":false,"pushed_at":"2021-10-31T19:26:45.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-15T06:16:51.600Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dmitriyakkerman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-21T16:48:31.000Z","updated_at":"2021-10-31T19:26:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"d561767d-a8c0-4814-9c65-4ea2637901c2","html_url":"https://github.com/dmitriyakkerman/wpo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitriyakkerman%2Fwpo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitriyakkerman%2Fwpo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitriyakkerman%2Fwpo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmitriyakkerman%2Fwpo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmitriyakkerman","download_url":"https://codeload.github.com/dmitriyakkerman/wpo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248036066,"owners_count":21037092,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T16:16:21.766Z","updated_at":"2025-10-24T01:50:12.231Z","avatar_url":"https://github.com/dmitriyakkerman.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"## Web Vitals guide\nhttps://web.dev/vitals/\n\n## First Contentful Paint (FCP) improving\n\nFCP is the time after which the user will see at least some content of your site on his screen.\nIn most cases this content is text and images.\n\nTherefore, to reduce the time to First Contentful Paint, we need some text or image to render faster.\nIt seems it is more logical to start with accelerating the rendering of texts, since they are already in the HTML-code: there is no need to make separate requests.\n\nMost often browsers do not display text that is written in a custom font at all until the font file is loaded.\n\n![](https://pbs.twimg.com/media/EwsFGSHWQAUAmFo?format=jpg\u0026name=4096x4096)\n\nThe download chronology for most sites looks like this: the browser downloads and parses HTML, finds a link to a CSS file in it and loads it, finds a font-face block in the CSS code and downloads the font file.\n\nSo you can speed up the appearance of the text by shortening the chain of critical requests, \"telling\" the browser about the font at the stage of parsing the page itself. The font download will start earlier and the text will appear on the screen faster.\n\n![](https://pbs.twimg.com/media/EwsJGSxXIAMni2c?format=jpg\u0026name=large)\n\nFortunately, there is a font-display CSS property that can be used to tell the browser to display text in a different font (from the font-family chain) while the font file is downloading.\n\n![](https://pbs.twimg.com/media/EwsJci2WUAMN3YT?format=jpg\u0026name=large)\n\nWith font-display: swap enabled, texts will be rendered on the page immediately after loading the CSS code.\n\n![](https://pbs.twimg.com/media/EwsJnU4XAAQ8aqb?format=jpg\u0026name=4096x4096)\n\n## Time to Interactive и Blocking Time improving\n\nOpen the \"Performance\" tab in DevTools, enable emulation of a slow CPU (you can also slow down the connection) and record the first seconds of page load.\n\n![](https://pbs.twimg.com/media/EwTrXZSWEAE3HRM?format=jpg\u0026name=large)\n\nExpand the \"Main\" section and find the tasks marked with shading - they block the main thread the most and greatly interfere with the rendering of the page.\n\n![](https://pbs.twimg.com/media/EwTr_p-WQAkMTIV?format=png\u0026name=large)\n\nIn most cases, the call chains that you will see inside these tasks refer to blocks that do not appear in the first viewport at all.\n\nJust make their code run only when the user scrolls to related elements. For example using the IntersectionObserver API\n\n![](https://pbs.twimg.com/media/EwTwsrAXIAIYPem?format=jpg\u0026name=large)\n\n## Page loading and rendering\n\n[How browser renders page](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction)\n\nConnect scripts with async / defer, and check the DOMContentLoaded event in them\n\nThe user, entering the page, sees only some part of it. It is important to make sure that this visible part is displayed as quickly as possible. To do this, you can select the styles required for rendering the first screen and inline them. Webpack plugin:\n\n[https://github.com/GoogleChromeLabs/critters](https://github.com/GoogleChromeLabs/critters)\n\nApplying critical css will have a positive effect on metrics, for example, Largest contentful paint\n\nContent metrics (Largest contentful paint / First meaningful paint) are also influenced by how fonts are connected and used.\n\nA little more about fonts:\n- the woff2 format is sufficient in most cases (https://caniuse.com/?search=woff2);\n- connect the font with preload;\n- use font-display: swap;\n\n![](https://pbs.twimg.com/media/Ew7pPkaXMAMZqUf?format=jpg\u0026name=large)\n\nAbout images:\n- specify width / height, so the browser will reserve space for pictures in advance\n- for content images - loading = \"lazy\" attribute ([https://caniuse.com/loading-lazy-attr](https://caniuse.com/loading-lazy-attr)) for native scrolling loading (polyfill: [https://github.com/mfranzke/loading-attribute-polyfill](https://github.com/mfranzke/loading-attribute-polyfill))\n\n## UX\n\nPreloading:\n\nFor the visible part, create the skeleton (the thing as in the picture) and inline its styles in \u003cstyle\u003e.\n\n![](https://pbs.twimg.com/media/Ew_QCCPWQAE0hon?format=jpg\u0026name=small)\n\nIf you use a skeleton rather than a spinner, then it seems to users that the page loads faster:\n[https://uxdesign.cc/what-you-should-know-about-skeleton-screens-a820c45a571a](https://uxdesign.cc/what-you-should-know-about-skeleton-screens-a820c45a571a)\n\n![](https://pbs.twimg.com/media/Ew_YYDrW8AAC3si?format=jpg\u0026name=900x900)\n\nIt is useful to study how users navigate the pages of your site and use this knowledge to preload resources. For example, from the main 80% go to registration, then you can download the resources in advance and render this page in the background.\n[https://caniuse.com/link-rel-prerender](https://caniuse.com/link-rel-prerender)\n\n![](https://pbs.twimg.com/media/ExAFwc4XAAASH_w?format=jpg\u0026name=medium)\n\nYou need to work carefully with rel = \"prerender\", as it speeds up the next page for some users by loading additional resources on the current one for everyone. It is not recommended to make more than one link with rel = \"prerender\" per page.\n\nUsing rel = \"preload\" you can download and cache resources that will be needed soon. Unlike rel = \"prerender\", they will not be executed (only downloaded).\n[https://caniuse.com/link-rel-preload](https://caniuse.com/link-rel-preload)\n\n![](https://pbs.twimg.com/media/ExAIEbBWEAI_CEJ?format=jpg\u0026name=medium)\n\nGuess.js is an experimental library that, based on Google analytics data, predicts which page the user will go to next, and dynamically makes a prerender / preload.\n[https://github.com/guess-js/guess](https://github.com/guess-js/guess)\n\n### img\n\nContent images\n- alt=\"My photo\"\n\nDecoration images:\n- background-image\n- alt=\"\"\n- role=\"presentation\"\n- aria-hidden=\"true\"\n\nSvg images:\n- role=\"img\"\n\n### Image compression \n[https://imageoptim.com/online](https://imageoptim.com/online)\n[https://github.com/MeFoDy/image-processor](https://github.com/MeFoDy/image-processor)\n\n## More\n\n[https://habr.com/ru/company/yandex/blog/434130/](https://habr.com/ru/company/yandex/blog/434130/)\n[https://twitter.com/harlan_zw/status/1397928487739027462](https://twitter.com/harlan_zw/status/1397928487739027462)\n[https://web.dev/](https://web.dev/)\n\n## DEFERRING STYLESHEETS \n\n\u003c!-- Deferred stylesheet --\u003e\n\u003clink rel=\"preload\" as=\"style\" href=\"path/to/stylesheet.css\" onload=\"this.onload=null;this.rel='stylesheet'\"\u003e\n\n\u003c!-- Fallback --\u003e\n\u003cnoscript\u003e\n  \u003clink rel=\"stylesheet\" href=\"path/to/stylesheet.css\"\u003e\n\u003c/noscript\u003e\n\nWith link rel=\"preload\" as=\"style\" makes sure that the stylesheet file is requested asynchronously, while onload JavaScript handler makes sure that the file is loaded and processed by the browser after the HTML document has finished loading. Some cleanup is needed, so we need to set the onload to null to avoid this function running multiple times and causing unnecessary re-renders.\n\nThis is exactly how Smashing Magazine handles its stylesheets. Each template (homepage, article categories, article pages, etc.) has a template-specific critical CSS inlined inside HTML style tag in the head element, and a deferred main.css stylesheet which contains all non-critical styles.\n\n## Web Vitals patterns\nhttps://web.dev/patterns/web-vitals-patterns/\n  \n## Async decoding\n  \nConsider this example:\n\n```html  \n\u003cp\u003e some introductory text \u003c/p\u003e\n\u003cimg src = \"very-big.jpg\" /\u003e\n\u003cp\u003e very important text for the user \u003c/p\u003e\n```  \n  \nIn this case, the user will have to wait until a large image is loaded to see the important information that follows it.\n\nTo avoid this situation, you can use the decoding co attribute with the value async. This will allow the browser to decode the image outside of the main thread, avoiding CPU overhead and not blocking further rendering of DOM elements. That is, the process of decoding the image will be postponed for the future, and the browser, in turn, will be able to render all the content without waiting for the image to load.\n\n```html  \n\u003cp\u003e some introductory text \u003c/p\u003e\n\u003cimg src = \"very-big.jpg\" decoding = \"async\" /\u003e\n\u003cp\u003e very important text for the user \u003c/p\u003e\n```\n\n## Reserving vertical space\n\nhttps://caniuse.com/?search=aspect\n  \n## Content-visibility\n \nhttps://codeguida.com/post/3130?fbclid=IwAR1DBqK_KU1OESwJ2zC4uuGrpun6fiep-7XGj18rbvve6v0A8zSVD0feaxE  \n  \n## Optimizing resource loading with Priority Hints\n  \nhttps://web.dev/priority-hints/\n  \n## Content optimizing with inifinite scroll and IOA\n\nhttps://dev.to/trex777/infinite-scrolling-using-intersection-observer-api-118l\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmitriyakkerman%2Fwpo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmitriyakkerman%2Fwpo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmitriyakkerman%2Fwpo/lists"}