Chia sẻ các phần tử với nhau bằng vị trí neo CSS

Hiện tại, bạn liên kết một phần tử với một phần tử khác như thế nào? Bạn có thể thử theo dõi vị trí của các phần tử này hoặc sử dụng một số dạng phần tử trình bao bọc.

<!-- index.html -->
<div class="container">
  <a href="/link" class="anchor">I’m the anchor</a>
  <div class="anchored">I’m the anchored thing</div>
</div>
/* styles.css */
.container {
  position: relative;
}
.anchored {
  position: absolute;
}

Những giải pháp này thường không lý tưởng. Chúng cần JavaScript hoặc thêm mã đánh dấu. API định vị neo CSS nhằm giải quyết vấn đề này bằng cách cung cấp API CSS cho các phần tử liên kết. Phương thức này cung cấp một phương tiện để định vị và xác định kích thước của một phần tử dựa trên vị trí và kích thước của các phần tử khác.

Hình ảnh cho thấy một cửa sổ trình duyệt mô phỏng chi tiết cấu trúc của chú giải công cụ.

Hỗ trợ trình duyệt

Bạn có thể dùng thử API định vị neo CSS trong Chrome Canary bằng cờ "Tính năng thử nghiệm của nền tảng web". Để bật cờ đó, hãy mở Chrome Canary rồi truy cập vào chrome://flags. Sau đó, hãy bật cờ "Tính năng thử nghiệm của nền tảng web".

Nhóm Oddbird cũng đang phát triển một polyfill. Hãy nhớ kiểm tra kho lưu trữ tại github.com/oddbird/css-anchor-positioning.

Bạn có thể kiểm tra khả năng hỗ trợ liên kết bằng:

@supports(anchor-name: --foo) {
  /* Styles... */
}

Xin lưu ý rằng API này vẫn đang trong giai đoạn thử nghiệm và có thể thay đổi. Bài viết này trình bày các phần quan trọng ở cấp độ tổng quát. Cách triển khai hiện tại cũng chưa hoàn toàn đồng bộ với thông số kỹ thuật của Nhóm làm việc CSS.

Vấn đề

Tại sao bạn cần phải làm việc này? Một trường hợp sử dụng nổi bật là tạo chú giải công cụ hoặc trải nghiệm tương tự như chú giải công cụ. Trong trường hợp đó, bạn thường muốn liên kết chú giải công cụ với nội dung mà chú giải công cụ đó tham chiếu. Thường thì bạn cần có một số cách để liên kết một phần tử với phần tử khác. Bạn cũng muốn việc tương tác với trang không làm gián đoạn kết nối đó, ví dụ: nếu người dùng cuộn hoặc đổi kích thước giao diện người dùng.

Một vấn đề khác là nếu bạn muốn đảm bảo phần tử được liên kết vẫn hiển thị, ví dụ: nếu bạn mở một chú giải công cụ và chú giải công cụ đó bị cắt bớt bởi các giới hạn khung nhìn. Đây có thể không phải là trải nghiệm tốt cho người dùng. Bạn muốn chú giải công cụ thích ứng.

Giải pháp hiện tại

Hiện tại, bạn có thể giải quyết vấn đề này theo một số cách.

Trước tiên, hãy xem phương pháp "Gói phần neo" cơ bản. Bạn lấy cả hai phần tử và gói chúng trong một vùng chứa. Sau đó, bạn có thể sử dụng position để định vị chú giải công cụ so với neo.

<div class="containing-block">
  <div class="tooltip">Anchor me!</div>
  <a class="anchor">The anchor</a>
</div>
.containing-block {
  position: relative;
}

.tooltip {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
}

Bạn có thể di chuyển vùng chứa và hầu hết mọi thứ sẽ vẫn ở vị trí bạn muốn.

Một phương pháp khác có thể là nếu bạn biết vị trí của neo hoặc bạn có thể theo dõi neo theo cách nào đó. Bạn có thể truyền giá trị này đến chú giải công cụ bằng các thuộc tính tuỳ chỉnh.

