sidenav 구성요소 빌드

반응형 슬라이드 아웃 사이드 탐색을 빌드하는 방법에 관한 기본 개요

이 글에서는 웹용 Sidenav 구성요소의 프로토타입을 제작한 반응형이고, 스테이트풀(Stateful)이고, 키보드 탐색을 지원하고, JavaScript 유무에 상관없이 작동합니다. 다양한 브라우저에서 작동합니다 데모 사용해 보기

동영상을 선호한다면 이 게시물의 YouTube 버전을 참고하세요.

개요

반응형 내비게이션 시스템을 빌드하는 것은 어렵습니다. 어떤 사용자는 키보드를 사용하고 강력한 데스크톱을 갖춘 휴대기기도 있고, 작은 휴대기기를 통해 방문하는 광고주도 있습니다. 방문하는 모든 사람이 메뉴를 열고 닫을 수 있어야 합니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">
</ph> 데스크톱에서 모바일로의 반응형 레이아웃 데모
<ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">
</ph> iOS 및 Android에서 밝은 테마와 어두운 테마 낮추기

웹 전략

이 구성요소 탐색에서는 몇 가지 중요한 웹 플랫폼 기능을 결합하는 즐거움을 느꼈습니다.

  1. CSS :target
  2. CSS 그리드
  3. CSS 변환
  4. 표시 영역 및 사용자 환경설정을 위한 CSS 미디어 쿼리
  5. focus용 JS UX 개선

내 솔루션에 하나의 사이드바가 있으며 '모바일'에 있을 때만 전환됨 540px 이하의 표시 영역입니다. 540px는 모바일 상호작용 레이아웃과 정적 데스크톱 레이아웃 간 전환을 위한 중단점입니다.

CSS :target 의사 클래스

<a> 링크는 URL 해시를 #sidenav-open로 설정하고 다른 하나는 비어 있음 ('')으로 설정합니다. 마지막으로 요소에는 해시와 일치하는 id가 있습니다.

<a href="#sidenav-open" id="sidenav-button" title="Open Menu" aria-label="Open Menu">

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<aside id="sidenav-open">
  …
</aside>

이러한 각 링크를 클릭하면 페이지 URL의 해시 상태가 변경되어 그런 다음 의사 클래스를 사용하여 sidenav를 표시하고 숨깁니다.

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
  }

  #sidenav-open:target {
    visibility: visible;
  }
}

CSS 그리드

이전에는 절대 또는 고정 게재순위만 사용했습니다. 사이드탐색 레이아웃과 구성요소를 활용할 수 있습니다. 하지만 grid-area 문법이 있는 그리드는 동일한 행이나 열에 여러 요소를 할당할 수 있습니다.

스택

기본 레이아웃 요소 #sidenav-container는 행 1개와 열 2개를 만드는 그리드입니다. 각 항목 중 하나의 이름은 stack입니다. 공간이 제한되면 CSS는 모든 <main> 요소의 하위 요소를 동일한 그리드 이름에 추가하여 모든 요소를 동일한 공간에 배치하여 스택을 만듭니다.

#sidenav-container {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;
  min-height: 100vh;
}

@media (max-width: 540px) {
  #sidenav-container > * {
    grid-area: stack;
  }
}

<aside>는 측면 탐색 메뉴가 포함된 애니메이션 요소입니다. 여기에는 다음이 있습니다. 하위 요소 2개: 이름이 [nav]인 탐색 컨테이너 <nav> 및 배경화면 <a> 메뉴를 닫는 데 사용되는 [escape]입니다.

#sidenav-open {
  display: grid;
  grid-template-columns: [nav] 2fr [escape] 1fr;
}

2fr 조정 및 1fr: 메뉴 오버레이와 빈 공간 닫기 버튼의 원하는 비율을 찾습니다.

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder"> <ph type="x-smartling-placeholder">
</ph> 비율을 변경하면 어떻게 되는지에 대한 데모입니다.

CSS 3D 변환 및 전환

이제 레이아웃이 모바일 표시 영역 크기로 스태킹됩니다. 새로운 스타일을 추가할 때까지 기본적으로 기사에 오버레이됩니다. 다음 섹션에서 목표로 삼고 있는 몇 가지 UX는 다음과 같습니다.

  • 열기 및 닫기 애니메이션
  • 사용자가 괜찮은 경우에만 모션이 적용된 애니메이션 처리
  • 키보드 포커스가 화면 밖 요소에 들어가지 않도록 visibility에 애니메이션 적용

모션 애니메이션을 구현할 때 접근성을 가장 먼저 떠올려 보겠습니다.

액세스 가능한 모션

모든 사용자가 슬라이드 아웃 모션 환경을 원하지는 않습니다. Google 솔루션에서 이 환경설정은 미디어 쿼리 내에서 --duration CSS 변수를 조정하여 적용됩니다. 이 미디어 쿼리 값은 모션에 대한 사용자 운영체제 환경설정 (가능한 경우).

