GODRICH
#css-animation#button#loader#transition#scroll#ui#xu-huong-thiet-ke

9 CSS tooltip examples — copy dán một dòng là chạy

CSS tooltip examples ở đây là chín kiểu bong bóng chú thích hiện lên khi bạn hover hoặc focus vào một phần tử, hầu hết chạy bằng CSS thuần chứ không cần

Tự chạy · bấm ô để tới mục đó · cả 9 trong một zip

Chín kiểu này không xếp theo độ phổ biến mà theo thứ tự tooltip gặp vấn đề trên thực tế: 01–02 là kiểu xuất hiện đơn giản nhất, 03–05 là lúc vị trí bắt đầu khó, 06–07 xử lý thời điểm hiện khác nhau, còn 08–09 là hai biến thể đã đi hơi xa khỏi khung "tooltip" thông thường. Mỗi mục chỉ giữ đoạn CSS cốt lõi; bản đầy đủ của cả chín file nằm trong một file zip duy nhất bên dưới.

01Hiện phía trên cơ bản

Bạn thấy gì

Một bong bóng nhỏ hiện phía trên phần tử nhờ hiệu ứng opacity và dịch chuyển theo trục dọc, rồi biến mất khi con trỏ rời đi. Lần cập nhật này, khi vừa hiện, tỉ lệ phóng lên tới 1,12 trước khi lắng xuống qua một vòng rung giảm chấn quanh trục cạnh dưới, xoay 2,6°→-1,5°→0,6° rồi dừng hẳn.

Hiện phía trên cơ bản
Mở trong tab mới

01 · Hiện phía trên cơ bản — Diện tích đo được 4.959% · khung hình chuyển động 15/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

상단 8px 간격opacity + translate 4px200ms

Dùng ở đâu

Bạn dùng kiểu này cho icon trợ giúp cạnh nút hoặc chú thích từ viết tắt trong tiêu đề bảng.

.tooltip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translate(-50%, 4px);
  opacity: 0;
}
.tooltip.is-demo {
  animation: tip-loop $duration $easing infinite;
}
@keyframes tip-loop {
  0%, 100% { opacity: 0; transform: translate(-50%, 4px); }
  20%, 55% { opacity: 1; transform: translate(-50%, 0); }
  80%      { opacity: 0; transform: translate(-50%, 4px); }
}

02Mờ dần và phóng to bật lên

Chuyện gì diễn ra trên màn hình

Tooltip bắt đầu từ trạng thái hơi thu nhỏ rồi phóng to lên đúng kích thước như vừa bật ra, tạo cảm giác mới xuất hiện chứ không phải một khung thông tin cứng nhắc. Đợt này thêm một vòng bật lò xo chỉ chạy một lần: tỉ lệ vọt lên 1,14 rồi giảm chấn qua các mốc xoay -2,4°→1,4°→-0,5° quanh cạnh trên trước khi đứng yên.

Mờ dần và phóng to bật lên
Mở trong tab mới

02 · Mờ dần và phóng to bật lên — Diện tích đo được 5.799% · khung hình chuyển động 11/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

scale(.9)→1cubic-bezier 팝180ms

Chỗ dùng

Hợp với huy hiệu tính năng mới hoặc icon trên toolbar cần gây chú ý.

.tooltip {
  top: calc(100% + 10px);
  left: 50%;
  transform-origin: top center;
  transform: translateX(-50%) scale(.85);
  opacity: 0;
}
.tooltip.is-demo {
  animation: pop-loop $duration $easing infinite;
}
@keyframes pop-loop {
  0%, 100% { opacity: 0; transform: translateX(-50%) scale(.85); }
  25%, 55% { opacity: 1; transform: translateX(-50%) scale(1); }
  80%      { opacity: 0; transform: translateX(-50%) scale(.85); }
}

03Tự lật hướng khi hết chỗ

Chuyển động thế nào

Gắn anchor-name cho phần tử kích hoạt rồi cho tooltip position-anchor cùng position-try-fallbacks: flip-block, trình duyệt sẽ tự lật tooltip sang phía còn chỗ trống mà bạn không phải tính toạ độ. Cả bản dự phòng lẫn bản định vị theo anchor giờ cùng chia sẻ một vòng xoay giảm chấn khi hiện lên — tỉ lệ vọt tới 1,1 rồi xoay 2,2°→-1,3°→0,5° quanh cạnh trên trước khi ổn định.

Tự lật hướng khi hết chỗ
Mở trong tab mới

03 · Tự lật hướng khi hết chỗ — Diện tích đo được 6.054% · khung hình chuyển động 15/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

anchor-nameposition-try-fallbacks자동 뒤집힘

Dùng khi nào

Dùng cho nút gần thanh cố định ở cuối màn hình hoặc icon trong sidebar hẹp, nơi vị trí khả dụng đổi liên tục.

.trigger {
  anchor-name: --tip03;
}
@supports (position-anchor: --tip03) {
  .tooltip {
    position: fixed;
    position-anchor: --tip03;
    position-area: top;
    position-try-fallbacks: flip-block;
    margin-block: 10px;
  }
}

04Tooltip xem trước dạng thẻ

