시나리오는 거의 항상 동일하며 스크롤 가능한 컨테이너 내부의 데이터 테이블입니다. 모든 행에는 편집, 복제 및 삭제와 같은 일부 옵션이 포함된 작은 드롭다운인 작업 메뉴가 있습니다. 여러분이 그것을 구축하면, 분리된 상태에서 완벽하게 작동하는 것처럼 보입니다. 그런 다음 누군가 스크롤 가능한 div 안에 그것을 넣으면 모든 것이 무너집니다. 저는 컨테이너, 스택, 프레임워크 등 세 가지 다른 코드베이스에서 이 정확한 버그를 보았습니다. 그러나 버그는 완전히 동일합니다. 드롭다운은 컨테이너 가장자리에서 잘립니다. 또는 논리적으로 그 아래에 있어야 하는 콘텐츠 뒤에 표시됩니다. 또는 사용자가 스크롤할 때까지 잘 작동하다가 표류합니다. z-index: 9999에 도달합니다. 도움이 될 때도 있지만 전혀 아무 것도 하지 않는 경우도 있습니다. 이러한 불일치는 더 깊은 일이 일어나고 있다는 첫 번째 단서입니다. 계속해서 나타나는 이유는 세 가지 별도의 브라우저 시스템이 관련되어 있고 대부분의 개발자는 각 시스템을 자체적으로 이해하지만 오버플로, 스택 컨텍스트 및 포함 블록 등 세 가지가 모두 충돌할 때 어떤 일이 발생하는지 전혀 생각하지 않기 때문입니다.

세 가지 모두가 어떻게 상호 작용하는지 이해하면 실패 모드가 무작위로 느껴지지 않습니다. 실제로 예측 가능해집니다. 실제로 이 문제를 일으키는 세 가지 각 항목을 자세히 살펴보겠습니다. 오버플로 문제 요소에overflow:hidden,overflow:scroll 또는overflow:auto를 설정하면 브라우저는 절대 위치에 있는 하위 항목을 포함하여 경계를 넘어서는 모든 항목을 잘라냅니다. .scroll-컨테이너 { 오버플로: 자동; 높이: 300px; /* 그러면 드롭다운이 잘리고 마침표가 표시됩니다. */ }

.드롭다운 { 위치: 절대; /* 상관없습니다 -- 여전히 .scroll-container에 의해 잘립니다 */ }

처음 접했을 때 그게 저를 놀라게 했어요. 나는 position:absolute가 요소가 컨테이너의 클리핑을 벗어날 수 있다고 가정했습니다. 그렇지 않습니다. 실제로 이는 절대 위치에 있는 메뉴가 보이지 않는 오버플로 값이 있는 조상에 의해 잘릴 수 있음을 의미합니다. 해당 조상이 메뉴의 포함 블록이 아니더라도 마찬가지입니다. 클리핑과 위치 지정은 별도의 시스템입니다. 두 가지를 모두 이해할 때까지 완전히 무작위로 보이는 방식으로 충돌합니다.

다음은 createPortal을 사용하는 React 예제입니다.

'react-dom'에서 { createPortal }을 가져옵니다. import { useState, useEffect, useRef } from 'react';

function Dropdown({anchorRef, isOpen, children }) { const [위치, setPosition] = useState({ 위쪽: 0, 왼쪽: 0 });

useEffect(() => { if (isOpen && 앵커Ref.current) { const REC = AnchorRef.current.getBoundingClientRect(); setPosition({ 상단: ret.bottom + window.scrollY, 왼쪽: ret.left + window.scrollX, }); } }, [isOpen, 앵커Ref]);

(!isOpen)인 경우 null을 반환합니다.

생성포털(

{어린이}
, 문서.본문 ); }

