Giới thiệu API định vị neo CSS

Ngày xuất bản: 10 tháng 5 năm 2024

CSS Anchor Positioning API là một bước đột phá trong quá trình phát triển web vì API này cho phép bạn đặt các phần tử ở vị trí gốc so với các phần tử khác, còn được gọi là neo. API này đơn giản hoá các yêu cầu phức tạp về bố cục cho nhiều tính năng giao diện như trình đơn và trình đơn con, chú thích, lựa chọn, nhãn, thẻ, hộp thoại cài đặt và nhiều tính năng khác. Với tính năng định vị điểm neo được tích hợp sẵn trong trình duyệt, bạn có thể tạo giao diện người dùng theo lớp mà không cần dựa vào các thư viện của bên thứ ba, mở ra một thế giới đầy sáng tạo.

Tính năng định vị điểm neo có trong Chrome 125.

Browser Support

  • Chrome: 125.
  • Edge: 125.
  • Firefox Technology Preview: supported.
  • Safari: 26.

Source

Các khái niệm cốt lõi: Điểm neo và phần tử được định vị

Cốt lõi của API này nằm ở mối quan hệ giữa neocác phần tử được định vị. Điểm neo là một phần tử được chỉ định làm điểm tham chiếu bằng cách sử dụng thuộc tính anchor-name. Phần tử được định vị là phần tử được đặt tương ứng với một điểm neo bằng cách sử dụng thuộc tính position-anchor hoặc sử dụng anchor-name một cách rõ ràng trong logic định vị của phần tử đó.

Phần tử liên kết và phần tử được định vị.

Thiết lập điểm neo

Việc tạo điểm đánh dấu rất đơn giản. Áp dụng thuộc tính anchor-name cho phần tử đã chọn và chỉ định giá trị nhận dạng duy nhất cho phần tử đó. Giá trị nhận dạng duy nhất này phải được thêm dấu gạch ngang kép ở phía trước, tương tự như một biến CSS.

.anchor-button {
    anchor-name: --anchor-el;
}

Sau khi được chỉ định một tên neo, .anchor-button sẽ đóng vai trò là một neo, sẵn sàng hướng dẫn việc đặt các phần tử khác. Bạn có thể kết nối điểm neo này với các phần tử khác theo một trong hai cách:

Đường liên kết ngầm

Cách đầu tiên để kết nối một điểm neo với một phần tử khác là sử dụng điểm neo ngầm như trong ví dụ về mã sau. Thuộc tính position-anchor được thêm vào phần tử mà bạn muốn kết nối với điểm neo và có tên của điểm neo (trong trường hợp này là --anchor-el) làm giá trị.

.positioned-notice {
    position-anchor: --anchor-el;
}

Với mối quan hệ neo ngầm, bạn có thể định vị các phần tử bằng cách sử dụng hàm anchor() mà không cần chỉ định rõ tên neo ở đối số đầu tiên.

.positioned-notice {
    position-anchor: --anchor-el;
    top: anchor(bottom);
}

Quảng cáo cố định rõ ràng