<div class="tooltip">Anchor me!</div>
<a class="anchor">The anchor</a>
:root {
  --anchor-width: 120px;
  --anchor-top: 40vh;
  --anchor-left: 20vmin;
}

.anchor {
  position: absolute;
  top: var(--anchor-top);
  left: var(--anchor-left);
  width: var(--anchor-width);
}

.tooltip {
  position: absolute;
  top: calc(var(--anchor-top));
  left: calc((var(--anchor-width) * 0.5) + var(--anchor-left));
  transform: translate(-50%, calc(-100% - 10px));
}

Nhưng nếu bạn không biết vị trí của neo thì sao? Bạn có thể cần can thiệp bằng JavaScript. Bạn có thể làm như mã sau, nhưng giờ đây, điều này có nghĩa là các kiểu của bạn bắt đầu bị rò rỉ từ CSS sang JavaScript.

const setAnchorPosition = (anchored, anchor) => {
  const bounds = anchor.getBoundingClientRect().toJSON();
  for (const [key, value] of Object.entries(bounds)) {
    anchored.style.setProperty(`--${key}`, value);
  }
};

const update = () => {
  setAnchorPosition(
    document.querySelector('.tooltip'),
    document.querySelector('.anchor')
  );
};

window.addEventListener('resize', update);
document.addEventListener('DOMContentLoaded', update);

Điều này đặt ra một số câu hỏi:

  • Khi nào tôi tính toán các kiểu?
  • Làm cách nào để tính toán các kiểu?
  • Tôi tính toán kiểu bao lâu một lần?

Cách đó có giải quyết được vấn đề không? Giải pháp này có thể phù hợp với trường hợp sử dụng của bạn, nhưng có một vấn đề: giải pháp của chúng tôi không thích ứng. Không thích ứng. Điều gì sẽ xảy ra nếu thành phần được liên kết của tôi bị cắt bớt bởi khung nhìn?

Bây giờ, bạn cần quyết định xem có phản ứng với điều này hay không và phản ứng như thế nào. Số lượng câu hỏi và quyết định bạn cần đưa ra đang bắt đầu tăng lên. Tất cả những gì bạn muốn làm là liên kết một phần tử với một phần tử khác. Và trong trường hợp lý tưởng, giải pháp của bạn sẽ điều chỉnh và phản ứng với môi trường xung quanh.

Để giảm bớt một số vấn đề đó, bạn có thể tìm đến giải pháp JavaScript để giúp bạn giải quyết. Điều đó sẽ làm phát sinh chi phí thêm phần phụ thuộc vào dự án và có thể gây ra các vấn đề về hiệu suất tuỳ thuộc vào cách bạn sử dụng các phần phụ thuộc đó. Ví dụ: một số gói sử dụng requestAnimationFrame để giữ đúng vị trí. Điều này có nghĩa là bạn và nhóm của bạn cần làm quen với gói này và các tuỳ chọn cấu hình của gói. Do đó, số lượng câu hỏi và quyết định của bạn có thể không giảm đi mà thay vào đó là thay đổi. Đây là một phần của "lý do" cho việc định vị neo CSS. Phương thức này sẽ giúp bạn không phải suy nghĩ về các vấn đề về hiệu suất khi tính toán vị trí.

Dưới đây là mã có thể dùng để sử dụng "floating-ui", một gói phổ biến cho vấn đề này:

import {computePosition, flip, offset, autoUpdate} from 'https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.2.1/+esm';

const anchor = document.querySelector('.anchor')
const tooltip = document.querySelector('.tooltip')

const updatePosition = () => {  
  computePosition(anchor, tooltip, {
    placement: 'top',
    middleware: [offset(10), flip()]
  })
    .then(({x, y}) => {
      Object.assign(tooltip.style, {
        left: `${x}px`,
        top: `${y}px`
      })
  })
};

const clean = autoUpdate(anchor, tooltip, updatePosition);

Hãy thử định vị lại phần neo trong bản minh hoạ sử dụng mã đó.

"Cụm từ gợi ý" có thể không hoạt động như mong đợi. Nó phản ứng khi ra khỏi khung nhìn trên trục y nhưng không phản ứng khi ra khỏi khung nhìn trên trục x. Hãy tìm hiểu tài liệu này và bạn có thể sẽ tìm thấy một giải pháp phù hợp với mình.

