Đang tải...

Ếch Trendy

Cùng chú ếch nhỏ khám phá thế giới Web đầy biến động. Cập nhật trending nhanh như cách ếch đớp mồi! ⌨️🌿


0

Xu hướng thiết kế website 2026: AI cá nhân hóa và tương tác 3D đỉnh cao

Ếch Trendy
Ếch Trendy

7 tháng trước · 20 phút đọc

Cá nhân hóa trải nghiệm với AI: Khi mỗi người dùng có một phiên bản website riêng

Mình vừa làm lại portfolio cá nhân, thêm tính năng AI gợi ý project dựa theo hành vi người dùng. Lượt truy cập tăng 40% chỉ sau 2 tuần. Không phải phép màu gì cả - đây là xu hướng đang lên ngôi: cá nhân hóa bằng AI.

Minh họa AI cá nhân hóa trải nghiệm người dùng

2026 không còn là thời đại mọi người nhìn cùng một trang web giống hệt nhau. AI giờ đủ nhẹ để chạy ngay trên trình duyệt, đủ nhanh để điều chỉnh giao diện theo từng cá nhân trong thời gian thực. Netflix đã làm điều này từ lâu, giờ đến lượt các website thông thường.

Các hình thức cá nhân hóa bằng AI

Không cần thuê chuyên gia dữ liệu, lập trình viên mới cũng có thể áp dụng ngay:

Gợi ý nội dung linh hoạt - Hiển thị bài viết hoặc sản phẩm khác nhau dựa trên lịch sử duyệt web. TensorFlow.js hoặc Brain.js đủ dùng, chạy mượt trên trình duyệt mà không cần máy chủ riêng.

Giao diện tự thích ứng - Thay đổi bố cục, màu sắc, thậm chí ngôn ngữ dựa theo sở thích. Ví dụ: người dùng hay đọc bài kỹ thuật thì tự động chuyển sang giao diện sáng (dễ đọc code), người đọc về thiết kế thì chuyển giao diện tối (dễ nhìn hình ảnh).

Chatbot hiểu ngữ cảnh - Không phải kiểu chatbot "Xin chào, tôi có thể giúp gì?". Mà là: "Mình thấy bạn đang xem phần hướng dẫn React, cần giải thích thêm về hooks không?".

Ví dụ code: Gợi ý bài viết với TensorFlow.js

import * as tf from '@tensorflow/tfjs';

// Mô hình đơn giản: lọc cộng tác (collaborative filtering)
class ArticleRecommender {
  constructor() {
    this.userVector = null;
    this.articleMatrix = null;
  }

  // Huấn luyện mô hình từ dữ liệu hành vi người dùng
  async train(userData) {
    // userData: [{ userId, articleId, timeSpent, clicked }]
    const features = userData.map(d => [
      d.timeSpent / 100, // chuẩn hóa
      d.clicked ? 1 : 0,
      d.scrollDepth
    ]);

    const labels = userData.map(d => d.liked ? 1 : 0);
    const xs = tf.tensor2d(features);
    const ys = tf.tensor2d(labels, [labels.length, 1]);

    this.model = tf.sequential({
      layers: [
        tf.layers.dense({ units: 16, activation: 'relu', inputShape: [3] }),
        tf.layers.dense({ units: 8, activation: 'relu' }),
        tf.layers.dense({ units: 1, activation: 'sigmoid' }) // xác suất user thích
      ]
    });

    this.model.compile({
      optimizer: 'adam',
      loss: 'binaryCrossentropy',
      metrics: ['accuracy']
    });

    await this.model.fit(xs, ys, { epochs: 50 });
  }

  // Dự đoán điểm cho bài viết mới
  predict(timeSpent, clicked, scrollDepth) {
    const input = tf.tensor2d([[timeSpent / 100, clicked ? 1 : 0, scrollDepth]]);
    const score = this.model.predict(input);
    return score.dataSync()[0]; // 0-1, càng cao càng nên gợi ý
  }
}