물론 접근성도 무시할 수 없습니다. 콘텐츠 위에 나타나는 고정 요소는 키보드로 접근할 수 있어야 합니다. 포커스 순서가 고정 드롭다운으로 자연스럽게 이동하지 않는 경우 코드를 사용하여 관리해야 합니다. 또한 무시할 수 있는 방법 없이 다른 대화형 콘텐츠 위에 놓여 있지 않은지 확인하는 것도 가치가 있습니다. 그것은 키보드 테스트에서 당신을 물었습니다. CSS 앵커 포지셔닝: 이것이 어디로 향하고 있다고 생각합니까? CSS Anchor Positioning은 제가 지금 가장 관심을 갖고 있는 방향입니다. 처음 스펙을 봤을 때는 실제로 얼마나 많은 스펙을 사용할 수 있는지 확신할 수 없었습니다. CSS에서 직접 드롭다운과 해당 트리거 사이의 관계를 선언할 수 있으며 브라우저가 좌표를 처리합니다. .트리거 { 앵커 이름: --my-trigger; }

.드롭다운 메뉴 { 위치: 절대; 위치 앵커: --my-trigger; 상단: 앵커(하단); 왼쪽: 앵커(왼쪽); position-try-fallbacks: 플립블록, 플립인라인; }

position-try-fallbacks 속성은 수동 계산보다 이것을 사용할 가치가 있는 이유입니다. 브라우저는 포기하기 전에 대체 배치를 시도하므로 뷰포트 하단의 드롭다운이 잘리는 대신 자동으로 위쪽으로 뒤집힙니다. 브라우저 지원은 Chromium 기반 브라우저에서 견고하며 Safari에서도 성장하고 있습니다. Firefox에는 폴리필이 필요합니다. @oddbird/css-anchor-positioning 패키지는 핵심 사양을 다룹니다. 예상하지 못한 폴백이 필요한 레이아웃 엣지 케이스에 부딪혔으므로 이를 점진적인 향상으로 처리하거나Firefox용 JavaScript 대체. 간단히 말해서, 유망하지만 아직 보편적이지는 않습니다. 대상 브라우저에서 테스트하세요. 접근성에 관한 한 CSS에서 시각적 관계를 선언해도 접근성 트리에 아무 것도 알려주지 않습니다. aria-controls, aria-expanded, aria-haspopup — 그 부분은 여전히 ​​여러분의 몫입니다. 때로는 수정 사항이 요소를 이동하는 것일 수도 있습니다. 포털에 도달하거나 좌표 계산을 하기 전에 저는 항상 한 가지 질문을 먼저 합니다. 이 드롭다운이 실제로 스크롤 컨테이너 내부에 있어야 합니까? 그렇지 않은 경우 마크업을 더 높은 수준의 래퍼로 이동하면 JavaScript나 좌표 계산 없이 문제가 완전히 제거됩니다. 이것이 항상 가능한 것은 아닙니다. 버튼과 드롭다운이 동일한 구성 요소에 캡슐화되어 있는 경우 다른 것 없이 하나만 이동한다는 것은 전체 API를 다시 생각한다는 것을 의미합니다. 하지만 그렇게 할 수 있으면 디버깅할 것이 없습니다. 문제는 존재하지 않습니다. 최신 CSS가 아직도 해결하지 못하는 것 CSS는 여기에서 많은 발전을 이루었지만 여전히 실망스러운 부분이 있습니다. 위치: 수정 및 변환 문제가 여전히 존재합니다. 이는 의도적으로 사양에 포함되어 있으며 이는 CSS 해결 방법이 존재하지 않음을 의미합니다. 변형된 요소로 레이아웃을 래핑하는 애니메이션 라이브러리를 사용하는 경우 다시 포털이나 앵커 위치 지정이 필요하게 됩니다. CSS 앵커 위치 지정은 유망하지만 새로운 것입니다. 앞서 언급했듯이, 내가 이 글을 쓰고 있는 시점에도 Firefox에는 여전히 폴리필이 필요합니다. 예상하지 못한 폴백이 필요한 레이아웃 엣지 케이스에 부딪혔습니다. 오늘날 모든 브라우저에서 일관된 동작이 필요하다면 여전히 까다로운 부분을 위해 JavaScript를 사용하고 있는 것입니다. 제가 실제로 작업 흐름을 변경한 추가 기능은 이제 모든 최신 브라우저에서 사용할 수 있는 HTML Popover API입니다. 팝오버 속성이 있는 요소는 JavaScript 위치 지정 없이 브라우저의 최상위 레이어에서 렌더링됩니다.