Tuy nhiên, việc tìm một gói phù hợp với dự án của bạn có thể mất nhiều thời gian. Đây là những quyết định bổ sung và có thể gây khó chịu nếu không hoạt động như mong muốn.

Sử dụng vị trí neo

Nhập API định vị neo CSS. Ý tưởng là giữ lại các kiểu trong CSS và giảm số lượng quyết định bạn cần đưa ra. Bạn hy vọng đạt được kết quả tương tự, nhưng mục tiêu là mang lại trải nghiệm tốt hơn cho nhà phát triển.

  • Không cần JavaScript.
  • Hãy để trình duyệt xác định vị trí phù hợp nhất theo hướng dẫn của bạn.
  • Không còn phần phụ thuộc của bên thứ ba
  • Không có phần tử trình bao bọc.
  • Hoạt động với các phần tử ở lớp trên cùng.

Hãy tạo lại và giải quyết vấn đề mà chúng ta đang cố gắng giải quyết ở trên. Thay vào đó, hãy sử dụng phép so sánh một chiếc thuyền có neo. Các phần tử này đại diện cho phần tử được neo và neo. Nước đại diện cho khối chứa.

Trước tiên, bạn cần chọn cách xác định neo. Bạn có thể thực hiện việc này trong CSS bằng cách đặt thuộc tính anchor-name trên phần tử neo. Thuộc tính này chấp nhận giá trị dashed-ident.

.anchor {
  anchor-name: --my-anchor;
}

Ngoài ra, bạn có thể xác định một neo trong HTML bằng thuộc tính anchor. Giá trị thuộc tính là mã nhận dạng của phần tử neo. Thao tác này sẽ tạo một neo ngầm.

<a id="my-anchor" class="anchor"></a>
<div anchor="my-anchor" class="boat">I’m a boat!</div>

Sau khi xác định một neo, bạn có thể sử dụng hàm anchor. Hàm anchor nhận 3 đối số:

  • Phần tử neo: anchor-name của neo cần sử dụng hoặc bạn có thể bỏ qua giá trị này để sử dụng neo implicit. Bạn có thể xác định thuộc tính này thông qua mối quan hệ HTML hoặc bằng thuộc tính anchor-default có giá trị anchor-name.
  • Bên neo: Từ khoá của vị trí bạn muốn sử dụng. Giá trị này có thể là top, right, bottom, left, center, v.v. Hoặc bạn có thể truyền một tỷ lệ phần trăm. Ví dụ: 50% sẽ bằng center.
  • Phương án dự phòng: Đây là giá trị dự phòng không bắt buộc, chấp nhận độ dài hoặc tỷ lệ phần trăm.

Bạn sử dụng hàm anchor làm giá trị cho các thuộc tính lồng ghép (top, right, bottom, left hoặc các thuộc tính tương đương logic) của phần tử được neo. Bạn cũng có thể sử dụng hàm anchor trong calc:

.boat {
  bottom: anchor(--my-anchor top);
  left: calc(anchor(--my-anchor center) - (var(--boat-size) * 0.5));
}

 /* alternative with anchor-default */
.boat {
  anchor-default: --my-anchor;
  bottom: anchor(top);
  left: calc(anchor(center) - (var(--boat-size) * 0.5));
}

Không có thuộc tính lồng ghép center, vì vậy, bạn có thể sử dụng calc nếu biết kích thước của phần tử được neo. Tại sao không sử dụng translate? Bạn có thể sử dụng mã sau:

.boat {
  anchor-default: --my-anchor;
  bottom: anchor(top);
  left: anchor(center);
  translate: -50% 0;
}

Tuy nhiên, trình duyệt không tính đến các vị trí đã chuyển đổi cho các phần tử được neo. Bạn sẽ thấy rõ lý do tại sao điều này quan trọng khi xem xét các phương án dự phòng về vị trí và tự động định vị.

