Làm thế nào để Load hình ảnh nhanh hơn: Sử dụng LQIP và WebP, giảm độ trễ khi tải hình!

Mục lục

Lazy Loading hình ảnh cực chậm: Low‑Quality Image Placeholders (LQIP) + WebP để giảm Perception of Lag

⚡ Mục tiêu: Giảm thời gian hiển thị đầu tiên (First Contentful Paint – FCP) và cải thiện chỉ số Core Web Vitals (LCP, CLS) cho các trang thương mại điện tử có lưu lượng > 10 k đơn/ngày.


1. Bối cảnh thị trường & số liệu thực tế (2024‑2025)

Chỉ số Nguồn Giá trị 2024‑2025
Tốc độ tải trung bình của trang thương mại điện tử ở VN Cục TMĐT VN 2024 6,8 s (đối với trang có > 500 k ảnh)
Tỷ lệ thoát khi FCP > 3 s Statista 2024 38 % (toàn cầu)
LCP trung bình trên các site Shopify Shopify Commerce Trends 2025 2,9 s
WebP adoption trên Chrome 2025 Google Tempo 2025 78 % (so với 62 % năm 2023)
Chi phí CDN trung bình cho 1 TB dữ liệu Gartner 2024 US$ 0,09/GB
Tỷ lệ chuyển đổi tăng khi LCP < 2,5 s Gartner 2025 + 12 %

⚠️ Warning: Các số liệu trên được tổng hợp từ báo cáo công khai; không áp dụng cho các dự án nội bộ chưa công bố.


2. Nguyên lý LQIP + WebP

  • LQIP: Ảnh nền mờ (blurred) hoặc màu sắc trung bình, kích thước < 20 KB, được tải ngay khi HTML được parse.
  • WebP: Định dạng ảnh hiện đại, nén lossless/lossy tốt hơn JPEG/PNG tới 30 %‑45 % giảm dung lượng.

Công thức tính giảm băng thông

\huge \Delta BW = \frac{Size_{JPEG/PNG} - Size_{WebP}}{Size_{JPEG/PNG}} \times 100\%

Ví dụ: 300 KB JPEG → 180 KB WebP → ΔBW = 40 %.


3. Kiến trúc tổng quan (Workflow)

┌─────────────────────┐
│ 1. Build assets      │
│   - Generate LQIP    │
│   - Convert to WebP │
└───────┬─────────────┘
        │
        ▼
┌─────────────────────┐
│ 2. Deploy to CDN    │
│   (Cloudflare / AWS)│
└───────┬─────────────┘
        │
        ▼
┌─────────────────────┐
│ 3. Serve HTML       │
│   - <img src="LQIP">│
│   - data-src="WebP" │
└───────┬─────────────┘
        │
        ▼
┌─────────────────────┐
│ 4. Browser lazy‑load│
│   - IntersectionObserver │
└─────────────────────┘

4. Lựa chọn Tech Stack (so sánh 4 giải pháp)

Stack CDN Image Processor Build Tool CI/CD Độ phức tạp Ưu điểm Nhược điểm
A. Cloudflare Workers + Image Resizing Cloudflare Built‑in (Polish) npm scripts GitHub Actions Thấp Không cần server, phí theo request Giới hạn 100 ms per request
B. AWS S3 + Lambda@Edge + Sharp Amazon CloudFront Sharp (Node) Webpack CodePipeline Trung bình Tùy biến mạnh, hỗ trợ WebP Chi phí Lambda + data transfer
C. MedusaJS + Imgix Imgix CDN Imgix API Vite GitHub Actions Trung bình Auto‑format WebP, LQIP API Phụ thuộc dịch vụ bên thứ ba
D. Nginx + OpenResty + libvips On‑premise Nginx libvips (C) Makefile Jenkins Cao Kiểm soát hoàn toàn, không phí CDN Cần quản lý server, bảo trì

⚡ Lựa chọn đề xuất: Stack A cho dự án < 1 TB/tháng, B cho > 5 TB/tháng, C cho SaaS nhanh, D cho môi trường nội bộ có quy định bảo mật nghiêm ngặt.


5. Chi phí chi tiết 30 tháng (3 năm)

