SnippetUI

Thanh Điều Hướng Floating Dock

Điều hướng dock nổi giống như macOS nơi các biểu tượng mở rộng khi được di chuột.

HTMLCSS

Xem trước

Menu điều hướng tương tự như macOS Dock, với các biểu tượng mở rộng mượt mà khi di chuột.

Trường hợp sử dụng và tính năng

Dock nổi này lý tưởng nếu bạn muốn vừa có tác động trực quan vừa muốn dễ sử dụng làm điều hướng chính cho ứng dụng của mình.

  • Trang tổng quan và ứng dụng web: Cố định vị trí ở cuối màn hình, tiết kiệm không gian và giúp truy cập các chức năng chính dễ dàng hơn.

  • Trang web danh mục đầu tư: Tương tác phong phú mang đến cho người dùng ấn tượng tinh tế.

  • Hoạt ảnh đặc trưng: Bằng cách sử dụng lớp giả CSS :has(), có thể đạt được hoạt ảnh mở rộng liên tục mượt mà mà không cần sử dụng JavaScript.

Điểm thiết kế và UX

  1. Glassmorphism: Áp dụng backdrop-filter: blur() cho nền mang lại cho nền một kết cấu hiện đại cho phép nhìn xuyên qua nội dung phía sau.

  2. Mở rộng mượt mà: Bằng cách chỉ định transform-origin: bottom center, biểu tượng sẽ tự nhiên mở rộng lên trên từ dưới lên.

  3. Hợp tác chú giải công cụ: Không chỉ các biểu tượng phóng to khi di chuột mà cả các chú giải công cụ cho biết vai trò của từng biểu tượng nổi lên, truyền tải rõ ràng các tên chức năng khó truyền tải chỉ bằng các biểu tượng.

  4. Tương thích với chế độ tối: Tự động điều chỉnh màu nền và bóng để duy trì khả năng hiển thị và vẻ đẹp trong mọi môi trường chủ đề.

Cách tùy chỉnh

Điều chỉnh các thuộc tính bên dưới để phù hợp với yêu cầu dự án của bạn.

  • Thay đổi tỷ lệ phóng to: Bạn có thể điều chỉnh kích thước phóng to tối đa bằng cách thay đổi giá trị transform: scale(1.4) của .dock-item:hover.

  • Tỷ lệ phóng đại phần tử liền kề: Điều chỉnh cường độ của hiệu ứng gợn sóng bằng cách thay đổi scale(1.15) hoặc scale(1.05) chẳng hạn như .dock-item:has(+ .dock-item:hover).

  • Kích thước đế: Bạn có thể tùy chỉnh kích thước tổng thể bằng cách thay đổi width / height của .dock-itemheight của .dock.

Mã triển khai

Sao chép mã bên dưới và sử dụng nó trong dự án của bạn.

<div class="dock-wrapper">

<nav class="dock">

  <a href="#" class="dock-item" data-tooltip="Home">

    <svg viewBox="0 0 24 24"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>

  </a>

  <a href="#" class="dock-item" data-tooltip="Messages">

    <svg viewBox="0 0 24 24"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6l-2 2V4h16v12z"/></svg>

  </a>

  <a href="#" class="dock-item" data-tooltip="Dashboard">

    <svg viewBox="0 0 24 24"><path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"/></svg>

  </a>

  <a href="#" class="dock-item" data-tooltip="Settings">

    <svg viewBox="0 0 24 24"><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.06-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.73,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.06,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.43-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.49-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></svg>

  </a>

  <a href="#" class="dock-item" data-tooltip="Profile">

    <svg viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>

  </a>

</nav>

</div>



<style>
.dock-wrapper {

  display: flex;

  justify-content: center;

  align-items: center;

  min-height: 200px;

  padding: 40px 20px;

  background-color: #f8fafc;

  overflow: hidden;

  border-radius: 12px;

}



/* Tương thích với chế độ tối */

