Kịch bản hầu như luôn giống nhau, đó là bảng dữ liệu bên trong vùng chứa có thể cuộn được. Mỗi hàng có một menu tác vụ, một danh sách thả xuống nhỏ với một số tùy chọn như Chỉnh sửa, Sao chép và Xóa. Bạn xây dựng nó, nó dường như hoạt động hoàn hảo một cách độc lập và sau đó ai đó đặt nó vào bên trong div có thể cuộn đó và mọi thứ sụp đổ. Tôi đã thấy chính xác lỗi này trong ba cơ sở mã khác nhau: vùng chứa, ngăn xếp và khung, tất cả đều khác nhau. Tuy nhiên, lỗi này hoàn toàn giống nhau. Danh sách thả xuống được cắt bớt ở cạnh của vùng chứa. Hoặc nó xuất hiện phía sau nội dung mà lẽ ra phải ở dưới nó một cách hợp lý. Hoặc nó hoạt động tốt cho đến khi người dùng cuộn và sau đó nó trôi đi. Bạn đạt tới chỉ số z: 9999. Đôi khi nó có ích nhưng đôi khi nó hoàn toàn không có tác dụng gì. Sự mâu thuẫn đó là manh mối đầu tiên cho thấy điều gì đó sâu sắc hơn đang xảy ra. Lý do nó tiếp tục quay trở lại là vì ba hệ thống trình duyệt riêng biệt có liên quan và hầu hết các nhà phát triển đều hiểu từng hệ thống nhưng không bao giờ nghĩ về điều gì sẽ xảy ra khi cả ba va chạm: tràn, xếp chồng bối cảnh và chứa các khối.

Khi bạn hiểu cách cả ba tương tác với nhau, các chế độ lỗi sẽ không còn cảm giác ngẫu nhiên nữa. Trên thực tế, chúng trở nên có thể đoán trước được. Ba điều thực sự gây ra điều này Chúng ta hãy xem xét chi tiết từng mục đó. Vấn đề tràn Khi bạn đặt tràn: ẩn, tràn: cuộn hoặc tràn: tự động trên một phần tử, trình duyệt sẽ cắt bất cứ thứ gì vượt quá giới hạn của nó, bao gồm cả các phần tử con được định vị tuyệt đối. .scroll-container { tràn: tự động; chiều cao: 300px; /* Thao tác này sẽ cắt phần thả xuống, dừng hoàn toàn */ }

.dropdown { vị trí: tuyệt đối; /* Không thành vấn đề -- vẫn bị cắt bớt bởi .scroll-container */ }

Điều đó làm tôi ngạc nhiên ngay lần đầu tiên tôi gặp phải nó. Tôi đã giả định rằng vị trí: tuyệt đối sẽ cho phép một phần tử thoát khỏi phần cắt của vùng chứa. Nó không. Trong thực tế, điều đó có nghĩa là một menu được định vị tuyệt đối có thể bị cắt bởi bất kỳ tổ tiên nào có giá trị tràn không nhìn thấy được, ngay cả khi tổ tiên đó không phải là khối chứa của menu. Cắt và định vị là các hệ thống riêng biệt. Chúng chỉ tình cờ va chạm nhau theo những cách trông hoàn toàn ngẫu nhiên cho đến khi bạn hiểu được cả hai.

Đây là một ví dụ về React sử dụng createPortal:

nhập { createPortal } từ 'Reac-dom'; nhập { useState, useEffect, useRef } từ 'react';

hàm Dropdown({ AnchorRef, isOpen, Children }) { const [vị trí, setPosition] = useState({ top: 0, left: 0 });

useEffect(() => { if (isOpen && AnchorRef.current) { const trực tràng = neoRef.current.getBoundingClientRect(); setPosition({ trên cùng: trực tràng.bottom + window.scrollY, trái: trực tràng.left + window.scrollX, }); } }, [isOpen, neoRef]);

if (!isOpen) trả về null;

trả về createPortal(

{trẻ em}
, tài liệu.body ); }

Và tất nhiên, chúng ta không thể bỏ qua khả năng tiếp cận. Các phần tử cố định xuất hiện trên nội dung vẫn phải truy cập được bằng bàn phím. Nếu thứ tự tiêu điểm không tự nhiên chuyển sang danh sách thả xuống cố định, bạn sẽ cần quản lý nó bằng mã. Bạn cũng cần kiểm tra xem nó có nằm đè lên nội dung tương tác khác mà không có cách nào để loại bỏ nó hay không. Điều đó sẽ khiến bạn khó chịu khi kiểm tra bàn phím. Định vị neo CSS: Nơi tôi nghĩ đây là tiêu đề CSS Anchor Định vị là hướng tôi quan tâm nhất hiện nay. Tôi không chắc có bao nhiêu thông số kỹ thuật thực sự có thể sử dụng được khi tôi nhìn vào nó lần đầu tiên. Nó cho phép bạn khai báo mối quan hệ giữa danh sách thả xuống và trình kích hoạt của nó trực tiếp trong CSS và trình duyệt xử lý tọa độ. .kích hoạt { tên neo: --my-trigger; }

