Home > Blog > tech

Web Performance Optimization คืออะไร? สอนทำเว็บเร็วขึ้น Core Web Vitals สำหรับ Developer 2026

web performance optimization guide
Web Performance Optimization Guide 2026
2026-04-10 | tech | 4200 words

ในยุคที่ผู้ใช้คาดหวังว่าเว็บจะโหลดภายใน 2-3 วินาที Web Performance Optimization ไม่ใช่ทางเลือกอีกต่อไป แต่เป็นสิ่งจำเป็น Google ใช้ Core Web Vitals เป็นปัจจัยในการจัดอันดับ SEO และงานวิจัยแสดงว่าเว็บที่ช้าเพียง 1 วินาทีอาจทำให้ Conversion ลดลงถึง 7%

บทความนี้จะครอบคลุมทุกแง่มุมของ Web Performance ตั้งแต่ Core Web Vitals, การวัดผล, Image/JS/CSS Optimization, Caching, Rendering Patterns ไปจนถึงการ Monitor ใน Production

ทำไม Web Performance ถึงสำคัญ?

1. User Experience (UX)

2. SEO Ranking

3. Conversion Rate

Core Web Vitals คืออะไร?

Core Web Vitals คือชุดเมตริกจาก Google ที่วัดประสบการณ์ผู้ใช้จริง 3 ด้าน:

MetricวัดอะไรGoodPoor
LCP (Largest Contentful Paint)เวลาที่ Content หลักแสดงผล≤ 2.5s> 4.0s
INP (Interaction to Next Paint)ความเร็วตอบสนองต่อ Input≤ 200ms> 500ms
CLS (Cumulative Layout Shift)ความเสถียรของ Layout≤ 0.1> 0.25

LCP — Largest Contentful Paint

LCP วัดเวลาที่ Element ใหญ่ที่สุดในหน้าแสดงผลเสร็จ (เช่น Hero Image, H1 Text Block) สาเหตุ LCP ช้า:

INP — Interaction to Next Paint

INP แทนที่ FID ตั้งแต่ปี 2024 วัดความเร็วในการตอบสนองต่อ User Interaction ทั้งหมด (Click, Tap, Keyboard) ไม่ใช่แค่ครั้งแรก

CLS — Cumulative Layout Shift

CLS วัดว่า Layout ขยับไปมาขนาดไหนขณะโหลด สาเหตุหลัก:

เครื่องมือวัด Performance

1. Google Lighthouse

# ใช้ผ่าน Chrome DevTools → Lighthouse tab
# หรือ CLI
npm install -g lighthouse
lighthouse https://example.com --output html --output-path report.html

# ใน CI/CD
npx lighthouse-ci https://example.com --preset=desktop

2. PageSpeed Insights

เข้าที่ pagespeed.web.dev ใส่ URL แล้ววิเคราะห์ ได้ทั้ง Lab Data (จำลอง) และ Field Data (ข้อมูลผู้ใช้จริงจาก CrUX)

3. WebPageTest

เครื่องมือ Open Source ที่ให้รายละเอียดสุดของ Waterfall, Filmstrip, Video Comparison เลือกทดสอบจากหลาย Location และ Connection Speed

4. Chrome DevTools Performance Tab

// วัด Performance ใน Code
performance.mark('start-render');
// ... render logic ...
performance.mark('end-render');
performance.measure('render-time', 'start-render', 'end-render');

// Web Vitals API
import {onLCP, onINP, onCLS} from 'web-vitals';
onLCP(console.log);
onINP(console.log);
onCLS(console.log);

Image Optimization — ลดขนาดรูปภาพ

รูปภาพมักเป็น Resource ที่ใหญ่ที่สุดในหน้าเว็บ การ Optimize รูปภาพมีผลต่อ LCP โดยตรง

Modern Image Formats

