Đ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

Motion UI & Micro-Interactions: Bí quyết giữ chân người dùng trên web 2026

Ếch Trendy
Ếch Trendy

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

Tại sao Motion UI lại quan trọng năm 2026?

Ribbit 🐸 - Mình vừa làm lại landing page cho một client, thêm vài scroll animations và button hover effects. Conversion rate tăng 28% chỉ sau 10 ngày. Không phải phép màu - đây là sức mạnh của Motion UImicro-interactions.

2026 không còn là thời đại web tĩnh. Người dùng Việt giờ quen với TikTok, Instagram Reels - họ mong đợi web cũng phải "sống động" như vậy. Một trang web không có chuyển động cảm giác như đọc báo giấy thời năm 2010.

Nhưng vấn đề ở chỗ: motion làm sao cho đúng? Quá nhiều animation thì người dùng chóng mặt, quá ít thì nhạt nhẽo. Mình sẽ chia sẻ cách tạo motion UI vừa đủ, tăng trải nghiệm mà không làm người dùng khó chịu.

16154 Minh họa sự khác biệt giữa web tĩnh và web có motion UI, thể hiện mức độ tương tác tăng lên

Bài này dành cho bạn đang làm web cho doanh nghiệp Việt, freelancer muốn nâng giá trị dịch vụ, hoặc developer muốn học cách tạo animations mượt mà. Bạn sẽ học được cách dùng CSS thuần, GSAP, kết hợp với Tailwind để tạo hiệu ứng chuyên nghiệp.

Không cần biết quá sâu về animation - chỉ cần hiểu CSS cơ bản và sẵn sàng thử nghiệm. Mình sẽ đưa code thực tế, giải thích từng dòng, và chỉ ra những sai lầm mình từng mắc phải.


Micro-interactions: Chi tiết nhỏ tạo khác biệt lớn

Micro-interactions là những phản hồi ngắn khi người dùng tương tác với web. Ví dụ: button đổi màu khi hover, icon "thích" phóng to khi click, form hiện thông báo khi submit thành công.

Nghe đơn giản nhưng đây là điểm phân biệt web "nghiệp dư" và "chuyên nghiệp". Người dùng không nói ra nhưng họ cảm nhận được. Một button không có feedback khi click khiến họ nghi ngờ "có hoạt động không nhỉ?" và click lại nhiều lần.

Nguyên tắc vàng cho micro-interactions

Đầu tiên, phản hồi phải tức thì. Độ trễ dù chỉ 100-200ms cũng làm người dùng cảm thấy lag. Mình thường đặt duration cho hover effects là 150-300ms.

Thứ hai, chuyển động phải tự nhiên. Không dùng linear - luôn dùng easing như ease-out, ease-in-out. Trong thực tế, không có vật gì di chuyển với tốc độ đều đặn.

Thứ ba, đừng làm quá. Một trang landing có 5 sections thì chỉ nên có animations ở 2-3 chỗ quan trọng nhất: hero section, CTA buttons, và phần testimonials.

16155 Sơ đồ minh họa timeline của một micro-interaction hiệu quả: trigger - feedback - completion

Hãy bắt đầu với button hover effect đơn giản nhất:

/* Button cơ bản với Tailwind */
.btn-primary {
  @apply bg-blue-600 text-white px-6 py-3 rounded-lg;
  transition: all 0.3s ease-out;
}

.btn-primary:hover {
  @apply bg-blue-700 shadow-lg;
  transform: translateY(-2px);
}

.btn-primary:active {
  @apply bg-blue-800;
  transform: translateY(0);
}

Chỉ với 3 states này, button đã cảm giác "sống" hơn rất nhiều. Effect translateY(-2px) tạo cảm giác button "nhấc lên" khi hover - một chi tiết nhỏ nhưng người dùng tiềm thức cảm nhận được.

Ripple effect kiểu Material Design

Nếu muốn cao cấp hơn, thêm ripple effect khi click:

