색상 적응형, 반응형, 접근성 있는 FAB 구성요소를 빌드하는 방법에 관한 기본 개요입니다.
이 게시물에서는 색상 적응형, 반응형, 접근성 있는 FAB 구성요소를 빌드하는 방법에 관한 생각을 공유하고자 합니다. 데모를 사용해 보고 소스를 확인하세요.
동영상을 선호하는 경우 이 게시물의 YouTube 버전을 확인하세요.
개요
FAB는 데스크톱보다 모바일에서 더 흔하지만 두 시나리오 모두에서 널리 사용됩니다. 기본 작업을 표시하여 편리하고 어디에나 표시되도록 합니다. 이 사용자 환경 스타일은 Material UI로 유명해졌으며 사용 및 배치에 관한 제안은 여기에서 확인할 수 있습니다.
요소 및 스타일
이러한 컨트롤의 HTML에는 컨테이너 요소와 하나 이상의 버튼 세트가 포함됩니다. 컨테이너는 표시 영역 내에 FAB를 배치하고 버튼 간 간격을 관리합니다. 버튼은 소형 또는 기본형일 수 있으므로 기본 작업과 보조 작업 간에 다양한 선택지를 제공합니다.
플로팅 작업 버튼 컨테이너
이 요소는 일반 <div>일 수 있지만 시각장애인 사용자를 위해 이 컨테이너의 목적과 콘텐츠를 설명하는 유용한 속성으로 태그를 지정해 보겠습니다.
FAB 마크업
스타일 연결을 위해 CSS의 .fabs 클래스로 시작한 다음 role="group" 및 aria-label를 추가하여 일반 컨테이너가 아닌 이름이 지정되고 목적이 있는 컨테이너가 되도록 합니다.
<div class="fabs" role="group" aria-label="Floating action buttons">
<!-- buttons will go here -->
</div>
FAB 스타일
FAB가 편리하려면 항상 표시 영역 내에 있어야 합니다.
이는 위치 fixed의 좋은 사용 사례입니다. 이 뷰포트 위치 내에서 inset-block 및 inset-inline를 사용하여 위치가 오른쪽에서 왼쪽 또는 왼쪽에서 오른쪽과 같은 사용자의 문서 모드를 보완하도록 했습니다. 맞춤 속성은 반복을 방지하고 뷰포트의 하단 및 측면 가장자리에서 동일한 거리를 유지하는 데도 사용됩니다.
.fabs {
--_viewport-margin: 2.5vmin;
position: fixed;
z-index: var(--layer-1);
inset-block: auto var(--_viewport-margin);
inset-inline: auto var(--_viewport-margin);
}
다음으로 컨테이너 디스플레이에 flex를 지정하고 레이아웃 방향을 column-reverse으로 변경합니다.
이렇게 하면 하위 요소가 서로 위에 쌓이고 (열) 시각적 순서도 반전됩니다. 이렇게 하면 포커스가 HTML 문서에 따라 일반적으로 이동하는 상단 요소 대신 포커스 가능 첫 번째 요소가 하단 요소가 됩니다. 시각적 순서를 반대로 하면 시각 장애인 사용자와 키보드 사용자의 환경이 통합됩니다. 기본 작업의 스타일이 소형 버튼보다 크면 시각 장애인 사용자에게 기본 작업임을 나타내고 키보드 사용자는 소스의 첫 번째 항목으로 포커스를 이동합니다.