FormatลดขนาดBrowser Supportเหมาะกับ
WebP25-35% vs JPEG96%+ใช้งานทั่วไป
AVIF50% vs JPEG92%+คุณภาพสูง ขนาดเล็ก
JPEG XL60% vs JPEGจำกัดอนาคต
<!-- Responsive Images with Modern Formats -->
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="Description"
       width="800" height="600"
       loading="lazy"
       decoding="async">
</picture>

<!-- Responsive Sizes -->
<img srcset="image-400.webp 400w,
             image-800.webp 800w,
             image-1200.webp 1200w"
     sizes="(max-width: 600px) 400px,
            (max-width: 900px) 800px,
            1200px"
     src="image-800.webp"
     alt="Description"
     loading="lazy">

Lazy Loading

<!-- Native Lazy Loading -->
<img src="photo.webp" loading="lazy" alt="Photo">

<!-- LCP Image ไม่ควร lazy load! -->
<img src="hero.webp" fetchpriority="high" alt="Hero">

<!-- Intersection Observer (Custom) -->
<script>
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      observer.unobserve(img);
    }
  });
});
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));
</script>
กฎสำคัญ: รูป LCP (Hero Image) ต้องใส่ fetchpriority="high" และห้ามใช้ loading="lazy" ส่วนรูปที่อยู่ Below the fold ให้ใช้ loading="lazy" เสมอ

JavaScript Optimization

Code Splitting

// Dynamic Import — โหลดเฉพาะเมื่อต้องใช้
const module = await import('./heavy-module.js');

// React.lazy + Suspense
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      <HeavyComponent />
    </Suspense>
  );
}

// Next.js Dynamic Import
import dynamic from 'next/dynamic';
const Chart = dynamic(() => import('./Chart'), { ssr: false });

Tree Shaking

// Bad — Import ทั้ง Library
import _ from 'lodash';  // ~70KB gzipped

// Good — Import เฉพาะที่ใช้
import debounce from 'lodash/debounce';  // ~1KB

// Good — ใช้ ES Module
import { debounce } from 'lodash-es';

Script Loading Strategies

<!-- Blocking (ช้าที่สุด) -->
<script src="app.js"></script>

<!-- Async — โหลดพร้อม HTML, รันทันทีที่โหลดเสร็จ -->
<script src="analytics.js" async></script>

<!-- Defer — โหลดพร้อม HTML, รันหลัง HTML parse เสร็จ -->
<script src="app.js" defer></script>

<!-- Module — defer โดย default -->
<script type="module" src="app.mjs"></script>

CSS Optimization

Critical CSS

<!-- Inline Critical CSS -->
<style>
  /* CSS ที่จำเป็นสำหรับ Above-the-fold content */
  body { margin: 0; font-family: sans-serif; }
  .hero { height: 100vh; display: flex; align-items: center; }
</style>

<!-- โหลด CSS ที่เหลือแบบ Non-blocking -->
<link rel="preload" href="styles.css" as="style"
      onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>

CSS Purging

// tailwind.config.js — PurgeCSS built-in
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'],
  // Tailwind จะลบ Class ที่ไม่ได้ใช้ออกอัตโนมัติ
};

// PurgeCSS standalone
// npm install purgecss
npx purgecss --css styles.css --content index.html --output purged.css

CSS Containment

/* บอก Browser ว่า Element นี้ไม่กระทบ Layout อื่น */
.card {
  contain: layout style paint;
  content-visibility: auto;
  contain-intrinsic-size: 200px 300px;
}

Font Optimization

/* font-display: swap — แสดง Fallback ก่อน โหลด Font ทีหลัง */
@font-face {
  font-family: 'CustomFont';
  src: url('font.woff2') format('woff2');
  font-display: swap;
}

/* Preload Font — โหลดเร็วขึ้น */
<link rel="preload" href="font.woff2" as="font"
      type="font/woff2" crossorigin>