#sidenav-open {
  --duration: .6s;
}

@media (prefers-reduced-motion: reduce) {
  #sidenav-open {
    --duration: 1ms;
  }
}
드림 <ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
기간이 적용된 상호작용과 적용되지 않은 상호작용의 데모입니다.

이제 측면 탐색 메뉴가 열리고 닫힐 때 사용자가 줄어드는 동작을 선호한다면 요소를 즉시 뷰로 이동하여 모션 없이 상태를 유지합니다.

전환, 변환, 변환

측면 탐색 바깥쪽 (기본값)

모바일에서 측면 탐색의 기본 상태를 화면 밖 상태로 설정하려면 transform: translateX(-110vw)로 요소를 배치합니다.

참고로 일반적인 오프스크린 코드 -100vw에 또 다른 10vw를 추가했습니다. 을 사용해야 합니다.box-shadow

@media (max-width: 540px) {
  #sidenav-open {
    visibility: hidden;
    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);
  }
}
측면 탐색

#sidenav 요소가 :target와 일치하면 translateX() 위치를 홈베이스 0로 설정합니다. CSS가 요소를 -110vw의 바깥쪽 위치에서 'in'으로 슬라이드하는 것을 관찰합니다. URL 해시가 변경되면 var(--duration)보다 0의 위치

@media (max-width: 540px) {
  #sidenav-open:target {
    visibility: visible;
    transform: translateX(0);
    transition:
      transform var(--duration) var(--easeOutExpo);
  }
}

전환 표시 여부

이제 목표는 아웃될 때 스크린 리더에서 메뉴를 숨기고, 시스템이 오프스크린 메뉴에 포커스를 두지 않습니다. 이렇게 하려면 :target 변경 시 공개 상태 전환을 처리합니다.

  • 들어갈 때는 공개 상태를 전환하지 마세요. 요소가 즉시 표시되고 포커스를 받아 볼 수 있습니다.
  • 밖으로 나가면 전환 공개 상태가 표시되긴 하지만 지연되어 전환 종료 시 hidden로 반전됩니다.

접근성 UX 개선

이 솔루션에서는 상태를 관리하기 위해 URL을 변경해야 합니다. 당연히 여기서 <a> 요소를 사용해야 하며, 이는 멋진 접근성을 얻습니다. 기능을 무료로 제공합니다 의도를 명확하게 표현하는 라벨로 상호작용 요소를 장식해 보겠습니다.

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu"></a>

<a href="#sidenav-open" id="sidenav-button" class="hamburger" title="Open Menu" aria-label="Open Menu">
  <svg>...</svg>
</a>
드림 <ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
음성 해설 및 키보드 상호작용 UX 데모입니다.

이제 기본 상호작용 버튼은 마우스와 키보드 모두에 대한 의도를 명확하게 설명합니다.

:is(:hover, :focus)

이 편리한 CSS 기능 의사 선택기를 사용하면 신속하게 포괄적이고 공유할 수도 있습니다.

.hamburger:is(:hover, :focus) svg > line {
  stroke: hsl(var(--brandHSL));
}

JavaScript 기반 스프링클

닫으려면 escape 키를 누르세요

키보드의 Escape 키를 누르면 메뉴가 닫히나요? 연결해 보겠습니다.

const sidenav = document.querySelector('#sidenav-open');

sidenav.addEventListener('keyup', event => {
  if (event.code === 'Escape') document.location.hash = '';
});
브라우저 방문 기록

열기 및 닫기 상호작용이 여러 개의 브라우저 기록에 다음 자바스크립트 인라인을 추가합니다. 닫기 버튼:

<a href="#" id="sidenav-close" title="Close Menu" aria-label="Close Menu" onchange="history.go(-1)"></a>

이렇게 하면 닫을 때 URL 기록 항목이 삭제되어 메뉴가 열립니다

포커스 UX

다음 스니펫은 자동으로 열리거나 닫힙니다. 쉽게 전환할 수 있게 하고 싶습니다.

sidenav.addEventListener('transitionend', e => {
  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
      ? document.querySelector('#sidenav-close').focus()
      : document.querySelector('#sidenav-button').focus();
})

측면 탐색 메뉴가 열리면 닫기 버튼에 포커스를 맞춥니다. 측면 탐색 메뉴가 닫히면 열기 버튼에 포커스를 맞추세요. JavaScript의 요소에서 focus()를 호출하여 이 작업을 실행합니다.

결론

이제 내가 어떻게 했는지 알았으니 어떻게 하면 어떨까?! 이렇게 하면 몇 가지 재미있는 구성요소 아키텍처가 만들어집니다. 슬롯이 있는 첫 번째 버전을 누가 만들 건가요? 🙂

다양한 방식으로 접근하고 웹에서 빌드하는 모든 방법을 배웁니다. 글리치 생성 트윗 트윗해 주시면 커뮤니티 리믹스 섹션을 참조하세요.

커뮤니티 리믹스