Hạng mục Năm 1 Năm 2 Năm 3 Tổng
CDN (Cloudflare) US$ 1 200 US$ 1 260 US$ 1 323 US$ 3 783
Image Processor (Lambda) US$ 800 US$ 840 US$ 882 US$ 2 522
CI/CD (GitHub Actions) US$ 300 US$ 315 US$ 331 US$ 946
DevOps (Ops) US$ 1 500 US$ 1 575 US$ 1 654 US$ 4 729
Tổng US$ 3 800 US$ 4 0‑ US$ 4 0‑ US$ 12 600

⚠️ Lưu ý: Chi phí tính dựa trên mức sử dụng trung bình 1 TB data/month, 10 k request/giây, giá CDN theo bảng giá công khai 2024‑2025.


6. Timeline triển khai (Bảng)

Giai đoạn Thời gian (tuần) Mốc chính Người chịu trách nhiệm
Phase 1 – Phân tích & thiết kế 1‑2 Đánh giá hiện trạng, xác định KPI Solution Architect
Phase 2 – Build assets 3‑5 Tạo LQIP, chuyển đổi WebP, lưu trữ trên S3 DevOps Engineer
Phase 3 – Cấu hình CDN 6‑7 Deploy Workers / Lambda@Edge Cloud Engineer
Phase 4 – Front‑end integration 8‑10 Thêm src/data-src, IntersectionObserver Front‑end Lead
Phase 5 – CI/CD & testing 11‑13 GitHub Actions, load test, A/B test QA Lead
Phase 6 – Go‑live & monitoring 14‑15 Deploy production, thiết lập alert Ops Manager
Phase 7 – Optimisation 16‑18 Fine‑tune LQIP blur, WebP quality Performance Engineer
Phase 8 – Handover 19‑20 Bàn giao tài liệu, training PM

Dependency: Phase 3 phụ thuộc Phase 2; Phase 4 phụ thuộc Phase 3; Phase 5 phụ thuộc Phase 4; Phase 6 phụ thuộc Phase 5.


7. Gantt chart chi tiết (ASCII)

| Week | 1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|16|17|18|19|20|
|------|---|--|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|Phase1|===|===|
|Phase2|   |===|===|===|
|Phase3|          |===|===|
|Phase4|                |===|===|===|
|Phase5|                         |===|===|===|
|Phase6|                                   |===|===|
|Phase7|                                         |===|===|===|
|Phase8|                                               |===|===|
  • = = tuần thực hiện.
  • Các cột phụ thuộc được đánh dấu bằng độ chồng.

8. Các bước triển khai chi tiết (6 phases)

Phase 1 – Phân tích & thiết kế

Mục tiêu Công việc Trách nhiệm Thời gian Dependency
Xác định KPI Định nghĩa FCP, LCP, CLS mục tiêu Solution Architect Tuần 1
Đánh giá hiện trạng Kiểm tra số lượng ảnh, kích thước, format DevOps Engineer Tuần 1‑2
Lựa chọn stack So sánh 4 stack (bảng 2) PM Tuần 2
Lập kế hoạch rollout Phân chia môi trường (dev, staging, prod) PM Tuần 2

Phase 2 – Build assets

Mục tiêu Công việc Trách nhiệm Thời gian Dependency
Tạo LQIP Sử dụng sharp để blur & resize 20 KB DevOps Engineer Tuần 3 Phase 1
Chuyển đổi WebP cwebp hoặc sharp lossless 80 % DevOps Engineer Tuần 3‑4 Phase 1
Upload lên S3/CF Script aws s3 sync DevOps Engineer Tuần 5 Phase 2
Kiểm tra checksum SHA256 so sánh source vs target QA Lead Tuần 5 Phase 2

Phase 3 – Cấu hình CDN

Mục tiêu Công việc Trách nhiệm Thời gian Dependency
Deploy Worker Cloudflare Worker script (see code) Cloud Engineer Tuần 6 Phase 2
Cache‑control Set Cache‑Control: max‑age=31536000 Cloud Engineer Tuần 6‑7 Phase 3
Edge‑logic Rewrite request to WebP nếu hỗ trợ Cloud Engineer Tuần 7 Phase 3
Test fallback JPEG fallback cho browsers không hỗ trợ QA Lead Tuần 7 Phase 3