Bạn thấy gì

Popover API đưa thẻ xem trước lên top layer nên nó luôn nằm trên mọi nội dung khác, bất kể overflow hay z-index của phần tử cha. Thẻ giờ cũng phóng lên với một vòng bật giảm chấn nhẹ — tỉ lệ vọt tới 1,08 rồi xoay 1,8°→-1°→0,4° quanh cạnh trên trước khi dừng.

Tooltip xem trước dạng thẻ
Mở trong tab mới

04 · Tooltip xem trước dạng thẻ — Diện tích đo được 23.918% · khung hình chuyển động 13/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

popover=manualtop layer280px 카드

Dùng ở đâu

Dùng khi bạn cần bản xem trước có ảnh và mô tả, như khi hover trên danh sách sản phẩm hoặc thẻ tóm tắt trên tên hồ sơ.

.card {
  position: absolute;
  top: calc(100% + 12px);
  left: 50%;
  transform: translateX(-50%);
}
.card:popover-open {
  position: fixed;
  top: 150px;
  left: 50%;
}

05Đuôi mũi tên chỉ hướng

Chuyện gì diễn ra trên màn hình

Một tam giác nhỏ được cắt bằng clip-path và gắn dưới bong bóng cho biết chính xác tooltip đang chỉ vào phần tử nào. Khi hiện lên, cả bong bóng lẫn mũi tên cùng phóng tới tỉ lệ 1,12 rồi giảm chấn qua vòng xoay 2,6°→-1,5°→0,6° quanh đúng trục mà mũi tên đang chỉ.

Đuôi mũi tên chỉ hướng
Mở trong tab mới

05 · Đuôi mũi tên chỉ hướng — Diện tích đo được 4.799% · khung hình chuyển động 15/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

clip-path 삼각형4px 간격opacity

Chỗ dùng

Dùng cho gợi ý định dạng cạnh ô nhập liệu hoặc chú thích một điểm dữ liệu trên biểu đồ.

.tooltip::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  width: 14px;
  height: 8px;
  clip-path: polygon(50% 100%, 0 0, 100% 0);
}

06Hiện có độ trễ

Chuyển động thế nào

Đoạn đầu của keyframe giữ opacity ở 0 nên tooltip không hiện ngay khi con trỏ lướt qua, chỉ hiện khi bạn dừng lại một chút. Khi độ trễ kết thúc và tooltip bật ra, tỉ lệ vọt lên 1,12 rồi giảm chấn qua vòng xoay 2,4°→-1,4°→0,5° trước khi đứng yên.

Hiện có độ trễ
Mở trong tab mới

06 · Hiện có độ trễ — Diện tích đo được 6.83% · khung hình chuyển động 13/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

@keyframes delay-loop짧은 등장긴 유지

Dùng khi nào

Hợp với toolbar nhiều icon sát nhau hoặc icon lặp lại trên từng dòng danh sách, nơi hiện quá nhanh chỉ gây rối mắt.

@keyframes delay-loop {
  0%, 20%  { opacity: 0; }
  40%, 80% { opacity: 1; }
  100%     { opacity: 0; }
}
.tooltip.is-demo {
  animation: delay-loop $duration $easing infinite;
}

07Hiện khi focus bàn phím

Bạn thấy gì

Cùng một rule CSS được gắn cho cả :hover và :focus-visible nên tooltip hiện y hệt nhau dù bạn rê chuột hay dùng phím Tab để di chuyển focus. Ở cả hai cách kích hoạt, tooltip giờ phóng tới tỉ lệ 1,12 rồi giảm chấn qua vòng xoay 2,6°→-1,5°→0,6° quanh cạnh dưới trước khi dừng hẳn.

Hiện khi focus bàn phím
Mở trong tab mới

07 · Hiện khi focus bàn phím — Diện tích đo được 5.953% · khung hình chuyển động 14/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

:focus-visible:hover 동시 대응aria-describedby

Dùng ở đâu

Đây gần như là điều bắt buộc cho nhãn form dành cho người chỉ dùng bàn phím hoặc nút icon cần đạt chuẩn tiếp cận.

.tooltip {
  opacity: 0;
  transition: opacity $duration $easing;
}
.gear-btn:hover + .tooltip,
.gear-btn:focus-visible + .tooltip {
  opacity: 1;
}

08Bong bóng kiểu ứng dụng nhắn tin

Chuyện gì diễn ra trên màn hình

Tooltip bo tròn ba góc và để một góc vuông làm đuôi bằng clip-path, nên trông giống tin nhắn chat hơn là một khung thông tin thông thường. Khi bong bóng bật ra, tỉ lệ vọt tới 1,14 rồi giảm chấn qua vòng xoay 3°→-1,7°→0,7° quanh góc đuôi tin nhắn trước khi ổn định.

Bong bóng kiểu ứng dụng nhắn tin
Mở trong tab mới

08 · Bong bóng kiểu ứng dụng nhắn tin — Diện tích đo được 9.751% · khung hình chuyển động 11/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

border-radius 18px꼬리 pseudo등장 바운스

Chỗ dùng

Dùng cho câu chào đầu tiên của chatbot hoặc chú thích trong hướng dẫn onboarding.