.dropdown-menu { vị trí: tuyệt đối; neo vị trí: --my-trigger; trên cùng: neo(dưới); trái: mỏ neo(trái); vị trí thử-dự phòng: flip-block, flip-inline; }

Thuộc tính vị trí thử dự phòng là điều làm cho thuộc tính này đáng được sử dụng hơn là tính toán thủ công. Trình duyệt thử các vị trí thay thế trước khi từ bỏ, do đó, trình đơn thả xuống ở cuối khung nhìn sẽ tự động lật lên thay vì bị cắt bỏ. Hỗ trợ trình duyệt rất ổn định trong các trình duyệt dựa trên Chrome và đang phát triển trong Safari. Firefox cần một polyfill. Gói định vị @oddbird/css-anchor bao gồm thông số cốt lõi. Tôi đã gặp phải các trường hợp khó khăn về bố cục với nó yêu cầu các dự phòng mà tôi không lường trước được, vì vậy hãy coi nó như một cải tiến tiến bộ hoặc ghép nối nó với mộtDự phòng JavaScript cho Firefox. Tóm lại, đầy hứa hẹn nhưng chưa phổ biến. Kiểm tra trong trình duyệt mục tiêu của bạn. Và liên quan đến khả năng truy cập, việc khai báo mối quan hệ trực quan trong CSS không cho cây khả năng truy cập biết bất cứ điều gì. aria-controls, aria-expanded, aria-haspopup — phần đó vẫn thuộc về bạn. Đôi khi cách khắc phục chỉ là di chuyển phần tử Trước khi tiếp cận một cổng hoặc thực hiện các phép tính tọa độ, trước tiên tôi luôn hỏi một câu hỏi: Danh sách thả xuống này có thực sự cần nằm bên trong vùng chứa cuộn không? Nếu không, việc di chuyển đánh dấu sang trình bao bọc cấp cao hơn sẽ loại bỏ hoàn toàn vấn đề mà không cần JavaScript và không cần tính toán tọa độ. Điều này không phải lúc nào cũng có thể thực hiện được. Nếu nút và danh sách thả xuống được gói gọn trong cùng một thành phần, việc di chuyển một thành phần mà không có thành phần kia có nghĩa là phải xem xét lại toàn bộ API. Nhưng khi bạn có thể làm được điều đó thì không có gì phải gỡ lỗi. Vấn đề không tồn tại. CSS hiện đại nào vẫn không giải quyết được CSS đã đi được một chặng đường dài ở đây, nhưng vẫn có những chỗ nó làm bạn thất vọng. Vị trí: các vấn đề đã sửa và chuyển đổi vẫn còn đó. Đó là thông số kỹ thuật có chủ ý, có nghĩa là không có cách giải quyết CSS nào tồn tại. Nếu bạn đang sử dụng thư viện hoạt ảnh bao bọc bố cục của mình trong một phần tử đã được chuyển đổi thì bạn sẽ quay lại cần cổng hoặc vị trí neo. Định vị neo CSS đầy hứa hẹn nhưng mới. Như đã đề cập trước đó, Firefox vẫn cần một polyfill tại thời điểm tôi viết bài này. Tôi đã gặp phải những trường hợp khó khăn về bố cục đòi hỏi phải có những dự phòng mà tôi không lường trước được. Nếu hiện nay bạn cần hành vi nhất quán trên tất cả các trình duyệt thì bạn vẫn đang sử dụng JavaScript cho những phần phức tạp. Phần bổ sung mà tôi thực sự đã thay đổi quy trình làm việc của mình là API HTML Popover, hiện có sẵn trong tất cả các trình duyệt hiện đại. Các phần tử có thuộc tính popover hiển thị ở lớp trên cùng của trình duyệt, trên hết mọi thứ mà không cần định vị JavaScript.

