GODRICH

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

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. 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.

상단 8px 간격opacity+translateY200ms
.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

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

scale(.9)→1cubic-bezier 팝180ms
.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ỗ

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ạ độ. 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.

anchor-nameposition-try-fallbacks자동 뒤집힘
.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ẻ

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. 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ơ.

popover=manualtop layer280px 카드
.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

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. 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 đồ.

clip-path 삼각형4px 간격opacity
.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ễ

Đ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. 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.

animation-delay 400ms짧은 등장긴 유지
@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

Cùng một rule CSS được gắn cho cả :hover: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. Đâ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.

:focus-visible:hover 동시 대응aria-describedby
.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

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. Dùng cho câu chào đầu tiên của chatbot hoặc chú thích trong hướng dẫn onboarding.

border-radius 18px꼬리 pseudo등장 바운스
.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

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. 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.

box-shadow 펄스2초 주기opacity 감쇠
.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

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

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.