iOS 및 Android 앱에 있는 탭 구성요소와 유사한 탭 구성요소를 빌드하는 방법에 관한 기본 개요입니다.
이 게시물에서는 반응성이 뛰어나고 여러 기기 입력을 지원하며 여러 브라우저에서 작동하는 웹용 탭 컴포넌트를 빌드하는 방법에 관한 생각을 공유하고자 합니다. 데모를 사용해 보세요.
동영상을 선호하는 경우 이 게시물의 YouTube 버전을 참고하세요.
개요
탭은 디자인 시스템의 일반적인 구성요소이지만 다양한 도형과 형태를 취할 수 있습니다. 처음에는 <frame>
요소를 기반으로 빌드된 데스크톱 탭이 있었지만 이제는 물리 속성을 기반으로 콘텐츠에 애니메이션을 적용하는 부드러운 모바일 구성요소가 있습니다.
모두 공간을 절약하기 위해 동일한 작업을 시도합니다.
오늘날 탭 사용자 환경의 핵심은 디스플레이 프레임에서 콘텐츠의 표시 여부를 전환하는 버튼 탐색 영역입니다. 다양한 콘텐츠 영역이 동일한 공간을 공유하지만 탐색에서 선택한 버튼에 따라 조건부로 표시됩니다.
웹 전술
몇 가지 중요한 웹 플랫폼 기능 덕분에 이 구성요소를 빌드하는 것이 매우 간단했습니다.
- 적절한 스크롤 중지 위치에서 우아한 스와이프 및 키보드 상호작용을 위한
scroll-snap-points
- 브라우저에서 처리되는 인페이지 스크롤 고정 및 공유 지원을 위한 URL 해시를 통한 딥 링크
<a>
및id="#hash"
요소 마크업을 사용한 스크린 리더 지원- 크로스페이드 전환 및 즉시 페이지 내 스크롤을 사용 설정하기 위한
prefers-reduced-motion
- 선택한 탭의 밑줄을 동적으로 표시하고 색상을 변경하는 초안 내
@scroll-timeline
웹 기능
HTML
기본적으로 여기서 UX는 링크를 클릭하고 URL이 중첩된 페이지 상태를 나타내도록 한 다음 브라우저가 일치하는 요소로 스크롤할 때 콘텐츠 영역이 업데이트되는 것을 확인하는 것입니다.
여기에는 링크와 :target
와 같은 몇 가지 구조적 콘텐츠 멤버가 있습니다. <nav>
에 적합한 링크 목록과 <section>
에 적합한 <article>
요소 목록이 필요합니다. 각 링크 해시는 섹션과 일치하므로 브라우저가 고정을 통해 스크롤할 수 있습니다.
예를 들어 링크를 클릭하면 Chrome 89에서 :target
도움말에 자동으로 포커스가 맞춰집니다. JS가 필요하지 않습니다. 그러면 사용자는 평소와 같이 입력 장치로 기사 콘텐츠를 스크롤할 수 있습니다. 마크업에 표시된 대로 무료 콘텐츠입니다.
다음 마크업을 사용하여 탭을 구성했습니다.
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
다음과 같이 href
및 id
속성을 사용하여 <a>
및 <article>
요소 간에 연결을 설정할 수 있습니다.
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
다음으로 기사를 다양한 길이의 Lorem Ipsum으로 채우고 링크를 다양한 길이의 제목 이미지 세트로 채웠습니다. 이제 작업할 콘텐츠가 있으므로 레이아웃을 시작할 수 있습니다.
스크롤 레이아웃
이 구성요소에는 다음과 같은 3가지 유형의 스크롤 영역이 있습니다.
- 탐색 (분홍색)을 가로로 스크롤할 수 있습니다.
- 콘텐츠 영역 (파란색)을 가로로 스크롤할 수 있습니다.
- 각 도움말 항목 (녹색)은 세로로 스크롤할 수 있습니다.
스크롤과 관련된 요소에는 두 가지 유형이 있습니다.
- 창
overflow
속성 스타일이 있는 정의된 크기의 상자입니다. - 대형 노출 영역
이 레이아웃에서는 목록 컨테이너(탐색 링크, 섹션 도움말, 도움말 콘텐츠)입니다.
<snap-tabs>
레이아웃
선택한 최상위 레이아웃은 flex (Flexbox)입니다. 방향을 column
로 설정하여 헤더와 섹션이 세로로 정렬됩니다. 이는 첫 번째 스크롤 창이며 overflow hidden으로 모든 항목을 숨깁니다. 헤더와 섹션이 곧 개별 영역으로 오버스크롤을 사용합니다.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
다채로운 3단 스크롤 다이어그램을 다시 살펴보겠습니다.
- 이제
<header>
가 (분홍색) 스크롤 컨테이너가 될 준비가 되었습니다. <section>
가 (파란색) 스크롤 컨테이너가 될 준비가 되었습니다.
아래에서 VisBug로 강조 표시한 프레임은 스크롤 컨테이너가 만든 창을 볼 수 있도록 도와줍니다.
탭 <header>
레이아웃
다음 레이아웃은 거의 동일합니다. flex를 사용하여 세로 순서를 만듭니다.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
는 링크 그룹과 함께 가로로 이동해야 하며 이 헤더 레이아웃은 이러한 단계를 설정하는 데 도움이 됩니다. 절대 위치로 배치된 요소가 없습니다.
다음은 스크롤 스타일입니다. 두 개의 가로 스크롤 영역 (헤더 및 섹션) 간에 스크롤 스타일을 공유할 수 있으므로 유틸리티 클래스 .scroll-snap-x
를 만들었습니다.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
각각 x축의 오버플로, 오버스크롤을 가두기 위한 스크롤 컨테이닝, 터치 기기의 숨겨진 스크롤바, 마지막으로 콘텐츠 프레젠테이션 영역 잠금을 위한 스크롤 스냅이 필요합니다. 키보드 탭 순서에 액세스할 수 있으며 모든 상호작용은 포커스를 자연스럽게 안내합니다. 스크롤 스냅 컨테이너는 키보드에서 멋진 캐러셀 스타일 상호작용도 받습니다.
탭 헤더 <nav>
레이아웃
탐색 링크는 줄바꿈 없이 한 줄에 배치되고 세로로 가운데에 정렬되어야 하며 각 링크 항목은 스크롤 스냅 컨테이너에 스냅되어야 합니다. 2021 CSS를 위한 Swift 작업
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
각 링크는 자체 스타일과 크기를 지정하므로 탐색 레이아웃은 방향과 흐름만 지정하면 됩니다. 탐색 항목의 고유한 너비는 표시기가 너비를 새 타겟으로 조정할 때 탭 간에 재미있는 전환을 만듭니다. 여기에 있는 요소의 수에 따라 브라우저에서 스크롤바를 렌더링할지 여부가 결정됩니다.
탭 <section>
레이아웃
이 섹션은 플렉스 항목이며 공간을 가장 많이 사용하는 항목이어야 합니다. 또한 도움말을 배치할 열을 만들어야 합니다. CSS 2021을 위해 다시 한번 신속하게 작업해 주세요. block-size: 100%
는 이 요소를 늘려 상위 요소를 최대한 채운 다음 자체 레이아웃을 위해 상위 요소의 너비의 100%
배인 일련의 열을 만듭니다. 상위에 강력한 제약 조건을 작성했기 때문에 여기서는 비율이 잘 작동합니다.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
마치 '세로로 최대한 확장하되 과도하게'(flex-shrink: 0
로 설정된 헤더를 기억하세요. 이 확장 푸시에 대한 방어입니다.)라고 말하는 것처럼 전체 높이 열 세트의 행 높이를 설정합니다. auto-flow
스타일은 그리드에 항상 하위 요소를 가로선으로 배치하도록 지시합니다. 래핑은 없으며, 바로 이것이 상위 창을 오버플로시키기 위해 원하는 바입니다.
때로는 이해하기 어렵습니다. 이 섹션 요소는 상자에 맞게 조정되지만 상자 세트도 만듭니다. 시각 자료와 설명이 도움이 되었기를 바랍니다.
탭 <article>
레이아웃
사용자가 기사 콘텐츠를 스크롤할 수 있어야 하며 스크롤바는 오버플로가 있는 경우에만 표시되어야 합니다. 이러한 도움말 요소는 정리된 위치에 있습니다. 스크롤 상위 요소이자 스크롤 하위 요소입니다. 브라우저가 여기서 몇 가지 까다로운 터치, 마우스, 키보드 상호작용을 처리합니다.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
부모 스크롤러 내에서 기사가 스냅되도록 선택했습니다. 탐색 링크 항목과 기사 요소가 각 스크롤 컨테이너의 인라인 시작에 스냅되는 방식이 마음에 듭니다. 조화로운 관계처럼 보이고 느껴집니다.
기사는 그리드 하위 요소이며 크기는 스크롤 UX를 제공하려는 뷰포트 영역으로 사전 결정됩니다. 즉, 여기에는 높이나 너비 스타일이 필요하지 않으며 오버플로 방식만 정의하면 됩니다. overflow-y를 auto로 설정한 다음 편리한 overscroll-behavior 속성으로 스크롤 상호작용을 트랩합니다.
스크롤 영역 3가지 요약
아래에서는 시스템 설정에서 '스크롤바 항상 표시'를 선택했습니다. 레이아웃과 스크롤 오케스트레이션을 검토하는 것만큼이나 이 설정을 사용 설정하여 레이아웃이 작동하는 것이 중요합니다.
이 구성요소에서 스크롤바 가터를 확인하면 스크롤 영역의 위치, 지원하는 방향, 서로 상호작용하는 방식을 명확하게 보여줄 수 있습니다. 이러한 각 스크롤 창 프레임이 레이아웃의 flex 또는 그리드 상위 요소가 되는 방식을 고려해 보세요.
DevTools를 사용하면 다음을 시각화할 수 있습니다.
스크롤 레이아웃이 완성되었습니다. 스냅, 딥 링크 가능, 키보드 액세스 가능 UX 개선, 스타일, 만족감을 위한 견고한 기반
주요 기능
스크롤 스냅된 하위 요소는 크기 조절 중에 잠긴 위치를 유지합니다. 즉, JavaScript는 기기 회전이나 브라우저 크기 조절 시 아무것도 표시할 필요가 없습니다. Chromium DevTools 기기 모드에서 Responsive가 아닌 모드를 선택한 다음 기기 프레임의 크기를 조절하여 사용해 보세요. 요소가 계속 표시되고 콘텐츠와 함께 고정된 것을 볼 수 있습니다. 이는 Chromium이 사양에 맞게 구현을 업데이트한 이후 사용할 수 있습니다. 관련 블로그 게시물을 참고하세요.
애니메이션
여기서 애니메이션 작업의 목표는 상호작용을 UI 피드백과 명확하게 연결하는 것입니다. 이렇게 하면 사용자가 모든 콘텐츠를 원활하게 탐색할 수 있도록 안내하거나 지원할 수 있습니다. 목적과 조건에 따라 모션을 추가할 예정입니다. 이제 사용자는 운영체제에서 모션 환경설정을 지정할 수 있으며, 저는 인터페이스에서 사용자의 환경설정에 응답하는 것을 매우 즐깁니다.
탭 밑줄을 기사 스크롤 위치와 연결하겠습니다. 스냅은 보기 좋게 정렬하는 것뿐만 아니라 애니메이션의 시작과 끝을 고정하는 것입니다.
이렇게 하면 미니 맵처럼 작동하는 <nav>
가 콘텐츠에 연결된 상태로 유지됩니다.
CSS와 JS에서 사용자의 모션 환경설정을 확인합니다. 다음과 같은 몇 가지 좋은 예가 있습니다.
스크롤 동작
:target
와 element.scrollIntoView()
의 모션 동작을 개선할 수 있습니다. 기본적으로 즉시 실행됩니다. 브라우저는 스크롤 위치만 설정합니다. 깜박이는 대신 해당 스크롤 위치로 전환하려면 어떻게 해야 하나요?
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
여기서는 모션과 사용자가 제어하지 않는 모션(예: 스크롤)을 도입하므로 사용자가 운영체제에서 모션 감소에 관해 선호하는 설정이 없는 경우에만 이 스타일을 적용합니다. 이렇게 하면 스크롤 모션을 괜찮게 생각하는 사용자에게만 소개할 수 있습니다.
탭 표시기
이 애니메이션의 목적은 표시기와 콘텐츠 상태를 연결하는 것입니다. 모션 감소를 선호하는 사용자를 위해 색상 크로스페이드 border-bottom
스타일을, 모션을 괜찮게 생각하는 사용자를 위해 스크롤 연결 슬라이딩 + 색상 페이드 애니메이션을 사용하기로 결정했습니다.
Chromium Devtools에서 환경설정을 전환하고 두 가지 전환 스타일을 보여줄 수 있습니다. 이 앱을 빌드하는 것이 정말 즐거웠습니다.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
사용자가 모션 감소를 선호하는 경우 더 이상 필요하지 않으므로 .snap-indicator
를 숨깁니다. 그런 다음 border-block-end
스타일과 transition
로 바꿉니다. 또한 탭 상호작용에서 활성 탐색 항목에 브랜드 밑줄 강조 표시가 있을 뿐만 아니라 텍스트 색상도 더 어둡습니다. 활성 요소는 텍스트 색상 대비가 더 높고 밝은 하단 조명 강조 표시가 있습니다.
CSS를 몇 줄만 추가하면 사용자의 모션 환경설정을 신중하게 고려한다는 의미에서 사용자에게 '눈에 띄는' 앱이라는 느낌을 줄 수 있습니다. 마음에 듭니다.
@scroll-timeline
위 섹션에서는 감소된 모션 크로스페이드 스타일을 처리하는 방법을 보여 드렸으며, 이 섹션에서는 표시기와 스크롤 영역을 함께 연결하는 방법을 보여드리겠습니다. 다음은 재미있는 실험용 기능입니다. 저만큼이나 기쁜 소식이길 바랍니다.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
먼저 JavaScript에서 사용자의 모션 환경설정을 확인합니다. 결과가 false
이면 사용자가 모션 감소를 선호한다는 의미이므로 스크롤 연결 모션 효과가 실행되지 않습니다.
if (motionOK) {
// motion based animation code
}
이 글을 작성하는 시점에서 @scroll-timeline
의 브라우저 지원은 없습니다. 실험용 구현만 있는 초안 사양입니다. 하지만 이 데모에서 사용하는 폴리필이 있습니다.
ScrollTimeline
CSS와 JavaScript 모두 스크롤 타임라인을 만들 수 있지만 애니메이션에서 실시간 요소 측정을 사용할 수 있도록 JavaScript를 선택했습니다.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
한 요소가 다른 요소의 스크롤 위치를 따라가도록 하려면 ScrollTimeline
를 만들어 스크롤 링크의 드라이버인 scrollSource
를 정의합니다.
일반적으로 웹의 애니메이션은 전역 시간 프레임 틱에 따라 실행되지만 메모리에 맞춤 sectionScrollTimeline
가 있으면 이 모든 것을 변경할 수 있습니다.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
애니메이션의 키프레임에 대해 알아보기 전에 스크롤의 추종자 tabindicator
가 맞춤 타임라인(섹션의 스크롤)을 기반으로 애니메이션된다는 점을 지적하는 것이 중요합니다. 이렇게 하면 연결이 완료되지만 애니메이션을 적용할 상태 저장 포인트(키프레임이라고도 함)라는 마지막 요소가 누락됩니다.
동적 키프레임
@scroll-timeline
로 애니메이션을 만드는 매우 강력한 순수 선언적 CSS 방법이 있지만 제가 선택한 애니메이션은 너무 역동적이었습니다. auto
너비 간에 전환하는 방법은 없으며 하위 요소 길이를 기반으로 여러 키프레임을 동적으로 만드는 방법도 없습니다.
하지만 JavaScript는 이 정보를 가져오는 방법을 알고 있으므로 자식 요소를 직접 반복하고 런타임에 계산된 값을 가져옵니다.
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
각 tabnavitem
의 경우 offsetLeft
위치를 역직렬화하고 이를 translateX
값으로 사용하는 문자열을 반환합니다. 그러면 애니메이션의 변환 키프레임 4개가 생성됩니다. 너비도 마찬가지입니다. 각 너비에 동적 너비가 무엇인지 묻고 키프레임 값으로 사용합니다.
다음은 내 글꼴 및 브라우저 환경설정에 따른 출력 예시입니다.
TranslateX 키프레임:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
너비 키프레임:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
전략을 요약하면 이제 탭 표시기가 섹션 스크롤러의 스크롤 스냅 위치에 따라 4개의 키프레임에서 애니메이션됩니다. 스냅 포인트는 키프레임 간에 명확한 구분을 만들고 애니메이션의 동기화된 느낌을 한층 더 높여줍니다.
사용자는 상호작용으로 애니메이션을 제어하며, 표시기의 너비와 위치가 섹션마다 변경되는 것을 보고 스크롤과 함께 완벽하게 추적합니다.
눈치채지 못하셨을 수도 있지만 강조 표시된 탐색 항목이 선택되면 색상이 전환되는 부분이 매우 마음에 듭니다.
강조 표시된 항목의 대비가 높을수록 선택되지 않은 밝은 회색이 더 뒤로 밀려 보입니다. 마우스 오버 시나 선택 시와 같이 텍스트의 색상을 전환하는 것은 일반적이지만 스크롤 시 색상을 전환하고 이 작업을 밑줄 표시기와 동기화하는 것은 한 단계 높은 수준입니다.
제가 취한 조치는 다음과 같습니다.
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
각 탭 탐색 링크에는 이 새로운 색상 애니메이션이 필요하며, 이 애니메이션은 밑줄 표시기와 동일한 스크롤 타임라인을 추적합니다. 이전과 동일한 타임라인을 사용합니다. 스크롤 시 틱을 내보내는 것이므로 원하는 모든 유형의 애니메이션에서 이 틱을 사용할 수 있습니다. 이전과 마찬가지로 루프에서 키프레임 4개를 만들고 색상을 반환합니다.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
색상 var(--text-active-color)
의 키프레임은 링크를 강조 표시하고, 그렇지 않으면 표준 텍스트 색상입니다. 중첩 루프를 사용하면 비교적 간단합니다. 외부 루프는 각 탐색 항목이고 내부 루프는 각 탐색 항목의 개인 키프레이프이기 때문입니다. 외부 루프 요소가 내부 루프 요소와 동일한지 확인하고 이를 사용하여 선택되었는지 확인합니다.
작성하는 데 재미있었습니다. 최고죠.
더 많은 JavaScript 개선사항
여기서 보여드리는 핵심은 JavaScript 없이도 작동합니다. 그렇다면 JS를 사용할 수 있을 때 이를 개선하는 방법을 알아보겠습니다.
딥 링크
딥 링크는 모바일 용어에 가깝지만 탭의 콘텐츠로 직접 URL을 공유할 수 있다는 점에서 탭을 통해 딥 링크의 의도를 충족할 수 있습니다. 브라우저는 페이지 내에서 URL 해시에서 일치하는 ID로 이동합니다. 이 onload
핸들러가 여러 플랫폼에서 효과를 낸 것으로 확인되었습니다.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
스크롤 끝 동기화
사용자는 항상 클릭하거나 키보드를 사용하지 않습니다. 자유롭게 스크롤할 수 있기 때문에 스크롤만 하는 경우도 있습니다. 섹션 스크롤러가 스크롤을 중지하면 상단 탐색 메뉴에서 스크롤러가 멈춘 위치와 일치해야 합니다.
스크롤 종료를 기다리는 방법은 다음과 같습니다.
js
tabsection.addEventListener('scroll', () => {
clearTimeout(tabsection.scrollEndTimer);
tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100);
});
섹션이 스크롤될 때마다 섹션 시간 초과가 있는 경우 이를 지우고 새 시간 초과를 시작합니다. 섹션 스크롤이 중지되면 제한 시간을 삭제하지 말고 100ms 후에 실행합니다. 이 이벤트가 발생하면 사용자가 중지한 위치를 찾는 함수를 호출합니다.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
스크롤이 고정되었다고 가정하면 현재 스크롤 위치를 스크롤 영역의 너비로 나눈 값은 소수점이 아닌 정수가 되어야 합니다. 그런 다음 계산된 색인을 통해 캐시에서 navitem을 가져오려고 시도하고, 항목을 찾으면 일치 항목을 전송하여 활성 상태로 설정합니다.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
활성 탭을 설정하려면 먼저 현재 활성 탭을 지우고 들어오는 탐색 항목에 활성 상태 속성을 지정합니다. scrollIntoView()
호출에는 주목할 만한 CSS와의 재미있는 상호작용이 있습니다.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
가로 스크롤 스냅 유틸리티 CSS에서 사용자의 모션 허용 여부에 따라 smooth
스크롤을 적용하는 미디어 쿼리를 중첩했습니다. JavaScript는 요소를 스크롤하여 뷰로 자유롭게 호출할 수 있고 CSS는 선언적으로 UX를 관리할 수 있습니다.
때로는 아주 멋진 조합이 만들어지기도 합니다.
결론
이제 제가 어떻게 했는지 알았으니 어떻게 하시겠어요? 이를 통해 재미있는 구성요소 아키텍처를 만들 수 있습니다. 좋아하는 프레임워크에 슬롯이 있는 첫 번째 버전을 만들 사람은 누구인가요? 🙂
접근 방식을 다양화하고 웹에서 빌드하는 모든 방법을 알아보겠습니다. Glitch를 만들고 내 버전을 트윗해 주시면 아래의 커뮤니티 리믹스 섹션에 추가해 드리겠습니다.
커뮤니티 리믹스
- @devnook, @rob_dodson, @DasSurma님과 함께 Web Components: 도움말을 작성했습니다.
- @jhvanderschee(Codepen 버튼 포함)