- PageSpeed Insights
This post has been translated by AI.
Post summarized by durumis AI
- Improving website performance using performance measurement tools (PageSpeed Insights, Lighthouse) can improve search engine visibility, and Web Core Vitals metrics are important.
- To improve metrics like CLS, LCP, FCP, and FID, you can apply techniques such as UI skeleton screens, image optimization, removing render-blocking elements, optimizing web fonts, and asynchronous JavaScript processing.
- Along with methods to improve each metric, we'll introduce various techniques for enhancing web performance (gzip compression, web workers, etc.) and plan to delve deeper into related topics in the future.
You can easily measure web performance through the site provided by Google.
You can measure by entering the URL into
https://pagespeed.web.dev/
or you can install Lighthouse as a Chrome extension to measure.
What are the benefits of improving these metrics?
You can get better search engine visibility. SEO often uses server-side rendering,
If the above performance indicators are low, its effectiveness will plummet.
How to improve?
The web.dev site provides detailed explanations of how to improve each metric.
In particular, three indicators account for a large portion of the score. (Web Core Vitals)
I want to record the things I've tried to improve the indicators.
How to measure locally?
export default () => { if (process.client && 'PerformanceObserver' in window) { let cumulativeLayoutShiftScore = 0; let largestContentfulPaint = 0; let firstInputDelay = 0; let firstContentfulPaint = 0;
// CLS const clsObserver = new PerformanceObserver((list) => { const entries = list.getEntries(); entries.forEach((entry) => { if (!entry.hadRecentInput) { cumulativeLayoutShiftScore += entry.value; } }); }); // LCP const lcpObserver = new PerformanceObserver((list) => { const entries = list.getEntries(); const lastEntry = entries[entries.length - 1]; largestContentfulPaint = lastEntry.startTime; }); // FID const fidObserver = new PerformanceObserver((list) => { const entries = list.getEntries(); const firstEntry = entries[0]; firstInputDelay = firstEntry.processingStart - firstEntry.startTime; }); // FCP const fcpObserver = new PerformanceObserver((list) => { const entries = list.getEntries(); const firstEntry = entries[0]; firstContentfulPaint = firstEntry.startTime; }); clsObserver.observe({ type: 'layout-shift', buffered: true }); lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true }); fidObserver.observe({ type: 'first-input', buffered: true }); fcpObserver.observe({ type: 'paint', buffered: true }); window.addEventListener('onload', () => { console.log('Final CLS Score:', cumulativeLayoutShiftScore); console.log('LCP:', largestContentfulPaint); console.log('FID:', firstInputDelay); console.log('FCP:', firstContentfulPaint); }); } };
Insert the above code. In the case of Nuxt, put it in plugins and check the console log.
Cumulative Layout Shift (CLS)
It measures the degree to which the layout changes as it renders.
For example, let's assume that there is a page that renders a 400x400 image by receiving the image URL through an API response,
The position of a certain layout will shift by 400px as the image is rendered.
This is an unexpected movement for the user, which is not only bad for UX, but also indirectly affects the browser when rendering the screen.
It has an adverse effect.
There are two easy ways to improve.
1. Apply UI Skeleton
- Most sites draw an appropriate skeleton according to the image size or component size. Consider this part when developing the screen. In Vue, use v-if and v-else to draw skeletons for each element.
2. Reserve Height
- If too many styles are included in the skeleton, maintenance becomes complicated and can backfire. Simply setting the min-height of the element to be rendered can have an effect.
- In the case of responsive web, etc., where the image size is different for each device, it is difficult to fix the height. In this case, you can use the smallest device as a reference or use vh or vw.
3. Specify width and height for image elements
- You can put width and height in the image element as follows.
Even if the actual image size is not 400x400, it tells the browser the expected size of the image.
4. Use font-display: swap to prevent layout changes due to web fonts
- By indicating an alternative font, layout shifts are prevented.
Largest Contentful Paint(LCP)
It is the time it takes for the largest element on the screen to render. It is usually an image, so intuitively, you just need to make the loading speed faster.
1. Reduce image size.
- Check if the image size is not larger than the rendering size.
- Optimize image rendering with extensions like WebP. When using lossy compression, WebP is about 30% smaller than JPEG format, and when using lossless compression, it is about 20% smaller than PNG.
- Lazy loading, which loads images based on scroll position, can also be considered.
2. Utilize caching or CDN.
3. Remove render-blocking resources.
- Most metrics are affected, so be sure to remove them. When the browser renders the screen, it first fetches the scripts in the head tag and then renders, so check if the scripts (usually external scripts) in the head tag need to be rendered first. You can easily manage this by using the async and defer tags.
* I will write another post about the script attributes in the head later.
4. Minimize bundle size.
- Regardless of the slow rendering speed of the image, if the delivery from the server is slow, you need to improve it.
If you are using a proxy server like Nginx, you can use gzip compression.
* I will write another post about Nginx configuration later.
First Contentful Paint(FCP)
It means the time when the first content on the page is rendered.
1. Remove render-blocking resources as well.
2. Minimize HTML size.
- If you wrap indiscriminately with div div tags, a very nested tree is created and the file size also increases.
3. External web fonts may be the problem. Actively use font-display: swap; to render the default font first.
First Input Delay(FID)
It refers to the time it takes for the browser to handle the user's first input (click, scroll, etc.) on the page. Occasionally, when you press a button, it may seem unresponsive, but it may actually be waiting for an API response, not unresponsive.
1. Develop well using asynchronous operations so that the JavaScript main thread is not tied up with heavy tasks.
2. You can use a web worker to perform another task separately from the main thread.
* I'll write another post about web workers later.
I'll finish here due to the word count limit.