Ngoài ra, bạn có thể sử dụng trực tiếp tên của phần tử neo trong hàm neo (ví dụ: top: anchor(--anchor-el bottom). Đây được gọi là phần tử neo rõ ràng và có thể hữu ích nếu bạn muốn neo vào nhiều phần tử (đọc tiếp để xem ví dụ).

.positioned-notice {
    top: anchor(--anchor-el bottom);
}

Định vị các phần tử tương ứng với các điểm neo

Sơ đồ định vị điểm neo có các thuộc tính vật lý.

Tính năng định vị điểm neo dựa trên tính năng định vị tuyệt đối của CSS. Để sử dụng các giá trị định vị, bạn cần thêm position: absolute vào phần tử được định vị. Sau đó, hãy dùng hàm anchor() để áp dụng các giá trị định vị. Ví dụ: để đặt một phần tử được neo ở trên cùng bên trái của phần tử neo, hãy sử dụng vị trí sau:

.positioned-notice {
    position-anchor: --anchor-el;
    /* absolutely position the positioned element */
    position: absolute;
    /* position the right of the positioned element at the right edge of the anchor */
    right: anchor(right);
    /* position the bottom of the positioned element at the top edge of the anchor */
    bottom: anchor(top);
}
Sơ đồ định vị các cạnh trên phần tử được định vị.

Giờ đây, bạn đã có một phần tử được liên kết với một phần tử khác, như trong hình sau.

Ảnh chụp màn hình bản minh hoạ.

Để sử dụng vị trí logic cho các giá trị này, các giá trị tương đương như sau:

  • top = inset-block-start
  • left= inset-inline-start
  • bottom = inset-block-end
  • right= inset-inline-end

Căn giữa một phần tử được định vị bằng anchor-center

Để dễ dàng căn giữa phần tử được đặt vị trí neo tương ứng với neo của phần tử đó, bạn có thể dùng một giá trị mới có tên là anchor-center với các thuộc tính justify-self, align-self, justify-itemsalign-items.

Ví dụ này sửa đổi ví dụ trước bằng cách sử dụng justify-self: anchor-center để căn giữa phần tử được định vị ở trên cùng của phần tử neo.

.positioned-notice {
  position: absolute;
  /*  Anchor reference  */
  position-anchor: --anchor-el;
  /*  Position bottom of positioned elem at top of anchor  */
  bottom: anchor(top);
  /*  Center justification to the anchor */
  justify-self: anchor-center;
}

Ảnh chụp màn hình bản minh hoạ.

Nhiều điểm neo

Các phần tử có thể được liên kết với nhiều điểm neo. Điều này có nghĩa là bạn có thể cần đặt các giá trị vị trí được đặt tương đối so với nhiều điểm neo. Hãy làm việc này bằng cách sử dụng hàm anchor() và nêu rõ neo mà bạn đang tham chiếu trong đối số đầu tiên. Trong ví dụ sau, phía trên cùng bên trái của một phần tử được định vị sẽ được liên kết với phía dưới cùng bên phải của một phần tử liên kết, còn phía dưới cùng bên phải của phần tử được định vị sẽ được liên kết với phía trên cùng bên trái của phần tử liên kết thứ hai:

.anchored {
  position: absolute;
  top: anchor(--one bottom);
  left: anchor(--one right);
  right: anchor(--two left);
  bottom: anchor(--two top);
}

Ảnh chụp màn hình bản minh hoạ.

Vị trí có inset-area

Ngoài chế độ định vị theo hướng mặc định từ chế độ định vị tuyệt đối, còn có một cơ chế bố cục mới có trong API neo, được gọi là vùng lồng ghép.

Vùng lồng ghép giúp bạn dễ dàng đặt các phần tử được định vị bằng điểm neo tương ứng với các điểm neo tương ứng và hoạt động trên lưới 9 ô với phần tử neo ở trung tâm.

Nhiều lựa chọn có thể có về vị trí vùng lồng ghép, xuất hiện trên lưới 9 ô

Để sử dụng vùng lồng ghép thay vì định vị tuyệt đối, hãy dùng thuộc tính inset-area, với các giá trị vật lý hoặc logic. Ví dụ:

  • Trên cùng ở giữa: inset-area: top hoặc inset-area: block-start
  • Bên trái – giữa: inset-area: left hoặc inset-area: inline-start
  • Dưới cùng chính giữa: inset-area: bottom hoặc inset-area: block-end
  • Giữa bên phải: inset-area: right hoặc inset-area: inline-end

Ảnh chụp màn hình bản minh hoạ.

Các phần tử kích thước có anchor-size()

Hàm anchor-size() (cũng là một phần của API định vị điểm neo) có thể được dùng để định kích thước hoặc định vị một phần tử được định vị điểm neo dựa trên kích thước của điểm neo (chiều rộng, chiều cao hoặc kích thước nội tuyến và kích thước khối).

CSS sau đây cho thấy ví dụ về cách sử dụng thuộc tính này cho chiều cao,sử dụng anchor-size(height) trong hàm calc() để đặt chiều cao tối đa của chú thích là gấp đôi chiều cao của phần tử neo.

.positioned-notice {
  position-anchor: --question-mark;

  /*  set max height of the tooltip to 2x height of the anchor  */
  max-height: calc(anchor-size(height) * 2);
}

Ảnh chụp màn hình bản minh hoạ.

Sử dụng điểm neo với các phần tử lớp trên cùng như cửa sổ bật lên và hộp thoại

Tính năng định vị phần tử cố định hoạt động cực kỳ hiệu quả với các phần tử lớp trên cùng như popover. và <dialog>. Mặc dù các phần tử này được đặt trong một lớp riêng biệt với phần còn lại của cây con DOM, nhưng tính năng định vị phần tử liên kết cho phép bạn liên kết chúng trở lại và cuộn cùng với các phần tử không nằm trong lớp trên cùng. Đây là một thành công lớn đối với các giao diện theo lớp.

Trong ví dụ sau, một nhóm chú thích bật lên sẽ được kích hoạt mở bằng một nút. Nút là phần tử cố định và chú thích là phần tử được định vị. Bạn có thể tạo kiểu cho phần tử được định vị giống như mọi phần tử được neo khác. Đối với ví dụ cụ thể này, anchor-nameposition-anchor là các kiểu nội tuyến trên nút và chú thích. Vì mỗi điểm neo cần có một tên điểm neo riêng biệt, nên khi tạo nội dung động, việc nội tuyến là cách dễ nhất để thực hiện việc này.

Ảnh chụp màn hình bản minh hoạ.

Điều chỉnh vị trí của điểm neo bằng @position-try

Sau khi có vị trí neo ban đầu, bạn có thể muốn điều chỉnh vị trí nếu neo chạm đến các cạnh của khối chứa. Để tạo các vị trí neo thay thế, bạn có thể sử dụng chỉ thị @position-try cùng với thuộc tính position-try-options.

Trong ví dụ sau, một trình đơn con xuất hiện ở bên phải của một trình đơn. Trình đơn và trình đơn con là một cách sử dụng hiệu quả API định vị điểm neo cùng với thuộc tính popover, vì các trình đơn này thường được neo vào một nút kích hoạt.

Đối với trình đơn con này, nếu không có đủ không gian theo chiều ngang, bạn có thể di chuyển trình đơn con này xuống dưới trình đơn. Để thực hiện việc này, trước tiên hãy thiết lập vị trí ban đầu:

#submenu {
  position: absolute;
  position-anchor: --submenu;

  /* initial position */
  margin-left: var(--padding);
  inset-area: right span-bottom;
}

