-
(UX/UI) 스켈레톤 UI프로그래머스 데브코스: 빅 데이터 플랫폼 프론트엔드 엔지니어링 2023. 8. 3. 20:00
skeleton ui 스켈레톤 UI는 실제 데이터가 렌더링(API로부터 data를 비동기적으로 로드하기까지) 되기 전에 보이게 될 화면의 윤곽(빈 껍데기)을 먼저 그려주는 로딩 애니메이션입니다.
콘텐츠를 기다리는 것에 사용자가 지루함을 느낄 수 있으므로 스켈레톤 UI 혹은 스피너를 보여주므로써 사용자의 이탈을 막아줍니다. 이런 스켈레톤 UI와 스피너 등을 progress indicator라고도 하는데요. 무작정 progress indicator 사용을 남발하는 것도 좋지는 않다고 합니다. 세계적인 UX 리서치 그룹 닐슨 노먼은 이에 대해 주요 지침을 내놓기도 하였는데요. 로드하는데 1초 미만이 소요되는 모든 항목의 경우 반복되는 애니메이션을 사용하면 주의가 산만해지므로 이때는 progress indicator 사용을 지양해야 한다고 합니다.스켈레톤 UI 구현하기
- async component (비동기적 컴포넌트, ProfileCard)
- skeleton loader (스켈레톤 로더, SkeletonProfileCard)
- <suspense> (서스팬스 컴포넌트, App)
비동기 작업이 일어나는 ProfileCard 컴포넌트를 먼저 봅시다.
async를 통해서 프로미스를 반환하고 비동기작업 후 resolve 된 데이터를 await이 받아(여기서는 setTimeout으로 delay를 줬어요.) 반환해 줬습니다. 그 값을 ref()를 통해 참조하고 setup() 통해 반환하여 DOM 요소에서 동적 데이터로 사용할 수 있게 했습니다.
API 호출로 인한 로딩을 모방하기 위해서 setTimeout()을 사용하여 시간 제한을 걸었습니다.
ref : reactive reference, 참조, Vue 3의 ref는 리액티브한 데이터를 가리킬 뿐만 아니라 템플릿 표현식도 함께 가리킵니다. 템플릿에 추가한 ref 속성의 키 값과 동일한 이름을 가진 ref(반응형 값)가 컨텍스트에 존재한다면, Vue 가상 돔의 마운트/패치 중 해당 요소 혹은 인스턴스를 지정된 ref 값에 할당시킵니다. <script setup>을 사용하지 않는 경우, setup()에서 참조를 반환해야 합니다:
<template> <div class="profile-card"> <div class="profile-image"> <img :src="userData.pic" /> </div> <div class="profile-info"> <span> Written By </span> <h3>{{ userData.name }}</h3> <p>{{ userData.bio }}</p> </div> </div> </template> <script> import { ref } from 'vue' const loadUserData = async () => { return new Promise((resolve) => { setTimeout(() => { resolve({ name: 'Ea Jung', pic: 'xxx.png', bio: 'xxx' }) }, 2000) }) } export default { async setup() { const userData = ref(await loadUserData()) return { userData, } }, } </script>
로딩을 담당하는 SkeletonProfileCard 컴포넌트 봅시다.
ProfileCard 컴포넌트와 동일 DOM구조를 만들어 줘야 하고 scoped 범위로 스타일을 입힙니다.
@keyframe을 이용해 1초 마다 애니메이션이 일어나도록 했습니다. delay를 위에서 5초 걸어 뒀으니 로딩 애니메이션도 2번 일어나겠죠?
<template> <div class="profile-card"> <div class="profile-image"> <img /> </div> <div class="profile-info"> <span /> <h3 /> <p /> </div> </div> </template> <style scoped> .profile-image img { width: 100%; padding-top: 100%; animation: pulse-bg 1s infinite; } .profile-info span { width: 100%; height: 16px; display: block; animation: pulse-bg 1s infinite; } .profile-info h3 { width: 250px; height: 24px; animation: pulse-bg 1s infinite; } .profile-info p { width: 80%; height: 16px; animation: pulse-bg 1s infinite; } @keyframes pulse-bg { 0% { background-color: #eee; } 50% { background-color: rgb(223, 246, 231); } 100% { background-color: #eee; } } </style>
이제 위의 두개의 컴포넌트를 App.vue 파일로 불러오면 됩니다.
여기서 비동기작업 중 임을 인지해서 컴포넌트를 적절히 rendering 해주는 역할을 하는 게 <Suspense>입니다.
<Suspense>는 컴포넌트 트리에서 비동기 의존성을 조정하기 위한 내장 컴포넌트입니다. 컴포넌트 트리 아래에 여러 개의 중첩된 비동기 의존성이 해결될 때까지 기다리는 동안 로드 상태를 렌더링 할 수 있습니다.
결과적으로 <Suspense> 가 비동기 작업이 끝나기 전(#fallback키워드를 이용)까지 skeleton loading screen을 render 해주고 비동기 작업이 끝나면(#default 키워드 이용) 실제 데이터가 담긴 컴포넌트를 보여주는 역할을 합니다.
<template> <Suspense> <template #default> <ProfileCard /> </template> <template #fallback> <ProfileCardSkeleton /> </template> </Suspense> </template> <script setup> import ProfileCard from './components/ProfileCard.vue' import ProfileCardSkeleton from './components/ProfileCardSkeleton.vue' </script>
참고 자료
무조건 스켈레톤 화면을 보여주는게 사용자 경험에 도움이 될까요? | 카카오페이 기술 블로그
카카오페이에서 프론트엔드 개발을 하며 스켈레톤 UI와 사용자 경험 향상에 대해 고민한 내용을 공유합니다.
tech.kakaopay.com
더 나은 UX를 위한 React에서 스켈레톤 컴포넌트 만들기
스켈레톤 컴포넌트가 무엇인지 알고 있는가? 스켈레톤 컴포넌트는 데이터를 가져오는 동안 콘텐츠를 표시하는 컴포넌트이다. 사용자는 콘텐츠를 기다리다가 쉽게 지치고 지루함을 느끼므로 단
ui.toast.com
Suspense | Vue.js
ko.vuejs.org
💡 서스펜스가 있는 쉬운 Vue 3 스켈레톤 로딩 화면 https://youtu.be/2-jQ1v6X7vA 를 참고하여 글을 작성했습니다.
반응형'프로그래머스 데브코스: 빅 데이터 플랫폼 프론트엔드 엔지니어링' 카테고리의 다른 글
HON KOK 프로젝트 회고 (2023.09.01 ~ 2023.09.27) (1) 2023.10.05 (7~8월/MIL) 프로그래머스 데브코스 FE 회고 (2) 2023.09.05 (6월/MIL) 프로그래머스 데브코스 FE 한달 회고 (2) 2023.07.10 notion 클로닝 프로젝트 회고 - History API, SPA (1) 2023.07.07 [프로그래머스 FE 데브코스/TIL] DAY4 2023.06.06 화 (2) 2023.06.06