Bạn có thể đã nhận thấy việc sử dụng thuộc tính tuỳ chỉnh --boat-size ở trên. Tuy nhiên, nếu muốn dựa vào kích thước phần tử được neo trên phần tử neo, bạn cũng có thể truy cập vào kích thước đó. Thay vì tự tính toán, bạn có thể sử dụng hàm anchor-size. Ví dụ: để làm cho thuyền của chúng ta có chiều rộng gấp 4 lần neo:

.boat {
  width: calc(4 * anchor-size(--my-anchor width));
}

Bạn cũng có thể truy cập vào chiều cao bằng anchor-size(--my-anchor height). Bạn cũng có thể sử dụng thuộc tính này để đặt kích thước của một hoặc cả hai trục.

Nếu bạn muốn liên kết với một phần tử có vị trí absolute thì sao? Quy tắc là các phần tử không được là phần tử đồng cấp. Trong trường hợp đó, bạn có thể gói neo bằng một vùng chứa có vị trí relative. Sau đó, bạn có thể liên kết đến phần tử đó.

<div class="anchor-wrapper">
  <a id="my-anchor" class="anchor"></a>
</div>
<div class="boat">I’m a boat!</div>

Hãy xem bản minh hoạ này để biết cách kéo neo và thuyền sẽ di chuyển theo.

Theo dõi vị trí cuộn

Trong một số trường hợp, phần tử neo có thể nằm trong vùng chứa cuộn được. Đồng thời, phần tử được liên kết có thể nằm bên ngoài vùng chứa đó. Vì thao tác cuộn diễn ra trên một luồng khác với bố cục, nên bạn cần có cách để theo dõi thao tác đó. Thuộc tính anchor-scroll có thể thực hiện việc này. Bạn đặt thuộc tính này trên phần tử được liên kết và gán giá trị của phần tử liên kết mà bạn muốn theo dõi.

.boat { anchor-scroll: --my-anchor; }

Hãy thử bản minh hoạ này để bạn có thể bật và tắt anchor-scroll bằng hộp đánh dấu ở góc.

Tuy nhiên, phép so sánh này không hoàn toàn chính xác, vì trong một thế giới lý tưởng, thuyền và neo của bạn đều ở dưới nước. Ngoài ra, các tính năng như API cửa sổ bật lên giúp bạn có thể giữ các phần tử liên quan ở gần. Tuy nhiên, tính năng định vị neo sẽ hoạt động với các phần tử nằm trong lớp trên cùng. Đây là một trong những lợi ích chính của API: có thể liên kết các phần tử trong nhiều luồng.

Hãy xem xét bản minh hoạ này có vùng chứa cuộn với các neo có chú giải công cụ. Các phần tử chú giải công cụ là cửa sổ bật lên có thể không nằm cùng vị trí với phần neo:

Tuy nhiên, bạn sẽ nhận thấy cách các cửa sổ bật lên theo dõi các đường liên kết neo tương ứng. Bạn có thể thay đổi kích thước vùng chứa cuộn đó và các vị trí sẽ được cập nhật.

Vị trí dự phòng và vị trí tự động

Đây là nơi sức mạnh của vị trí neo tăng lên một cấp. position-fallback có thể định vị phần tử được liên kết dựa trên một tập hợp các phương án dự phòng mà bạn cung cấp. Bạn hướng dẫn trình duyệt bằng các kiểu và để trình duyệt xác định vị trí cho bạn.

Trường hợp sử dụng phổ biến ở đây là chú giải công cụ sẽ lật giữa việc hiển thị phía trên hoặc phía dưới một neo. Và hành vi này dựa trên việc liệu chú giải công cụ có bị vùng chứa cắt bớt hay không. Vùng chứa đó thường là khung nhìn.

Nếu tìm hiểu mã của bản minh hoạ gần đây nhất, bạn sẽ thấy có một thuộc tính position-fallback đang được sử dụng. Nếu cuộn vùng chứa, bạn có thể nhận thấy các cửa sổ bật lên được neo đó đã nhảy. Điều này xảy ra khi neo tương ứng của chúng gần đến ranh giới khung nhìn. Tại thời điểm đó, các cửa sổ bật lên đang cố gắng điều chỉnh để nằm trong khung nhìn.