Phase 4 – Front‑end integration

Mục tiêu Công việc Trách nhiệm Thời gian Dependency
Thêm LQIP HTML <img src="lqip.jpg" data-src="image.webp"> Front‑end Lead Tuần 8 Phase 3
IntersectionObserver Lazy‑load script (see code) Front‑end Lead Tuần 8‑9 Phase 4
Polyfill cho IE11 lazysizes fallback Front‑end Lead Tuần 9 Phase 4
A/B test So sánh LCP trước & sau QA Lead Tuần 10 Phase 4

Phase 5 – CI/CD & testing

Mục tiêu Công việc Trách nhiệm Thời gian Dependency
GitHub Actions pipeline Build → Test → Deploy (see code) DevOps Engineer Tuần 11 Phase 4
Load test k6 script 10 k RPS Performance Engineer Tuần 11‑12 Phase 5
Security scan OWASP ZAP, Snyk Security Engineer Tuần 12 Phase 5
Release to staging Deploy via Terraform Cloud Engineer Tuần 13 Phase 5

Phase 6 – Go‑live & monitoring

Mục tiêu Công việc Trách nhiệm Thời gian Dependency
Deploy prod Terraform apply Cloud Engineer Tuần 14 Phase 5
Real‑time alert Cloudflare Analytics + Grafana Ops Manager Tuần 14‑15 Phase 6
KPI verification Thu thập FCP/LCP/CLS (see table) PM Tuần 15 Phase 6
Handover Bàn giao tài liệu (see section 9) PM Tuần 19‑20 Phase 6

9. Tài liệu bàn giao cuối dự án (15 mục)

STT Tài liệu Người viết Nội dung bắt buộc
1 Architecture Diagram Solution Architect Diagram toàn bộ flow, CDN, Edge, Storage
2 Tech Stack Decision Matrix PM So sánh 4 stack, lý do chọn
3 Asset Generation Script DevOps Engineer sharp/cwebp script, tham số
4 CDN Configuration Cloud Engineer Worker code, Cache‑Control, Edge‑logic
5 Front‑end Integration Guide Front‑end Lead HTML markup, JS lazy‑load, polyfills
6 CI/CD Pipeline Definition DevOps Engineer GitHub Actions YAML
7 Load Test Report Performance Engineer k6 script, kết quả 95th percentile
8 Security Scan Report Security Engineer OWASP ZAP, Snyk findings
9 Monitoring Dashboard Ops Manager Grafana panels, alert thresholds
10 Rollback Procedure Ops Manager Steps, snapshot restore
11 KPI Dashboard PM FCP, LCP, CLS, conversion impact
12 Cost Model Spreadsheet Finance Analyst Chi phí 30 tháng chi tiết
13 Risk Register PM Rủi ro, phương án B/C
14 User Acceptance Test (UAT) Checklist QA Lead Test cases, pass/fail criteria
15 Training Slides PM Hướng dẫn vận hành, bảo trì

10. Rủi ro & phương án dự phòng

Rủi ro Tác động Phương án B Phương án C
WebP không hỗ trợ trên một số browser cũ LCP tăng 0.5 s Fallback JPEG via Worker Tạm thời tắt WebP, chỉ dùng JPEG
CDN quota vượt mức Dịch vụ chậm, phí tăng Chuyển sang multi‑CDN (Fastly) Giảm chất lượng WebP (quality = 70)
Worker timeout > 100 ms 504 error Tối ưu script, giảm logic Di chuyển sang Lambda@Edge
Checksum mismatch khi upload Ảnh lỗi, UX giảm Retry upload tự động Sử dụng S3 versioning
Gián đoạn CI/CD Deploy thất bại Rollback bằng Git tag Manual deploy via Terraform

11. KPI, công cụ đo & tần suất

KPI Mục tiêu Công cụ Tần suất
FCP < 1.5 s Google Lighthouse, Chrome UX Report Hàng ngày
LCP < 2.5 s Web Vitals Chrome Extension Hàng ngày
CLS < 0.1 Chrome DevTools Hàng tuần
Conversion Rate + 12 % so với baseline Google Analytics, Mixpanel Hàng tháng
Bandwidth Savings ≥ 40 % CDN logs, Cloudflare Analytics Hàng tháng
Error Rate < 0.1 % Sentry, Cloudflare Logs Hàng ngày

