색상 적응형, 반응형, 접근성 있는 FAB 구성요소를 빌드하는 방법에 관한 기본 개요입니다.
이 게시물에서는 색상 적응형, 반응형, 접근성 있는 FAB 구성요소를 빌드하는 방법에 관한 생각을 공유하고자 합니다. 데모를 사용해 보고 소스를 확인해 보세요.
동영상을 선호한다면 이 게시물의 YouTube 버전을 참고하세요.
개요
FAB는 데스크톱보다 모바일에서 더 일반적이지만 두 시나리오 모두에서 널리 사용됩니다. 기본 작업을 계속 표시하여 편리하고 항상 사용할 수 있습니다. 이 사용자 환경 스타일은 Material UI로 유명했으며 사용 및 배치에 관한 권장사항은 여기에서 확인할 수 있습니다.
요소 및 스타일
이러한 컨트롤의 HTML에는 컨테이너 요소와 하나 이상의 버튼 세트가 포함됩니다. 컨테이너는 FAB를 표시 영역 내에 배치하고 버튼 간의 간격을 관리합니다. 버튼은 미니 버튼 또는 기본 버튼으로 설정할 수 있으므로 기본 작업과 보조 작업 간에 다양한 버튼을 사용할 수 있습니다.
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의 소스 코드