// Thêm ripple effect vào button
function createRipple(event) {
  const button = event.currentTarget;
  const ripple = document.createElement('span');
  const rect = button.getBoundingClientRect();
  
  // Tính vị trí click tương đối với button
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  
  ripple.style.left = `${x}px`;
  ripple.style.top = `${y}px`;
  ripple.classList.add('ripple');
  
  button.appendChild(ripple);
  
  // Xóa element sau khi animation xong
  setTimeout(() => ripple.remove(), 600);
}

// Gắn vào tất cả buttons
document.querySelectorAll('.btn-primary').forEach(btn => {
  btn.addEventListener('click', createRipple);
});
/* Style cho ripple effect */
.btn-primary {
  position: relative;
  overflow: hidden;
}

.ripple {
  position: absolute;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.6);
  transform: translate(-50%, -50%) scale(0);
  animation: ripple-animation 0.6s ease-out;
}

@keyframes ripple-animation {
  to {
    transform: translate(-50%, -50%) scale(20);
    opacity: 0;
  }
}

Effect này tạo cảm giác "phản hồi vật lý" khi click - giống như bạn chạm vào mặt nước và tạo gợn sóng.


Scroll animations với Intersection Observer

Phần này hơi sâu, bám chặt lá sen nhé. Scroll animations giúp nội dung "hiện ra" khi người dùng cuộn đến - tạo cảm giác trang web đang "kể chuyện" thay vì dump hết thông tin một lúc.

Trước đây mình hay dùng thư viện như AOS (Animate On Scroll), nhưng giờ với Intersection Observer API của browser, ta có thể tự code nhẹ và kiểm soát tốt hơn.

Cách hoạt động của Intersection Observer

API này theo dõi khi một element "giao" với viewport (vùng nhìn thấy của browser). Khi element vào viewport, ta trigger animation.

// Khởi tạo observer
const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        // Element đã vào viewport
        entry.target.classList.add('animate-in');
        // Ngừng observe sau khi animate (tùy chọn)
        observer.unobserve(entry.target);
      }
    });
  },
  {
    threshold: 0.1, // Trigger khi 10% element hiện ra
    rootMargin: '0px 0px -50px 0px' // Trigger sớm hơn 50px
  }
);

// Gắn observer vào các elements cần animate
document.querySelectorAll('.fade-up').forEach(el => {
  observer.observe(el);
});

16156 Diagram minh họa Intersection Observer API hoạt động khi element scroll vào viewport

Với CSS, định nghĩa trạng thái ban đầu và sau khi animate:

/* Trạng thái ban đầu - ẩn và ở dưới */
.fade-up {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}

/* Trạng thái sau khi vào viewport */
.fade-up.animate-in {
  opacity: 1;
  transform: translateY(0);
}

Stagger effect - animations lần lượt

Nếu có nhiều items cùng lúc (ví dụ danh sách features), làm chúng animate lần lượt thay vì cùng một lúc:

// Thêm delay cho mỗi item
const items = document.querySelectorAll('.feature-card');
items.forEach((item, index) => {
  // Mỗi item delay thêm 100ms
  item.style.transitionDelay = `${index * 0.1}s`;
  observer.observe(item);
});
.feature-card {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}

.feature-card.animate-in {
  opacity: 1;
  transform: translateY(0);
}

Với Tailwind, bạn có thể tận dụng utility classes:

<div class="fade-up opacity-0 translate-y-8 transition-all duration-700 ease-out">
  <h3>Feature 1</h3>
  <p>Mô tả feature...</p>
</div>

Rồi chỉ cần thêm classes khi element vào viewport:

if (entry.isIntersecting) {
  entry.target.classList.remove('opacity-0', 'translate-y-8');
  entry.target.classList.add('opacity-100', 'translate-y-0');
}

Lưu ý: đừng animate quá nhiều elements cùng lúc. Mình thường giới hạn 3-4 items mỗi lần, nếu nhiều hơn thì chia thành groups.


GSAP: Công cụ tạo animations phức tạp

CSS transitions tốt cho animations đơn giản, nhưng khi cần timeline phức tạp, chuyển động nhiều bước, hoặc animation theo con trỏ chuột, GSAP (GreenSock Animation Platform) là lựa chọn tốt nhất.