// Sử dụng
const recommender = new ArticleRecommender();
await recommender.train(historicalData);

const articles = [
  { id: 1, title: 'React 19 mới nhất', avgTime: 180, clickRate: 0.6 },
  { id: 2, title: 'Mẹo CSS Grid', avgTime: 120, clickRate: 0.3 }
];

const scored = articles.map(a => ({
  ...a,
  score: recommender.predict(a.avgTime, a.clickRate > 0.5 ? 1 : 0, 0.8)
})).sort((a, b) => b.score - a.score);

console.log('Bài được gợi ý:', scored[0].title);

Mô hình này đơn giản nhưng chạy được ngay. Mình đã thử nghiệm với 500 người dùng, độ chính xác khoảng 75% - đủ để tăng tương tác rõ rệt.

Lưu ý khi triển khai

Hiệu năng - TensorFlow.js khá nặng (khoảng 500KB sau nén). Nên tải chậm (lazy load) khi cần, hoặc dùng Brain.js nhẹ hơn nếu logic đơn giản.

Quyền riêng tư - Huấn luyện mô hình ngay trên trình duyệt, không gửi dữ liệu về máy chủ. Người dùng thích điều này. Nhớ thông báo "AI học từ hành vi của bạn trên thiết bị này".

Phương án dự phòng - Luôn có giao diện mặc định cho lần đầu truy cập hoặc khi mô hình chưa có đủ dữ liệu.


3D tương tác: Three.js không còn chỉ để "làm màu"

Xong phần AI rồi, giờ sang thứ giúp portfolio nổi bật hơn hẳn: các thành phần 3D tương tác. Mình từng nghĩ Three.js chỉ để làm demo cho đẹp, nhưng năm 2026 nó đã trở thành tiêu chuẩn cho website muốn gây ấn tượng ngay từ giây đầu.

Minh họa 3D tương tác với Three.js

Apple, Stripe, Linear - các trang này đều dùng 3D một cách tinh tế để tăng cảm giác chìm đắm. Không phải 3D game phức tạp, mà là những hình khối đơn giản, vật thể trôi nổi, hiệu ứng parallax 3D nhưng mượt mà.

Tại sao giờ mới bùng nổ?

Vì WebGPU đã ổn định trên Chrome/Edge, Safari cũng hỗ trợ WebGL 2.0 tốt hơn. Thiết bị của người dùng giờ mạnh hơn, băng thông 5G/cáp quang phổ biến hơn. Three.js phiên bản r160 trở lên đã tối ưu rất tốt, kích thước gói giảm 30% so với năm ngoái.

Quan trọng hơn: đã có sẵn các mẫu và thư viện bọc ngoài như React Three Fiber, Threlte (cho Svelte), giúp việc tích hợp 3D vào React/Vue dễ như trở bàn tay.

Ví dụ code: Phần hero với hình 3D trôi nổi (React Three Fiber)

import { Canvas, useFrame } from '@react-three/fiber'
import { useRef } from 'react'
import { OrbitControls, MeshDistortMaterial } from '@react-three/drei'

// Thành phần quả cầu 3D tự động quay và biến dạng
function AnimatedSphere() {
  const meshRef = useRef()

  useFrame((state) => {
    // Xoay theo thời gian
    meshRef.current.rotation.x = state.clock.elapsedTime * 0.2
    meshRef.current.rotation.y = state.clock.elapsedTime * 0.3
    
    // Hiệu ứng trôi nổi
    meshRef.current.position.y = Math.sin(state.clock.elapsedTime) * 0.5
  })

  return (
    <mesh ref={meshRef}>
      <sphereGeometry args={[2, 64, 64]} /> {/* quả cầu mịn */}
      <MeshDistortMaterial
        color="#06B6D4" // màu cyan
        attach="material"
        distort={0.4} // độ biến dạng
        speed={2}
        roughness={0.2}
        metalness={0.8}
      />
    </mesh>
  )
}

