Back in 2017 Google changed the way it scores page load speed. Previously, points were awarded for following the recommendations the tool listed after an audit: compress your images, CSS and JS, get rid of render-blocking resources — well done, boxes ticked, points earned. Now the tool measures the actual load speed, the moment content first appears, and how quickly a user can start interacting with the page. Under the new criteria most sites saw their scores drop, so we carried out a series of measures to bring our clients' sites back into the "green" zone.
What changed in Google's scoring
The difference between the old and the new scoring logic is fundamental: it used to measure diligence, now it measures the result seen by a real person on a real device over a real connection.
How it worked before 2017
Points were awarded for following the recommendations the tool listed after an audit. Compress your images, CSS and JS, get rid of resources that block page rendering — item closed, points credited. With that approach, reaching the "green zone" was not hard.
How it works now
The tool measures the page's actual load speed, the first appearance of content, and how quickly a user can start interacting with the page. Formally ticking off the items in the report guarantees nothing in itself any more.
CSS and JS: the main render-blocking resources
The biggest speed penalty comes from scripts, images and CSS — these are precisely the resources that block page rendering.
A solid performance gain came from loading JS via a <script> tag with the async and defer attributes, where scripts are downloaded alongside the page and parsed and executed afterwards.
But it is worth understanding exactly which script you are dealing with. Before attaching those attributes, we check three things:
- whether the script is self-contained;
- whether it depends on other scripts;
- whether it relies on a fully parsed DOM.
The second point — loading via the framework's own tools
Most scripts are loaded through the framework's own methods: enterprise CMS platforms provide a dedicated construct for this. Loading them this way gives you all the benefits — automatic script bundling, compression, and serving the gzipped version of the script, provided the relevant options are enabled in the admin panel and the server is configured to serve .gz files.
By loading scripts through a <script> tag, we lose those advantages. The solution is CompressionWebpackPlugin: it creates a compressed gzipped copy of the JS build alongside the main one. The result is files compressed by more than three times.

What else is worth doing with CSS and JS
- load the JS and CSS used only on specific pages where that is possible;
- minify CSS and JS — this is a requirement, not a nice-to-have;
- defer the loading of third-party scripts wherever you can.
In total, loading scripts asynchronously added around 15 points in PageSpeed, and minifying CSS and JS another 12.
Importing only the modules you need
Component libraries let you import individual components. Instead of the entire library, of which we only use a few forms and buttons, we import just the components we actually need.
This can save up to 300 KB in the final build — weight the user would otherwise download for nothing.
Fonts
Google requires text to become visible as early as possible while the page is loading. So when a project uses non-standard fonts, they need to be loaded lazily, with a standard font shown first.
- Loading. We load fonts via @font-face.
- Asynchronous loading. This is handled by the font-display property.
- Choosing the value. font-display accepts several values, but the best speed figures come from font-display: fallback.
Loading fonts this way can be worth 15–20 points.
Images
It stands to reason that the less an image weighs, the faster it loads. Google promotes its own .webp image format, so for the images on a site you need to create .webp copies and serve them in your templates through the <picture> tag, specifying two sources inside it — the regular image and the .webp one. The new format works in most modern browsers, but not in Safari — which is exactly why the second source is essential.
You can also add lazy loading for images — using the jQuery Lazy plugin or IntersectionObserver.
Deferred GTM loading
We have singled this point out because GTM can pull in a whole pile of third-party marketing scripts along with it — and every one of them is capable of causing a serious speed penalty.
So GTM can be loaded via setTimeout, with a delay of about three seconds, using the async and defer attributes.
How many points each step delivered
The outcome, using intertop.ua as an example
Here is how all of the measures listed above look together on a real project.


Checklist and what comes next
| Measure | What we do | What it delivers |
|---|---|---|
| CSS and JS | async and defer, minification, per-page loading, a gzipped copy of the build | around 15 points for asynchronous loading and another 12 for minification |
| Modules | import individual components instead of the whole library | up to 300 KB saved in the final build |
| Fonts | @font-face plus font-display: fallback | 15–20 points |
| Images | webp copies via <picture> and lazy loading | a lighter page and faster content display |
| GTM | loading via setTimeout with async and defer | removes the penalty from third-party marketing scripts |
The main takeaway from this story is simple: catching up on these metrics after the fact is always more expensive than building them into the project from the start.
We now optimise for PageSpeed while the sites are still being built, so that the best possible figures are there from day one.Bohdan Panasenko / Front-end developer