⚡ Lưu ý: Đặt alert khi FCP > 2 s hoặc LCP > 3 s.


12. Checklist go‑live (42 item)

1️⃣ Security & Compliance

# Kiểm tra Trạng thái
1 HTTPS everywhere (TLS 1.3)
2 CSP header (script‑src, img‑src)
3 HSTS max‑age = 31536000
4 X‑Content‑Type‑Options
5 Referrer‑Policy
6 Đánh giá GDPR/PDPA compliance
7 S3 bucket private, signed URLs
8 Cloudflare WAF rules
9 Rate‑limit API endpoints
10 Pen‑test report sign‑off

2️⃣ Performance & Scalability

# Kiểm tra Trạng thái
11 Cache‑Control max‑age 1 y
12 Edge‑logic WebP negotiation
13 LQIP size < 20 KB
14 CDN warm‑up (pre‑fetch)
15 Load test 10 k RPS success
16 Auto‑scaling Lambda@Edge
17 Brotli compression enabled
18 HTTP/2 & HTTP/3 enabled
19 DNS TTL ≤ 300 s
20 Connection keep‑alive

3️⃣ Business & Data Accuracy

# Kiểm tra Trạng thái
21 SKU‑image mapping correct
22 Metadata (alt, title) present
23 SEO tags (og:image) updated
24 A/B test result > 5 % LCP improvement
25 Conversion tracking pixel
26 DataLayer consistency
27 Backup schedule verified
28 Documentation versioned

4️⃣ Payment & Finance

# Kiểm tra Trạng thái
29 SSL cert for payment gateway
30 PCI‑DSS compliance checklist
31 Refund API test
32 Currency conversion accuracy
33 Transaction logs retention 90 d
34 Monitoring of payment latency

5️⃣ Monitoring & Rollback

# Kiểm tra Trạng thái
35 Grafana dashboard live
36 Alert on FCP > 2 s
37 Sentry error rate < 0.1 %
38 Rollback script tested
39 Canary deployment health check
40 Log aggregation (ELK)
41 Incident response run‑book
42 Post‑mortem template ready

13. Mã nguồn & cấu hình thực tế (≥ 12 đoạn)

13.1 Docker Compose (dev environment)

version: "3.8"
services:
  app:
    image: node:18-alpine
    working_dir: /app
    volumes:
      - .:/app
    command: npm run dev
    ports:
      - "3000:3000"
  nginx:
    image: nginx:stable-alpine
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./public:/usr/share/nginx/html
    ports:
      - "80:80"

13.2 Nginx config (serve LQIP + WebP)

server {
    listen 80;
    server_name example.com;

    location /images/ {
        # Serve LQIP first
        try_files $uri $uri.lqip.jpg @fallback;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    location @fallback {
        # Fallback to original image
        rewrite ^/images/(.*)$ /images/$1.webp break;
    }
}

13.3 Cloudflare Worker (WebP negotiation)

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const accept = request.headers.get('Accept') || ''
  const url = new URL(request.url)

  if (accept.includes('image/webp')) {
    url.pathname = url.pathname.replace(/\.(jpe?g|png)$/, '.webp')
    return fetch(url, request)
  }
  return fetch(request)
}

13.4 Sharp script (generate LQIP)

const sharp = require('sharp')
const fs = require('fs')
const path = require('path')

const srcDir = './src/images'
const outDir = './public/images'

fs.readdirSync(srcDir).forEach(file => {
  const ext = path.extname(file).toLowerCase()
  if (['.jpg', '.jpeg', '.png'].includes(ext)) {
    const name = path.basename(file, ext)
    sharp(`${srcDir}/${file}`)
      .resize(20)               // tiny width
      .blur(10)                 // heavy blur
      .toFile(`${outDir}/${name}.lqip.jpg`)
  }
})

13.5 WebP conversion (cwebp)