툴팁, 공개 위젯, 간단한 오버레이 등에 대해 이스케이프 처리, 외부 클릭 시 해제 및 견고한 접근성 의미 체계가 무료로 제공됩니다. 현재 제가 처음으로 접하는 도구입니다. 즉, 위치 지정이 해결되지는 않습니다. 레이어링을 해결해줍니다. 팝오버를 트리거에 정렬하려면 앵커 위치 지정이나 JavaScript가 여전히 필요합니다. Popover API는 레이어링을 처리합니다. 앵커 위치 지정이 배치를 처리합니다. 함께 사용하면 이전에 도서관에서 수행했던 작업의 대부분을 처리할 수 있습니다. 귀하의 상황에 맞는 결정 가이드 이 모든 과정을 힘들게 겪은 후, 지금 제가 실제로 선택에 대해 생각하는 방식은 다음과 같습니다.

포털을 사용하세요. 트리거가 중첩된 스크롤 컨테이너에 깊이 있을 때 이것을 사용하겠습니다. 나는 이 패턴을 테이블 작업 메뉴에 사용했고 이를 포커스 복원 및 접근성 검사와 결합했습니다. 가장 신뢰할 수 있는 옵션이지만 추가 배선을 위한 예산 시간이 필요합니다. 고정 위치 지정을 사용합니다. 이는 바닐라 JavaScript 또는 경량 프레임워크를 사용하고 변환이나 필터를 적용하는 상위 항목이 없는지 확인할 수 있는 경우에 사용됩니다. 하나의 제약 조건이 유지되는 한 설정도 간단하고 디버깅도 간단합니다. 브라우저 지원이 허용하는 경우 CSS Anchor Positioning.Reach를 사용하세요. Firefox 지원이 필요한 경우 @oddbird 폴리필과 쌍을 이루세요. 이것이 플랫폼이 궁극적으로 향하고 있는 곳이며 결국 여러분이 선호하는 접근 방식이 될 것입니다. DOM을 재구성합니다. 아키텍처에서 허용하고 런타임 복잡성을 없애고 싶을 때 이를 사용하세요. 아마도 가장 과소평가된 옵션일 것이라고 생각합니다. 패턴을 결합합니다. 앵커 위치 지정을 기본 접근 방식으로 사용하고 지원되지 않는 브라우저에 대한 JavaScript 폴백과 함께 사용하려면 이 작업을 수행하십시오. 또는 좌표 정확도를 위해 getBoundingClientRect()와 쌍을 이루는 DOM 배치용 포털입니다.

결론 나는 이 버그를 일회성 문제, 즉 패치하고 넘어가야 할 문제로 취급하곤 했습니다. 그러나 오버플로 클리핑, 컨텍스트 스택, 블록 포함 등 관련된 세 가지 시스템을 모두 이해할 수 있을 만큼 오랫동안 사용하고 나자 무작위라는 느낌이 사라졌습니다. 깨진 드롭다운을 보고 어느 조상이 책임이 있는지 즉시 추적할 수 있었습니다. DOM을 읽는 방식의 변화는 정말 중요한 점이었습니다. 정답은 하나도 없습니다. 내가 도달한 것은 코드베이스에서 제어할 수 있는 것에 달려 있습니다. 조상 트리를 예측할 수 없을 때의 포털; 깨끗하고 단순할 때의 고정 위치; 아무것도 나를 막을 수 없을 때 요소를 이동합니다. 이제 앵커 위치를 지정하고내가 할 수 있는 곳. 무엇을 선택하든 접근성을 마지막 단계로 여기지 마세요. 내 경험상 바로 그때가 건너뛰는 경우이다. ARIA 관계, 포커스 관리, 키보드 동작 등은 세련되지 않습니다. 그것들은 일을 실제로 작동하게 만드는 것의 일부입니다. 내 GitHub 저장소에서 전체 소스 코드를 확인하세요. 추가 자료 이 작업을 진행하는 동안 제가 계속해서 찾아본 참고 자료는 다음과 같습니다.

스태킹 컨텍스트(MDN) “CSS 앵커 위치 지정 가이드”, Juan Diego Rodriguez "팝오버 API 시작하기", Godstime Aburu 플로팅 UI(floating-ui.com) 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