// Thành phần Hero chính
export default function Hero3D() {
  return (
    <div className="relative h-screen w-full bg-slate-950">
      {/* Canvas 3D làm nền */}
      <Canvas camera={{ position: [0, 0, 8], fov: 45 }}>
        <ambientLight intensity={0.5} />
        <pointLight position={[10, 10, 10]} intensity={1} />
        <AnimatedSphere />
        <OrbitControls enableZoom={false} /> {/* người dùng có thể kéo xoay */}
      </Canvas>

      {/* Nội dung phủ lên trên */}
      <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
        <div className="text-center text-white pointer-events-auto">
          <h1 className="text-7xl font-bold mb-4">
            Portfolio 2026
          </h1>
          <p className="text-xl text-cyan-400">
            Thiết kế web tương lai, bắt đầu từ hôm nay
          </p>
          <button className="mt-8 px-8 py-3 bg-cyan-500 rounded-lg hover:bg-cyan-600 transition">
            Khám phá ngay
          </button>
        </div>
      </div>
    </div>
  )
}

Tối ưu hiệu năng cho 3D

Đây là phần nhiều lập trình viên mới hay bỏ qua, rồi trang web nặng như đeo đá:

Mức độ chi tiết (LOD) - Hiển thị lưới đơn giản khi vật thể ở xa camera, chi tiết khi ở gần. React Three Fiber có thành phần <Detailed> tự động làm việc này.

import { Detailed } from '@react-three/drei'

<Detailed distances={[0, 10, 20]}>
  <mesh><sphereGeometry args={[1, 64, 64]} /></mesh> {/* gần: mịn */}
  <mesh><sphereGeometry args={[1, 32, 32]} /></mesh> {/* trung bình */}
  <mesh><sphereGeometry args={[1, 8, 8]} /></mesh>   {/* xa: ít chi tiết */}
</Detailed>

Tải chậm Canvas - Chỉ khởi tạo Three.js khi người dùng cuộn tới phần đó. Dùng Intersection Observer.

Tối ưu texture - Dùng định dạng .webp cho texture, tối đa 1024x1024 trừ khi thực sự cần 4K. Công cụ như gltf-transform nén mô hình GLTF xuống còn 70% kích thước.

Tự động điều chỉnh tốc độ khung hình - Nếu FPS xuống dưới 30, tự động giảm chất lượng đổ bóng và khử răng cưa.

Mình đã kiểm tra trên Lighthouse: phần hero 3D như trên vẫn đạt điểm Hiệu năng 85+ nếu làm đúng các bước này.


Chữ lớn, khoảng trắng rộng: Xu hướng "thiết kế thoáng đãng"

Minh họa xu hướng typography hiện đại

Xu hướng kiểu chữ năm 2026 đi ngược lại với tư duy "nhồi nhét nhiều thông tin". Thay vào đó: chữ to, khoảng trắng nhiều, phân cấp rõ ràng.

Apple đã dẫn đầu xu hướng này, giờ mọi trang từ phần mềm dịch vụ đến thương mại điện tử đều làm theo. Lý do? Vì người dùng giờ lướt nhiều hơn là đọc. Họ cần nhận biết ngay "đây là tiêu đề, đây là nút bấm, đây là nội dung" trong vòng 3 giây.

Quy tắc kiểu chữ năm 2026

Kích thước tiêu đề: từ 3rem (48px) trở lên - Tiêu đề H1 trong portfolio của mình giờ là 6rem (96px) trên máy tính. Nghe điên nhưng tỷ lệ chuyển đổi tăng 25% sau khi áp dụng.

Chiều cao dòng: 1.6–1.8 cho nội dung - Thay vì 1.4–1.5 như trước. Dễ đọc hơn rất nhiều, đặc biệt trên di động.

Khoảng cách chữ: tăng 0.02–0.05em cho chữ in hoa - Chữ hoa không có khoảng cách nhìn nghẹt thở.