@media (prefers-color-scheme: dark) {

  .dock-wrapper {

    background-color: #0f172a;

  }

}



.dock {

  display: flex;

  justify-content: center;

  align-items: flex-end;

  padding: 12px;

  background: rgba(255, 255, 255, 0.4);

  backdrop-filter: blur(20px);

  -webkit-backdrop-filter: blur(20px);

  border: 1px solid rgba(255, 255, 255, 0.7);

  border-radius: 24px;

  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05), inset 0 1px 0 rgba(255, 255, 255, 0.8);

  gap: 12px;

  height: 74px;

  position: relative;

}



@media (prefers-color-scheme: dark) {

  .dock {

    background: rgba(30, 41, 59, 0.5);

    border-color: rgba(255, 255, 255, 0.1);

    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.05);

  }

}



.dock-item {

  width: 50px;

  height: 50px;

  background: linear-gradient(135deg, #ffffff 0%, #f1f5f9 100%);

  border-radius: 14px;

  display: flex;

  justify-content: center;

  align-items: center;

  color: #334155;

  text-decoration: none;

  transition: all 0.25s cubic-bezier(0.25, 1, 0.5, 1);

  position: relative;

  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.08), inset 0 1px 1px rgba(255, 255, 255, 1);

  transform-origin: bottom center;

}



@media (prefers-color-scheme: dark) {

  .dock-item {

    background: linear-gradient(135deg, #334155 0%, #1e293b 100%);

    color: #cbd5e1;

    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3), inset 0 1px 1px rgba(255, 255, 255, 0.1);

  }

}



.dock-item svg {

  width: 24px;

  height: 24px;

  fill: currentColor;

  transition: all 0.25s ease;

}



/* ツールチップ */

.dock-item::before {

  content: attr(data-tooltip);

  position: absolute;

  top: -45px;

  background: rgba(15, 23, 42, 0.9);

  color: white;

  padding: 6px 12px;

  border-radius: 8px;

  font-size: 12px;

  font-weight: 500;

  opacity: 0;

  transform: translateY(10px);

  transition: all 0.3s cubic-bezier(0.25, 1, 0.5, 1);

  pointer-events: none;

  white-space: nowrap;

  box-shadow: 0 4px 12px rgba(0,0,0,0.15);

}



@media (prefers-color-scheme: dark) {

  .dock-item::before {

    background: rgba(255, 255, 255, 0.9);

    color: #0f172a;

  }

}



/* ホバー時の中央要素 */

.dock-item:hover {

  transform: scale(1.4);

  margin: 0 12px;

  z-index: 10;

  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15), inset 0 1px 1px rgba(255, 255, 255, 1);

}



@media (prefers-color-scheme: dark) {

  .dock-item:hover {

    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.4), inset 0 1px 1px rgba(255, 255, 255, 0.2);

  }

}



.dock-item:hover::before {

  opacity: 1;

  transform: translateY(0);

}



/* 直近の隣接要素(左右) */

.dock-item:has(+ .dock-item:hover),

.dock-item:hover + .dock-item {

  transform: scale(1.15);

  margin: 0 4px;

  z-index: 5;

}



/* 2つ隣の要素(左右) */

.dock-item:has(+ .dock-item + .dock-item:hover),

.dock-item:hover + .dock-item + .dock-item {

  transform: scale(1.05);

  z-index: 1;

}

</style>

Trạng thái tương thích với trình duyệt

Đoạn mã này sử dụng lớp giả CSS :has() để đạt được hoạt ảnh mượt mà.

  • Chrome/Edge: 105+ (được hỗ trợ đầy đủ)

  • Safari: 15.4+ (được hỗ trợ đầy đủ)

  • Firefox: 121+ (được hỗ trợ đầy đủ)

Ngay cả trong môi trường trình duyệt cũ hơn, hành vi dự phòng là chỉ phóng to biểu tượng được di chuột mà không gây ra lỗi.