.fabs {
…
display: flex;
flex-direction: column-reverse;
place-items: center;
gap: var(--_viewport-margin);
}
가운데 맞춤은 place-items로 처리되고 gap는 컨테이너에 배치된 FAB 버튼 사이에 공간을 추가합니다.
FAB 버튼
이제 버튼이 다른 요소 위에 떠 있는 것처럼 보이도록 스타일을 지정할 차례입니다.
기본 FAB
스타일을 지정할 첫 번째 버튼은 기본 버튼입니다. 이 레이아웃은 모든 FAB 버튼의 기반이 됩니다. 나중에 이러한 기본 스타일을 최대한 적게 수정하면서 대체 모양을 구현하는 변형을 만들 것입니다.
FAB 마크업
<button> 요소가 적합합니다. 마우스, 터치, 키보드 사용자 환경이 우수하므로 이를 기반으로 시작할 예정입니다. 이 마크업에서 가장 중요한 측면은 aria-hidden="true"를 사용하여 스크린 리더 사용자에게 아이콘을 숨기고 필요한 라벨 텍스트를 <button> 마크업 자체에 추가하는 것입니다. 이러한 경우 라벨을 추가할 때 title도 추가하여 마우스 사용자가 아이콘이 전달하고자 하는 정보에 대해 알 수 있도록 합니다.
<button data-icon="plus" class="fab" title="Add new action" aria-label="Add new action">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
FAB 스타일
먼저 버튼을 패딩이 적용된 강한 그림자가 있는 원형 버튼으로 만들어 보겠습니다. 이는 버튼의 첫 번째 정의 기능이기 때문입니다.
.fab {
--_size: 2rem;
padding: calc(var(--_size) / 2);
border-radius: var(--radius-round);
aspect-ratio: 1;
box-shadow: var(--shadow-4);
}
이제 색상을 추가해 보겠습니다. 이전 GUI 챌린지에서 사용한 전략을 사용합니다. 밝은 색상과 어두운 색상을 정적으로 보유하는 명확한 이름의 맞춤 속성 세트를 만든 다음 색상에 관한 사용자의 시스템 환경설정에 따라 밝은 변수 또는 어두운 변수로 설정되는 적응형 맞춤 속성을 만듭니다.
.fab {
…
/* light button and button hover */
--_light-bg: var(--pink-6);
--_light-bg-hover: var(--pink-7);
/* dark button and button hover */
--_dark-bg: var(--pink-4);
--_dark-bg-hover: var(--pink-3);
/* adaptive variables set to light by default */
--_bg: var(--_light-bg);
/* static icon colors set to the adaptive foreground variable */
--_light-fg: white;
--_dark-fg: black;
--_fg: var(--_light-fg);
/* use the adaptive properties on some styles */
background: var(--_bg);
color: var(--_fg);
&:is(:active, :hover, :focus-visible) {
--_bg: var(--_light-bg-hover);
@media (prefers-color-scheme: dark) {
--_bg: var(--_dark-bg-hover);
}
}
/* if users prefers dark, set adaptive props to dark */
@media (prefers-color-scheme: dark) {
--_bg: var(--_dark-bg);
--_fg: var(--_dark-fg);
}
}
다음으로 SVG 아이콘이 공간에 맞도록 스타일을 추가합니다.
.fab {
…
& > svg {
inline-size: var(--_size);
block-size: var(--_size);
stroke-width: 3px;
}
}
마지막으로 상호작용을 위한 자체 시각적 피드백을 추가했으므로 버튼에서 탭 강조 표시를 삭제합니다.
.fab {
-webkit-tap-highlight-color: transparent;
}
미니 FAB
이 섹션의 목표는 FAB 버튼의 변형을 만드는 것입니다. FAB 중 일부를 기본 작업보다 작게 만들어 사용자가 가장 자주 실행하는 작업을 홍보할 수 있습니다.
미니 FAB 마크업
HTML은 FAB와 동일하지만 CSS가 변형에 연결되도록 '.mini' 클래스를 추가합니다.
<button data-icon="heart" class="fab mini" title="Like action" aria-label="Like action">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
미니 FAB 스타일
맞춤 속성을 사용하면 --_size 변수만 조정하면 됩니다.
.fab.mini {
--_size: 1.25rem;
}