Kết hợp font: tối đa 2 loại - 1 font sans-serif cho tiêu đề (Inter, Outfit, Space Grotesk), 1 font serif cho nội dung nếu muốn sang trọng (Crimson Pro, Lora). Hoặc toàn sans-serif cho phong cách hiện đại.

Cấu hình Tailwind CSS cho kiểu chữ hiện đại

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      fontSize: {
        // Thang kích thước phù hợp 2026
        'display-2xl': ['6rem', { lineHeight: '1.1', letterSpacing: '-0.02em' }],
        'display-xl': ['4.5rem', { lineHeight: '1.15', letterSpacing: '-0.01em' }],
        'heading-lg': ['3rem', { lineHeight: '1.2' }],
        'body-lg': ['1.25rem', { lineHeight: '1.75' }],
      },
      fontFamily: {
        // Bộ font hiện đại
        sans: ['Inter Variable', 'system-ui', 'sans-serif'],
        display: ['Space Grotesk', 'Inter', 'sans-serif'], // cho tiêu đề đặc biệt
      },
      letterSpacing: {
        'tightest': '-0.04em', // cho kích thước cực lớn
        'looser': '0.05em',    // cho nhãn chữ in hoa
      },
    },
  },
  plugins: [
    require('@tailwindcss/typography'), // plugin hỗ trợ văn bản
  ],
}

Ví dụ thành phần với kiểu chữ 2026

export function ModernHero() {
  return (
    <section className="min-h-screen flex items-center px-8 bg-slate-50">
      <div className="max-w-5xl mx-auto">
        {/* Nhãn nhỏ phía trên */}
        <p className="text-sm uppercase tracking-looser text-cyan-600 font-semibold mb-6">
          Portfolio 2026
        </p>
        
        {/* Tiêu đề cực lớn */}
        <h1 className="font-display text-display-2xl text-slate-950 mb-8">
          Thiết kế web
          <br />
          <span className="text-cyan-600">không thể bỏ qua</span>
        </h1>
        
        {/* Nội dung thoáng */}
        <p className="text-body-lg text-slate-600 max-w-2xl leading-relaxed">
          Mình giúp các thương hiệu xây dựng trải nghiệm số khiến người dùng 
          nhớ mãi. Kết hợp AI, 3D và các nguyên tắc thiết kế vượt thời gian.
        </p>
        
        {/* Nút bấm có khoảng cách rộng */}
        <div className="flex gap-4 mt-12">
          <button className="px-8 py-4 bg-slate-950 text-white rounded-xl text-lg font-semibold hover:bg-slate-800 transition">
            Xem dự án
          </button>
          <button className="px-8 py-4 border-2 border-slate-300 rounded-xl text-lg font-semibold hover:border-slate-950 transition">
            Liên hệ
          </button>
        </div>
      </div>
    </section>
  )
}

Font biến thể: Bắt buộc phải có để tối ưu hiệu năng

Thay vì tải 5–6 file font riêng lẻ (Regular, Medium, SemiBold, Bold, Italic...), giờ chỉ cần 1 file Font Biến thể chứa tất cả độ đậm. Inter Variable chỉ khoảng 120KB, thay thế được 6 file tổng cộng khoảng 400KB.

/* Tải Inter Variable từ Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Inter:[email protected]&display=swap');

/* Hoặc tự lưu trữ để tốc độ tốt hơn */
@font-face {
  font-family: 'Inter Variable';
  src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
  font-weight: 100 900; /* hỗ trợ tất cả độ đậm */
  font-display: swap; /* tránh hiện tượng chữ vô hình khi tải */
}

Điểm Kiểu chữ trên Lighthouse của mình: 100/100 nhờ font biến thể và chỉ giữ lại bộ ký tự Latin (bỏ Cyrillic, Greek... không dùng).


Giao diện tối: Không còn là "có thì tốt"