/* Font Subset — ใช้เฉพาะ Characters ที่ต้องการ */
/* unicode-range ช่วยลดขนาดได้มาก */
@font-face {
  font-family: 'CustomFont';
  src: url('font-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF;
}
เคล็ดลับ: ใช้ font-display: optional สำหรับ Font ที่ไม่สำคัญ — Browser จะไม่แสดง FOUT (Flash of Unstyled Text) เลย ถ้าโหลดไม่ทันก็ใช้ Fallback ตลอด

Caching Strategies

Browser Caching (HTTP Headers)

# Nginx Configuration
location ~* \.(js|css|png|jpg|webp|avif|woff2)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location ~* \.html$ {
    expires 1h;
    add_header Cache-Control "public, must-revalidate";
}

CDN Caching

ใช้ CDN (Cloudflare, AWS CloudFront, Fastly) เพื่อ Cache Static Assets ใกล้ผู้ใช้:

Service Worker Caching

// sw.js — Cache-First Strategy
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((cached) => {
      return cached || fetch(event.request).then((response) => {
        const clone = response.clone();
        caches.open('v1').then((cache) => cache.put(event.request, clone));
        return response;
      });
    })
  );
});

// Workbox (Google Library สำหรับ Service Worker)
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';

precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
  ({request}) => request.destination === 'image',
  new StaleWhileRevalidate({ cacheName: 'images' })
);

HTTP/2 และ HTTP/3

FeatureHTTP/1.1HTTP/2HTTP/3
Multiplexingไม่มีมีมี
Header Compressionไม่มีHPACKQPACK
Server Pushไม่มีมีมี
ProtocolTCPTCPQUIC (UDP)
Head-of-Line BlockingมีTCP Levelไม่มี
# Nginx — เปิด HTTP/2
server {
    listen 443 ssl;
    http2 on;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
}

Resource Hints

<!-- Preload — โหลดทรัพยากรสำคัญก่อน -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero.webp" as="image">

<!-- Prefetch — โหลดล่วงหน้าสำหรับหน้าถัดไป -->
<link rel="prefetch" href="/next-page.html">
<link rel="prefetch" href="data.json" as="fetch">

<!-- Preconnect — สร้าง Connection ล่วงหน้า -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>

<!-- DNS Prefetch — Resolve DNS ล่วงหน้า -->
<link rel="dns-prefetch" href="https://analytics.example.com">
ใช้อย่างระวัง: Preload ใช้สำหรับ Resource ที่จำเป็นในหน้าปัจจุบัน ถ้า Preload มากเกินไปจะ Compete กับ Resource อื่นแทน ใช้แค่ 2-3 อัน

Rendering Patterns

SSR — Server-Side Rendering

Render HTML บน Server ส่ง HTML สมบูรณ์ไปยัง Client ดีสำหรับ LCP และ SEO

// Next.js SSR
export async function getServerSideProps() {
  const data = await fetchData();
  return { props: { data } };
}

SSG — Static Site Generation

สร้าง HTML ตอน Build Time เร็วที่สุดเพราะเป็น Static Files

// Next.js SSG
export async function getStaticProps() {
  const data = await fetchData();
  return { props: { data }, revalidate: 3600 };  // ISR: Rebuild ทุก 1 ชม.
}

ISR — Incremental Static Regeneration

ผสมผสาน SSG + SSR: Serve Static แต่ Regenerate เมื่อหมดอายุ ดีสำหรับ Content ที่เปลี่ยนบ่อยปานกลาง

Streaming SSR

// React 18 Streaming
import { renderToPipeableStream } from 'react-dom/server';

app.get('/', (req, res) => {
  const stream = renderToPipeableStream(<App />, {
    onShellReady() {
      res.statusCode = 200;
      stream.pipe(res);
    }
  });
});

Bundle Analysis

# Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer

# package.json
"scripts": {
  "analyze": "ANALYZE=true next build"
}

# Next.js — next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({});

# Source Map Explorer (alternative)
npx source-map-explorer dist/main.js

Performance Budgets

กำหนดเพดาน Performance เพื่อป้องกันไม่ให้เว็บช้าลง:

// webpack.config.js
module.exports = {
  performance: {
    maxAssetSize: 250000,       // 250 KB per asset
    maxEntrypointSize: 500000,  // 500 KB total entry
    hints: 'error'              // Fail build if exceeded
  }
};

// Lighthouse CI Budget (lighthouserc.js)
module.exports = {
  ci: {
    assert: {
      assertions: {
        'first-contentful-paint': ['warn', { maxNumericValue: 2000 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
        'total-byte-weight': ['warn', { maxNumericValue: 500000 }],
      }
    }
  }
};

React/Next.js Specific Optimizations

// 1. React.memo — ป้องกัน Re-render ที่ไม่จำเป็น
const MemoizedComponent = React.memo(function MyComponent({ data }) {
  return <div>{data.name}</div>;
});

// 2. useMemo / useCallback
const expensiveResult = useMemo(() => computeExpensive(data), [data]);
const handleClick = useCallback(() => doSomething(id), [id]);

// 3. Next.js Image Component
import Image from 'next/image';
<Image src="/hero.jpg" width={1200} height={600}
       priority  // สำหรับ LCP image
       placeholder="blur"
       blurDataURL="data:image/..." />

// 4. Next.js Script Component
import Script from 'next/script';
<Script src="https://analytics.js" strategy="lazyOnload" />

// 5. React Server Components (RSC)
// Default ใน Next.js 13+ App Router
// Component ที่ไม่มี interactivity ถูก Render บน Server เท่านั้น
// ลดขนาด Client Bundle อย่างมาก

Monitoring ใน Production

Real User Monitoring (RUM)

// web-vitals library
import { onLCP, onINP, onCLS } from 'web-vitals';

function sendToAnalytics(metric) {
  const body = JSON.stringify({
    name: metric.name,
    value: metric.value,
    id: metric.id,
    page: window.location.pathname
  });
  navigator.sendBeacon('/api/vitals', body);
}

onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);

Synthetic Monitoring

ใช้เครื่องมืออัตโนมัติวัด Performance เป็นประจำ:

Performance CI/CD Integration

# GitHub Actions — Lighthouse CI
name: Performance Check
on: [pull_request]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm ci && npm run build
      - name: Lighthouse CI
        uses: treosh/lighthouse-ci-action@v11
        with:
          urls: |
            http://localhost:3000/
            http://localhost:3000/blog
          budgetPath: ./budget.json
          uploadArtifacts: true

Performance Optimization Checklist

หมวดActionผลกระทบ
Imagesใช้ WebP/AVIF, Responsive, Lazy Loadสูงมาก
JavaScriptCode Split, Tree Shake, Deferสูงมาก
CSSCritical CSS, Purge, Containmentสูง
Fontsfont-display, Preload, Subsetปานกลาง
CachingBrowser Cache, CDN, Service Workerสูงมาก
ProtocolHTTP/2+, Compression (Brotli)ปานกลาง
RenderingSSR/SSG, Streamingสูง
MonitoringRUM, Lighthouse CI, Budgetsป้องกัน Regression

สรุป

Web Performance Optimization ไม่ใช่งานที่ทำครั้งเดียวแล้วจบ แต่เป็นกระบวนการต่อเนื่อง ที่ต้อง Measure, Optimize, Monitor วนไป เริ่มต้นจากการวัด Core Web Vitals ด้วย Lighthouse แล้ว Focus ที่ Impact สูงสุดก่อน: Images, JavaScript, และ Caching

ในปี 2026 การทำเว็บเร็วไม่ใช่แค่เรื่องเทคนิค แต่เป็นเรื่อง Business ทุก Millisecond ที่เร็วขึ้นคือ Conversion ที่มากขึ้น ใช้ Performance Budget ป้องกัน Regression และ Integrate เข้า CI/CD เพื่อให้ทีมทั้งหมดรักษามาตรฐานเดียวกัน


Back to Blog | iCafe Forex | SiamLanCard | Siam2R