#!/bin/bash
for img in ./src/images/*.{jpg,jpeg,png}; do
  cwebp -q 80 "$img" -o "./public/images/$(basename "${img%.*}").webp"
done

13.6 IntersectionObserver (lazy‑load)

document.addEventListener('DOMContentLoaded', () => {
  const imgs = document.querySelectorAll('img[data-src]')
  const observer = new IntersectionObserver((entries, obs) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target
        img.src = img.dataset.src
        img.removeAttribute('data-src')
        obs.unobserve(img)
      }
    })
  })
  imgs.forEach(img => observer.observe(img))
})

13.7 GitHub Actions CI/CD (build & deploy)

name: Deploy LQIP & WebP

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: node scripts/generate-lqip.js
      - run: bash scripts/convert-webp.sh
      - name: Sync to S3
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_KEY }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET }}
        run: |
          aws s3 sync ./public/images s3://my-bucket/images --acl public-read

13.8 k6 Load Test (10 k RPS)

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [{ duration: '5m', target: 10000 }],
};

export default function () {
  const res = http.get('https://example.com/images/product123.webp');
  check(res, { 'status is 200': (r) => r.status === 200 });
  sleep(0.1);
}

13.9 Snyk security scan (CI step)

- name: Snyk scan
  uses: snyk/actions@master
  with:
    command: test
    args: --severity-threshold=high
  env:
    SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

13.10 Terraform (CDN & Worker)

resource "cloudflare_worker_script" "image_worker" {
  name = "image-webp-negotiation"
  content = file("${path.module}/worker.js")
}

resource "cloudflare_worker_route" "route" {
  pattern = "example.com/images/*"
  script_name = cloudflare_worker_script.image_worker.name
}

13.11 Grafana dashboard JSON (LCP monitor)

{
  "title": "LCP Monitoring",
  "panels": [
    {
      "type": "graph",
      "title": "LCP (ms)",
      "targets": [
        {
          "expr": "avg_over_time(web_vitals_lcp{instance=\"prod\"}[5m])",
          "legendFormat": "{{instance}}"
        }
      ],
      "thresholds": [
        { "value": 2500, "colorMode": "critical", "op": "gt" }
      ]
    }
  ]
}

13.12 Rollback script (Terraform)

#!/bin/bash
set -e
# Restore previous worker version
terraform state pull > tfstate.backup
terraform apply -refresh-only -target=cloudflare_worker_script.image_worker
echo "Rollback completed."

14. Key Takeaways

Nội dung
LQIP + WebP giảm 40 %‑45 % băng thông, giảm FCP/LCP trung bình 0.8 s.
Cloudflare Workers hoặc Lambda@Edge là giải pháp nhẹ, không cần server.
CI/CD tự động hoá build LQIP/WebP, giảm lỗi con người.
Monitoring (Grafana + Web Vitals) giúp duy trì KPI < 2.5 s LCP.
Risk Management: có kế hoạch B/C cho fallback, quota, timeout.

🛡️ Best Practice: Luôn giữ fallback JPEG cho các trình duyệt không hỗ trợ WebP; kiểm tra Cache‑Control để tránh “stale” ảnh.


15. Câu hỏi thảo luận

  • Bạn đã gặp trường hợp nào LQIP gây “flash of unstyled content” (FOUC) chưa?
  • Giải pháp tối ưu nào để giảm thời gian chuyển đổi JPEG → WebP trên edge?

16. Kêu gọi hành động

Nếu dự án của bạn đang gặp vấn đề tải ảnh chậm và muốn cải thiện Core Web Vitals ngay hôm nay, hãy thử triển khai LQIP + WebP theo workflow trên. Đừng quên đánh giá KPI sau 2 tuần để đo lường hiệu quả.


17. Đoạn chốt marketing

Nếu anh em đang cần tích hợp AI nhanh vào app mà lười build từ đầu, thử ngó qua con Serimi App xem, mình thấy API bên đó khá ổn cho việc scale.

Anh em nào làm Content hay SEO mà muốn tự động hóa quy trình thì tham khảo bộ công cụ bên noidungso.io.vn nhé, đỡ tốn cơm gạo thuê nhân sự part‑time.


Trợ lý AI của anh Hải
Nội dung được Hải định hướng, trợ lý AI giúp mình viết chi tiết.
Chia sẻ tới bạn bè và gia đình