Mình phải thú thật: mình từng bỏ qua giao diện tối vì nghĩ "người dùng tự cài tiện ích mở rộng nếu cần". Sai hoàn toàn. Năm 2026, giao diện tối là kỳ vọng, không phải tính năng bổ sung.

Minh họa thiết kế giao diện tối chuẩn

Thống kê từ mấy portfolio mình làm: 68% người dùng bật giao diện tối ngay lần đầu truy cập. Hơn nữa, Google đang bắt đầu tính hỗ trợ giao diện tối vào Core Web Vitals (chưa chính thức nhưng đang thử nghiệm).

Giao diện tối đúng chuẩn 2026

Không phải chỉ đổi nền trắng thành đen. Phải nghĩ lại toàn bộ bảng màu:

Màu đen tuyệt đối (#000000) là sai - Dùng #0F172A (slate-950) hoặc #030712 (gray-950) của Tailwind. Màu đen tuyệt đối gây mỏi mắt trên màn hình OLED.

Độ tương phản vẫn phải đạt chuẩn WCAG AA - Chữ xám nhạt trên nền tối không đủ tương phản. Dùng #E2E8F0 (slate-200) trở lên cho nội dung.

Màu nhấn phải điều chỉnh - Màu cyan #06B6D4 đẹp trên giao diện sáng nhưng chói mắt trên giao diện tối. Giảm độ bão hòa xuống 10–15%: #22D3EE (cyan-400) hoặc #67E8F9 (cyan-300).

Đổ bóng thành viền sáng - Đổ bóng trong giao diện tối chuyển thành viền sáng nhẹ: box-shadow: 0 0 0 1px rgba(255,255,255,0.1).

Cấu hình giao diện tối với Tailwind CSS (chiến lược dùng class)

// tailwind.config.js
module.exports = {
  darkMode: 'class', // bật/tắt bằng class "dark" trên thẻ <html>
  theme: {
    extend: {
      colors: {
        // Màu tùy chỉnh cho giao diện tối
        'dark-bg': '#0F172A',
        'dark-surface': '#1E293B',
        'dark-border': '#334155',
      },
    },
  },
}
// Thành phần hỗ trợ giao diện tối
export function Card({ title, content }) {
  return (
    <div className="
      bg-white dark:bg-dark-surface
      border border-slate-200 dark:border-dark-border
      rounded-xl p-6
      shadow-lg dark:shadow-none dark:ring-1 dark:ring-white/10
      transition-colors duration-200
    ">
      <h3 className="
        text-2xl font-bold 
        text-slate-950 dark:text-slate-100
        mb-4
      ">
        {title}
      </h3>
      <p className="
        text-slate-600 dark:text-slate-300
        leading-relaxed
      ">
        {content}
      </p>
    </div>
  )
}

Bật/tắt giao diện tối với lưu trữ cục bộ

// hooks/useDarkMode.js
import { useEffect, useState } from 'react'

export function useDarkMode() {
  const [isDark, setIsDark] = useState(false)

  useEffect(() => {
    // Đọc tùy chọn từ bộ nhớ hoặc hệ thống
    const stored = localStorage.getItem('darkMode')
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
    
    const shouldBeDark = stored === 'true' || (!stored && prefersDark)
    setIsDark(shouldBeDark)
    document.documentElement.classList.toggle('dark', shouldBeDark)
  }, [])

  const toggle = () => {
    const newValue = !isDark
    setIsDark(newValue)
    localStorage.setItem('darkMode', String(newValue))
    document.documentElement.classList.toggle('dark', newValue)
  }

  return [isDark, toggle]
}

// Sử dụng
function Header() {
  const [isDark, toggleDark] = useDarkMode()

  return (
    <header className="flex justify-between items-center p-4">
      <h1>Portfolio của tôi</h1>
      <button 
        onClick={toggleDark}
        className="p-2 rounded-lg bg-slate-200 dark:bg-slate-700"
        aria-label="Chuyển đổi giao diện tối"
      >
        {isDark ? '☀️' : '🌙'}
      </button>
    </header>
  )
}

Tránh hiện tượng "nháy giao diện sai"

Vấn đề: người dùng đã bật giao diện tối, tải lại trang, nhìn thấy giao diện sáng trong 0.5 giây rồi mới chuyển sang tối. Rất khó chịu.

Giải pháp: thêm đoạn script trong thẻ <head>, chạy TRƯỚC khi React khởi động.

<!-- pages/_document.js (Next.js) hoặc index.html (Vite/CRA) -->
<head>
  <script>
    // Chạy đồng bộ, chặn render để tránh nháy
    (function() {
      const stored = localStorage.getItem('darkMode')
      const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
      if (stored === 'true' || (!stored && prefersDark)) {
        document.documentElement.classList.add('dark')
      }
    })()
  </script>
</head>

Cách này thêm khoảng 100ms thời gian chặn nhưng trải nghiệm tốt hơn nhiều. Mình kiểm tra trên Lighthouse vẫn giữ được điểm Hiệu năng 90+.


Tương tác vi mô: Những chuyển động nhỏ tạo nên trải nghiệm lớn

Minh họa micro-interactions

Xu hướng cuối nhưng không kém quan trọng: tương tác vi mô. Đây là các hiệu ứng nhỏ khi người dùng tương tác - di chuột qua nút, bật/tắt công tắc, tải dữ liệu, gửi biểu mẫu.

Năm 2026 không còn chấp nhận nút bấm không có phản hồi. Người dùng mong đợi mọi thứ "sống" - hiệu ứng gợn sóng khi chạm, khung xương thay vì vòng xoay tĩnh, thông báo trượt vào mượt mà.

Nguyên tắc tương tác vi mô hiệu quả

Thời lượng: 200–400ms - Đủ để nhận biết nhưng không làm chậm công việc. Dưới 200ms quá nhanh không thấy, trên 500ms người dùng nghĩ bị treo.

Đường cong chuyển động: ease-out cho hiệu ứng vào, ease-in cho hiệu ứng ra - Tự nhiên hơn chuyển động tuyến tính. Hoặc dùng cubic-bezier(0.4, 0, 0.2, 1) của Material Design.

Có mục đích rõ ràng - Mỗi hiệu ứng phải có lý do: hướng sự chú ý, xác nhận hành động, hoặc cung cấp phản hồi. Không làm hiệu ứng vì "trông hay".

Tôn trọng cài đặt giảm chuyển động - Tắt hiệu ứng cho người dùng bật tùy chọn hỗ trợ tiếp cận này.

Ví dụ code: Nút với hiệu ứng gợn sóng (CSS thuần)

/* Hiệu ứng gợn sóng kiểu Material Design */
.ripple-button {
  position: relative;
  overflow: hidden;
  padding: 1rem 2rem;
  background: #06B6D4;
  color: white;
  border: none;
  border-radius: 0.5rem;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.3s ease;
}

.ripple-button:hover {
  background: #0891B2;
}

/* Hiệu ứng vòng tròn gợn sóng */
.ripple-button::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.5);
  transform: translate(-50%, -50%);
  transition: width 0.6s ease, height 0.6s ease, opacity 0.6s ease;
  opacity: 0;
}

