Codelab: Sidenav 구성요소 빌드

이 Codelab에서는 웹에서 반응형 슬라이드 아웃 측면 탐색 레이아웃 구성요소를 빌드하는 방법을 알아봅니다. HTML, CSS, JavaScript 순으로 구성요소를 빌드합니다.

사이드 탐색 메뉴 구성요소 빌드 블로그 게시물에서 이 구성요소를 빌드하는 데 선택한 CSS 웹 플랫폼 기능에 대해 알아보세요.

설정

  1. 리믹스하여 수정을 클릭하여 프로젝트를 수정할 수 있도록 합니다.
  2. app/index.html를 엽니다.

HTML

먼저 콘텐츠와 작업할 수 있는 상자가 있도록 HTML 설정의 기본사항을 가져옵니다.

다음 HTML을 <body> 태그에 배치합니다.

<aside></aside>
<main></main>

<aside>는 기본 페이지 콘텐츠를 포함하는 <main>의 보완 요소로 탐색 메뉴를 포함합니다.

다음으로 나머지 페이지 콘텐츠로 이러한 시맨틱 요소를 채웁니다.

<aside> 요소 내에 탐색 요소, 탐색 링크, 닫기 링크를 추가합니다.

<aside>
  <nav>
    <h4>My</h4>
    <a href="#">Dashboard</a>
    <a href="#">Profile</a>
    <a href="#">Preferences</a>
    <a href="#">Archive</a>

    <h4>Settings</h4>
    <a href="#">Accessibility</a>
    <a href="#">Theme</a>
    <a href="#">Admin</a>
  </nav>

  <a href="#"></a>
</aside>

링크는 <nav> 요소 내에 배치하는 것이 좋고 <nav> 요소는 <aside> 사이드바에 배치하는 것이 좋습니다. 하지만 개선할 수 있는 부분이 더 있습니다.

기본 콘텐츠 요소에서 레이아웃 콘텐츠를 의미적으로 보유하는 헤더와 기사를 추가합니다.

<main>
  <header>
    <a href="#sidenav-open" class="hamburger">
      <svg viewBox="0 0 50 40">
        <line x1="0" x2="100%" y1="10%" y2="10%" />
        <line x1="0" x2="100%" y1="50%" y2="50%" />
        <line x1="0" x2="100%" y1="90%" y2="90%" />
      </svg>
    </a>
    <h1>Site Title</h1>
  </header>

  <article>
    {put some placeholder content here}
  </article>
</main>

헤더에 메뉴 열기 링크가 있습니다. aside에는 닫기 버튼이 있습니다. 곧 뷰포트 크기에 따라 요소를 표시하거나 숨길 수 있습니다.

<article> 요소에 자리표시자 문장을 붙여넣었습니다. `` 를 직접 만든 콘텐츠로 바꾸거나 아래에 제공된 lorem을 붙여넣습니다.

<h2>Totam Header</h2>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Cum consectetur, necessitatibus velit officia ut impedit veritatis temporibus soluta? Totam odit cupiditate facilis nisi sunt hic necessitatibus voluptatem nihil doloribus! Enim.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

<h3>Subhead Totam Odit</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

<h3>Subhead</h3>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit rerum, amet odio explicabo voluptas eos cum libero, ex esse quasi optio incidunt soluta eligendi labore error corrupti! Dolore, cupiditate porro.</p>

이 콘텐츠와 길이가 표시 영역 높이를 초과하면 페이지가 스크롤 가능해집니다.

지금까지 탐색, 링크, 사이드 탐색을 닫는 방법이 포함된 aside 요소를 추가했습니다. 또한 헤더, 사이드 탐색을 여는 방법, 기본 요소에 기사를 추가했습니다. 이미 깔끔하고 시맨틱하며 시대를 타지 않지만, 모든 사용자가 더 깔끔하고 명확하게 이해할 수 있도록 만들 수 있습니다. 사이드 탐색에서 링크 열기가 더 명확하게 표시될 수 있습니다.

헤더 열기 링크 요소에 titlearia-label 속성을 추가합니다.

<a href="#sidenav-open" class="hamburger">
<a href="#sidenav-open" title="Open Menu" aria-label="Open Menu" class="hamburger">

열린 SVG 아이콘도 더 명확하게 표시할 수 있습니다. 열린 링크 요소 내의 SVG에 다음 속성을 추가합니다.