GSAP nhanh hơn CSS animations, hỗ trợ nhiều easing functions, và quan trọng là API dễ hiểu. Mình dùng GSAP cho hầu hết projects có yêu cầu animation phức tạp.

Cài đặt và sử dụng cơ bản

npm install gsap

Hoặc dùng CDN:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>

Animation đơn giản với GSAP:

import gsap from 'gsap';

// Animate một element
gsap.to('.hero-title', {
  opacity: 1,
  y: 0,
  duration: 1,
  ease: 'power3.out'
});

16157 So sánh syntax giữa CSS transitions và GSAP animations, thể hiện ưu điểm của từng cách

Timeline - chuyển động nhiều bước

Đây là nơi GSAP tỏa sáng. Bạn có thể tạo chuỗi animations chạy lần lượt hoặc đồng thời:

// Tạo timeline cho hero section
const tl = gsap.timeline();

tl.from('.hero-title', {
  opacity: 0,
  y: 50,
  duration: 0.8,
  ease: 'power3.out'
})
.from('.hero-subtitle', {
  opacity: 0,
  y: 30,
  duration: 0.6,
  ease: 'power2.out'
}, '-=0.4') // Bắt đầu trước khi animation trước kết thúc 0.4s
.from('.hero-cta', {
  opacity: 0,
  scale: 0.8,
  duration: 0.5,
  ease: 'back.out(1.4)' // Easing có hiệu ứng "bounce back"
}, '-=0.2');

Parameter -=0.4 giúp animations chồng lên nhau một chút, tạo cảm giác mượt mà hơn là chờ từng cái chạy xong.

ScrollTrigger plugin - animations theo scroll

Plugin này kết hợp GSAP với scroll, mạnh hơn nhiều so với Intersection Observer:

import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);

// Parallax effect đơn giản
gsap.to('.background-image', {
  y: 200,
  scrollTrigger: {
    trigger: '.section-hero',
    start: 'top top',
    end: 'bottom top',
    scrub: true // Animation gắn với scroll, mượt mà
  }
});

// Pin element khi scroll
gsap.to('.feature-visual', {
  scrollTrigger: {
    trigger: '.feature-section',
    start: 'top center',
    end: 'bottom center',
    pin: '.feature-visual', // Giữ element cố định trong khi scroll
    pinSpacing: false
  }
});

Parameter scrub: true quan trọng - nó làm animation "gắn" với scroll position, di chuyển lên xuống theo scroll thay vì chạy một lần.

Ví dụ thực tế: Landing page với GSAP

Dưới đây là setup GSAP cho một landing page điển hình:

// Hero section animation khi load trang
const heroTL = gsap.timeline({ defaults: { ease: 'power3.out' } });

heroTL
  .from('.hero-background', { scale: 1.2, duration: 1.5 })
  .from('.hero-title', { opacity: 0, y: 60, duration: 1 }, 0.3)
  .from('.hero-description', { opacity: 0, y: 40, duration: 0.8 }, 0.5)
  .from('.hero-cta-group button', {
    opacity: 0,
    y: 20,
    stagger: 0.15, // Mỗi button xuất hiện cách nhau 0.15s
    duration: 0.6
  }, 0.7);

// Features cards xuất hiện khi scroll đến
gsap.from('.feature-card', {
  scrollTrigger: {
    trigger: '.features-section',
    start: 'top 80%',
    toggleActions: 'play none none reverse'
  },
  opacity: 0,
  y: 50,
  stagger: 0.2,
  duration: 0.8,
  ease: 'power2.out'
});

// Testimonials với parallax nhẹ
gsap.to('.testimonial-bg', {
  yPercent: 30,
  ease: 'none',
  scrollTrigger: {
    trigger: '.testimonials-section',
    start: 'top bottom',
    end: 'bottom top',
    scrub: 0.5
  }
});

Một lần mình quên set ease cho ScrollTrigger animation, kết quả là chuyển động giật cục, mất cả buổi chiều debug mới phát hiện.


Case study thực tế: Landing page cho startup Việt