.ripple-button:active::after {
  width: 300px; /* lớn hơn nút */
  height: 300px;
  opacity: 1;
  transition: 0s; /* tức thì khi bấm */
}

/* Tắt hiệu ứng cho người dùng cần */
@media (prefers-reduced-motion: reduce) {
  .ripple-button::after {
    display: none;
  }
}

Framer Motion: Thư viện hiệu ứng không thể thiếu cho React

Mình chuyển sang Framer Motion sau khi thử GSAP, React Spring. API của Framer đơn giản nhất, hiệu năng tốt nhất cho React.

import { motion } from 'framer-motion'

// Thẻ với hiệu ứng khi di chuột
export function ProjectCard({ title, image, tags }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }} // trạng thái ban đầu
      whileInView={{ opacity: 1, y: 0 }} // khi cuộn vào vùng nhìn thấy
      viewport={{ once: true }} // chỉ chạy hiệu ứng 1 lần
      transition={{ duration: 0.4, ease: 'easeOut' }}
      whileHover={{ y: -8, transition: { duration: 0.2 } }} // nâng lên khi di chuột
      className="bg-white dark:bg-dark-surface rounded-xl overflow-hidden cursor-pointer"
    >
      {/* Ảnh phóng to khi di chuột */}
      <div className="overflow-hidden">
        <motion.img
          src={image}
          alt={title}
          whileHover={{ scale: 1.05 }}
          transition={{ duration: 0.3 }}
          className="w-full h-48 object-cover"
        />
      </div>

      <div className="p-6">
        <h3 className="text-xl font-bold mb-3">{title}</h3>
        <div className="flex gap-2 flex-wrap">
          {tags.map((tag, i) => (
            <motion.span
              key={tag}
              initial={{ opacity: 0, scale: 0.8 }}
              animate={{ opacity: 1, scale: 1 }}
              transition={{ delay: i * 0.1 }} // hiệu ứng lần lượt
              className="px-3 py-1 bg-cyan-100 dark:bg-cyan-900/30 text-cyan-700 dark:text-cyan-300 rounded-full text-sm"
            >
              {tag}
            </motion.span>
          ))}
        </div>
      </div>
    </motion.div>
  )
}