<svg viewBox="0 0 50 40">
<svg viewBox="0 0 50 40" role="presentation" focusable="false" aria-label="trigram for heaven symbol">

사이드 탐색 메뉴의 닫기 링크가 더 명확하게 표시되어야 합니다. 사이드 탐색 닫기 링크 요소에 titlearia-label 속성을 추가합니다.

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

CSS

요소를 배치할 시간입니다. 기본 콘텐츠와 사이드 탐색은 <body> 태그의 직접 하위 요소이므로 여기에서 시작하는 것이 좋습니다.

<body> 요소가 하위 요소를 배치하도록 css/sidenav.css에 다음 CSS를 추가합니다.

body {
  display: grid;
  grid: [stack] 1fr / min-content [stack] 1fr;

  @media (max-width: 540px) {
    & > :matches(aside, main) {
      grid-area: stack;
    }
  }
}

이 레이아웃은 기본적으로 '모든 항목이 포함된 stack라는 명명된 행을 만들고 해당 행에 2개의 열을 만드는데, 그중 두 번째 열의 이름도 stack입니다.'라고 말합니다. 첫 번째 열은 최소 콘텐츠 요구사항에 따라 크기가 조정되어야 하고 두 번째 열은 나머지를 차지할 수 있습니다. 그런 다음 540px 이하의 제한된 뷰포트에서 사이드 탐색과 기본 콘텐츠 요소를 동일한 행과 열에 배치하여 1x1 그리드에서 서로 위에 배치되도록 합니다.

이제 이 반응형 스태킹 기능을 기반으로 URL 표시줄의 상태를 활용하여 사이드 탐색의 가시성과 전환 스타일을 전환할 수 있습니다.

app/index.html에서 <aside> 요소를 다시 업데이트합니다.

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

이를 통해 CSS가 요소와 URL 해시를 함께 일치시킬 수 있습니다. 이는 :target 사용에 중요합니다. 이제 요소의 ID가 <a> 태그로 설정할 URL 해시와 일치할 수 있습니다.

또한 JavaScript 타겟팅을 더 쉽게 할 수 있도록 사이드 탐색을 제어하는 주요 요소의 ID를 추가합니다. 먼저 ID를 sidenav 열기 링크에 추가합니다.

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

다음으로 사이드 탐색 닫기 링크에 ID를 추가합니다.

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

이렇게 하면 매크로 <body> 반응형 스태킹 레이아웃이 래핑되고 URL 표시줄에 연결됩니다. 계속 진행하겠습니다.

<aside>의 레이아웃도 깔끔합니다. 여기에는 두 개의 하위 요소가 있습니다. 하나는 슬라이드 아웃되는 종이 모양의 컴포넌트인 <nav>이고, 다른 하나는 URL을 #로 설정하는 닫기 <a> 링크 요소입니다. 이 링크는 페이퍼 슬라이드 아웃 탐색의 오른쪽에 표시되지 않습니다. 사용자가 시각적 구성요소를 '클릭하여 닫기'할 수 있도록 하기 위해서입니다.

css/sidenav.css에 다음 CSS를 추가합니다.

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

여기서는 비율과 이름이 정말 멋진 터치라고 생각합니다. 그리드가 빛을 발하고 디자이너에게 많은 제어권을 부여할 수 있습니다.

다음으로 기본 콘텐츠를 조건부로 오버레이하고 문서 스크롤을 통해 내 위치를 유지해야 합니다. position: sticky 및 일부 overscroll-behavior에 적합한 작업입니다.

사이드 탐색 메뉴에 다음 스타일을 추가합니다.

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

  @media (max-width: 540px) {
    position: sticky;
    top: 0;
    max-height: 100vh;
    overflow: hidden auto;
    overscroll-behavior: contain;

    visibility: hidden; /* not keyboard accessible when closed */
  }
}

이러한 스타일은 사이드 탐색 메뉴가 뷰포트 높이이고, 세로로 스크롤되며 스크롤을 포함하도록 합니다. 매우 중요한 점은 요소를 숨긴다는 것입니다. 기본적으로 표시 영역이 540px 이하인 경우 사이드 탐색 메뉴를 숨깁니다. 아니면!

#sidenav-open 요소에 :target 가상 선택기를 추가합니다.