Cuối năm 2025, mình nhận làm landing page cho một startup edtech Việt Nam. Họ muốn trang web "bắt mắt" nhưng không quá "lòe loẹt". Budget hạn chế nên không thể thuê motion designer riêng.

Mình kết hợp Tailwind + GSAP, tổng thời gian làm animations là 2 ngày. Kết quả: conversion rate từ 2.1% lên 2.7% (tăng 28%), bounce rate giảm từ 68% xuống 54%.

Những animations mình triển khai

Hero section: Background gradient có parallax nhẹ khi scroll, title + subtitle fade in lần lượt với stagger effect. CTA button có ripple effect khi click.

// Hero animations
const heroTL = gsap.timeline();
heroTL
  .from('.hero-bg', { scale: 1.1, opacity: 0, duration: 1.2 })
  .from('.hero-title span', {
    opacity: 0,
    y: 40,
    stagger: 0.1, // Mỗi từ xuất hiện lần lượt
    duration: 0.8,
    ease: 'power3.out'
  }, 0.3)
  .from('.hero-cta', { scale: 0.9, opacity: 0, duration: 0.5 }, '-=0.3');

// Parallax cho background
gsap.to('.hero-bg', {
  yPercent: 20,
  ease: 'none',
  scrollTrigger: {
    trigger: '.hero-section',
    start: 'top top',
    end: 'bottom top',
    scrub: 1
  }
});

16158 Screenshots minh họa các animation states của landing page từ hero đến CTA section

Features section: Mỗi feature card slide từ dưới lên khi scroll đến, có slight rotation để tạo động.

gsap.from('.feature-card', {
  scrollTrigger: {
    trigger: '.features-grid',
    start: 'top 75%'
  },
  opacity: 0,
  y: 60,
  rotation: 2, // Xoay nhẹ 2 độ
  stagger: 0.15,
  duration: 0.7,
  ease: 'back.out(1.2)'
});

Testimonials carousel: Thay vì dùng thư viện carousel nặng, mình tự code bằng GSAP:

let currentIndex = 0;
const testimonials = document.querySelectorAll('.testimonial-item');

function showTestimonial(index) {
  const tl = gsap.timeline();
  
  // Fade out testimonial hiện tại
  tl.to(testimonials[currentIndex], {
    opacity: 0,
    x: -50,
    duration: 0.3
  })
  // Fade in testimonial mới
  .set(testimonials[index], { x: 50 })
  .to(testimonials[index], {
    opacity: 1,
    x: 0,
    duration: 0.4,
    ease: 'power2.out'
  });
  
  currentIndex = index;
}

// Auto-rotate mỗi 5s
setInterval(() => {
  const nextIndex = (currentIndex + 1) % testimonials.length;
  showTestimonial(nextIndex);
}, 5000);

CTA section: Button có hover effect "magnetic" - nhẹ nhàng kéo theo cursor:

const ctaButton = document.querySelector('.cta-final');

ctaButton.addEventListener('mousemove', (e) => {
  const rect = ctaButton.getBoundingClientRect();
  const x = e.clientX - rect.left - rect.width / 2;
  const y = e.clientY - rect.top - rect.height / 2;
  
  gsap.to(ctaButton, {
    x: x * 0.3, // Chỉ di chuyển 30% khoảng cách
    y: y * 0.3,
    duration: 0.3,
    ease: 'power2.out'
  });
});

ctaButton.addEventListener('mouseleave', () => {
  gsap.to(ctaButton, {
    x: 0,
    y: 0,
    duration: 0.5,
    ease: 'elastic.out(1, 0.5)'
  });
});

Những sai lầm mình đã mắc

Ban đầu mình làm quá nhiều animations - mỗi section đều có chuyển động. Kết quả là người dùng phàn nàn "hoa mắt". Mình phải giảm bớt 40% animations, chỉ giữ lại những cái thực sự cần thiết.

Một sai lầm khác: không test trên mobile. Một số animations mượt trên desktop nhưng lag trên điện thoại. Mình phải disable một số hiệu ứng nặng trên mobile:

// Chỉ chạy animations nặng trên desktop
if (window.innerWidth > 768) {
  gsap.to('.heavy-animation', { ... });
}