Sau đó, hãy thiết lập các vị trí cố định dự phòng bằng cách sử dụng @position-try:

/* alternate position */
@position-try --bottom {
  margin: var(--padding) 0 0 var(--padding);
  inset-area: bottom;
}

Cuối cùng, hãy kết nối hai thiết bị bằng position-try-options. Tất cả cùng nhau sẽ có dạng như sau:

#submenu {
  position: absolute;
  position-anchor: --submenu;
  /* initial position */
  margin-left: var(--padding);
  inset-area: right span-bottom;
  */ connect with position-try options */
  position-try-options: --bottom;
}

/* alternate position */
@position-try --bottom {
  margin: var(--padding) 0 0 var(--padding);
  inset-area: bottom;
}

Từ khoá tự động lật vị trí của điểm neo

Nếu có một chế độ điều chỉnh cơ bản, chẳng hạn như lật từ trên xuống dưới hoặc từ trái sang phải (hoặc cả hai), bạn thậm chí có thể bỏ qua bước tạo các khai báo @position-try tuỳ chỉnh và sử dụng các từ khoá lật được trình duyệt tích hợp hỗ trợ như flip-blockflip-inline. Các chú thích này hoạt động như một giải pháp thay thế cho các khai báo @position-try tuỳ chỉnh và có thể được dùng kết hợp với nhau:

position-try-options: flip-block, flip-inline, flip-block flip-inline;

Từ khoá flip có thể giúp đơn giản hoá đáng kể mã liên kết. Chỉ với vài dòng, bạn có thể tạo một phần tử neo có đầy đủ chức năng với các vị trí thay thế:

#my-tooltip {
  position-anchor: --question-mark;
  inset-area: top;
  position-try-options: flip-block;
}

position-visibility cho các điểm neo trong thành phần cuộn phụ