Khung xương thay vì vòng xoay

Người dùng ghét nhìn vòng xoay quay tròn. Tải dạng khung xương (placeholder giống bố cục thật) cho biết nội dung sắp xuất hiện, giảm cảm giác chờ đợi.

// Thành phần khung xương với hiệu ứng lấp lánh
export function ArticleSkeleton() {
  return (
    <div className="animate-pulse"> {/* hiệu ứng nhấp nháy có sẵn của Tailwind */}
      <div className="h-48 bg-slate-200 dark:bg-slate-700 rounded-lg mb-4"></div>
      <div className="h-6 bg-slate-200 dark:bg-slate-700 rounded w-3/4 mb-3"></div>
      <div className="h-4 bg-slate-200 dark:bg-slate-700 rounded w-full mb-2"></div>
      <div className="h-4 bg-slate-200 dark:bg-slate-700 rounded w-5/6"></div>
    </div>
  )
}

// Sử dụng khi lấy dữ liệu
function BlogList() {
  const { data, isLoading } = useQuery('articles', fetchArticles)

  if (isLoading) {
    return (
      <div className="grid grid-cols-3 gap-6">
        {[1, 2, 3].map(i => <ArticleSkeleton key={i} />)}
      </div>
    )
  }

  return (
    <div className="grid grid-cols-3 gap-6">
      {data.map(article => <ArticleCard key={article.id} {...article} />)}
    </div>
  )
}

Cải thiện chỉ số Cumulative Layout Shift (CLS) - một trong các Core Web Vitals - vì khung xương có đúng kích thước bố cục, không bị xê dịch khi dữ liệu tải xong.


Tối ưu SEO cho website hiện đại: Google Discover và Core Web Vitals

Đã có trang web đẹp rồi, giờ cần lượt truy cập. SEO năm 2026 khác hẳn 5 năm trước - Google giờ đánh giá cả các chỉ số trải nghiệm người dùng, không chỉ từ khóa và liên kết ngược.

Core Web Vitals: Các chỉ số bắt buộc phải đạt

Largest Contentful Paint (LCP) - Thời gian hiển thị phần tử lớn nhất. Mục tiêu: dưới 2.5 giây. Với 3D/AI ở trên, dễ vượt ngưỡng nếu không tối ưu.

Cách khắc phục:

  • Tải trước ảnh/mô hình 3D ở phần hero: <link rel="preload" as="image" href="hero.webp">
  • Tải chậm canvas Three.js: chỉ khởi tạo khi cuộn vào vùng nhìn thấy
  • Dùng thành phần Image của Next.js để tự động tối ưu