Xử lý thoát, loại bỏ khi nhấp chuột bên ngoài và ngữ nghĩa trợ năng vững chắc được cung cấp miễn phí cho những thứ như chú giải công cụ, tiện ích tiết lộ và lớp phủ đơn giản. Đây là công cụ đầu tiên tôi tiếp cận bây giờ. Điều đó nói rằng, nó không giải quyết được việc định vị. Nó giải quyết việc phân lớp. Bạn vẫn cần định vị neo hoặc JavaScript để căn chỉnh cửa sổ bật lên với trình kích hoạt của nó. API Popover xử lý việc phân lớp. Định vị neo xử lý vị trí. Được sử dụng cùng nhau, chúng bao gồm hầu hết những gì bạn muốn thư viện thực hiện trước đây. Hướng dẫn đưa ra quyết định cho tình huống của bạn Sau khi trải qua tất cả những điều này một cách khó khăn, đây là cách tôi thực sự nghĩ về sự lựa chọn bây giờ.

Sử dụng một cổng thông tin. Tôi sẽ sử dụng cổng này khi trình kích hoạt nằm sâu trong các vùng chứa cuộn lồng nhau. Tôi đã sử dụng mẫu này cho các menu hành động trên bảng và kết hợp nó với tính năng khôi phục tiêu điểm và kiểm tra khả năng truy cập. Đó là lựa chọn đáng tin cậy nhất nhưng lại dành thời gian cho việc đi dây bổ sung. Sử dụng định vị cố định. Điều này áp dụng khi bạn đang sử dụng JavaScript thuần hoặc một khung nhẹ và có thể xác minh rằng không có tổ tiên nào áp dụng các phép biến đổi hoặc bộ lọc. Việc thiết lập và gỡ lỗi đơn giản, miễn là có một ràng buộc đó. Sử dụng CSS Anchor Định vị.Reach để thực hiện việc này khi hỗ trợ trình duyệt của bạn cho phép. Nếu cần hỗ trợ Firefox, hãy ghép nối nó với polyfill @oddbird. Đây chính là nơi nền tảng hướng tới và cuối cùng sẽ trở thành phương pháp tiếp cận phù hợp của bạn. Tái cấu trúc DOM. Hãy sử dụng điều này khi kiến ​​trúc cho phép và bạn muốn độ phức tạp khi chạy bằng không. Tôi tin rằng đó có thể là lựa chọn bị đánh giá thấp nhất. Kết hợp các mẫu. Thực hiện việc này khi bạn muốn định vị cố định làm phương pháp tiếp cận chính của mình, kết hợp với phương pháp dự phòng JavaScript cho các trình duyệt không được hỗ trợ. Hoặc một cổng dành cho vị trí DOM được ghép nối với getBoundingClientRect() để có được độ chính xác của tọa độ.

Kết luận Tôi đã từng coi lỗi này là sự cố chỉ xảy ra một lần - cần phải vá và tiếp tục. Nhưng khi tôi ngồi với nó đủ lâu để hiểu cả ba hệ thống liên quan - cắt tràn, xếp chồng bối cảnh và chứa các khối - thì nó không còn cảm giác ngẫu nhiên nữa. Tôi có thể nhìn vào danh sách thả xuống bị hỏng và ngay lập tức tìm ra tổ tiên nào chịu trách nhiệm. Sự thay đổi trong cách tôi đọc DOM thực sự là điều đáng chú ý. Không có câu trả lời đúng duy nhất. Những gì tôi đạt được phụ thuộc vào những gì tôi có thể kiểm soát trong cơ sở mã: các cổng khi cây tổ tiên không thể đoán trước được; định vị cố định khi nó sạch sẽ và đơn giản; di chuyển phần tử khi không có gì ngăn cản tôi; và định vị mỏ neo bây giờ,nơi tôi có thể. Dù cuối cùng bạn chọn gì, đừng coi khả năng tiếp cận là bước cuối cùng. Theo kinh nghiệm của tôi, đó chính xác là lúc nó bị bỏ qua. Các mối quan hệ ARIA, quản lý tiêu điểm, hành vi bàn phím - những thứ đó không hề bóng bẩy. Chúng là một phần khiến mọi thứ thực sự hoạt động. Kiểm tra mã nguồn đầy đủ trong kho GitHub của tôi. Đọc thêm Đây là những tài liệu tham khảo mà tôi liên tục quay lại khi thực hiện việc này:

Bối cảnh xếp chồng (MDN) “Hướng dẫn định vị neo CSS”, Juan Diego Rodriguez “Bắt đầu với API Popover”, Godstime Aburu Giao diện người dùng nổi (floating-ui.com) Tràn CSS (MDN)

You May Also Like

Enjoyed This Article?

Get weekly tips on growing your audience and monetizing your content — straight to your inbox.

No spam. Join 138,000+ creators. Unsubscribe anytime.

Create Your Free Bio Page

Join 138,000+ creators on Seemless.

Get Started Free