Đang tải...

Ếch Trendy

Cùng chú ếch nhỏ khám phá thế giới Web đầy biến động. Cập nhật trending nhanh như cách ếch đớp mồi! ⌨️🌿


0

Core Web Vitals 2026: Tối ưu performance website với Lazy Loading Images và Cumulative Layout Shift Fix

Ếch Trendy
Ếch Trendy

3 tháng trước · 8 phút đọc

Core Web Vitals 2026 là gì và tại sao bạn không thể bỏ qua

Hồi 2023, mình từng nghĩ tối ưu Core Web Vitals chỉ là "nice to have" - làm khi có thời gian rảnh. Kết quả? Traffic organic giảm 30% sau một đợt Google update. Bài học đắt giá.

Năm 2026, hiệu suất trang web chiếm khoảng khoảng 15% tổng tín hiệu xếp hạng - tăng gấp 3 lần so với 5% năm 2023. Không còn là yếu tố phụ nữa.

Google đo lường trải nghiệm người dùng qua ba chỉ số chính:

Chỉ số Đo lường Ngưỡng "Tốt"
LCP (Largest Contentful Paint) Tốc độ tải nội dung chính < 2.5 giây
INP (Interaction to Next Paint) Độ trễ tương tác < 200ms
CLS (Cumulative Layout Shift) Độ ổn định thị giác < 0.1

Điểm quan trọng cần nhớ: INP đã thay thế hoàn toàn FID từ 2024. Nghĩa là bạn không thể chỉ tối ưu tương tác đầu tiên - mọi click, scroll, input trên trang đều phải phản hồi dưới 200ms.

345741 Đạt dưới 2.0s LCP và 0.08 CLS sẽ là lợi thế cạnh tranh lớn hơn mức ngưỡng cơ bản

Các chỉ số được đo tại phân vị thứ 75 (p75) của lượt truy cập thực tế - không phải môi trường lab. 75% người dùng của bạn phải đạt ngưỡng tốt, không phải chỉ median.

Mục tiêu thực tế cho 2026: LCP dưới 2.0s, CLS dưới 0.08, INP dưới 150ms. Cao hơn ngưỡng cơ bản, nhưng đây là vùng an toàn khi Google tiếp tục siết chặt.


Lazy Loading Images: Ít code, nhiều lợi ích

Lazy Loading là kỹ thuật chỉ tải ảnh khi người dùng sắp cuộn đến - thay vì tải toàn bộ ngay lúc mở trang. Nghe đơn giản, nhưng tác động lên LCP rất đáng kể.

Vấn đề cụ thể: trang landing page trung bình có hàng chục ảnh. Nếu tải tất cả cùng lúc, bandwidth bị chia nhỏ, ảnh hero (ảnh đầu trang - phần tử LCP) phải chờ các ảnh below-fold tải xong mới được ưu tiên.

Cách thêm Lazy Loading - 1 dòng HTML:

<!-- Ảnh below-fold: thêm loading="lazy" -->
<img
  src="product-photo.jpg"
  alt="Mô tả sản phẩm"
  loading="lazy"
  width="800"
  height="600"
/>

<!-- Ảnh hero (above-fold): KHÔNG lazy, ưu tiên tải trước -->
<img
  src="hero-banner.webp"
  alt="Banner chính"
  fetchpriority="high"
  width="1200"
  height="630"
/>

Quy tắc đơn giản: ảnh nào người dùng thấy ngay khi mở trang → fetchpriority="high". Ảnh cần cuộn xuống mới thấy → loading="lazy".

345742 Chỉ một thuộc tính HTML nhưng giảm được đáng kể dữ liệu tải ban đầu

Format ảnh 2026: Chuyển sang WebP hoặc AVIF. WebP nhỏ hơn JPEG khoảng 25-35% cùng chất lượng. AVIF nhỏ hơn nữa nhưng encode lâu hơn. Ảnh hero nên dưới 80KB sau khi nén.

<!-- Dùng <picture> để fallback cho browser cũ -->
<picture>
  <source srcset="hero.avif" type="image/avif" />
  <source srcset="hero.webp" type="image/webp" />
  <img src="hero.jpg" alt="Banner" fetchpriority="high" width="1200" height="630" />
</picture>

Nếu đang dùng Next.js, component <Image> đã xử lý hết: tự động lazy loading, WebP conversion, và responsive sizing. Không cần cấu hình thêm.


Fix Cumulative Layout Shift: Hết giật nội dung

Bạn có bao giờ đang đọc bài, chuẩn bị click một link thì toàn bộ trang nhảy xuống vì ảnh vừa load xong? Đó là CLS - và người dùng ghét nó hơn trang load chậm.

Nguyên nhân số 1: ảnh không có kích thước cố định. Khi trình duyệt tải trang, nó không biết ảnh to cỡ nào nên không giữ chỗ. Ảnh load xong → đẩy toàn bộ nội dung phía dưới xuống.

Fix đơn giản nhất - thêm width và height:

<!-- SAI: không có kích thước, CLS cao -->
<img src="product.jpg" alt="Sản phẩm" loading="lazy" />

<!-- ĐÚNG: có kích thước, trình duyệt giữ chỗ trước -->
<img
  src="product.jpg"
  alt="Sản phẩm"
  loading="lazy"
  width="800"
  height="600"
/>

Ngay cả khi CSS của bạn dùng max-width: 100%, trình duyệt vẫn tính được tỉ lệ aspect ratio từ width/height để giữ chỗ đúng.

CSS Aspect Ratio - linh hoạt hơn:

/* Container giữ chỗ trước khi ảnh load */
.img-wrapper {
  aspect-ratio: 16 / 9;
  background-color: #f0f0f0; /* Placeholder màu xám nhạt */
  overflow: hidden;
}

.img-wrapper img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

345743 Aspect-ratio giữ chỗ chính xác, nội dung không bị nhảy khi ảnh load

Các nguồn CLS hay bị bỏ qua:

  • Quảng cáo và banner động: Chèn quảng cáo vào vị trí không có kích thước cố định là nguyên nhân CLS phổ biến nhất. Fix: luôn có wrapper với min-height bằng kích thước ad.
  • Web fonts: Font load muộn khiến text re-render. Dùng font-display: swap và preload font chính.
  • Nội dung inject từ JavaScript: Analytics widgets, chat bubbles load sau → đẩy nội dung. Fix: đặt chúng ở vị trí fixed hoặc có placeholder.
/* Tránh font gây CLS */
@font-face {
  font-family: 'MyFont';
  src: url('font.woff2') format('woff2');
  font-display: swap; /* Dùng font fallback trước, swap khi load xong */
}

Mục tiêu: CLS dưới 0.1 là "tốt", nhưng dưới 0.05 mới thực sự clean. Dùng PageSpeed Insights để kiểm tra CLS chi tiết từng element.


Tối ưu JavaScript và INP: Phần hay bị bỏ quên

LCP và CLS thường được fix trước vì dễ thấy. INP thì khó hơn - nó đo mọi tương tác trong suốt vòng đời trang, không chỉ lần đầu.

Vấn đề cốt lõi của INP cao: main thread bị block. JavaScript nặng chạy trên main thread khiến trình duyệt không thể xử lý input của người dùng.

Giảm blocking JavaScript - 3 bước thực tế:

Bước 1 - Defer scripts không cần thiết:

<!-- Script analytics: không cần chạy ngay -->
<script src="analytics.js" defer></script>

<!-- Script bên thứ 3: load sau khi trang render xong -->
<script>
  window.addEventListener('load', () => {
    // Load chat widget sau khi trang đã interactive
    loadChatWidget();
  });
</script>

Bước 2 - Code splitting: Chỉ load JavaScript của trang hiện tại, không phải toàn bộ app.

// Thay vì import tất cả lúc đầu
// import HeavyComponent from './HeavyComponent'

// Dùng dynamic import - chỉ load khi cần
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

Bước 3 - Web Workers cho tác vụ nặng:

// Đẩy xử lý data nặng ra khỏi main thread
const worker = new Worker('data-processor.js');
worker.postMessage({ data: largeDataset });
worker.onmessage = (e) => {
  // Kết quả về, update UI
  updateTable(e.data.result);
};

345744 Web Worker giải phóng main thread - trang phản hồi ngay cả khi đang xử lý data nặng

Edge Caching & CDN: Giảm TTFB (Time to First Byte) là cách nhanh nhất cải thiện LCP. Cloudflare Workers hoặc Vercel Edge Functions cache response gần người dùng nhất - thay vì request phải đi về server gốc.

Một số framework như Next.js đã tích hợp edge caching sẵn. Với các app thuần, cấu hình CDN cache headers:

Cache-Control: public, max-age=31536000, immutable

Dùng cho static assets (JS, CSS, ảnh). Với HTML thì khác - cần no-cache hoặc stale-while-revalidate.

Nếu bạn đang học JavaScript để hiểu sâu hơn về async, event loop và tại sao main thread blocking xảy ra, khóa Lập Trình JavaScript Nâng Cao cover chi tiết phần này - từ closure đến event loop đến Web Workers.


Checklist và công cụ đo lường Core Web Vitals

Biết cách fix là một chuyện, nhưng phải đo được mới biết mình đang ở đâu.

Công cụ đo lường chính:

  • PageSpeed Insights - dùng dữ liệu thực từ CrUX (Chrome User Experience Report). Đây là số liệu Google thực sự dùng để rank, không phải Lighthouse.
  • Lighthouse trong Chrome DevTools - dữ liệu lab, hữu ích để debug nhưng không phản ánh trải nghiệm người dùng thực.
  • Web Vitals Extension - hiển thị LCP, INP, CLS real-time khi bạn duyệt trang.
  • Search Console tab Core Web Vitals - xem báo cáo theo URL, phân loại Poor/Needs Improvement/Good.

Thứ tự ưu tiên fix:

  1. LCP trước: Tối ưu ảnh hero (WebP, fetchpriority="high"), giảm TTFB qua CDN.
  2. CLS tiếp theo: Thêm width/height cho tất cả ảnh, fix fonts, fix ads.
  3. INP cuối: Defer scripts, code splitting, Web Workers nếu cần.

345745 Bắt đầu từ PageSpeed Insights với dữ liệu thực - không phải Lighthouse lab data

Tải checklist đầy đủ tại đây: Tải checklist Core Web Vitals 2026

Quick wins có thể làm ngay hôm nay:

  • Thêm loading="lazy" cho tất cả ảnh below-fold
  • Thêm width và height cho tất cả thẻ <img>
  • Thêm fetchpriority="high" cho ảnh hero
  • Chuyển ảnh sang WebP
  • Thêm defer cho analytics scripts

Năm thứ này không yêu cầu refactor lớn - chỉ cần 2-3 giờ review toàn bộ ảnh và scripts. Chạy PageSpeed Insights trước và sau, bạn sẽ thấy điểm số thay đổi ngay.

Gặp vướng mắc khi fix CLS hay INP cụ thể, drop comment - mình hay check.

Trang web dùng cookie để hoạt động và đo hiệu quả quảng cáo. Xem chính sách bảo mật