Trước khi tạo position-fallback rõ ràng, tính năng định vị neo cũng sẽ cung cấp tính năng định vị tự động. Bạn có thể thực hiện thao tác lật đó miễn phí bằng cách sử dụng giá trị auto trong cả hàm neo và thuộc tính lồng ghép đối diện. Ví dụ: nếu bạn sử dụng anchor cho bottom, hãy đặt top thành auto.

.tooltip {
  position: absolute;
  bottom: anchor(--my-anchor auto);
  top: auto;
}

Giải pháp thay thế cho tính năng tự động định vị là sử dụng position-fallback rõ ràng. Để làm việc này, bạn cần xác định một nhóm dự phòng vị trí. Trình duyệt sẽ xem xét các vị trí này cho đến khi tìm thấy một vị trí có thể sử dụng rồi áp dụng vị trí đó. Nếu không tìm thấy một phương thức hoạt động, phương thức này sẽ mặc định là phương thức đầu tiên được xác định.

position-fallback cố gắng hiển thị chú giải công cụ ở trên rồi ở dưới có thể có dạng như sau:

@position-fallback --top-to-bottom {
  @try {
    bottom: anchor(top);
    left: anchor(center);
  }

  @try {
    top: anchor(bottom);
    left: anchor(center);
  }
}

Khi áp dụng mã đó cho chú giải công cụ, bạn sẽ thấy như sau:

.tooltip {
  anchor-default: --my-anchor;
  position-fallback: --top-to-bottom;
}

Việc sử dụng anchor-default có nghĩa là bạn có thể sử dụng lại position-fallback cho các phần tử khác. Bạn cũng có thể sử dụng thuộc tính tuỳ chỉnh có giới hạn để đặt anchor-default.

Hãy xem xét lại bản minh hoạ này bằng cách sử dụng lại chiếc thuyền. Có một position-fallback được đặt. Khi bạn thay đổi vị trí của neo, thuyền sẽ điều chỉnh để vẫn nằm trong vùng chứa. Hãy thử thay đổi giá trị khoảng đệm để điều chỉnh khoảng đệm của phần thân. Hãy lưu ý cách trình duyệt sửa lỗi định vị. Các vị trí đang được thay đổi bằng cách thay đổi căn chỉnh lưới của vùng chứa.

position-fallback lần này chi tiết hơn khi thử các vị trí theo chiều kim đồng hồ.

.boat {
  anchor-default: --my-anchor;
  position-fallback: --compass;
}

@position-fallback --compass {
  @try {
    bottom: anchor(top);
    right: anchor(left);
  }

  @try {
    bottom: anchor(top);
    left: anchor(right);
  }

  @try {
    top: anchor(bottom);
    right: anchor(left);
  }

  @try {
    top: anchor(bottom);
    left: anchor(right);
  }
}


Ví dụ

Giờ bạn đã biết các tính năng chính để định vị neo, hãy xem một số ví dụ thú vị ngoài chú giải công cụ. Những ví dụ này nhằm giúp bạn có ý tưởng về cách sử dụng vị trí neo. Cách tốt nhất để phát triển thêm thông số kỹ thuật là nhận ý kiến đóng góp từ những người dùng thực tế như bạn.

Trình đơn theo bối cảnh

Hãy bắt đầu với trình đơn theo bối cảnh bằng cách sử dụng Popover API. Ý tưởng là khi nhấp vào nút có biểu tượng mũi tên lên xuống, trình đơn theo bối cảnh sẽ xuất hiện. Và trình đơn đó sẽ có trình đơn riêng để mở rộng.

Phần đánh dấu không phải là phần quan trọng ở đây. Tuy nhiên, bạn có ba nút, mỗi nút sử dụng popovertarget. Sau đó, bạn sẽ có 3 phần tử sử dụng thuộc tính popover. Nhờ đó, bạn có thể mở trình đơn theo bối cảnh mà không cần JavaScript. Mã có thể như sau:

<button popovertarget="context">
  Toggle Menu
