Skip to main content
Performance8 min read15/12/2024

Tối ưu Web Performance với Core Web Vitals 2024

Cách đo lường và cải thiện INP, LCP, CLS — những chỉ số quan trọng nhất của Google để xếp hạng website. Hướng dẫn thực chiến từ dự án thực tế.

N

Nguyễn Duy Noa

Frontend Developer

Năm 2024, Google chính thức đưa Interaction to Next Paint (INP) thay thế First Input Delay (FID) trở thành một trong ba Core Web Vitals chính thức. Cùng với Largest Contentful Paint (LCP) và Cumulative Layout Shift (CLS), ba chỉ số này chi phối trực tiếp trải nghiệm người dùng và thứ hạng tìm kiếm của website.

Trong bài viết này, tôi sẽ chia sẻ cách tôi đã tối ưu những chỉ số này từ dự án thực tế — một website thương mại điện tử cho chuỗi phòng khám thẩm mỹ với 15,000 người dùng hàng tháng. Trước khi tối ưu, điểm Lighthouse chỉ đạt 62. Sau ba tuần, trang đạt 99 điểm trên cả mobile và desktop.

Core Web Vitals là gì và tại sao chúng quan trọng

Core Web Vitals là bộ chỉ số do Google định nghĩa để đo lường trải nghiệm người dùng trên web. Ba chỉ số chính:

Largest Contentful Paint (LCP) — Thời gian để nội dung lớn nhất hiển thị trên màn hình. Mục tiêu: dưới 2.5 giây. LCP thường bị ảnh hưởng bởi ảnh không optimized, render-blocking JavaScript, hoặc server response chậm.

Interaction to Next Paint (INP) — Thời gian từ khi người dùng tương tác đến khi trình duyệt phản hồi. Mục tiêu: dưới 200ms. INP thay thế FID từ tháng 3/2024 và đo lường toàn bộ interactions trong suốt session, không chỉ lần đầu.

Cumulative Layout Shift (CLS) — Mức độ layout di chuyển không mong muốn. Mục tiêu: dưới 0.1. Nguyên nhân thường gặp: ảnh không có kích thước, quảng cáo động, web fonts gây FOUT.

Đo lường hiện trạng: CrUX vs Lighthouse

Trước khi tối ưu, tôi luôn đo lường hai nguồn dữ liệu khác nhau:

Lighthouse chạy trong môi trường lab kiểm soát — kết nối 4G, CPU 4x slowdown. Tốt để phát hiện vấn đề và so sánh trước/sau trong cùng điều kiện.

PageSpeed Insights cung cấp cả dữ liệu lab (Lighthouse) và dữ liệu thực tế (CrUX) từ người dùng Chrome thật trong 28 ngày gần nhất.

Chrome DevTools Performance panel là công cụ mạnh nhất để phân tích sâu — xem flame chart, network waterfall, và identify main-thread bottlenecks.

measure-cwv.js
javascript
// Measure INP with web-vitals library
import { onINP } from 'web-vitals';

onINP(({ value, attribution }) => {
  console.log('INP:', value);
  console.log('Interaction:', attribution.eventType);
  console.log('Processing time:', attribution.eventDuration, 'ms');
  console.log('Presentation delay:', attribution.processingStart - attribution.eventEnd, 'ms');

  // Send to analytics
  sendToAnalytics({
    name: 'INP',
    value,
    rating: value < 200 ? 'good' : value < 500 ? 'needs-improvement' : 'poor',
  });
});

Tối ưu LCP: Từ 4.2s xuống 1.8s

LCP của website thẩm mỹ ban đầu là 4.2s trên mobile — rất kém. Nguyên nhân chính:

Ảnh hero không optimized. Trang dùng ảnh PNG 2.4MB làm hero. Tôi đã chuyển sang WebP với responsive images:

Kết quả: LCP giảm từ 4.2s xuống 1.8s chỉ với việc tối ưu ảnh. Đây là impact lớn nhất với effort thấp nhất.

HeroImage.tsx
tsx
// Next.js Image với priority + sizes
import Image from 'next/image';

export function HeroImage() {
  return (
    <Image
      src="/hero-clinic.webp"
      alt="NexZen Clinic — dịch vụ thẩm mỹ nội bất"
      fill
      priority  // QUAN TRỌNG: preload ảnh LCP
      sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
      quality={85}
      placeholder="blur"
      blurDataURL="data:image/jpeg;base64,..."
      className="object-cover"
    />
  );
}