접근성
FAB의 접근성에서 가장 중요한 부분은 페이지의 키보드 흐름 내 배치입니다. 이 데모에는 FAB만 있으므로 키보드 순서와 흐름 측면에서 경쟁할 요소가 없습니다. 즉, 의미 있는 키보드 흐름을 보여줄 기회가 없습니다. 포커스를 두고 경쟁하는 요소가 있는 시나리오에서는 사용자에게 FAB 버튼 흐름이 표시되어야 하는 흐름의 위치를 깊이 생각해 보는 것이 좋습니다.
사용자가 FAB 컨테이너에 포커스를 맞추면 이미 role="group"와 aria-label="floating action buttons"가 추가되어 화면 리더 사용자에게 포커스가 맞춰진 콘텐츠에 관해 알립니다. 사용자가 기본 작업을 먼저 찾을 수 있도록 기본 FAB를 먼저 배치했습니다. 그런 다음 flex-direction: column-reverse;를 사용하여 기본 버튼을 하단에 시각적으로 배치하여 사용자가 쉽게 액세스할 수 있도록 합니다. 기본 버튼이 시각적으로 눈에 띄고 키보드 사용자에게도 첫 번째로 표시되므로 매우 유사한 환경을 제공할 수 있습니다.
마지막으로 스크린 리더 사용자에게 아이콘을 숨기고 버튼에 라벨을 제공하여 버튼이 무엇인지 알 수 있도록 해야 합니다. 이는 이미 HTML에서 <svg>의 aria-hidden="true"와 <button>의 aria-label="Some action"로 처리되었습니다.
애니메이션
다양한 유형의 애니메이션을 추가하여 사용자 환경을 개선할 수 있습니다. 다른 GUI 챌린지와 마찬가지로 모션 감소 환경과 전체 모션 환경의 의도를 보유하는 맞춤 속성을 몇 개 설정합니다. 기본적으로 스타일은 사용자가 동작을 줄이기를 원한다고 가정하고 prefers-reduced-motion 미디어 쿼리를 사용하여 전환 값을 전체 동작으로 바꿉니다.
맞춤 속성이 있는 모션 감소 전략
다음 CSS에는 --_motion-reduced, --_motion-ok, --_transition의 세 가지 맞춤 속성이 생성됩니다. 처음 두 변수는 사용자의 환경설정을 고려하여 적절한 전환을 유지하고 마지막 변수 --_transition는 각각 --_motion-reduced 또는 --_motion-ok로 설정됩니다.
.fab {
/* box-shadow and background-color can safely be transitioned for reduced motion users */
--_motion-reduced:
box-shadow .2s var(--ease-3),
background-color .3s var(--ease-3);
/* add transform and outline-offset for users ok with motion */
--_motion-ok:
var(--_motion-reduced),
transform .2s var(--ease-3),
outline-offset 145ms var(--ease-2);
/* default the transition styles to reduced motion */
--_transition: var(--_motion-reduced);
/* set the transition to our adaptive transition custom property*/
transition: var(--_transition);
/* if motion is ok, update the adaptive prop to the respective transition prop */
@media (prefers-reduced-motion: no-preference) {
--_transition: var(--_motion-ok);
}
}
위의 사항이 적용되면 box-shadow, background-color, transform, outline-offset의 변경사항을 전환하여 사용자에게 상호작용이 수신되었다는 멋진 UI 피드백을 제공할 수 있습니다.
이제 translateY을 약간 조정하여 :active 상태에 약간의 멋을 더합니다. 이렇게 하면 버튼에 멋진 눌림 효과가 적용됩니다.
.fab {
…
&:active {
@media (prefers-reduced-motion: no-preference) {
transform: translateY(2%);
}
}
}
마지막으로 버튼의 SVG 아이콘에 대한 변경사항을 전환합니다.
.fab {
…
&[data-icon="plus"]:hover > svg {
transform: rotateZ(.25turn);
}
& > svg {
@media (prefers-reduced-motion: no-preference) {
will-change: transform;
transition: transform .5s var(--ease-squish-3);
}
}
}
결론
이제 제가 어떻게 했는지 아셨으니, 어떻게 하시겠어요? 🙂
다양한 접근 방식을 사용하고 웹에서 빌드하는 모든 방법을 알아보세요.
데모를 만들고 트윗으로 링크를 보내주세요. 아래 커뮤니티 리믹스 섹션에 추가해 드리겠습니다.
커뮤니티 리믹스
아직 표시할 내용이 없습니다.
리소스
- GitHub의 소스 코드