✍️
cssadvand
cssadvand
cssadvand
  • [BEM] Exploring SMACSS: Scalable and Modular Architecture for CSS
  • aspect-ratio thuộc tính giúp tạo hình vuông tuyệt đối square (ok)
  • Animation Anh Huy
    • Ứng dụng
      • Áp dụng thực tế
  • 😀CSS-only infinite scrolling carousel animation (ok)
  • css carousel
  • Rotate3d sử dụng các tham số như nào?
  • 🤡 Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 1)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 2)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 3)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 4)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 5)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 6)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 7)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 8)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 9)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 10)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 11)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 12) [Phần đặc biệt]
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 13)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 14)
  • 😘Thuộc tính tabindex="-1" không ngờ lại nguy hiểm vậy đọc bài dưới 😌
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 15)
  • 🥸CSS tạo theme cho dark mode đọc bài (Phần 16)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 16)
  • Mẹo để optimize Google Fonts API mà ít dev để ý đọc (Phần 17)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 17)
  • Thật may nhờ có white-space: pre-line đọc (Phần 18)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 18)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 19)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 20)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 21)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 22)
  • Thuộc tính image-rendering nhờ bài (Phần 23) mà phát hiện ra cách làm bức ảnh mờ trở nên rõ nét
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 23)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết 🤡
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 24)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 25)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 26)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 27)
  • 😘mix-blend-mode pha trộn giữa 1 đối tượng với đối tượng bên dưới đó (Phần 28)
    • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 28)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 29)
  • 🥸aspect-ratio (Phần 30)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 30)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 31)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 32)
  • Một vài thủ thuật CSS mà chính Frontend có thể còn chưa biết (Phần 33)
  • 😘CSS Scroll Triggered Animations Full (ok)
  • 🥹Difference between animation and transition in CSS
  • 😄animation-timeline có phải nó làm việc với thanh cuộn (ok)
  • 😍Từ bài animation-timeline làm việc với thanh cuộn tìm ra cách sử dụng background-clip: text;
  • background-clip: text;
  • 😅Sử dụng list-style-type để tạo icon đẹp (ok)
  • 😁Convert css to scss good (ok)
  • 😁CSS - Hướng dẫn: Tạo ảnh động với hàm steps()
  • 😆Multiple image cross fading in CSS - without (java) khá đẹp script (ok)
  • 😇Function css full 🤩
  • 😅[SVG] SVG viewBox Attribute (ok)
  • 😅Tailwind CSS (ok)
  • 😍Thật không thể tin được sử dụng filter: brightness(0) invert(1); để chuyển màu ảnh 🤣
  • 😅Background text matter.vn (ok)
  • 😆Chọn màu, color, color contrast ratio (ok)
  • 😁Tổng hợp Animating SVG text cực đẹp (ok)
  • 😂Chuyển động tròn :(
  • 😆MOVE-BG mepop.vn (ok)
  • 😆Counter Increment list, number xuongkhopbacninh.com (ok)
  • Boxes That Fill Height, full Height(Or More) (and Don’t Squish) (ok)
  • Equal Height (chiều cao bằng nhau) (oK)
  • 😅Sử dụng nodejs và scss cấu trúc thư mục tốt P.1(ok)
  • 🥲Sử dụng nodejs và js cấu trúc thư mục tốt P.2 (ok)
  • === START STUDY P.1 && P.2 SỬ DỤNG NODEJS VÀ CẤU TRÚC ===
  • 😉1 Giao diện sử dụng thuộc tính data-coreui-toggle="dropdown" (ok)
  • === END STUDY P.1 && P.2 SỬ DỤNG NODEJS VÀ CẤU TRÚC ===
  • 😆Css box-shadow đẹp (ok)
  • === START Tutorials Classical BEM stack ===
  • 😀HTML with BEM (ok)
  • 😀CSS with BEM (ok)
  • === END Tutorials Classical BEM stack ===
  • === START SMACSS ===
  • Categorizing CSS Rules
  • Base Rules
  • Layout Rules
  • Module Rules
  • State Rules
  • Theme Rules
  • Changing State
  • === END SMACSS ===
  • All CSS Grid Properties (ok)
  • 😇Column Grid full example(Responsive)
  • === Start Điều quan trọng nhất cách chia cột và thay đổi vị trí ===
  • CSS Grid căn bản - Phần 1
  • CSS Grid căn bản - Phần 2
  • CSS Grid: Holy Grail Layout
  • Sử dụng CSS Grid để xây dựng web layout
  • Luyện tập CSS Grid qua bài tập tạo layout Airbnb, youtube, Pinterest
  • === End Điều quan trọng nhất cách chia cột và thay đổi vị trí ===
  • Overflow:hidden dots at the end full (ok)
  • Gulp để viết Sass && cai dat
  • Cách nhúng font vào svg (ok)
  • font-face Hướng dẫn conver font và nhúng sử dụng online (ok)
  • 😇Create CSS Animations on Scroll (ok)
  • Hiệu ứng hover bằng js hiện phần description (ok)
  • Text Link on Hover phần 1 (ok)
  • Kết hợp transition & transform-origin phần 2 (ok)
  • Text Hover Phần 3 (ok)
  • Social Media Icons hover effect (ok)
  • css rotate a pseudo :after or :before content:""
  • Hiệu ứng ảnh tự zoom, animation, scale phần 1 full (ok)
  • CodePen Home Image zoom on hover - auto run - view (ok)
  • scroll-padding (ok)
  • Tạo vòm giống styleathome (ok)
  • Tổng hợp những css đẹp để làm trang trí (ok)
  • Cách thay đổi màu svg full (ok_)
  • Disable Auto Zoom in Input “Text” tag - Safari on iPhone (ok)
  • function calc css (ok)
  • Get the scroll distance from bottom to scroll, var distanceFromBottom (ok) vinmec.com (ok)
  • ---------- Start CSSscan không sử dụng ----------------------
  • Unused CSSscan your website for unused CSS selectors (ok)
  • PurifyCSS OnlineRemove unused CSS code from your stylesheets (ok)
  • Remove unused CSS styles from Bootstrap using PurgeCSS (ok)
  • 😆Thêm column, media bootstrap, custom bootstrap (ok)
  • ---------- End CSSscan không sử dụng ----------------------
  • Xây dựng blog đơn giản (Node + React)
  • Các tham số của Gulp
  • File đã thực hành với Gulp (ok
  • gulp-livereload (chưa đọc)
  • Tối ưu hiệu năng Google Fonts (ok)
  • Cách nhúng font dùng 1 tên và chỉ khác src, font-weight (ok)
  • Học CSS GRID thông qua những layout phức tạp
  • [GRID] sử dụng grid xây dựng layout giống Masonry (ok)
  • PageSpeed Insights Chrome Extension (ok)
  • Tăng tốc website bằng cách cải thiện front-end
  • Code chuẩn SEO là gì
  • 10 CSS3 Animation Tools phổ biến
  • Trang check SEO OKE
  • Làm sao để SEO từ khóa?
  • Kiểm soát web typography với việc hiển thị CSS font (ok)
  • Các mẫu phông chữ hiển thị và thuộc tính hiển thị phông chữ của CSS
  • Một số mẹo tối ưu hóa HTML/CSS/JS đúng chuẩn
  • Web Performance
  • Preload, Prefetch, Preconnect (ok)
  • Tối ưu hóa phần Front end cho trình duyệt (part 1)
  • Tối ưu hóa phần Front end cho trình duyệt (part 2)
  • Sử dụng thuộc tính attr html && css (ok)
  • Disable Auto Zoom in Input “Text” tag - Safari on iPhone (ok)
  • CSS submit button weird rendering on iPad/iPhone submit color (ok)
  • Turn off iPhone/Safari input element rounding (ok)
  • scroll bongda.com.vn (ok)
  • Làm chiếc xe ô tô chuyển động giống 2020.yp.vn (ok)
  • Sự khác biệt giữa :empty và :blank trong CSS (ok)
  • Is there a CSS parent selector? (ok)
Powered by GitBook
On this page
  • Nghiên cứu các thuộc tính animation
  • — animation-duration
  • — animation-delay
  • — animation-direction
  • — animation-fill-mode
  • — animation-play-state
  • — animation-name
  • — animation-timeline
  • Nghiên cứu các thuộc tính transition
  • — transition-behavior
  • — transition-duration
  • — transition-timing-function
  • — transition-delay
  • — transition-property
  • 📙 Dưới đây là một mini map ghi nhớ các thuộc tính CSS liên quan đến transition để bạn dễ hình dung và ghi nhớ:
  • transition-property là thuộc tính CSS dùng để chỉ định tên của (những) thuộc tính CSS sẽ được áp dụng hiệu ứng chuyển tiếp (transition) khi giá trị của chúng thay đổi.

Was this helpful?

Animation Anh Huy

Previousaspect-ratio thuộc tính giúp tạo hình vuông tuyệt đối square (ok)NextỨng dụng

Last updated 22 days ago

Was this helpful?

https://animista.net
https://ianlunn.github.io/Hover

Nghiên cứu các thuộc tính animation

— animation-duration

Trong CSS, animation-duration là thuộc tính xác định thời gian một chu kỳ của animation kéo dài bao lâu (tức là mất bao nhiêu thời gian để hoàn thành một lần chạy của animation).

animation-duration: 2s; → animation kéo dài 2 giây.
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.box {
  animation-name: fadeIn;
  animation-duration: 1.5s;
}
Trong ví dụ trên, .box sẽ chạy animation fadeIn trong vòng 1.5 giây.

— animation-delay

animation-delay trong CSS dùng để chỉ định khoảng thời gian chờ trước khi một animation bắt đầu chạy.

Khi phần tử được áp dụng animation, animation-delay giúp trì hoãn thời điểm animation bắt đầu, thay vì chạy ngay lập tức.

Có thể dùng số âm (-1s) để làm cho animation bắt đầu như thể nó đã chạy được một thời gian rồi.

.box {
  animation-name: slideIn;
  animation-duration: 2s;
  animation-delay: 1s;
}

@keyframes slideIn {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}
.box sẽ chờ 1 giây sau khi được hiển thị, rồi mới bắt đầu chạy animation slideIn.

— animation-direction

animation-direction trong CSS là thuộc tính dùng để xác định hướng mà animation sẽ chạy, đặc biệt khi nó lặp lại nhiều lần.

Nó điều khiển xem animation chạy từ đầu đến cuối (bình thường), ngược lại (từ cuối về đầu), hay luân phiên qua lại mỗi lần lặp.

animation-direction: normal | reverse | alternate | alternate-reverse;
@keyframes move {
  from { transform: translateX(0); }
  to { transform: translateX(200px); }
}

.box {
  animation-name: move;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
}
 Kết quả: .box sẽ di chuyển qua phải rồi trở lại vị trí ban đầu, lặp đi lặp lại.
Giá trị
Ý nghĩa

normal (mặc định)

Animation chạy từ đầu đến cuối (từ from đến to).

reverse

Animation chạy ngược lại (từ to về from).

alternate

Animation chạy bình thường, rồi ngược lại (lặp luân phiên).

alternate-reverse

Animation chạy ngược lại, rồi bình thường (cũng luân phiên).

— animation-fill-mode

animation-fill-mode trong CSS dùng để xác định trạng thái của phần tử trước khi animation bắt đầu và sau khi animation kết thúc.

Animation thường chỉ “tác động” trong thời gian nó chạy. Nhưng nếu bạn muốn phần tử giữ nguyên hiệu ứng sau khi kết thúc (hoặc trước khi bắt đầu), thì dùng animation-fill-mode.

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.box {
  animation-name: fadeIn;
  animation-duration: 2s;
  animation-fill-mode: forwards;
}
.box sẽ mờ dần từ 0 → 1 (opacity).
Sau khi animation kết thúc, nó vẫn giữ nguyên opacity: 1 nhờ forwards.
.box {
  animation-name: fadeIn;
  animation-duration: 2s;
  animation-delay: 3s;
  animation-fill-mode: backwards;
}

Trong 3 giây delay, phần tử sẽ tạm thời có opacity: 0 (như trong keyframe from) thay vì hiển thị trạng thái ban đầu.

none (mặc định)

Không áp dụng bất kỳ style nào từ animation trước/sau khi nó chạy.

forwards

Sau khi animation kết thúc, giữ lại trạng thái của keyframe cuối cùng.

backwards

Trước khi animation bắt đầu, tạm thời áp dụng trạng thái keyframe đầu tiên (đặc biệt khi có animation-delay).

both

Kết hợp cả forwards và backwards.

— animation-play-state

animation-play-state trong CSS dùng để tạm dừng hoặc tiếp tục một animation đang chạy.

Nó giống như nút pause/play cho animation: bạn có thể dừng animation lại rồi cho nó chạy tiếp bất cứ lúc nào.

animation-play-state: running | paused;
@keyframes move {
  from { transform: translateX(0); }
  to { transform: translateX(300px); }
}

.box {
  animation-name: move;
  animation-duration: 4s;
  animation-iteration-count: infinite;
  animation-play-state: running;
}

Nếu bạn thêm animation-play-state: paused; → phần tử sẽ không di chuyển dù có animation.

Dùng với JavaScript hoặc hover:

.box:hover {
  animation-play-state: paused;
}

👉 Khi bạn hover vào .box, animation sẽ tạm dừng, khi bỏ hover sẽ chạy tiếp.

— animation-name

animation-name trong CSS dùng để chỉ định tên của animation (được định nghĩa bằng @keyframes) sẽ áp dụng cho phần tử.

animation-name là cách bạn nói với CSS: “Ê, dùng cái animation nào cho phần tử này đi!”

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.box {
  animation-name: fadeIn;
  animation-duration: 2s;
}
  • fadeIn là tên animation bạn đã định nghĩa.

  • .box sẽ được áp dụng animation đó và mờ dần trong 2 giây.

— animation-timeline

animation-timeline là một thuộc tính mới trong CSS (hiện đang được chuẩn hóa theo CSS Scroll-Linked Animations), dùng để điều khiển tiến trình animation dựa trên một "timeline" tùy chỉnh — ví dụ: theo vị trí cuộn (scroll position) thay vì thời gian.

Thay vì animation chạy theo thời gian (animation-duration: 2s), bạn có thể cho nó chạy theo tiến độ scroll của trang, phần tử, hoặc một timeline khác.

Giá trị
Ý nghĩa

auto (mặc định)

Dùng timeline mặc định (thường là theo thời gian như bình thường).

none

Không gắn animation với timeline nào cả.

scroll()

Gắn animation theo tiến độ scroll (rất hay dùng với scroll-driven effects).

<custom-name>

Dùng một timeline bạn đã khai báo thủ công (dùng với @scroll-timeline).

Đây là ví dụ (giả lập - chỉ hỗ trợ trong một số trình duyệt như Chrome 115+ và cần bật experimental flags):

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@scroll-timeline myScrollTimeline {
  source: auto;
  orientation: block;
  scroll-offsets: start 0%, end 100%;
}

.box {
  animation-name: fadeIn;
  animation-duration: 1s;
  animation-timeline: myScrollTimeline;
}
  • Animation fadeIn không chạy theo thời gian mà chạy dựa trên vị trí scroll của người dùng.

  • Khi cuộn từ đầu đến cuối, .box sẽ mờ dần vào.

Nghiên cứu các thuộc tính transition

— transition-behavior

transition-behavior là một thuộc tính CSS dùng để kiểm soát hành vi của transition khi thuộc tính bị thay đổi, đặc biệt là khi sử dụng JavaScript hoặc khi thay đổi giữa các trạng thái lớp (class) trong DOM.

transition-behavior: normal | allow-discrete;
Giá trị
Ý nghĩa

normal (default)

Chỉ áp dụng transition cho những thuộc tính hỗ trợ hoạt ảnh liên tục (continuous transitions), như opacity, transform, v.v.

allow-discrete

Cho phép các thuộc tính không liên tục (discrete) như display, visibility, hoặc content cũng có thể "hiển thị theo cách chuyển tiếp" nếu trình duyệt hỗ trợ.

.box {
  transition: opacity 0.3s ease, visibility 0.3s ease;
  transition-behavior: allow-discrete;
}

Nếu visibility được thay đổi (visible ↔ hidden), trình duyệt có thể xử lý nó một cách mượt nếu hỗ trợ allow-discrete.

  • Hiện tại (2024–2025), transition-behavior: allow-discrete chưa được hỗ trợ rộng rãi ở tất cả các trình duyệt. Chủ yếu có mặt trên Chrome, Edge với các flag thử nghiệm.

  • Không có tác dụng nếu dùng với các thuộc tính vốn đã hỗ trợ transition như opacity, transform.

Khi nào dùng?

  • Khi bạn muốn một số thuộc tính như visibility, content, hoặc display có thể chuyển đổi mượt thay vì bật tắt đột ngột (nếu trình duyệt hỗ trợ).

  • Dùng kết hợp với @starting-style (trong CSS animation phức tạp).

transition-behavior là một tính năng tiềm năng, giúp kiểm soát tốt hơn cách transition hoạt động – đặc biệt cho những thuộc tính trước giờ không thể chuyển tiếp mượt. Nhưng bạn nên kiểm tra khả năng hỗ trợ trình duyệt trước khi dùng trong sản phẩm thực tế.


Nếu bạn đang làm animation mượt khi cuộn (với IntersectionObserver), bạn không cần dùng transition-behavior trừ khi bạn đang xử lý thuộc tính "cứng đầu" như visibility.

— transition-duration

transition-duration là một thuộc tính CSS dùng để xác định thời gian (tính bằng giây hoặc mili giây) mà transition sẽ mất để hoàn thành, tức là thời gian diễn ra hiệu ứng chuyển tiếp giữa hai trạng thái của một thuộc tính.

.box {
  transition-property: opacity;
  transition-duration: 0.5s;
}

Ở đây, khi .box thay đổi opacity, hiệu ứng mờ dần sẽ mất 0.5 giây để hoàn tất.

Bạn cũng có thể viết gọn:

.box {
  transition: opacity 0.5s ease;
}
opacity: là thuộc tính cần chuyển tiếp
0.5s: chính là transition-duration
ease: là transition-timing-function (kiểu chuyển động)

Bạn có thể chỉ định nhiều thời gian nếu đang transition nhiều thuộc tính:

transition-property: opacity, transform;
transition-duration: 0.5s, 1s;
// opacity mất 0.5 giây
// transform mất 1 giây

Nếu không khai báo transition-duration? Trình duyệt sẽ mặc định là 0s → không có hiệu ứng chuyển tiếp gì cả, chuyển đổi xảy ra ngay lập tức.

transition-duration

Thời gian chuyển tiếp (mượt hay tức thì)

Đơn vị

s (giây), ms (mili giây)

Mặc định

0s (không có chuyển tiếp)

— transition-timing-function

transition-timing-function là thuộc tính CSS dùng để xác định cách tốc độ của transition thay đổi trong suốt quá trình thực hiện — hay nói cách khác, nó điều khiển nhịp điệu (chuyển động nhanh/chậm/đều) của hiệu ứng.

transition-timing-function: ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier(...) | steps(...);
Giá trị
Mô tả

ease

Mặc định – bắt đầu chậm, tăng tốc, rồi chậm lại ở cuối

linear

Tốc độ đều từ đầu đến cuối

ease-in

Bắt đầu chậm, sau đó nhanh dần

ease-out

Bắt đầu nhanh, chậm dần về cuối

ease-in-out

Chậm ở cả đầu và cuối, nhanh ở giữa

cubic-bezier(x1, y1, x2, y2)

Tùy chỉnh đường cong tốc độ (chi tiết bên dưới)

`steps(n, start

end)`

.box {
  transition: transform 0.5s ease-in-out;
}
Khi .box bị transform (ví dụ translate, scale...), nó sẽ:
Chuyển động chậm ban đầu → nhanh ở giữa → chậm ở cuối.

Minh họa trực quan (tưởng tượng):

Giả sử bạn đang animate một khối vuông sang phải:

Hàm
Cảm giác chuyển động

ease

tự nhiên, giống vật thật

linear

tốc độ máy móc, đều đặn

ease-in

như xe tăng tốc từ điểm dừng

ease-out

như xe đang phanh lại dần

ease-in-out

mềm mại cả hai đầu

Tùy chỉnh nâng cao với cubic-bezier

cssCopyEdittransition-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
  • Tạo chuyển động như "bật nảy" (springy)

Tổng kết:

Thuộc tính
Chức năng

transition-timing-function

Điều khiển tốc độ diễn ra hiệu ứng

Tác động

Làm hiệu ứng mượt, tự nhiên hơn

Dùng kèm

transition-duration, transition-property, v.v.

— transition-delay

transition-delay là thuộc tính CSS dùng để chỉ định khoảng thời gian chờ trước khi hiệu ứng chuyển tiếp (transition) bắt đầu sau khi thuộc tính thay đổi.

.box {
  transition: opacity 0.5s ease;
  transition-delay: 0.3s;
}

👉 Khi .box thay đổi opacity, trình duyệt sẽ:

  • Đợi 0.3 giây, rồi

  • Thực hiện hiệu ứng mờ trong 0.5 giây

Dùng gộp:

.box {
  transition: opacity 0.5s ease 0.3s;
}

giá trị trong transition:

  1. opacity → thuộc tính cần chuyển tiếp

  2. 0.5s → thời gian thực hiện (transition-duration)

  3. ease → nhịp độ (transition-timing-function)

  4. 0.3s → thời gian chờ trước khi bắt đầu (transition-delay)

Ứng dụng thực tế

Hiệu ứng hover bắt đầu trễ:

.button {
  transition: background-color 0.4s ease-in-out 0.2s;
}
.button:hover {
  background-color: #ff6600;
}

Khi người dùng hover:

  • Chờ 0.2s rồi mới đổi màu nền

  • Tạo cảm giác phản hồi có "độ trễ tự nhiên"

Nhiều thuộc tính

Khi bạn chuyển tiếp nhiều thuộc tính, bạn có thể đặt delay riêng:

transition-property: opacity, transform;
transition-duration: 0.3s, 0.5s;
transition-delay: 0s, 0.2s;

→ opacity sẽ chạy ngay lập tức, còn transform sẽ chạy sau 0.2s.

Thuộc tính
Chức năng

transition-delay

Trì hoãn thời gian bắt đầu của hiệu ứng chuyển tiếp

Đơn vị

s hoặc ms

Mặc định

0s (không chờ – hiệu ứng bắt đầu ngay lập tức)

— transition-property

transition-property: none | all | <property-name> [, <property-name>, ...];
Giá trị
Ý nghĩa

all (mặc định)

Áp dụng transition cho mọi thuộc tính có thể chuyển tiếp

none

Không áp dụng transition cho bất kỳ thuộc tính nào

opacity, transform, background-color, v.v.

Chỉ áp dụng transition cho các thuộc tính cụ thể

.box {
  transition-property: opacity;
  transition-duration: 0.5s;
}

👉 Khi opacity thay đổi, sẽ có hiệu ứng mờ trong 0.5 giây. 📌 Nếu bạn thay đổi thuộc tính khác như transform, sẽ không có hiệu ứng gì cả, vì không nằm trong transition-property.

Ví dụ nhiều thuộc tính:

.box {
  transition-property: opacity, transform;
  transition-duration: 0.5s, 1s;
}
  • opacity mất 0.5 giây

  • transform mất 1 giây

Gộp đầy đủ:

.box {
  transition: opacity 0.3s ease-in, transform 0.5s ease-out;
}

Tương đương với:

transition-property: opacity, transform;
transition-duration: 0.3s, 0.5s;
transition-timing-function: ease-in, ease-out;

Khi nào nên dùng transition-property?

Khi dùng transition: all ... gây lỗi

Tránh animate những thuộc tính không mong muốn

transition-property

Xác định thuộc tính CSS nào sẽ có hiệu ứng transition

Dùng kèm với

transition-duration, transition-timing-function, transition-delay

Mặc định

all (mọi thuộc tính có thể transition)

📙 Dưới đây là một mini map ghi nhớ các thuộc tính CSS liên quan đến transition để bạn dễ hình dung và ghi nhớ:

Mind Map: Các thuộc tính CSS Transitio

transition-property là thuộc tính CSS dùng để chỉ định tên của (những) thuộc tính CSS sẽ được áp dụng hiệu ứng chuyển tiếp (transition) khi giá trị của chúng thay đổi.

app\app.css

@import "tailwindcss";
.spacer {
  height: 100vh;
}
.box {
  width: 120px;
  height: 120px;
  border-radius: 12px;
  color: white;
  font-weight: bold;
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.box-red {
  background-color: #e74c3c;
}
.box-blue {
  background-color: #3498db;
}
.box-green {
  background-color: #2ecc71;
}
.box-purple {
  background-color: #9b59b6;
}
.box.show {
  opacity: 1;
  transform: translateY(0);
}

app\welcome\welcome.tsx

import { useEffect } from 'react';
export function Welcome() {
  useEffect(() => {
    const boxes = document.querySelectorAll('.box');
    const timeoutMap = new Map();
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach(entry => {
          const el = entry.target;
          if (entry.isIntersecting) {
            clearTimeout(timeoutMap.get(el)); // Hủy bỏ nếu có timeout đang chờ xóa
            el.classList.add('show');
          } else {
            // Trì hoãn việc xóa class
            const timeoutId = setTimeout(() => {
              el.classList.remove('show');
            }, 300); // ví dụ 300ms sau mới xóa
            timeoutMap.set(el, timeoutId);
          }
        });
      },
      {
        threshold: Array.from({ length: 11 }, (_, i) => i / 10),
      }
    );
    boxes.forEach(box => observer.observe(box));
    return () => {
      boxes.forEach(box => observer.unobserve(box));
      timeoutMap.forEach(timeoutId => clearTimeout(timeoutId));
    };
  }, []);
  return (
    <main className="items-center pt-16 pb-4">
      <div className="spacer"></div>
      <div className="container-flex">
        <div className="box box-red">Đỏ</div>
        <div className="box box-blue">Xanh</div>
        <div className="box box-green">Lá</div>
        <div className="box box-purple">Tím</div>
      </div>
    </main>
  );
}
:root {
  --animate-duration: 1s;
  --animate-delay: 1s;
  --animate-repeat: 1;
}
@mixin mp-duration($time) {
  -webkit-animation-duration: $time;
  animation-duration: $time;
}
@mixin mp-delay($time) {
  -webkit-animation-delay: $time;
  animation-delay: $time;
}
@mixin mp-name($name) {
  -webkit-animation-name: $name;
  animation-name: $name;
}
@mixin mp-fillMode($fmode){
  -webkit-animation-fill-mode: $fmode;
  animation-fill-mode: $fmode;
}
.mp-animation{
    opacity:0;
    -webkit-animation-duration: 1s;
    animation-duration: 1s;
    -webkit-animation-fill-mode: both;
    animation-fill-mode: both;
}
.mp-animated{
    opacity: 1; 
}
//--------------------------- Pulse---------------------------------//
@-webkit-keyframes mp-pulse {
  from {
    opacity:0;
    -webkit-transform: scale3d(1.05, 1.05, 1.05);
    transform: scale3d(1.05, 1.05, 1.05);
  }

  50% {
    opacity:1;
    -webkit-transform: scale3d(1.05, 1.05, 1.05);
    transform: scale3d(1.05, 1.05, 1.05);
  }

  to {
    opacity:1;
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}
@keyframes mp-pulse {
  from {
      opacity:0;
    -webkit-transform: scale3d(1.05, 1.05, 1.05);
    transform: scale3d(1.05, 1.05, 1.05);
  }

  50% {
    opacity:1;
    -webkit-transform: scale3d(1.05, 1.05, 1.05);
    transform: scale3d(1.05, 1.05, 1.05);
  }

  to {
    opacity:1;
    -webkit-transform: scale3d(1, 1, 1);
    transform: scale3d(1, 1, 1);
  }
}
.mp-pulse {
  -webkit-animation-name: mp-pulse;
  animation-name: mp-pulse;
  -webkit-animation-timing-function: ease-in-out;
  animation-timing-function: ease-in-out;
}
//--------------------------- Fade In---------------------------------//
@-webkit-keyframes mp-fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}
@keyframes mp-fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}
.mp-fadeIn {
  -webkit-animation-name: mp-fadeIn;
  animation-name: mp-fadeIn;
}
//--------------------------- Fade In Up---------------------------------//
@-webkit-keyframes mp-fadeInUp {
  from {
    opacity: 0;
    -webkit-transform: translate3d(0, 100%, 0);
    transform: translate3d(0, 100%, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}
@keyframes mp-fadeInUp {
  from {
    opacity: 0;
    -webkit-transform: translate3d(0, 100%, 0);
    transform: translate3d(0, 100%, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}
.mp-fadeInUp {
  -webkit-animation-name: mp-fadeInUp;
  animation-name: mp-fadeInUp;
}
//--------------------------- Fade In Down---------------------------------//
@-webkit-keyframes mp-fadeInDown {
  from {
    opacity: 0;
    -webkit-transform: translate3d(0, -100%, 0);
    transform: translate3d(0, -100%, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}
@keyframes mp-fadeInDown {
  from {
    opacity: 0;
    -webkit-transform: translate3d(0, -100%, 0);
    transform: translate3d(0, -100%, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}
.mp-fadeInDown {
  -webkit-animation-name: mp-fadeInDown;
  animation-name: mp-fadeInDown;
}
//--------------------------- Fade In Left---------------------------------//
@-webkit-keyframes mp-fadeInLeft {
  from {
    opacity: 0;
    -webkit-transform: translate3d(-100%, 0, 0);
    transform: translate3d(-100%, 0, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}
@keyframes mp-fadeInLeft {
  from {
    opacity: 0;
    -webkit-transform: translate3d(-100%, 0, 0);
    transform: translate3d(-100%, 0, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}
.mp-fadeInLeft {
  -webkit-animation-name: mp-fadeInLeft;
  animation-name: mp-fadeInLeft;
}
//--------------------------- Fade In Right---------------------------------//
@-webkit-keyframes mp-fadeInRight {
  from {
    opacity: 0;
    -webkit-transform: translate3d(100%, 0, 0);
    transform: translate3d(100%, 0, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}
@keyframes mp-fadeInRight {
  from {
    opacity: 0;
    -webkit-transform: translate3d(100%, 0, 0);
    transform: translate3d(100%, 0, 0);
  }

  to {
    opacity: 1;
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }
}
.mp-fadeInRight {
  -webkit-animation-name: mp-fadeInRight;
  animation-name: mp-fadeInRight;
}
//--------------------------- Fade Out Right---------------------------------//
@-webkit-keyframes mp-fadeOutRight {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
    -webkit-transform: translate3d(100%, 0, 0);
    transform: translate3d(100%, 0, 0);
  }
}
@keyframes mp-fadeOutRight {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
    -webkit-transform: translate3d(100%, 0, 0);
    transform: translate3d(100%, 0, 0);
  }
}
.mp-fadeOutRight {
  -webkit-animation-name: mp-fadeOutRight;
  animation-name: mp-fadeOutRight;
}
//--------------------------- Fade Zoom---------------------------------//
@-webkit-keyframes mp-fadeZoom {
   from {
    opacity:0;
    -webkit-transform: scale(1.1);
    transform: scale(1.1);
  }
  to {
    opacity:1;
    -webkit-transform: scale(1);
    transform:scale(1);
  }
}
@keyframes mp-fadeZoom {
    from {
    opacity:0;
    -webkit-transform: scale(1.1);
    transform: scale(1.1);
  }
    to{
    opacity:1;
    -webkit-transform: scale(1);
    transform:scale(1);
  }
}
.mp-fadeZoom {
  -webkit-animation-name: mp-fadeZoom;
  animation-name: mp-fadeZoom;
}
//--------------------------- Fade Zoom Big---------------------------------//
@-webkit-keyframes mp-fadeZoomBig {
   from {
    opacity:0;
    -webkit-transform: scale(1.3);
    transform: scale(1.3);
  }
  to {
    opacity:1;
    -webkit-transform: scale(1);
    transform:scale(1);
  }
}
@keyframes mp-fadeZoomBig {
    from {
    opacity:0;
    -webkit-transform: scale(1.3);
    transform: scale(1.3);
  }
    to{
    opacity:1;
    -webkit-transform: scale(1);
    transform:scale(1);
  }
}
.mp-fadeZoomBig {
  -webkit-animation-name: mp-fadeZoomBig;
  animation-name: mp-fadeZoomBig;
}
//--------------------------- Bounce Big---------------------------------//
@-webkit-keyframes mp-bounceBig {
  from,
  20%,
  53%,
  to {
    opacity: 1;
    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }

  40%,
  43% {
    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    -webkit-transform: translate3d(0, -30px, 0) scaleY(1.1);
    transform: translate3d(0, -30px, 0) scaleY(1.1);
  }

  70% {
    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    -webkit-transform: translate3d(0, -15px, 0) scaleY(1.05);
    transform: translate3d(0, -15px, 0) scaleY(1.05);
  }

  80% {
    -webkit-transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    -webkit-transform: translate3d(0, 0, 0) scaleY(0.95);
    transform: translate3d(0, 0, 0) scaleY(0.95);
  }

  90% {
    -webkit-transform: translate3d(0, -4px, 0) scaleY(1.02);
    transform: translate3d(0, -4px, 0) scaleY(1.02);
  }
}
@keyframes mp-bounceBig {
  from,
  20%,
  53%,
  to {
    opacity: 1;
    -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
  }

  40%,
  43% {
    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    -webkit-transform: translate3d(0, -30px, 0) scaleY(1.1);
    transform: translate3d(0, -30px, 0) scaleY(1.1);
  }

  70% {
    -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    -webkit-transform: translate3d(0, -15px, 0) scaleY(1.05);
    transform: translate3d(0, -15px, 0) scaleY(1.05);
  }

  80% {
    -webkit-transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    -webkit-transform: translate3d(0, 0, 0) scaleY(0.95);
    transform: translate3d(0, 0, 0) scaleY(0.95);
  }

  90% {
    -webkit-transform: translate3d(0, -4px, 0) scaleY(1.02);
    transform: translate3d(0, -4px, 0) scaleY(1.02);
  }
}
.mp-bounceBig{
  -webkit-animation-name: mp-bounceBig;
  animation-name: mp-bounceBig;
  -webkit-transform-origin: center bottom;
  transform-origin: center bottom;
}
//--------------------------- Bounce---------------------------------//
@-webkit-keyframes mp-bounce{
  from,20%,53%,80%,to{
    opacity: 1;
    -webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);
    animation-timing-function:cubic-bezier(.215,.61,.355,1);
    -webkit-transform:translateZ(0);
    transform:translateZ(0);
  }
  40%,43%{
    -webkit-transform:translate3d(0,-15px,0);
    transform:translate3d(0,-15px,0);
  }
  40%,43%,70%{
    -webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);
    animation-timing-function:cubic-bezier(.755,.05,.855,.06);
  }
  70%{
    -webkit-transform:translate3d(0,-10px,0);
    transform:translate3d(0,-10px,0);
  }
  90%{
    -webkit-transform:translate3d(0,-4px,0);
    transform:translate3d(0,-4px,0);
  }
}
@keyframes mp-bounce{
  from,20%,53%,80%,to{
    opacity: 1;
    -webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);
    animation-timing-function:cubic-bezier(.215,.61,.355,1);
    -webkit-transform:translateZ(0);
    transform:translateZ(0);
  }40%,43%{
    -webkit-transform:translate3d(0,-15px,0);
    transform:translate3d(0,-15px,0);
  }
  40%,43%,70%{
    -webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);
    animation-timing-function:cubic-bezier(.755,.05,.855,.06);
  }
  70%{
    -webkit-transform:translate3d(0,-10px,0);
    transform:translate3d(0,-10px,0);
  }
  90%{
    -webkit-transform:translate3d(0,-4px,0);
    transform:translate3d(0,-4px,0);
  }
}
.mp-bounce {
  -webkit-animation-name: mp-bounce;
  animation-name: mp-bounce;
  -webkit-transform-origin: center bottom;
  transform-origin: center bottom;
}
//--------------------------- Flash---------------------------------//
@-webkit-keyframes mp-flash {
  from,
  50%,
  to {
    opacity: 1;
  }

  25%,
  75% {
    opacity: 0;
  }
}
@keyframes mp-flash {
  from,
  50%,
  to {
    opacity: 1;
  }

  25%,
  75% {
    opacity: 0;
  }
}
.mp-flash {
  -webkit-animation-name: mp-flash;
  animation-name: mp-flash;
}
//--------------------------- clipY---------------------------------//
@-webkit-keyframes mp-clipY{
    0%
    { 
        opacity: 1;
        -webkit-transform: scale(0, 1);
    }
    100%
    {
        opacity: 1;
        -webkit-transform: scale(1, 1);
    }
}
@keyframes mp-clipY{
    0%
    {
        opacity: 1;
        transform: scale(0, 1);
    }
    100%
    {
        opacity: 1;
        transform: scale(1, 1);
    }
}
.mp-clipY
{ 
    -webkit-animation-name: mp-clipY;
    animation-name: mp-clipY;
    -webkit-animation-timing-function: ease-out;
    animation-timing-function: ease-out;
}
//--------------------------- clipX---------------------------------//
@-webkit-keyframes mp-clipX{
    0%
    { 
        opacity: 1;
        -webkit-transform: scale(1, 0);
    }
    100%
    {
        opacity: 1;
        -webkit-transform: scale(1, 1);
    }
}
@keyframes mp-clipX{
    0%
    {
        opacity: 1;
        transform: scale(1, 0);
    }
    100%
    {
        opacity: 1;
        transform: scale(1, 1);
    }
}
.mp-clipX
{ 
    -webkit-animation-name: mp-clipX;
    animation-name: mp-clipX;
    -webkit-animation-timing-function: ease-out;
    animation-timing-function: ease-out;
}
//--------------------------- clipXY---------------------------------//
@-webkit-keyframes mp-clipXY{
    0%
    { 
        opacity: 1;
        -webkit-transform: scale(0, 0);
    }
    100%
    {
        opacity: 1;
        -webkit-transform: scale(1, 1);
    }
}
@keyframes mp-clipXY{
    0%
    {
        opacity: 1;
        transform: scale(0, 0);
    }
    100%
    {
        opacity: 1;
        transform: scale(1, 1);
    }
}
.mp-clipYY
{ 
    -webkit-animation-name: mp-clipXY;
    animation-name: mp-clipXY;
    -webkit-animation-timing-function: ease-out;
    animation-timing-function: ease-out;
}
//--------------------------- Back In Up---------------------------------//
@-webkit-keyframes mp-backInUp{
    0%
    {
        -webkit-transform: translateY(1200px) scale(.7);
        opacity: .5;
    }
    80%
    {
        -webkit-transform: translateY(0px) scale(.7);
        opacity: .7;
    }
    100%
    {
        -webkit-transform: scale(1);
        opacity: 1;
    }
}
@keyframes mp-backInUp{
    0%
    {
        transform: translateY(1200px) scale(.7);
        opacity: .5;
    }
    80%
    {
        transform: translateY(0px) scale(.7);
        opacity: .7;
    }
    100%
    {
        transform: scale(1);
        opacity: 1;
    }
}
.mp-backInUp{
    -webkit-animation: mp-backInUp;
            animation: mp-backInUp;
    -webkit-animation-timing-function: ease-out;
            animation-timing-function: ease-out;
}
//--------------------------- Zoom In---------------------------------//
@-webkit-keyframes mp-zoomIn {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.5, 0.5, 0.5);
    transform: scale3d(0.5, 0.5, 0.5);
  }

  50% {
    opacity: 1;
  }
  to{
    opacity: 1;
  }
}
@keyframes mp-zoomIn {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.5, 0.5, 0.5);
    transform: scale3d(0.5, 0.5, 0.5);
  }

  50% {
    opacity: 1;
  }
  to{
    opacity: 1;
  }
}
.mp-zoomIn {
  -webkit-animation-name: mp-zoomIn;
  animation-name: mp-zoomIn;
}
//--------------------------- Zoom In Down---------------------------------//
@-webkit-keyframes mp-zoomInDown {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
  }
  to{
    opacity: 1;
  }
}
@keyframes mp-zoomInDown {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0);
    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0);
    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
  }
  to{
    opacity: 1;
  }
}
.mp-zoomInDown {
  -webkit-animation-name: mp-zoomInDown;
  animation-name: mp-zoomInDown;
}
//--------------------------- Zoom In Up---------------------------------//
@-webkit-keyframes mp-zoomInUp {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
  }
  to{
    opacity: 1;
  }
}
@keyframes mp-zoomInUp {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
    transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0);
    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
    transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0);
    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
  }
  to{
    opacity: 1;
  }
}
.mp-zoomInUp {
  -webkit-animation-name: mp-zoomInUp;
  animation-name: mp-zoomInUp;
}
//--------------------------- Zoom In Left---------------------------------//
@-webkit-keyframes mp-zoomInLeft {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
    transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
    transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
  }
  to{
    opacity: 1;
  }
}
@keyframes mp-zoomInLeft {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
    transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0);
    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
    transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0);
    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
  }
  to{
    opacity: 1;
  }
}
.mp-zoomInLeft {
  -webkit-animation-name: mp-zoomInLeft;
  animation-name: mp-zoomInLeft;
}
//--------------------------- Zoom In Right---------------------------------//
@-webkit-keyframes mp-zoomInRight {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
    transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
    transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
  }
  to{
    opacity: 1;
  }
}
@keyframes mp-zoomInRight {
  from {
    opacity: 0;
    -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
    transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0);
    -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
    animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19);
  }

  60% {
    opacity: 1;
    -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
    transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0);
    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
    animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1);
  }
  to{
    opacity: 1;
  }
}
.mp-zoomInRight {
  -webkit-animation-name: mp-zoomInRight;
  animation-name: mp-zoomInRight;
}
//--------------------------- Typing---------------------------------//
@-webkit-keyframes mp-typing{
    0% { width: 0%; }
    30%{ width: 0%; }
    100%{ width: 100%;}
}
@keyframes mp-typing{
    0% { width: 0%; }
    30%{ width: 0%; }
    100%{ width: 100%;}
}
.mp-typing{
    -webkit-animation: mp-typing;
            animation: mp-typing;
}
//--------------------------- Pulsate---------------------------------//
@-webkit-keyframes mp-pulsate {
  0% {
    -webkit-transform: scale(0.62);
    transform: scale(0.62);
    opacity: 1;
    box-shadow: inset 0px 0px 25px 3px rgba(207, 172, 114, 0.75), 0px 0px 25px 10px rgba(207, 172, 114, 0.75);
  }
  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
    opacity: 0;
    box-shadow: none;

  }
}
@keyframes mp-pulsate {
    0% {
        -webkit-transform: scale(0.62);
        transform: scale(0.62);
        opacity: 1;
        box-shadow: inset 0px 0px 25px 3px rgba(207, 172, 114, 0.75), 0px 0px 25px 10px rgba(207, 172, 114, 0.75);
    }
    100% {
        -webkit-transform: scale(1, 1);
        transform: scale(1);
        opacity: 0;
        box-shadow: none;

    }
}
.mp-pulsate{
    -webkit-animation: mp-pulsate;
            animation: mp-pulsate;
}
//--------------------------- Hotspot Pulse---------------------------------//
@-webkit-keyframes hotspot-pulse {
    0% {
        -webkit-transform: scale(1);
        box-shadow: 0 0 0 0 rgba($color: #fff, $alpha: .8);
    }
    70% {
        -webkit-transform: scale(1.1);
        box-shadow: 0 0 0 12px rgba(255, 255, 255, 0);
    }
    100% {
        -webkit-transform: scale(1);
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
    }
}
@keyframes hotspot-pulse {
    0% {
        transform: scale(1);
        box-shadow: 0 0 0 0 rgba($color: #fff, $alpha: .8);
    }
    70% {
        transform: scale(1.1);
        box-shadow: 0 0 0 12px rgba(255, 255, 255, 0);
    }
    100% {
        transform: scale(1);
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
    }
}

Bạn có thể thử trực tiếp ở trang

cubic-bezier.com
Animista - CSS Animations on DemandAnimista - CSS Animations on Demand
23KB
_mpa.scss
Logo