</button>        
<div popover="auto" id="context">
  <ul>
    <li><button>Save to your Liked Songs</button></li>
    <li>
      <button popovertarget="playlist">
        Add to Playlist
      </button>
    </li>
    <li>
      <button popovertarget="share">
        Share
      </button>
    </li>
  </ul>
</div>
<div popover="auto" id="share">...</div>
<div popover="auto" id="playlist">...</div>

Giờ đây, bạn có thể xác định position-fallback và chia sẻ position-fallback đó giữa các trình đơn theo bối cảnh. Chúng ta cũng nhớ huỷ đặt mọi kiểu inset cho cửa sổ bật lên.

[popovertarget="share"] {
  anchor-name: --share;
}

[popovertarget="playlist"] {
  anchor-name: --playlist;
}

[popovertarget="context"] {
  anchor-name: --context;
}

#share {
  anchor-default: --share;
  position-fallback: --aligned;
}

#playlist {
  anchor-default: --playlist;
  position-fallback: --aligned;
}

#context {
  anchor-default: --context;
  position-fallback: --flip;
}

@position-fallback --aligned {
  @try {
    top: anchor(top);
    left: anchor(right);
  }

  @try {
    top: anchor(bottom);
    left: anchor(right);
  }

  @try {
    top: anchor(top);
    right: anchor(left);
  }

  @try {
    bottom: anchor(bottom);
    left: anchor(right);
  }

  @try {
    right: anchor(left);
    bottom: anchor(bottom);
  }
}

@position-fallback --flip {
  @try {
    bottom: anchor(top);
    left: anchor(left);
  }

  @try {
    right: anchor(right);
    bottom: anchor(top);
  }

  @try {
    top: anchor(bottom);
    left: anchor(left);
  }

  @try {
    top: anchor(bottom);
    right: anchor(right);
  }
}

Điều này mang đến cho bạn giao diện người dùng trình đơn theo bối cảnh lồng ghép thích ứng. Hãy thử thay đổi vị trí nội dung bằng phần tử select. Lựa chọn bạn chọn sẽ cập nhật cách căn chỉnh lưới. Điều này ảnh hưởng đến cách định vị neo đặt các cửa sổ bật lên.

Lấy nét và theo dõi

Bản minh hoạ này kết hợp các thành phần gốc CSS bằng cách đưa vào :has(). Ý tưởng là chuyển đổi chỉ báo hình ảnh cho input có tiêu điểm.

Hãy thực hiện việc này bằng cách đặt một neo mới trong thời gian chạy. Đối với bản minh hoạ này, một thuộc tính tuỳ chỉnh có phạm vi sẽ được cập nhật khi có tiêu điểm đầu vào.

#email {
    anchor-name: --email;
  }
  #name {
    anchor-name: --name;
  }
  #password {
    anchor-name: --password;
  }
:root:has(#email:focus) {
    --active-anchor: --email;
  }
  :root:has(#name:focus) {
    --active-anchor: --name;
  }
  :root:has(#password:focus) {
    --active-anchor: --password;
  }

:root {
    --active-anchor: --name;
    --active-left: anchor(var(--active-anchor) right);
    --active-top: calc(
      anchor(var(--active-anchor) top) +
        (
          (
              anchor(var(--active-anchor) bottom) -
                anchor(var(--active-anchor) top)
            ) * 0.5
        )
    );
  }
.form-indicator {
    left: var(--active-left);
    top: var(--active-top);
    transition: all 0.2s;
}

Nhưng làm cách nào để bạn có thể phát triển hơn nữa? Bạn có thể sử dụng lớp phủ này cho một số hình thức lớp phủ hướng dẫn. Chú giải công cụ có thể di chuyển giữa các điểm yêu thích và cập nhật nội dung của chú giải đó. Bạn có thể chuyển đổi nội dung. Ảnh động riêng biệt cho phép bạn tạo ảnh động cho display hoặc Hiệu ứng chuyển đổi khung hiển thị có thể hoạt động ở đây.

Tính toán biểu đồ thanh

Một điều thú vị khác mà bạn có thể làm với tính năng định vị neo là kết hợp tính năng này với calc. Hãy tưởng tượng một biểu đồ có một số cửa sổ bật lên chú thích biểu đồ.

