1. 서론
서버에서 데이터를 불러오기까지 보여줘야 할 대체 UI로 Skeleton을 가끔 사용하곤 한다.
그럴 때마다 그저 다른 사람의 코드를 긁어오곤 했는데, 직접 만들어보며 Skeleton에 주로 쓰이는 css 속성을 학습하고자 한다.
Skeleton을 만들 때 사용하는 핵심 css 속성은 다음과 같다.
- background: 배경색
- linear-gradient: 색상을 그러데이션으로 만든다.
- background-size: 배경의 크기를 조절한다.
- background-position: 배경의 위치를 조절한다.
- animation: 애니메이션을 정의한다.
- keyframes: 애니매이션 시작점과 끝점의 css 속성을 정의하고, 이를 부드럽게 연결시켜 준다.
- background-position을 이용해 배경을 움직인다.(슈욱(0% 100%) 또는 왔다리갔다리 (0% 50% 100%)
2. 직접 만들어보자
목표로 하는 스켈레톤의 UI는 다음과 같다.
css 속성을 하나씩 추가하면서 제작해 보자!
css 라이브러리는 emotion을 사용한다.
2.1 기본 뼈대 구축
width, height를 받는다.
이제 div 태그에 스타일을 해나간다.
2.1 background (linear-gradient): 배경 설정
예시의 줄무늬를 보면 그라데이션 형태로 되어있다.
linear-gradient 속성을 이용해 배경색을 만들어보자.
linear-gradient(color1, color2, color3)는 위에서 아래로 color1, color2, color3 색상으로 그린다.
맨 앞 파라미터로 90deg 같은 각도를 줄 수 있는데, 반시계 방향으로 회전한다고 생각하자. (mdn에는 시계방향으로 되어있는데, 왜 그런지 모르겠다)
2.2. 배경을 움직여보자: animation, keyframes, background-position, background-size
이제 배경을 움직여서 스켈레톤이 살아있는 것처럼 만들어야 한다.
움직이기 위해 animation 속성을 추가해 주자.
또한 animation을 적용하기 위해 배경을 배치하는 속성인 background-position를 이용해 keyframes를 만들어줘야 한다.
그런데 그전에! 현재 배경이 container에 꽉 차있다. 그 의미는 background-position을 설정해도 적용이 되지 않는다는 뜻이다. (background-position은 background를 가진 container(지금은 div)와 background의 크기가 달라야 적용가능하다)
따라서 먼저 background-size를 이용해 background의 크기를 조절하자.
background-size
배경을 확대해야 할까 줄여야 할까?
background-size는 width, height를 정해주면 된다.
기본값은 background-size: auto, auto이며
크기는 맨 왼쪽, 맨 위 기준으로 조절된다.
background-size: 200%, 100%라면 배경의 가로길이를 두 배 늘리게 된다.
(이해를 위해 배경색을 약간 바꾸었다)
배경은 커진 반면에 container의 크기는 그대로이기 때문에, 우리가 보는 부분은 빨간색 박스에 해당한다.
background-size가 50%, 100%라면 가로길이가 두 배 줄어든다.
그럼 이런 결과를 예상할 수 있다.
그러나 실제로는 이런 결과를 볼 수 있다.
그 이유는 배경은 끊임없이 반복되고 있기 때문이다.
실제로 가로길이를 늘인 첫 번째 예시에서도, container 바깥쪽에서는 background가 계속 반복되고 있다.
background-position을 이용해 animation을 만들 때 알아둬야 할 중요한 특징이다.
추가로, background-repeat: 'no-repeat'를 적용하면 반복이 없어진다.
이제 background-position을 알아보자.
background-position
요전에 background-position은 background를 가진 container(지금은 div)와 background의 크기가 달라야 적용가능하다
라는 개념을 언급했다.
background-position은 배경의 x축, y축이 왼쪽 변과 위쪽 변을 기준으로 얼마나 떨어져 있는지를 정의해서 배경을 위치시킬 수 있다.
그 값은 px이 될 수도 있고, %가 될 수도 있다. (등등 더 다양함)
그중 %는 좀 특이하기도 하고, 스켈레톤 keyframes에 사용할 거라 짚고 넘어가 보자.
position 기준은 배경의 크기에 따라 달라진다.
쉽게 말해서 x축 기준 배경의 왼쪽변과 container의 왼쪽변이 닿아있는 상태가 0%, 각 오른쪽변이 닿아있는 상태가 100%이다.
이 말은 background가 container보다 작거나 크거나 상관없이 적용된다.
이해를 위해 background-repeat: 'no-repeat'를 적용해 놓겠다.
먼저 0%, 100%를 만들어놓으면, 중간값 계산하기가 편해진다.
또한 마이너스 값은 반대로 생각하면 된다.
참고로 계산 공식이 따로 있는데, 공식문서에 잘 나와있다.
위 결과들이 왜 저렇게 나왔는지 공식을 대입해 보면서 비교해보자.
나는 공식 적용보다 그려보면서 적용하는 게 훨씬 편했다.
그러나 정확한 값이 필요하다면 공식을 적용하자.
이제 이전에 언급했던 "현재 배경이 container에 꽉 차있다. 그 의미는 background-position을 설정해도 적용이 되지 않는다는 뜻이다."가 왜 그런지 이해할 수 있을 것이다.
이제 스켈레톤 animation keyframes를 만들어보자
목표하는 스켈레톤을 다시 보자
흰색 줄무늬가 왼쪽에서 오른쪽으로 이동한다.
즉 배경이 왼쪽에서 오른쪽으로 이동해야 한다.
그전에, 배경이 가로로 길어 보이므로 background-size를 이용해 width를 늘려주자. (늘려주지 않으면 background-position이 동작하지 않는 이유도 있다)
그럼 이제 저 배경을 오른쪽에서 왼쪽으로 옮겨주기 위해서 keyframes와 background-position을 이용한다.
아까 위에서 말한 것처럼 background-position에 따른 배경의 위치는 다음과 같다.
따라서 keyframes 0%(from)의 background-position을 100%, 0% (x, y)으로,
keyframes 100%(to)의 background-position을 0%, 0%으로 하면 배경이 왼쪽에서 오른쪽으로 이동할 것이다.
물론 배경은 무한반복되므로 그걸 고려해서 background-position을 0% 0%(from) -100% 0%(to)로 잡아도 상관없다.
그런데 조금씩 끊겨보인다.
흰색 배경 부분이 전부 없어지기 전에 새로이 animation이 시작돼서 그렇다.
linear-gradient 색 비율을 조절하여 container에 회색 부분이 많이 보이게 하여 자연스럽게 연결되도록 해보자.
마무리: 스켈레톤이 꼭 필요할까?
스켈레톤을 무작정 적용하지 말고, 기준을 적당히 정하고 적용하자.
응답시간이 빠른 경우 그냥 흰 화면으로 보여주는 게 UX 관점에서 나을 수도 있다.
https://tech.kakaopay.com/post/skeleton-ui-idea/
이 글에는 나름의 이유(사용자의 75%가 200ms 이하에서 로딩이 끝난다)를 들어 로딩 시간이 200ms 이상이 되었을 때부터 Skeleton을 보여주는 것으로 정했다.
이 영역은 휴리스틱(알잘딱..)의 영역이지 싶다.
여담: 명언은 감상하라고 있는 것이 아니다
개인적인 숙원사업이었던 스켈레톤 만들어보기가 끝났다.
여러 css 속성을 잘 모르고 사용했고, 상호 간의 관계를 잘 몰랐었는데, 이번 작업으로 어느 정도 이해하게 되어 기쁘다.
쉽게 이해하기 위해 나름대로 정리해 보았다.
최근 제임스가 올린 sns에서 "아무리 흐린 먹물이라도 가장 훌륭한 기억력보다 낫다", "울면서 시를 써야 남도 울면서 시를 읽는다"는 구절을 봤는데, 그 글을 보고 느낀 바가 많다.
이 글을 보시는 분들, 그리고 미래의 나를 위해 열심히 글을 써야겠다.
Reference
https://snyk.io/advisor/npm-package/skeleton-loader-vue
'프론트엔드' 카테고리의 다른 글
[컨셉비] 2. 1차 스프린트 과정 정리 (4) | 2024.02.13 |
---|---|
[컨셉비] 1. 프론트엔드 중간 합류와 각오 (2) | 2024.01.27 |
vite + typescript + react 프로젝트에서 절대경로 설정하기 (4) | 2024.01.03 |
react-router-dom 으로 첫번째 페이지 라우팅하기 (2) | 2024.01.01 |
react-router-dom에서 404페이지 보여주기 (0) | 2023.12.30 |