Trong một số trường hợp, bạn có thể muốn cố định một phần tử trong một trình cuộn phụ của trang. Trong những trường hợp này, bạn có thể kiểm soát chế độ hiển thị của điểm neo bằng cách sử dụng position-visibility. Khi nào thì chú thích vẫn xuất hiện? Khi nào thì thông báo này biến mất? Bạn có thể kiểm soát các lựa chọn này bằng tính năng này. Bạn sử dụng position-visibility: anchors-visible khi muốn phần tử được định vị vẫn hiển thị cho đến khi phần tử neo không còn hiển thị:

#tooltip {
  position: fixed;
  position-anchor: --anchor-top-anchor;
  position-visibility: anchors-visible;
  bottom: anchor(top);
}

Hoặc bạn có thể dùng position-visibility: no-overflow để ngăn neo tràn vùng chứa.

#tooltip {
  position: absolute;
  position-anchor: --anchor-top-anchor;
  position-visibility: no-overflow;
  bottom: anchor(top);
}

Phát hiện tính năng và polyfill

Vì trình duyệt hiện chỉ hỗ trợ ở mức hạn chế, nên bạn có thể muốn sử dụng API này một cách thận trọng. Trước tiên, bạn có thể kiểm tra khả năng hỗ trợ ngay trong CSS bằng cách sử dụng truy vấn tính năng @supports. Cách thực hiện việc này là gói các kiểu liên kết trong phần sau:

@supports (anchor-name: --myanchor) {

  /* Anchor styles here */

}

Ngoài ra, bạn có thể polyfill tính năng định vị phần tử neo bằng CSS anchor positioning polyfill của Oddbird. Tính năng này hoạt động từ Firefox 54, Chrome 51, Edge 79 và Safari 10. Polyfill này hỗ trợ hầu hết các tính năng cơ bản về vị trí của phần tử neo, mặc dù chế độ triển khai hiện tại chưa hoàn chỉnh và có chứa một số cú pháp lỗi thời. Bạn có thể sử dụng đường liên kết unpkg hoặc nhập trực tiếp đường liên kết đó vào trình quản lý gói.

Lưu ý về khả năng hỗ trợ tiếp cận

Mặc dù API định vị phần tử neo cho phép định vị một phần tử tương ứng với các phần tử khác, nhưng API này vốn không tạo ra mối quan hệ ngữ nghĩa có ý nghĩa nào giữa các phần tử đó. Nếu thực sự có mối quan hệ ngữ nghĩa giữa phần tử liên kết và phần tử được định vị (ví dụ: phần tử được định vị là một bình luận trên thanh bên về văn bản liên kết), thì một cách để thực hiện việc đó là sử dụng aria-details để trỏ từ phần tử liên kết đến(các) phần tử được định vị. Phần mềm trình đọc màn hình vẫn đang học cách xử lý aria-details, nhưng khả năng hỗ trợ đang được cải thiện.

<div class="anchor" aria-details="sidebar-comment">Main content</div>
<div class="positioned" id="sidebar-comment">Sidebar content</div>
.anchor {
  anchor-name: --anchor;
}

.positioned {
  position: fixed;
  position-anchor: --anchor;
}

Nếu bạn đang sử dụng tính năng định vị phần tử neo bằng thuộc tính popover hoặc bằng phần tử <dialog>, thì trình duyệt sẽ xử lý các điểm điều chỉnh điều hướng tiêu điểm để đảm bảo khả năng tiếp cận phù hợp, do đó, bạn không cần phải sắp xếp các cửa sổ bật lên hoặc hộp thoại theo thứ tự DOM. Đọc thêm về ghi chú về khả năng hỗ trợ tiếp cận trong quy cách.

Kết luận

Đây là một tính năng hoàn toàn mới và chúng tôi rất háo hức chờ đón những điều mà bạn sẽ xây dựng bằng tính năng này. Cho đến nay, chúng tôi đã thấy một số trường hợp sử dụng thực sự hữu ích từ cộng đồng, chẳng hạn như nhãn động trong biểu đồ, đường kết nối, chú thích và tham chiếu chéo trực quan. Trong quá trình thử nghiệm tính năng định vị điểm neo, chúng tôi rất mong nhận được ý kiến phản hồi của bạn. Nếu bạn phát hiện thấy lỗi, hãy cho chúng tôi biết.

Tài liệu đọc thêm