Codelab: Sidenav 구성요소 빌드

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

이 구성요소를 빌드하기 위해 선택한 CSS 웹 플랫폼 기능에 관해 알아보려면 블로그 게시물 Sidenav 구성요소 빌드를 확인하세요.

설정

  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>

헤더에는 메뉴 열기 링크가 있습니다. 측면에는 닫기 버튼이 있습니다. 곧 표시 영역 크기에 따라 요소를 표시하거나 숨길 예정입니다.

<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>

이 콘텐츠와 길이가 표시 영역 높이를 초과하면 페이지를 스크롤할 수 있게 됩니다.

지금까지 탐색, 링크, 측면 탐색을 닫는 방법이 포함된 측면 요소를 추가했습니다. 또한 헤더, 측면 탐색을 여는 방법, 도움말을 기본 요소에 추가했습니다. 깔끔하고 의미론적이며 시대를 초월한 방법이지만, 모든 사용자에게 더 명확하고 또렷하게 만들 수 있습니다. 측면 탐색 메뉴의 열린 링크를 더 명확하게 표시할 수 있습니다

헤더 열기 링크 요소에 title 속성과 aria-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> 태그의 직계 하위 요소이므로 이 부분부터 시작하는 것이 좋습니다.

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

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를 추가합니다.

<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>도 깔끔한 레이아웃으로 꾸며져 있습니다. 하위 요소 2개가 있습니다. 하나는 종이처럼 보이는 구성요소인 <nav>이고 다른 하나는 URL을 #로 설정하는 닫는 <a> 링크 요소입니다. 이 링크는 종이의 오른쪽에 탐색 슬라이드 아웃으로 표시되지 않습니다. 따라서 사용자는 시각적 구성요소를 '클릭'하여 닫을 수 있습니다.

다음 CSS를 css/sidenav.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를 css/sidenav.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를 js/index.js에 추가합니다.

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

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

측면 탐색 요소의 주요 이벤트를 수신 대기합니다. Escape인 경우 URL 해시가 비어 있도록 설정되므로 Sidenav가 출력됩니다.

UX JS의 다음 부분은 포커스 관리입니다. 열기 및 닫기를 쉽게 만들고 싶으므로 측면 탐색에서 일종의 전환이 완료될 때까지 기다린 다음 URL 해시와 교차 확인하여 탐색 중인지 확인합니다. 그런 다음 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();
});

사용해 보기

  • 사이트를 미리 보려면 View App을 누른 다음 Fullscreen 전체 화면을 누릅니다.

결론

구성요소와 관련된 요구사항을 마치겠습니다. 자유롭게 이를 기반으로 URL 대신 JavaScript 상태로 만든 후 일반적으로 원하는 대로 만들 수 있습니다. 항상 추가하거나 다뤄야 할 사용 사례가 많아집니다

css/brandnav.css를 열어 이 구성요소에 적용한 비레이아웃 관련 스타일을 확인합니다. 중점을 두고 있는 지형지물 세트에는 중요하지 않은 것 같았고, 레이아웃과 스타일을 분리하면 복사하여 붙여넣기가 잘 되기를 바랐습니다. 더 많은 내용을 배울 수 있습니다.

반응형 사이드 탐색 구성요소를 슬라이드 아웃하려면 어떻게 해야 하나요? 양쪽에 하나씩처럼 두 개 이상 있나요? 여러분의 해결 방법을 YouTube 동영상에 소개하고 싶습니다. 트윗이나 YouTube에서 여러분의 코드를 사용해 YouTube에 댓글을 달아주시면 모두에게 도움이 될 것입니다.