Tối ưu PageSpeed không phải chạy theo điểm số — mà là hệ thống hóa các kỹ thuật để website load nhanh, tương tác mượt, và ổn định trực quan. Bài viết này hướng dẫn chi tiết cách cải thiện từng chỉ số Core Web Vitals: LCP, INP, và CLS — với checklist cụ thể, tool miễn phí, và ví dụ code thực tế.
🎁 Lead magnet: Tải miễn phí Performance Optimization Checklist — 30 điểm kiểm tra hiệu suất website, chia theo priority, có hướng dẫn fix cho từng điểm.
Core Web Vitals là gì?
3 chỉ số chính
| Chỉ số | Đo gì | Tốt | Cần cải thiện | Kém |
|---|---|---|---|---|
| LCP (Largest Contentful Paint) | Thời gian render phần tử lớn nhất (hero image, heading) | ≤2.5s | 2.5-4s | >4s |
| INP (Interaction to Next Paint) | Độ responsive khi user tương tác (click, tap, type) | ≤200ms | 200-500ms | >500ms |
| CLS (Cumulative Layout Shift) | Layout có bị “nhảy” khi load không | ≤0.1 | 0.1-0.25 | >0.25 |
Tại sao 3 chỉ số này quan trọng?
- LCP: User đánh giá “website nhanh hay chậm” dựa trên lúc nhìn thấy nội dung chính
- INP: Khi click button mà 500ms sau mới phản hồi → user nghĩ website hỏng
- CLS: Đang đọc text → layout nhảy → bấm nhầm nút → user tức giận
Google dùng cả 3 làm ranking factor cho SEO.
Tối ưu LCP (Largest Contentful Paint)
LCP phần tử nào?
LCP thường là 1 trong:
- Hero image/banner
- Heading text lớn (
<h1>) - Video poster image
- Background image lớn
Cách xác định: Chrome DevTools → Performance tab → xem “LCP” marker, hoặc PageSpeed Insights hiện rõ phần tử LCP.
Nguyên nhân LCP chậm và cách fix
Nguyên nhân 1: Server response chậm (TTFB cao)
Vấn đề: Server mất 2-3 giây để trả response đầu tiên.
Chẩn đoán: PageSpeed Insights → “Reduce server response times (TTFB)”
Giải pháp:
| Action | Cải thiện TTFB | Effort |
|---|---|---|
| CDN (Cloudflare Free) | -50-70% | 15 phút setup |
| Upgrade hosting (shared → VPS) | -40-60% | 1-2 giờ |
| Server-side caching (Redis, Varnish) | -60-80% | 2-4 giờ |
| Database optimization | -20-40% | 4-8 giờ |
| Static site generation (SSG) | -90% | 1-2 tuần (rebuild) |
Nguyên nhân 2: Hình ảnh LCP nặng
Vấn đề: Hero image 2MB JPEG, load mất 3 giây.
Giải pháp:
<!-- Trước: JPEG 2MB, không responsive -->
<img src="hero.jpg" alt="Hero banner">
<!-- Sau: WebP, responsive, preload -->
<link rel="preload" as="image" href="hero.webp"
imagesrcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
imagesizes="100vw">
<picture>
<source srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
type="image/webp" sizes="100vw">
<img src="hero-800.jpg" alt="Hero banner"
width="1200" height="600" fetchpriority="high">
</picture>
Checklist hình ảnh LCP:
- Format: WebP hoặc AVIF
- Size: ≤200KB (cho hero image)
- Responsive: srcset với nhiều kích thước
- Preload:
<link rel="preload">cho LCP image -
fetchpriority="high"trên LCP element - KHÔNG lazy load LCP image
Nguyên nhân 3: Render-blocking resources
Vấn đề: CSS/JS nặng block rendering — browser phải download xong mới render.
Giải pháp:
<!-- Trước: CSS block rendering -->
<link rel="stylesheet" href="styles.css"> <!-- 200KB -->
<!-- Sau: Inline critical CSS + async load full CSS -->
<style>
/* Critical CSS — chỉ CSS cần cho above-the-fold */
body { font-family: sans-serif; }
.hero { background: #f5f5f5; height: 60vh; }
/* ... ~5KB */
</style>
<link rel="preload" href="styles.css" as="style" onload="this.rel='stylesheet'">
<!-- JS: defer thay vì block -->
<script src="app.js" defer></script>
<!-- hoặc -->
<script src="analytics.js" async></script>
Nguyên nhân 4: Web fonts chậm
Vấn đề: Custom font 200KB, download từ Google Fonts → text invisible trong 2 giây.
Giải pháp:
<!-- Preload font quan trọng nhất -->
<link rel="preload" href="/fonts/Inter-Regular.woff2" as="font"
type="font/woff2" crossorigin>
<!-- Font display swap: hiện text ngay bằng system font, swap khi custom font ready -->
<style>
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Regular.woff2') format('woff2');
font-display: swap;
}
</style>
Tips thêm: Subset font (chỉ giữ ký tự cần dùng), self-host thay vì Google Fonts (giảm 1 DNS lookup).
LCP Optimization Checklist
| # | Action | Impact | Effort |
|---|---|---|---|
| 1 | Preload LCP image | Cao | 5 phút |
| 2 | Convert LCP image sang WebP | Cao | 15 phút |
| 3 | Inline critical CSS | Cao | 1-2 giờ |
| 4 | CDN (Cloudflare) | Cao | 15 phút |
| 5 | Defer non-critical JS | Trung bình | 30 phút |
| 6 | Preload web font | Trung bình | 10 phút |
| 7 | Server caching | Cao | 2-4 giờ |
| 8 | Reduce TTFB (upgrade hosting) | Cao | 1-2 giờ |
Tối ưu INP (Interaction to Next Paint)
INP đo gì?
INP đo thời gian từ khi user tương tác (click, tap, keypress) đến khi browser cập nhật visual. Bao gồm:
- Input delay: Event handler chờ main thread rảnh
- Processing time: Event handler chạy
- Presentation delay: Browser render kết quả
Nguyên nhân INP kém
| Nguyên nhân | Ví dụ | Impact |
|---|---|---|
| Long tasks trên main thread | JS xử lý nặng >50ms | Cao |
| Third-party scripts | Chat widget, analytics, ads | Cao |
| DOM size quá lớn | >1,500 elements | Trung bình |
| Layout thrashing | JS đọc/ghi DOM liên tục | Trung bình |
Giải pháp INP
1. Break long tasks:
// Trước: 1 long task 200ms
function processData(items) {
items.forEach(item => heavyComputation(item)); // block 200ms
}
// Sau: yield to main thread
async function processData(items) {
for (const item of items) {
heavyComputation(item);
// Yield mỗi 50ms để browser render
if (performance.now() - startTime > 50) {
await new Promise(resolve => setTimeout(resolve, 0));
startTime = performance.now();
}
}
}
2. Defer third-party scripts:
<!-- Load chat widget sau khi page load xong -->
<script>
window.addEventListener('load', () => {
setTimeout(() => {
// Load Tawk.to, Intercom, etc.
const script = document.createElement('script');
script.src = 'https://embed.tawk.to/...';
document.head.appendChild(script);
}, 3000); // Delay 3 giây sau page load
});
</script>
3. Debounce input handlers:
// Search input: không gọi API mỗi keystroke
const debouncedSearch = debounce((query) => {
fetch(`/api/search?q=${query}`);
}, 300); // Đợi 300ms sau keystroke cuối
input.addEventListener('input', (e) => debouncedSearch(e.target.value));
Tối ưu CLS (Cumulative Layout Shift)
CLS xảy ra khi nào?
Layout shift = phần tử trên trang di chuyển vị trí sau khi đã render. User thấy trang “nhảy.”
Nguyên nhân CLS phổ biến
| # | Nguyên nhân | Ví dụ |
|---|---|---|
| 1 | Image/video không có dimensions | Ảnh load → đẩy text xuống |
| 2 | Ads/banner inject vào DOM | Quảng cáo xuất hiện → đẩy content |
| 3 | Web font swap | Text thay đổi kích thước khi font load |
| 4 | Dynamic content insert | ”Bạn có thể thích…” load sau → đẩy content |
| 5 | Cookie consent banner | Banner xuất hiện → đẩy content xuống |
Giải pháp CLS
1. Luôn set width/height cho img/video:
<!-- Trước: CLS khi ảnh load -->
<img src="product.webp" alt="Product">
<!-- Sau: Browser dành sẵn không gian -->
<img src="product.webp" alt="Product" width="400" height="300">
<!-- hoặc dùng aspect-ratio CSS -->
<style>
img { aspect-ratio: 4/3; width: 100%; height: auto; }
</style>
2. Dành sẵn không gian cho ads/banners:
.ad-slot {
min-height: 250px; /* Dành sẵn không gian cho ad */
background: #f5f5f5; /* Placeholder color */
}
3. Font display: optional (thay vì swap):
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter.woff2') format('woff2');
font-display: optional; /* Dùng system font nếu custom font chưa sẵn */
}
4. Transform thay vì thay đổi layout properties:
/* Trước: gây layout shift */
.element { top: 10px; left: 20px; }
/* Sau: chỉ composite, không layout shift */
.element { transform: translate(20px, 10px); }
Bảng tổng hợp: 20 kỹ thuật tối ưu PageSpeed
| # | Kỹ thuật | Chỉ số cải thiện | Impact | Effort |
|---|---|---|---|---|
| 1 | CDN (Cloudflare) | LCP, TTFB | Cao | Thấp |
| 2 | Image optimization (WebP/AVIF) | LCP | Cao | Thấp |
| 3 | Lazy loading (images) | LCP (cho below-fold) | Trung bình | Thấp |
| 4 | Critical CSS inline | LCP | Cao | Trung bình |
| 5 | Preload LCP resource | LCP | Cao | Thấp |
| 6 | Defer JS | LCP, INP | Cao | Thấp |
| 7 | GZIP/Brotli compression | LCP | Cao | Thấp |
| 8 | Browser caching | LCP (repeat visits) | Trung bình | Thấp |
| 9 | Reduce DOM size | INP | Trung bình | Trung bình |
| 10 | Break long tasks | INP | Cao | Trung bình |
| 11 | Debounce handlers | INP | Trung bình | Thấp |
| 12 | Set image dimensions | CLS | Cao | Thấp |
| 13 | Font display: swap/optional | CLS, LCP | Trung bình | Thấp |
| 14 | Placeholder for dynamic content | CLS | Cao | Thấp |
| 15 | Code splitting | INP, LCP | Cao | Cao |
| 16 | Tree shaking | LCP | Trung bình | Trung bình |
| 17 | Server-side rendering (SSR) | LCP | Cao | Cao |
| 18 | Database index optimization | LCP (TTFB) | Cao | Trung bình |
| 19 | HTTP/2 or HTTP/3 | LCP | Trung bình | Thấp |
| 20 | Remove unused CSS/JS | LCP, INP | Trung bình | Trung bình |
Tool hỗ trợ
| Tool | Mục đích | Free |
|---|---|---|
| PageSpeed Insights | Measure Core Web Vitals | ✅ |
| Lighthouse (Chrome) | Detailed audit | ✅ |
| WebPageTest | Multi-location, filmstrip | ✅ |
| CrUX Dashboard | Real user data | ✅ |
| Squoosh | Image optimization | ✅ |
| PurgeCSS | Remove unused CSS | ✅ |
| Bundle Analyzer | Visualize JS bundle | ✅ |
| Chrome DevTools | Debug performance | ✅ |
FAQ — Câu hỏi thường gặp
1. Bao lâu thì Google update Core Web Vitals data?
CrUX data (Chrome User Experience Report) update mỗi 28 ngày. Sau khi optimize, đợi ~1 tháng để Google nhận diện cải thiện. PageSpeed Insights hiện cả lab data (ngay lập tức) và field data (28 ngày).
2. Trang nào cần tối ưu trước?
Ưu tiên: (1) Trang chủ, (2) Landing pages chạy ads, (3) Trang sản phẩm/dịch vụ, (4) Blog posts có traffic cao. Dùng Google Search Console → Core Web Vitals report để xem trang nào “kém.”
3. WordPress page builder (Elementor, Divi) có tối ưu được không?
Khó đạt 90+ mobile với page builder vì: DOM quá lớn, CSS/JS nặng, inline styles. Tối ưu được lên 60-75. Nếu cần 90+, cân nhắc custom theme hoặc framework nhẹ (Astro, Next.js, hoặc GeneratePress + custom blocks).
Kết luận
Tối ưu PageSpeed là cuộc chơi của chi tiết — mỗi kỹ thuật nhỏ cải thiện 100-500ms, cộng dồn lại tạo ra trải nghiệm nhanh vượt trội. Bắt đầu với quick wins (CDN, image optimization, defer JS) → đã cải thiện 40-60%. Sau đó deep dive vào từng chỉ số Core Web Vitals.
Nếu bạn cần hỗ trợ audit và tối ưu hiệu suất website, hãy liên hệ Trinh Digital — chúng tôi cung cấp dịch vụ Performance Optimization chuyên nghiệp cho website mọi nền tảng.