.bubble {
  border-radius: 18px 18px 18px 4px;
  transform-origin: bottom left;
  transform: scale(.85);
  opacity: 0;

  &::after {
    content: "";
    position: absolute;
    left: -6px;
    bottom: 0;
    width: 12px;
    height: 12px;
    clip-path: polygon(100% 0, 100% 100%, 0 100%);
  }
}

09Chấm pulse gợi ý thông tin

Chuyển động thế nào

Một quầng sáng mờ phía sau chấm nhỏ phóng to rồi mờ dần liên tục, báo hiệu có thông tin đáng xem trước khi bạn kịp hover vào. Khi tooltip hiện lên cạnh chấm, nó cũng phóng tới tỉ lệ 1,12 rồi giảm chấn qua vòng xoay 2,6°→-1,5°→0,6° quanh cạnh dưới, tách biệt hẳn với nhịp pulse-ring nền.

Chấm pulse gợi ý thông tin
Mở trong tab mới

09 · Chấm pulse gợi ý thông tin — Diện tích đo được 7.869% · khung hình chuyển động 20/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · Xem mật khẩu

@keyframes pulse-ring2초 주기opacity 감쇠

Dùng khi nào

Dùng cho huy hiệu tính năng mới hoặc icon trợ giúp ở góc màn hình cài đặt.

.dot::before {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  animation: pulse-ring $duration $easing infinite;
}
@keyframes pulse-ring {
  0%, 100% { transform: scale(.6); opacity: .5; }
  50%      { transform: scale(1.6); opacity: 0; }
}

Chỗ dễ hỏng ở đâu? — cái bẫy

Thuộc tính popover và lớp trên cùng

Trong chín kiểu này, mục 04 tooltip xem trước dạng thẻ tốn nhiều thời gian nhất để làm cho đúng. Khi một phần tử có thuộc tính popover được mở ra, trình duyệt sẽ đưa nó lên top layer, và containing block của nó đổi từ phần tử cha sang chính viewport. Bản đầu tiên vẫn giữ position: absolute; top: calc(100% + 12px) như trước khi mở, nên thẻ bị đẩy hẳn ra ngoài khung xem — nhìn qua bạn sẽ tưởng CSS viết sai, nhưng lý do thật là containing block đã đổi. Chỉ khi thêm riêng một rule cho :popover-open với top là một giá trị pixel cố định theo chiều cao khung demo thì thẻ mới trở lại đúng chỗ, và ngay trong câu này bạn cũng đã có mật khẩu uauwf4hn để mở file gốc ra đối chiếu, khỏi phải đoán.

Khả năng tiếp cận

Trạng thái cuối khi giảm chuyển động

Cả chín demo đều phản hồi prefers-reduced-motion, nhưng không phải lúc nào cũng tắt hẳn animation — có lúc là nhảy thẳng tới trạng thái cuối. Từ mục 01 đến mục 06, cùng mục 08 và 09, bỏ animation và giữ nguyên opacity: 1 ở trạng thái đã hiện, để nội dung tooltip vẫn đọc được mà không cần chờ bước mờ dần hay bật lên. Mục 07 (hiện khi focus bàn phím) không phụ thuộc animation-loop của demo, vì rule :focus-visible chạy độc lập với animation, nên dù tắt chuyển động thì tooltip vẫn hiện ngay khi bạn Tab tới nút. Tài liệu MDN về prefers-reduced-motion ghi rõ mức hỗ trợ trình duyệt của media query này.

@media (prefers-reduced-motion: reduce) {
  .tooltip, .bubble, .card, .dot::before {
    animation: none !important;
    opacity: 1;
  }
}

Xem thêm các kiểu CSS phản hồi khác trong chuyên mục CSS, còn lý do blog này tồn tại thì nằm ở trang giới thiệu.

FAQ

CSS tooltip examples có bắt buộc dùng JavaScript không?

Không. Tám trong chín kiểu ở đây chạy hoàn toàn bằng CSS thuần. Chỉ mục 04 tooltip xem trước dạng thẻ cần một dòng script gọi showPopover() để mở phần tử popover, còn vị trí và chuyển động sau đó vẫn do CSS quyết định.

Popover API được trình duyệt nào hỗ trợ?

Theo MDN về Popover API, tính năng này chạy được từ Chrome 114, Safari 17 và Firefox 125. Mục 04 trong gói zip vẫn giữ position: absolute làm phần dự phòng cho trình duyệt cũ hơn.

CSS anchor positioning ở mục 03 chạy được trên trình duyệt nào?

Theo caniuse (kiểm tra 9/2026), Chrome và Edge hỗ trợ từ bản 125, đầy đủ theo đặc tả kể từ bản 151; Safari hỗ trợ đầy đủ từ bản 27; Firefox mới hỗ trợ một phần từ bản 147. Trước khi đưa vào dự án thật, hãy bọc rule anchor trong @supports (position-anchor: --tip03) như mục 03 trong gói zip đã làm.

Nhập mật khẩu file nén

Mật khẩu nằm ngay trong bài viết này. Đọc tới đó bạn sẽ thấy.