Facing similar challenges?

I can help you optimize your website — reach out for a free consultation.

Tối ưu INP: Giải phóng main thread

INP cao nhất trên trang là 890ms — rất kém. Nguyên nhân chính là một third-party chat widget chạy heavy JavaScript trên main thread ngay khi page load.

Chiến lược tối ưu INP:

1. Defer non-critical JS. Tải chat widget sau khi page đã interactive bằng dynamic import:
2. Break up long tasks. Nếu có logic nặng trên main thread, chia nhỏ bằng scheduler.yield() hoặc requestIdleCallback:
3. Optimize event handlers. Tránh layout thrashing trong handlers bằng cách đọc layout values trước, rồi mới write DOM changes.

tsx
// Dynamic import để tách chunk
const ChatWidget = dynamic(() => import('./ChatWidget'), {
  loading: () => null,
  ssr: false,
});

// Trong component:
const handleClick = async (e) => {
  // UI feedback ngay lập tức
  setLoading(true);

  // Heavy computation: yield cho main thread breathe
  await scheduler.yield();

  // Logic nặng
  const result = await heavyComputation(data);

  setLoading(false);
  setResult(result);
};

Tối ưu CLS: Ngăn layout shift

CLS ban đầu là 0.24 — cao hơn ngưỡng "poor" của Google. Nguyên nhân chính:

Web fonts gây FOUT (Flash of Unstyled Text). Khi web font chưa load, trình duyệt dùng fallback font có metrics khác → text reflow khi font load.

Giải pháp:
1. Dùng font-display: optional cho body text — trình duyệt bỏ qua font nếu network chậm
2. Preload font files quan trọng nhất
3. Sử dụng @font-face size-adjust và ascent-override để match fallback font metrics
4. Đặt explicit width/height trên ảnh và aspect-ratio containers

fonts.css
css
/* Preload critical font */
<link rel="preload" href="/fonts/geist.woff2" as="font" type="font/woff2" crossorigin>

/* CSS font-face với size-adjust */
@font-face {
  font-family: 'GeistFallback';
  src: local('Arial');
  size-adjust: 107%;
  ascent-override: 95%;
  descent-override: 25%;
}

body {
  font-family: 'Geist', 'GeistFallback', system-ui, sans-serif;
  font-display: optional; /* Không block render, không reflow */
}

Kết quả sau ba tuần tối ưu

Sau khi áp dụng tất cả optimizations trên:

Trước
Chỉ số
Mục tiêu |
Sau
-------
--------
-----------|
-----
4.2s
LCP
< 2.5s ✅ |
1.8s
890ms
INP
< 200ms ✅ |
120ms
0.24
CLS
< 0.1 ✅ |
0.04
62
Lighthouse
90+ ✅ |

Điều quan trọng hơn điểm số: tỷ lệ thoát (bounce rate) giảm 34%, thời gian trên trang tăng 45%, và doanh thu từ organic tăng 22% trong tháng đầu tiên sau khi deploy changes.

Kết luận

Tối ưu Core Web Vitals không cần phải phức tạp. Bắt đầu với việc đo lường chính xác, xác định nguyên nhân gốc rễ (thường là ảnh, font, hoặc JavaScript nặng), và fix từng vấn đề một.

Ba nguyên tắc tôi luôn áp dụng:
1. Measure trước, optimize sau — đừng guess, hãy có data
2. Ảnh là low-hanging fruit — tối ưu ảnh trước, impact lớn nhất
3. Main thread là tài nguyên quý giá — defer mọi thứ không cần thiết

Nếu bạn cần hỗ trợ tối ưu website, liên hệ với tôi qua form bên dưới.

Core Web VitalsLCPINPCLSNext.jsWeb Vitals

Want to discuss further?

If you have specific questions about web performance, React, or want to collaborate on a project — reach out directly.

Send an email

Let's build something exceptional together.

I'm open to new front-end opportunities, freelance projects, and select consulting work. Tell me what you're building — I'll tell you whether I can help.

duynoanguyen@gmail.com033 687 8073
20–2000

Replies within 24 hours · No mailing list · No spam

© 2026 Duy Noa Nguyen. All rights reserved.Built with Next.js, Tailwind CSS and Framer Motion.
99