Bạn có thể theo dõi giá trị cao nhất và thấp nhất bằng cách sử dụng CSS minmax. CSS cho phần đó có thể có dạng như sau:

.chart__tooltip--max {
    left: anchor(--chart right);
    bottom: max(
      anchor(--anchor-1 top),
      anchor(--anchor-2 top),
      anchor(--anchor-3 top)
    );
    translate: 0 50%;
  }

Có một số JavaScript đang hoạt động để cập nhật các giá trị biểu đồ và một số CSS để tạo kiểu cho biểu đồ. Nhưng việc định vị neo sẽ giúp chúng ta cập nhật bố cục.

Đổi kích thước tay cầm

Bạn không nhất thiết phải liên kết với một phần tử. Bạn có thể sử dụng nhiều neo cho một phần tử. Bạn có thể đã nhận thấy điều đó trong ví dụ về biểu đồ thanh. Chú giải công cụ được liên kết với biểu đồ rồi đến thanh thích hợp. Nếu mở rộng thêm một chút về khái niệm đó, bạn có thể sử dụng khái niệm đó để đổi kích thước các phần tử.

Bạn có thể coi các điểm neo như các tay cầm đổi kích thước tuỳ chỉnh và dựa vào giá trị inset.

.container {
   position: absolute;
   inset:
     anchor(--handle-1 top)
     anchor(--handle-2 right)
     anchor(--handle-2 bottom)
     anchor(--handle-1 left);
 }

Trong bản minh hoạ này, GreenSock Draggable giúp các tay cầm có thể kéo. Tuy nhiên, phần tử <img> sẽ đổi kích thước để lấp đầy vùng chứa điều chỉnh để lấp đầy khoảng trống giữa các tay cầm.

Một SelectMenu?

Phần cuối cùng này là một chút thông tin trêu ghẹo về những nội dung sắp tới. Tuy nhiên, bạn có thể tạo một cửa sổ bật lên có thể lấy tiêu điểm và hiện đã có vị trí neo. Bạn có thể tạo nền tảng của một phần tử <select> có thể tạo kiểu.

<div class="select-menu">
<button popovertarget="listbox">
 Select option
 <svg>...</svg>
</button>
<div popover="auto" id="listbox">
   <option>A</option>
   <option>Styled</option>
   <option>Select</option>
</div>
</div>

anchor ngầm ẩn sẽ giúp việc này dễ dàng hơn. Tuy nhiên, CSS cho một điểm xuất phát cơ bản có thể có dạng như sau:

[popovertarget] {
 anchor-name: --select-button;
}
[popover] {
  anchor-default: --select-button;
  top: anchor(bottom);
  width: anchor-size(width);
  left: anchor(left);
}

Hãy kết hợp các tính năng của API Popover với tính năng định vị neo CSS và bạn đã gần hoàn tất.

Bạn sẽ thấy gọn gàng khi bắt đầu giới thiệu các thành phần như :has(). Bạn có thể xoay điểm đánh dấu khi mở:

.select-menu:has(:open) svg {
  rotate: 180deg;
}

Bạn có thể đưa dự án này đi theo hướng nào tiếp theo? Chúng ta cần làm gì khác để biến đó thành một select hoạt động? Chúng ta sẽ đề cập đến vấn đề này trong bài viết tiếp theo. Nhưng đừng lo, các phần tử lựa chọn có thể tạo kiểu sẽ ra mắt. Hãy tiếp tục theo dõi!


Vậy là xong!

Nền tảng web đang phát triển. Vị trí neo CSS là một phần quan trọng để cải thiện cách bạn phát triển các thành phần điều khiển giao diện người dùng. Điều này sẽ giúp bạn tránh được một số quyết định khó khăn. Nhưng nó cũng sẽ cho phép bạn làm những việc mà trước đây bạn chưa từng làm được. Chẳng hạn như tạo kiểu cho phần tử <select>! Hãy chia sẻ suy nghĩ của bạn.

Ảnh chụp của CHUTTERSNAP trên Unsplash