#sidenav-open {

  @media (max-width: 540px) {

    &:target {
      visibility: visible;
    }
  }
}

해당 요소의 ID와 URL 표시줄이 동일한 경우 visibilityvisible로 설정합니다. 페이지를 스크롤한 후 사이드 메뉴를 열거나, 사이드 탐색 메뉴가 열려 있는 동안 페이지를 스크롤해 보세요. 어떻게 생각하시나요?

app/sidenav.css 하단에 다음 CSS를 추가합니다.

#sidenav-button,
#sidenav-close {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
  touch-action: manipulation;

  @media (min-width: 540px) {
    display: none;
  }
}

이 스타일은 열기 및 닫기 버튼을 타겟팅하고, 탭 및 터치 스타일을 지정하며, 뷰포트가 540px 이상인 경우 버튼을 숨깁니다.

약간의 멋을 내기 위해 접근성을 고려한 CSS 변환을 추가해 보겠습니다. css/sidenav.css에 다음 CSS를 추가합니다.

#sidenav-open {
  --easeOutExpo: cubic-bezier(0.16, 1, 0.3, 1);
  --duration: .6s;

  ...

  @media (max-width: 540px) {
    ...

    transform: translateX(-110vw);
    will-change: transform;
    transition:
      transform var(--duration) var(--easeOutExpo),
      visibility 0s linear var(--duration);

    &:target {
      visibility: visible;
      transform: translateX(0);
      transition: transform var(--duration) var(--easeOutExpo);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    --duration: 1ms;
  }
}
`prefers-reduced-motion` 미디어 쿼리를 기반으로 지속 시간이 적용된 경우와 적용되지 않은 경우의 상호작용 데모입니다.

JavaScript 추가

Escape 키를 누르면 메뉴가 닫혀야 합니다. js/index.js에 다음 JS를 추가합니다.

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

sidenav.addEventListener('keyup', e => {
  if (e.code === 'Escape') {
    document.location.hash = '';
  }
});

이는 사이드 탐색 메뉴 요소에서 키 이벤트를 수신합니다. Escape인 경우 URL 해시를 비워 사이드 탐색이 전환되도록 합니다.

다음 UX JS는 포커스 관리입니다. 열고 닫는 작업을 쉽게 하고 싶어서 사이드 탐색 메뉴가 어떤 종류의 전환을 완료할 때까지 기다린 다음 URL 해시와 교차 확인하여 사이드 탐색 메뉴가 열려 있는지 닫혀 있는지 확인합니다. 그런 다음 JavaScript를 사용하여 방금 누른 버튼과 상호 보완적인 버튼에 포커스를 설정합니다.

다음 JavaScript를 js/index.js에 추가합니다.

const closenav = document.querySelector('#sidenav-close');
const opennav = document.querySelector('#sidenav-button');

sidenav.addEventListener('transitionend', e => {
  if (e.propertyName !== 'transform') {
    return;
  }

  const isOpen = document.location.hash === '#sidenav-open';

  isOpen
    ? closenav.focus()
    : opennav.focus();
});

사용해 보기

  • 사이트를 미리 보려면 앱 보기를 누릅니다. 그런 다음 전체 화면 전체 화면을 누릅니다.

결론

구성요소와 관련해 필요한 사항은 여기까지입니다. 자유롭게 빌드하고, URL 대신 JavaScript 상태로 구동하고, 일반적으로 나만의 것으로 만들어 보세요. 항상 추가할 내용이나 다룰 사용 사례가 더 있습니다.

css/brandnav.css을 열어 이 구성요소에 적용한 레이아웃과 관련이 없는 스타일을 확인합니다. 제가 집중하고 있는 기능 세트에는 중요하지 않다고 생각했고, 스타일을 레이아웃에서 분리하면 복사 및 붙여넣기가 장려될 것이라고 기대했습니다. 여기에서 더 많은 것을 배울 수 있습니다.

슬라이드 아웃 반응형 사이드 탐색 메뉴 구성요소는 어떻게 만드나요? 양쪽에 하나씩 있는 것처럼 2개 이상인 경우도 있나요? YouTube 동영상에 내 솔루션을 소개하고 싶습니다. 내 트위터 계정을 멘션하거나 YouTube에 코드를 댓글로 달아주세요. 모두에게 도움이 될 것입니다.