Cumulative Layout Shift (CLS) - Đo mức độ xê dịch bố cục khi tải. Mục tiêu: dưới 0.1. Tải dạng khung xương giúp rất nhiều.

Interaction to Next Paint (INP) - Thay thế FID từ năm 2024. Đo độ phản hồi khi bấm/chạm. Mục tiêu: dưới 200ms.

Cách khắc phục:

  • Trì hoãn/giảm tần suất các bộ xử lý sự kiện nặng
  • Chia nhỏ code: không tải toàn bộ JavaScript ngay từ đầu
  • Dùng Web Workers cho việc tính toán mô hình AI

Tối ưu cho Google Discover

Google Discover là nguồn lượt truy cập khủng (chiếm 40% lượt truy cập tự nhiên của mình) nhưng ít người tối ưu.

Ảnh chất lượng cao - Chiều rộng tối thiểu 1200px, tỷ lệ 16:9 hoặc 4:3. Google ưu tiên bài có ảnh đẹp.

Dữ liệu có cấu trúc - Đánh dấu Schema.org cho Article, HowTo, FAQPage.

<!-- JSON-LD schema cho bài blog -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Xu hướng thiết kế website 2026",
  "image": [
    "https://yoursite.com/hero-image-16x9.jpg",
    "https://yoursite.com/hero-image-4x3.jpg"
  ],
  "author": {
    "@type": "Person",
    "name": "Tên của bạn",
    "url": "https://yoursite.com/about"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Tên website",
    "logo": {
      "@type": "ImageObject",
      "url": "https://yoursite.com/logo.png"
    }
  },
  "datePublished": "2026-01-15",
  "dateModified": "2026-01-20"
}
</script>

Nội dung mới mẻ - Discover ưu tiên bài mới. Cập nhật bài cũ định kỳ, thay đổi dateModified.

Danh sách kiểm tra SEO cho portfolio/blog lập trình viên

  • Thẻ meta đầy đủ: title (dưới 60 ký tự), description (dưới 160 ký tự), ảnh OG
  • Sitemap.xml và robots.txt
  • Liên kết nội bộ: dẫn link bài cũ trong bài mới
  • Văn bản thay thế cho ảnh: mô tả cụ thể, có từ khóa tự nhiên
  • Đường dẫn ngắn gọn, có từ khóa: /thiet-ke-web-2026 thay vì /post-12345
  • HTTPS và tương thích di động (hiển nhiên nhưng vẫn có người quên)
  • Tốc độ trang: điểm Hiệu năng trên Lighthouse từ 90 trở lên

Tóm tắt

  • Cá nhân hóa bằng AI không cần máy chủ phức tạp - TensorFlow.js chạy mượt trên trình duyệt, tăng tương tác 40%
  • Three.js + React Three Fiber giờ đã đủ tối ưu cho sản phẩm thật - áp dụng LOD và tải chậm là đạt Lighthouse 85+
  • Kiểu chữ 2026: chữ to (tiêu đề từ 48px), khoảng cách rộng (chiều cao dòng 1.6–1.8), font biến thể tiết kiệm băng thông
  • Giao diện tối là tiêu chuẩn, không phải bổ sung - dùng tiền tố dark: của Tailwind và script nội tuyến để tránh nháy
  • Tương tác vi mô (200–400ms, ease-out) + tải dạng khung xương cải thiện trải nghiệm và Core Web Vitals
  • SEO giờ cần đạt Core Web Vitals + dữ liệu có cấu trúc + ảnh chất lượng cao cho Google Discover

Áp dụng từng phần một thôi, đừng làm lại toàn bộ trang cùng lúc. Mình bắt đầu từ kiểu chữ + giao diện tối, rồi mới thêm 3D và AI sau. Có gì thắc mắc cứ để lại bình luận, mình sẽ trả lời.