Cuối cùng, ban đầu mình quên optimize performance. Một số animations trigger liên tục khi scroll, làm CPU tăng vọt. Sau khi thêm debounce và tối ưu ScrollTrigger, mọi thứ mượt hơn nhiều.


Performance và tối ưu hóa

Animations đẹp nhưng làm trang web chậm thì phản tác dụng. Mình có vài nguyên tắc để giữ performance tốt:

Ưu tiên transform và opacity

Chỉ animate các properties này vì browser xử lý chúng hiệu quả nhất (chạy trên GPU):

  • transform (translateX, translateY, scale, rotate)
  • opacity

Tránh animate:

  • width, height (trigger reflow)
  • top, left, margin (trigger reflow)
  • background-position (tốn CPU)
/* ❌ CHẬM - trigger reflow */
.box:hover {
  width: 300px;
  margin-left: 20px;
}

/* ✅ NHANH - chỉ dùng transform */
.box:hover {
  transform: translateX(20px) scale(1.1);
}

Sử dụng will-change một cách thông minh

Property will-change báo cho browser biết element sẽ animate, giúp tối ưu trước:

.animate-element {
  will-change: transform, opacity;
}

Nhưng đừng lạm dụng - chỉ dùng cho elements thực sự cần animate thường xuyên. Nếu set will-change cho quá nhiều elements, browser sẽ tốn nhiều bộ nhớ hơn.

16159 Infographic so sánh hiệu năng khi animate các CSS properties khác nhau

Debounce scroll events

Khi listen scroll event, đừng chạy function mỗi lần scroll - quá tốn tài nguyên:

// Helper debounce function
function debounce(func, wait) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}

// Sử dụng
window.addEventListener('scroll', debounce(() => {
  // Code xử lý scroll
}, 100)); // Chỉ chạy tối đa mỗi 100ms

Với GSAP ScrollTrigger, optimization đã được built-in rồi, bạn không cần debounce thủ công.

Lazy load animations trên mobile

Trên điện thoại, disable hoặc đơn giản hóa animations:

const isMobile = window.innerWidth < 768;
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

if (!isMobile && !reducedMotion) {
  // Chạy animations đầy đủ
  gsap.from('.feature-card', {
    opacity: 0,
    y: 50,
    stagger: 0.2,
    scrollTrigger: { ... }
  });
} else {
  // Chỉ fade in đơn giản
  gsap.from('.feature-card', {
    opacity: 0,
    duration: 0.5
  });
}

Lưu ý parameter prefers-reduced-motion - một số người dùng bật setting này vì họ bị chóng mặt với animations. Luôn tôn trọng preference này.

Measure performance

Dùng Chrome DevTools để kiểm tra:

  1. Mở DevTools -> Performance tab
  2. Record trong khi scroll/interact
  3. Kiểm tra FPS (frames per second) - nên giữ ở 60fps
  4. Tìm "long tasks" màu đỏ - những đoạn code chạy quá lâu

Nếu thấy FPS xuống dưới 30, đơn giản hóa animations hoặc giảm số lượng elements animate cùng lúc.


Checklist triển khai Motion UI cho dự án thực tế

Sau khi làm hàng chục landing pages, mình tổng hợp checklist này. Mỗi lần bắt đầu dự án mới, mình đều chạy qua list để đảm bảo không bỏ sót gì:

Giai đoạn lên kế hoạch

  • Xác định 3-5 moments quan trọng nhất cần animation (hero, CTA, key features)
  • Quyết định tone: playful hay professional? Subtle hay bold?
  • Kiểm tra target audience - tuổi, device chủ yếu, bandwidth
  • Thống nhất với client về duration tổng (landing page không nên mất quá 2s để "settle")

Giai đoạn development

  • Setup GSAP hoặc CSS transitions framework
  • Implement animations từ đơn giản -> phức tạp
  • Test trên Chrome, Safari, Firefox
  • Test trên mobile (iOS Safari, Chrome Android)
  • Kiểm tra prefers-reduced-motion setting
  • Measure FPS với Chrome DevTools, đảm bảo >= 50fps
  • Optimize nếu thấy lag: giảm số elements, đơn giản hóa easing, disable trên mobile

