Tấn Phát Digital — Bài viết được biên dịch và phân tích chuyên sâu từ tài liệu chính thức "Understanding Core Web Vitals and Google search results" của Google Search Central. Đây là bài kỹ thuật quan trọng nhất dành cho developer, designer và chủ website muốn tối ưu performance theo tiêu chuẩn của Google.
1 giây chậm = $1.6 triệu doanh thu mất đi
Năm 2017, Amazon công bố một con số gây sốc: Mỗi 1 giây chậm = giảm $1.6 tỷ doanh thu hàng năm.
Walmart tìm thấy: Mỗi 1 giây cải thiện = +2% conversion.
Google nghiên cứu: Trang load >3 giây = 53% người rời bỏ.
Tại Việt Nam, 60% website chạy chậm hơn 3 giây. Điều này có nghĩa là:
Mất 50%+ traffic tiềm năng
Conversion thấp hơn 20-40%
Bounce rate cao
Ranking SEO bị ảnh hưởng
Google nhận ra performance là yếu tố quyết định trải nghiệm user, nên đã giới thiệu Core Web Vitals — bộ 3 metrics đo lường trải nghiệm web thực tế.
Năm 2024, Google chính thức đổi từ FID sang INP — một thay đổi quan trọng nhiều site VN chưa cập nhật.
Bài viết này, Tấn Phát Digital sẽ giải mã toàn bộ Core Web Vitals 2026 — từ định nghĩa đến optimization techniques.
Bài viết này dành cho:
Frontend Developer tối ưu performance
Backend Developer cần hiểu performance impact
DevOps quản lý infrastructure
Chủ website muốn hiểu performance tác động SEO
Marketing manager cần justify performance investment
Phần 1: Core Web Vitals — Tổng quan
1.1. Định nghĩa từ Google
Google nói:
"Core Web Vitals là một bộ metrics đo lường REAL-WORLD USER EXPERIENCE cho LOADING PERFORMANCE, INTERACTIVITY, và VISUAL STABILITY của page."
3 trụ cột:
┌─────────────────────────────────────────────────┐
│ ⚡ LOADING (Tốc độ tải) │
│ Metric: LCP │
│ Target: < 2.5 giây │
├─────────────────────────────────────────────────┤
│ 🖱️ INTERACTIVITY (Phản hồi) │
│ Metric: INP │
│ Target: < 200 milliseconds │
├─────────────────────────────────────────────────┤
│ 🎯 VISUAL STABILITY (Ổn định) │
│ Metric: CLS │
│ Target: < 0.1 │
└─────────────────────────────────────────────────┘
1.2. Tầm quan trọng cho SEO
Google nhấn mạnh:
"We HIGHLY RECOMMEND site owners achieve good Core Web Vitals for SUCCESS WITH SEARCH và để ensure a GREAT USER EXPERIENCE generally."
"This, along with other page experience aspects, ALIGNS WITH WHAT OUR CORE RANKING SYSTEMS SEEK TO REWARD."
🎯 Translation:
Core Web Vitals là ranking factor thực sự
Site có CWV tốt được Google thưởng
Không có CWV tốt = bất lợi cạnh tranh
1.3. "Real-world" data nghĩa là gì?
⚠️ Quan trọng: Google dùng real user data, không phải synthetic tests.
2 loại data:
Lab Data (Synthetic)
Đo trong môi trường controlled
Tools: Lighthouse, PageSpeed Insights
Hữu ích cho debugging
KHÔNG dùng cho ranking
Field Data (Real-world)
Đo từ người dùng thực tế
Source: Chrome User Experience Report (CrUX)
DÙNG cho ranking ⭐
Có thể khác xa lab data
→ Insight quan trọng: Site có thể Lighthouse 100/100 nhưng field data tệ → vẫn xếp hạng kém.
Phần 2: LCP — Largest Contentful Paint (Tải)
2.1. Định nghĩa
LCP = Thời gian để element lớn nhất trong viewport xuất hiện.
Element được tính:
Hình ảnh (
<img>)Hình ảnh background (CSS)
Video poster
Block-level text (paragraph, heading)
SVG
KHÔNG tính:
Hidden elements
Elements ngoài viewport
Decorative elements (border, gradient...)
2.2. Thresholds
✅ GOOD: < 2.5 giây
🟡 NEEDS WORK: 2.5 - 4.0 giây
❌ POOR: > 4.0 giây
2.3. Các yếu tố ảnh hưởng LCP
4 yếu tố chính:
1. Server response time
Slow server = LCP cao.
Cách đo: TTFB (Time To First Byte)
✅ Good: < 800ms
🟡 OK: 800ms - 1.8s
❌ Poor: > 1.8s
Optimization:
# Nginx caching
location ~* \.(jpg|jpeg|png|gif|webp|css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Apache .htaccess
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/webp "access plus 1 year"
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
</IfModule>
2. Render-blocking resources
CSS/JS chặn render = LCP chậm.
Optimization:
<!-- ❌ Render-blocking -->
<link rel="stylesheet" href="styles.css">
<!-- ✅ Async CSS -->
<link rel="preload" href="critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="critical.css"></noscript>
<!-- ✅ Defer JS -->
<script src="app.js" defer></script>
<!-- ✅ Async JS (không phụ thuộc DOM) -->
<script src="analytics.js" async></script>
3. Resource load time
Images/videos lớn = LCP chậm.
Optimization images:
<!-- Modern format + responsive -->
<picture>
<source
srcset="hero.avif"
type="image/avif">
<source
srcset="hero.webp"
type="image/webp">
<img
src="hero.jpg"
alt="Hero image"
width="1200"
height="600"
fetchpriority="high">
</picture>
Critical:
✅
fetchpriority="high"cho LCP image✅ AVIF (modern) > WebP > JPEG
✅ Responsive với srcset
✅ Specify width/height (avoid CLS too)
4. Client-side rendering
JS render content = LCP chậm.
Optimization:
// ❌ Tránh: Render tất cả từ JS
const App = () => {
const [content, setContent] = useState('');
useEffect(() => {
fetch('/api/content').then(r => r.json()).then(setContent);
}, []);
return <div>{content}</div>; // LCP very late
};
// ✅ Đúng: SSR/SSG với placeholder
// Next.js example
export async function getStaticProps() {
const content = await fetchContent();
return { props: { content }, revalidate: 60 };
}
export default function Page({ content }) {
return <div>{content}</div>; // LCP fast
}
2.4. Top 7 optimization techniques cho LCP
Technique 1: Preload critical resources
<head>
<!-- Preload LCP image -->
<link rel="preload"
as="image"
href="/hero.webp"
fetchpriority="high">
<!-- Preload fonts -->
<link rel="preload"
as="font"
type="font/woff2"
href="/font.woff2"
crossorigin>
<!-- Preconnect to external domains -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
</head>
Technique 2: Image optimization
# Convert to WebP với Sharp (Node.js)
npm install sharp
# Script
const sharp = require('sharp');
sharp('input.jpg')
.webp({ quality: 80 })
.toFile('output.webp');
# AVIF (better)
sharp('input.jpg')
.avif({ quality: 70 })
.toFile('output.avif');
Size guidelines:
Hero images: < 200KB (WebP), < 100KB (AVIF)
Content images: < 100KB
Thumbnails: < 30KB
Icons: < 5KB (SVG ideal)
Technique 3: CDN usage
Static assets serve qua CDN:
<!-- Trước: -->
<img src="/images/hero.jpg">
<!-- Sau: -->
<img src="https://cdn.example.com/images/hero.jpg">
Vietnam-friendly CDNs:
Cloudflare (free tier tốt)
Bunny CDN ($1/month)
Amazon CloudFront
KeyCDN
Technique 4: Critical CSS inline
<head>
<style>
/* Critical CSS for above-the-fold */
body { margin: 0; font-family: sans-serif; }
.hero { padding: 2rem; background: #fff; }
.hero h1 { font-size: 3rem; }
/* ... only above-the-fold styles */
</style>
<!-- Defer non-critical CSS -->
<link rel="preload"
href="/full-styles.css"
as="style"
onload="this.onload=null;this.rel='stylesheet'">
</head>
Technique 5: Compress text
# Nginx gzip
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
application/javascript application/json;
gzip_comp_level 6;
# Brotli (better than gzip)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json
application/javascript text/xml;
Technique 6: HTTP/2 hoặc HTTP/3
server {
listen 443 ssl http2; # HTTP/2
# listen 443 ssl http3; # HTTP/3 (newer)
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
}
Technique 7: Database query optimization
Slow DB query → slow TTFB → slow LCP.
-- Add indexes cho frequent queries
CREATE INDEX idx_status_created
ON products(status, created_at);
-- Use EXPLAIN để analyze
EXPLAIN SELECT * FROM products
WHERE status = 'active'
ORDER BY created_at DESC LIMIT 10;
Phần 3: INP — Interaction to Next Paint (Phản hồi)
3.1. INP là gì?
INP = Đo thời gian phản hồi của trang với user interactions.
⚠️ Thay đổi quan trọng 2024:
INP thay thế FID (First Input Delay)
Tính từ tháng 3/2024 chính thức
Tại sao đổi?
FID chỉ đo first interaction
INP đo TẤT CẢ interactions trong session
Phản ánh chính xác hơn UX thực tế
3.2. INP đo gì?
INP đo độ trễ giữa:
Click button
Tap link
Type input
Scroll touch
... và phản hồi visual của trang
3.3. Thresholds
✅ GOOD: < 200ms
🟡 NEEDS WORK: 200ms - 500ms
❌ POOR: > 500ms
3.4. Nguyên nhân INP kém
Top 5 culprits:
1. Heavy JavaScript execution
// ❌ BAD: Block main thread
function processData(items) {
return items.map(item => {
// Heavy computation
return expensiveOperation(item);
});
}
button.addEventListener('click', () => {
const result = processData(largeArray); // Blocks 500ms+
updateUI(result);
});
// ✅ GOOD: Use Web Workers
button.addEventListener('click', () => {
const worker = new Worker('processor.js');
worker.postMessage(largeArray);
worker.onmessage = (e) => updateUI(e.data);
});
2. Synchronous third-party scripts
<!-- ❌ BAD: Blocks main thread -->
<script src="https://analytics.example.com/track.js"></script>
<!-- ✅ GOOD: Async/defer -->
<script src="https://analytics.example.com/track.js" async></script>
3. Long-running event handlers
// ❌ BAD
button.onclick = () => {
for (let i = 0; i < 100000; i++) {
doSomething(i); // Block UI
}
};
// ✅ GOOD: Use scheduler
button.onclick = async () => {
for (let i = 0; i < 100000; i++) {
if (i % 100 === 0) {
// Yield to main thread every 100 iterations
await new Promise(r => setTimeout(r, 0));
}
doSomething(i);
}
};
// ✅ BEST: Use scheduler.yield() (modern API)
button.onclick = async () => {
for (let i = 0; i < 100000; i++) {
if (i % 100 === 0 && 'yield' in scheduler) {
await scheduler.yield();
}
doSomething(i);
}
};
4. Large DOM size
DOM lớn = updates chậm.
Solution: Virtual scrolling cho long lists
// React with react-window
import { FixedSizeList } from 'react-window';
function VirtualList({ items }) {
return (
<FixedSizeList
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{({ index, style }) => (
<div style={style}>{items[index].name}</div>
)}
</FixedSizeList>
);
}
5. CSS animations heavy
/* ❌ BAD: Animate layout properties */
.element {
transition: width 0.3s, height 0.3s, top 0.3s, left 0.3s;
}
/* ✅ GOOD: Animate transform/opacity (GPU) */
.element {
transition: transform 0.3s, opacity 0.3s;
will-change: transform; /* hint to browser */
}
.element:hover {
transform: translate(10px, 10px) scale(1.1);
}
3.5. 5 techniques tối ưu INP
Technique 1: Code splitting
// Next.js dynamic imports
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(
() => import('../components/HeavyComponent'),
{
loading: () => <p>Loading...</p>,
ssr: false
}
);
// React.lazy
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
);
}
Technique 2: Debounce/Throttle
// Debounce search input
function debounce(fn, delay) {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), delay);
};
}
const handleSearch = debounce((query) => {
fetchResults(query);
}, 300);
searchInput.addEventListener('input', (e) => {
handleSearch(e.target.value);
});
Technique 3: requestIdleCallback
// Schedule non-urgent tasks
function processNonUrgent() {
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
// Do non-critical work
sendAnalytics();
updateCache();
});
} else {
setTimeout(() => {
sendAnalytics();
updateCache();
}, 0);
}
}
Technique 4: Optimize React renders
// ❌ BAD: Re-render on every parent update
function Child({ data }) {
return <div>{expensiveCalculation(data)}</div>;
}
// ✅ GOOD: Memoize
const Child = React.memo(({ data }) => {
return <div>{expensiveCalculation(data)}</div>;
});
// ✅ BETTER: useMemo for calculations
function Child({ data }) {
const result = useMemo(
() => expensiveCalculation(data),
[data]
);
return <div>{result}</div>;
}
// useCallback for functions
function Parent() {
const handleClick = useCallback(() => {
// ...
}, []);
return <Child onClick={handleClick} />;
}
Technique 5: Use CSS containment
/* Isolate rendering for components */
.card {
contain: layout style paint;
}
/* Strict containment */
.modal {
contain: strict;
}
Phần 4: CLS — Cumulative Layout Shift (Ổn định)
4.1. CLS là gì?
CLS = Đo lường độ ổn định visual của trang.
Layout shift xảy ra khi:
Element xuất hiện và push content xuống
Image load và đẩy text
Font load và reflow text
Ads/embeds load chậm
Animations thay đổi layout
4.2. Thresholds
✅ GOOD: < 0.1
🟡 NEEDS WORK: 0.1 - 0.25
❌ POOR: > 0.25
4.3. Tính CLS như thế nào?
CLS Score = Impact Fraction × Distance Fraction
Impact Fraction: % viewport bị ảnh hưởng Distance Fraction: Khoảng cách dịch chuyển / viewport height
Ví dụ:
50% viewport bị shift
Element dịch 25% chiều cao viewport
CLS = 0.5 × 0.25 = 0.125 (Poor)
4.4. Top 6 nguyên nhân CLS
1. Images không có dimensions
❌ Sai:
<img src="photo.jpg" alt="Photo">
✅ Đúng:
<!-- Specify width/height -->
<img src="photo.jpg"
width="800"
height="600"
alt="Photo">
<!-- HOẶC dùng aspect-ratio CSS -->
<img src="photo.jpg"
style="aspect-ratio: 4/3; width: 100%;"
alt="Photo">
2. Ads không có placeholder
❌ Sai:
<div id="ad-container">
<!-- Ad loaded dynamically, pushes content -->
</div>
✅ Đúng:
<div id="ad-container"
style="min-height: 250px;">
<!-- Reserved space -->
</div>
3. Web fonts gây FOUT/FOIT
FOUT = Flash of Unstyled Text FOIT = Flash of Invisible Text
✅ Solution: font-display: optional
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: optional; /* Best for CLS */
/* hoặc: font-display: swap; (better UX) */
}
Preload critical fonts:
<link rel="preload"
href="/fonts/main.woff2"
as="font"
type="font/woff2"
crossorigin>
4. Dynamic content injection
❌ Sai:
// Inject banner at top
const banner = document.createElement('div');
banner.innerHTML = 'Sale!';
document.body.insertBefore(banner, document.body.firstChild);
// Pushes content down
✅ Đúng:
// Show banner without shifting layout
const banner = document.createElement('div');
banner.style.position = 'fixed';
banner.style.top = '0';
banner.style.zIndex = '9999';
banner.innerHTML = 'Sale!';
document.body.appendChild(banner);
5. Embedded videos/iframes
❌ Sai:
<iframe src="https://youtube.com/embed/xyz"></iframe>
✅ Đúng:
<div style="aspect-ratio: 16/9; position: relative;">
<iframe
src="https://youtube.com/embed/xyz"
style="position: absolute; width: 100%; height: 100%;"
width="560"
height="315">
</iframe>
</div>
6. CSS animations với layout properties
❌ Sai:
.menu {
height: 0;
transition: height 0.3s;
}
.menu.open {
height: auto; /* Causes layout shift */
}
✅ Đúng:
.menu {
transform: translateY(-100%);
transition: transform 0.3s;
}
.menu.open {
transform: translateY(0);
}
Phần 5: Tools đo lường Core Web Vitals
5.1. PageSpeed Insights (Khuyến nghị #1)
URL: https://pagespeed.web.dev
Features:
Lab + Field data
Mobile + Desktop
Specific recommendations
Diagnostics đầy đủ
Cách dùng:
1. Paste URL
2. Click Analyze
3. Xem 2 tab: Mobile + Desktop
4. Field Data (real users) - QUAN TRỌNG NHẤT
5. Lab Data (Lighthouse)
6. Opportunities + Diagnostics
5.2. Chrome DevTools
Lighthouse panel:
1. Open DevTools (F12)
2. Tab "Lighthouse"
3. Categories: Performance
4. Device: Mobile (default cho ranking)
5. Click "Analyze"
Performance tab:
1. Tab "Performance"
2. Click record
3. Refresh page
4. Stop recording
5. Analyze flame chart
5.3. Search Console Core Web Vitals Report
Vị trí: Search Console → Experience → Core Web Vitals
Features:
Real field data từ users của bạn
Mobile + Desktop breakdown
Good / Needs Improvement / Poor counts
Trend over time
⭐ Đây là data Google dùng cho ranking.
5.4. CrUX API (Chrome User Experience Report)
# Get CrUX data cho URL
curl -X POST \
'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com"
}'
5.5. Real User Monitoring (RUM)
Tools:
web-vitals library (Google official)
SpeedCurve
DebugBear
Cloudflare Analytics
web-vitals library implementation:
import { onCLS, onINP, onLCP } from 'web-vitals';
function sendToAnalytics({ name, value, id }) {
// Send to your analytics
fetch('/analytics', {
method: 'POST',
body: JSON.stringify({ name, value, id }),
headers: { 'Content-Type': 'application/json' }
});
}
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
Phần 6: Framework-specific Optimization
6.1. WordPress
Top plugins:
🚀 Caching:
├── WP Rocket (premium, best)
├── W3 Total Cache (free)
└── LiteSpeed Cache (free, nếu dùng LiteSpeed server)
🖼️ Image optimization:
├── ShortPixel (premium)
├── Smush (free)
└── Imagify (mix)
📊 Database:
├── WP-Optimize
└── Advanced Database Cleaner
🎨 CSS/JS:
├── Autoptimize
└── Asset CleanUp
WP best practices:
// functions.php - Defer non-critical scripts
function defer_parsing_of_js($url) {
if (is_admin()) return $url;
if (strpos($url, '.js') === false) return $url;
if (strpos($url, 'jquery.js')) return $url;
return str_replace(' src', ' defer src', $url);
}
add_filter('script_loader_tag', 'defer_parsing_of_js', 10);
// Preload LCP image
function preload_lcp_image() {
if (is_front_page()) {
echo '<link rel="preload" as="image"
href="/hero.webp" fetchpriority="high">';
}
}
add_action('wp_head', 'preload_lcp_image', 1);
6.2. Next.js
// next.config.js
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
experimental: {
optimizeCss: true,
optimizePackageImports: ['lodash', 'date-fns'],
},
compress: true,
};
// pages/_app.js
import Script from 'next/script';
export default function App({ Component, pageProps }) {
return (
<>
{/* Lazy load analytics */}
<Script
src="https://analytics.example.com/track.js"
strategy="lazyOnload"
/>
<Component {...pageProps} />
</>
);
}
// Component: Optimize image
import Image from 'next/image';
function HeroSection() {
return (
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // For LCP
fetchPriority="high"
placeholder="blur"
blurDataURL="data:image/svg+xml;base64,..."
/>
);
}
6.3. Shopify
Built-in optimizations:
Image optimization (WebP auto)
CDN global
HTTP/2
Custom optimizations:
{% comment %} Preload critical resources {% endcomment %}
<link rel="preload" as="image"
href="{{ section.settings.hero | image_url: width: 1200 }}"
fetchpriority="high">
{% comment %} Lazy load non-critical {% endcomment %}
<img src="{{ image | image_url: width: 600 }}"
loading="lazy"
decoding="async"
width="600"
height="400"
alt="{{ image.alt }}">
{% comment %} Critical CSS inline {% endcomment %}
<style>
{% render 'critical-css' %}
</style>
{% comment %} Defer non-critical CSS {% endcomment %}
<link rel="preload"
href="{{ 'main.css' | asset_url }}"
as="style"
onload="this.onload=null;this.rel='stylesheet'">
6.4. Custom React App
// App.jsx - Code splitting
import { lazy, Suspense } from 'react';
const ProductPage = lazy(() => import('./ProductPage'));
const CheckoutPage = lazy(() => import('./CheckoutPage'));
function App() {
return (
<Routes>
<Route path="/" element={<HomePage />} />
<Route
path="/product/:id"
element={
<Suspense fallback={<Loading />}>
<ProductPage />
</Suspense>
}
/>
<Route
path="/checkout"
element={
<Suspense fallback={<Loading />}>
<CheckoutPage />
</Suspense>
}
/>
</Routes>
);
}
// Optimize images component
function OptimizedImage({ src, alt, priority = false }) {
const [loaded, setLoaded] = useState(false);
return (
<div style={{ aspectRatio: '16/9', position: 'relative' }}>
<img
src={src}
alt={alt}
loading={priority ? 'eager' : 'lazy'}
fetchPriority={priority ? 'high' : 'auto'}
decoding="async"
onLoad={() => setLoaded(true)}
style={{
width: '100%',
height: '100%',
objectFit: 'cover',
opacity: loaded ? 1 : 0,
transition: 'opacity 0.3s'
}}
/>
</div>
);
}
Phần 7: Case Study - Tối ưu thực tế
7.1. Trước optimization
Website ecommerce VN:
📊 BEFORE Optimization:
┌────────────────────────────────────┐
│ Metric │ Value │ Status │
├────────────────────────────────────┤
│ LCP │ 4.8s │ ❌ Poor │
│ INP │ 620ms │ ❌ Poor │
│ CLS │ 0.34 │ ❌ Poor │
└────────────────────────────────────┘
Symptoms:
- Bounce rate: 68%
- Conversion: 1.2%
- Mobile speed score: 23
7.2. Optimization steps
Week 1-2: LCP fixes
✅ Compress all images (WebP, -70% size)
✅ Setup Cloudflare CDN
✅ Implement critical CSS inline
✅ Preload hero image
✅ Lazy load below-fold images
✅ Defer non-critical JS
→ LCP: 4.8s → 2.1s
Week 3: INP fixes
✅ Code splitting cho main bundle
✅ Defer analytics scripts
✅ Optimize event handlers
✅ Virtual scrolling cho long lists
✅ Web Worker cho heavy calculations
→ INP: 620ms → 180ms
Week 4: CLS fixes
✅ Add width/height cho tất cả images
✅ Reserve space cho ads
✅ font-display: optional cho web fonts
✅ Fix banner injection method
✅ Aspect-ratio cho iframes
→ CLS: 0.34 → 0.08
7.3. After optimization
📊 AFTER Optimization:
┌────────────────────────────────────┐
│ Metric │ Value │ Status │
├────────────────────────────────────┤
│ LCP │ 2.1s │ ✅ Good │
│ INP │ 180ms │ ✅ Good │
│ CLS │ 0.08 │ ✅ Good │
└────────────────────────────────────┘
Results sau 3 tháng:
- Bounce rate: 68% → 42% (-26%)
- Conversion: 1.2% → 2.8% (+133%)
- Mobile speed score: 23 → 89
- Organic traffic: +47%
- Revenue: +180%
Phần 8: 10 lỗi phổ biến và cách fix
❌ Lỗi 1: Optimize chỉ với Lighthouse
Vấn đề: Lab data ≠ Field data
Fix: Track field data với Search Console + RUM
❌ Lỗi 2: Quên optimize mobile
Vấn đề: Google dùng mobile data cho ranking
Fix: Test mobile-first, ưu tiên mobile experience
❌ Lỗi 3: Web fonts quá nhiều
Vấn đề: Mỗi font weight = 1 file load
Fix: Tối đa 2-3 font weights, subset characters
❌ Lỗi 4: Images không có dimensions
Vấn đề: CLS cao
Fix: Always specify width/height hoặc aspect-ratio
❌ Lỗi 5: Block third-party scripts
Vấn đề: INP cao
Fix: Async/defer hoặc lazy load
❌ Lỗi 6: Không có caching
Vấn đề: LCP cao cho repeat visits
Fix: Cache static assets 1 year, HTML 1 hour
❌ Lỗi 7: Quá nhiều plugins (WordPress)
Vấn đề: Slow performance
Fix: Audit plugins, remove unused
❌ Lỗi 8: Không dùng CDN
Vấn đề: Slow cho users xa server
Fix: Cloudflare/Bunny CDN cho static assets
❌ Lỗi 9: Database queries không optimized
Vấn đề: Slow TTFB
Fix: Add indexes, query optimization
❌ Lỗi 10: Test chỉ với fast connection
Vấn đề: Không phản ánh user thực tế
Fix: Test với throttling (Slow 3G, mid-tier device)
Phần 9: Monitoring & Maintenance
9.1. Weekly checks
Every Monday (15 phút):
□ Search Console Core Web Vitals report
└── Check trend last 7 days
□ PageSpeed Insights top 5 pages
└── Mobile + Desktop
□ Any new "Poor" URLs?
└── Priority fix list
9.2. Monthly deep dive
First Monday each month (2 hours):
□ Full audit top 20 pages
□ Review RUM data
□ Identify regressions
□ Plan optimizations
□ Update team on metrics
9.3. Quarterly review
Every quarter:
□ Compare quarter-over-quarter trends
□ ROI analysis (revenue, conversion correlations)
□ Tool/infrastructure review
□ Update optimization roadmap
□ Train team on new techniques
Kết luận: Performance là Business Investment
Core Web Vitals không chỉ là "technical SEO" — đó là business investment với ROI rất cao:
Conversion +20-40%
Bounce rate -25-35%
Organic traffic +30-50%
Revenue +50-200%
5 thông điệp cuối
1. Field data > Lab data. Lighthouse 100/100 không đảm bảo gì.
2. Mobile-first optimization. Google dùng mobile data cho ranking.
3. LCP quan trọng nhất. Tối ưu LCP đầu tiên.
4. INP thay thế FID từ 2024. Đảm bảo dùng INP.
5. Continuous monitoring. Performance dễ regress, monitor weekly.
Tài liệu tham khảo
Về Tấn Phát Digital
Tấn Phát Digital chuyên Core Web Vitals optimization:
CWV Audit - Phân tích toàn diện
Performance Optimization - LCP, INP, CLS fixes
WordPress Speed Optimization
Custom App Performance
Continuous Monitoring Setup
Liên hệ Tấn Phát Digital để tăng tốc website và boost SEO performance.
Biên soạn từ tài liệu Google Search Central, cập nhật 10/12/2025. Code samples và optimization techniques thuộc về Tấn Phát Digital.
Core Web Vitals không chỉ là bộ chỉ số kỹ thuật mà còn phản ánh trải nghiệm thực tế của khách hàng trên website.
Nếu bạn muốn tối ưu tốc độ website, cải thiện Core Web Vitals và nâng cao hiệu suất SEO, hãy liên hệ Tấn Phát Digital để được tư vấn giải pháp phù hợp.