Giai đoạn polish

  • Adjust timing - có animations nào chạy quá nhanh/chậm?
  • Kiểm tra stagger delays - có hợp lý không?
  • Test UX flow: người dùng có bị distract bởi animations không?
  • A/B test nếu có thể: version có animation vs không có
  • Thu thập feedback từ 3-5 người không phải developer

16160 Flowchart quy trình triển khai Motion UI từ lên ý tưởng đến optimize cuối cùng

Tools và resources hữu ích

Một số công cụ mình hay dùng:

Easings.net - xem preview tất cả easing functions, copy code luôn. Mình hay dùng easeOutCubic cho hầu hết cases.

Lottie + LottieFiles - nếu cần animations phức tạp hơn (illustrative), xuất từ After Effects sang JSON, render bằng Lottie library. Nhẹ hơn nhiều so với GIF/video.

GSAP Docs & CodePen - GSAP có docs cực tốt với nhiều demos. Khi không biết làm effect nào, mình vào CodePen search "gsap [tên effect]", thường có sẵn.

Chrome DevTools Performance tab - không thể thiếu để debug performance.

Một trick: khi client nói "tôi muốn animation như trang X", mình vào trang đó, inspect element, xem họ dùng gì. Đa số dùng GSAP hoặc Framer Motion (cho React).

Khi nào KHÔNG nên dùng animations

Có những trường hợp animations phản tác dụng:

  • Trang dashboard/admin: người dùng cần truy cập thông tin nhanh, không cần "wow factor"
  • Forms phức tạp: animation làm người dùng mất tập trung khi điền form
  • Content-heavy sites: blog, trang tin tức - người dùng đến để đọc, không phải xem show
  • Target audience lớn tuổi: họ thường không quen và có thể bối rối với quá nhiều chuyển động

Một lần mình làm landing page cho công ty luật, thêm nhiều animations "sang chảnh". Client feedback: "Trông không đủ nghiêm túc". Phải remove hết, chỉ giữ lại fade-ins nhẹ nhàng.

Bắt đầu từ đâu?

Nếu bạn chưa từng làm Motion UI, đừng overwhelm bản thân. Bắt đầu từ đây:

Tuần 1: Làm button hover effects bằng CSS transitions thuần. Thử 5-6 kiểu khác nhau: scale, shadow, transform, color change. Cảm nhận duration và easing nào mượt nhất.

Tuần 2: Implement Intersection Observer cho scroll animations. Làm một trang demo với 3-4 sections, mỗi section fade in khi scroll đến.

Tuần 3: Học GSAP cơ bản. Làm hero section với timeline: background -> title -> subtitle -> CTA. Điều chỉnh timing cho tự nhiên.

Tuần 4: Kết hợp tất cả vào một mini landing page. Đo performance, optimize.

Không cần ngay lập tức làm được những animations điên rồ. Ngay cả những micro-interactions nhỏ như button hover effect tốt cũng đã cải thiện UX rõ rệt.

Một điều mình học được: motion UI giống như gia vị - một chút là đủ. Quá nhiều thì người dùng ngán. Mục tiêu là họ cảm thấy trang web "mượt mà" và "responsive", chứ không phải "wow animation quá đỉnh".


Ghi chú từ đầm:

  • Ưu tiên animate transformopacity - chạy trên GPU, mượt nhất
  • GSAP timeline giúp kiểm soát animations phức tạp tốt hơn CSS
  • Luôn test trên mobile và tôn trọng prefers-reduced-motion
  • Conversion rate tăng 28% không phải từ animation "đẹp" mà từ animation "đúng chỗ"

Bắt đầu nhỏ: button hover -> scroll fade-ins -> GSAP timeline. Mỗi tuần một skill, sau một tháng bạn đã tự tin làm landing page với motion UI chuyên nghiệp. Quan trọng nhất: đo performance, thu thập feedback thực tế từ người dùng, và điều chỉnh.

Có gì thắc mắc cứ kêu quạ quạ ở comment, mình sẽ nhảy vào trả lời 🐸