본문으로 건너뛰기
:tech
← Articles

같은 연출, 다른 CLS: transform을 제외한 설계 의도를 찾아서

Justin Jeong
Justin Jeong

Frontend Engineer

같은 연출, 다른 CLS: transform을 제외한 설계 의도를 찾아서

최근 출시한 제품을 데이터독으로 모니터링하던 중 CLS가 좋지 않다는 것을 확인했습니다. 실제 화면을 다시 살펴봤지만, 무엇이 문제인지 쉽게 눈에 들어오지는 않았습니다.

레이아웃 이동이 발생한 시점을 따라가 보니, 미션 완료 후 거위 영역이 줄어드는 구간이었습니다. height가 줄면서 아래 콘텐츠의 레이아웃 위치도 바뀌고 있었으므로, 이동이 기록되는 이유는 분명했습니다. 다만 궁금한 점은 남았습니다. 사용자가 보는 연출을 유지하면서 transform으로 구현하면, 왜 시각적 안정성을 평가하는 CLS의 결과는 달라질까요?

문제를 발견했던 기간의 실제 데이터독 대시보드. 인앱 화면의 5분 단위 CLS P75가 여러 차례 0.25를 넘는다.

2026년 11월 2일 08:44부터 11월 3일 08:44까지, 한국 시간 기준입니다. 현재 대시보드에서 당시 기간을 다시 조회한 화면이며, 5분 단위 P75의 추이입니다.

미션 완료 후 거위 영역을 줄인 이유

거위는 이 화면에서 큰 비중을 차지하는 캐릭터입니다. 미션을 마친 뒤에는 사용자가 아래의 다른 콘텐츠로 관심을 옮길 수 있도록 거위 영역을 줄였습니다.

화면 높이가 갑자기 바뀌면 어색하니, 거위가 작아지는 동안 아래 콘텐츠도 부드럽게 올라오게 했습니다. 완료 상태를 보여준 뒤 다음 행동으로 자연스럽게 이어주려는 연출이었습니다.

기존 구현은 영역의 height를 513px에서 294px로 애니메이션했습니다. 문서 흐름에서 차지하는 높이가 줄어드니, 아래 콘텐츠도 그 차이인 219px만큼 올라옵니다. 화면에서는 부드러운 연출로 보였지만, 브라우저는 이 과정에서 기존 요소의 위치가 계속 바뀌는 것을 기록했습니다.

변경 전 실제 앱. 큰 거위와 거위 영역이 함께 줄어들면서 아래 콘텐츠가 부드럽게 올라온다.

기존 height 기반 연출입니다.

지표를 낮추기 위해 움직임을 없애고 싶지는 않았습니다. 그렇다고 의도한 연출이라는 이유로 측정 결과를 무시할 수도 없었습니다. 사용자가 안정적으로 화면을 읽고 조작할 수 있도록 CLS를 관리하는 일은 중요합니다. 의도한 연출 때문에 높은 값을 당연하게 받아들이면, 실제로 읽기나 클릭을 방해하는 이동이 발생해도 구분해 알아채기 어려워질 수 있습니다. 그래서 같은 흐름을 유지하면서 CLS를 낮출 방법을 찾기로 했습니다.

CLS가 측정하는 레이아웃 이동

CLS는 예상치 못한 레이아웃 이동으로 생기는 시각적 불안정을 측정하는 지표입니다. 누르려던 버튼이 밀리거나 읽던 문장이 이동하는 문제가 대표적입니다.

브라우저는 기존에 보이던 요소의 프레임 간 위치 변화를 보고 영향을 받은 화면 면적과 이동 거리를 이용해 점수를 계산합니다. 이동이 연속해서 발생하는 시간 구간들을 묶고, 그중 가장 큰 구간의 점수를 사용합니다. 따라서 특정 동작이 CLS에 미치는 영향을 확인하려면 CLS 값뿐 아니라 개별 레이아웃 이동이 발생한 시점도 살펴봐야 합니다. CLS 공식 설명

height 애니메이션을 transform으로 옮기기

height 변경에 따른 레이아웃 계산을 줄이기 위해 움직임을 transform으로 옮겼습니다. 구현에서 신경 쓴 부분은 문서 흐름상의 배치와 화면에 보이는 움직임을 분리하면서, 기존 연출을 유지하는 것이었습니다.

전체 영역을 scaleY로 줄이면 글자와 카드까지 함께 찌그러질 수 있습니다. 그래서 최종 배치가 차지할 높이는 고정하고, 거위와 하단 콘텐츠의 움직임을 나눠 구현했습니다. 거위는 scale과 translate로 크기와 위치를 바꾸고, 하단 콘텐츠는 translateY로 이동시켰습니다. 배경과 보이는 경계도 맞춰 이동 중 두 영역 사이에 흰 공간이 드러나지 않게 했습니다.

적립 오버레이가 떠 있는 동안 모션을 보류하는 기존 조건도 유지했습니다. transform이 적용된 부모는 fixed 요소의 위치 기준에도 영향을 줄 수 있습니다. 그래서 결과 시트와 오버레이를 이동 레이어 밖에 두고, 화면 전체에 고정되는지 함께 확인했습니다.

실제 화면 비교: 연출은 유지하고 CLS 줄이기

기존 height 모션과 transform 기반 모션 비교. 거위가 줄어들고 아래 콘텐츠가 올라오는 연출을 유지한다.

실제 앱을 각각 실행해 촬영했습니다. 왼쪽은 기존 height 모션, 오른쪽은 transform 기반 모션을 사용합니다.

운영에서 확인한 CLS 문제를 조사하면서, 로컬에서는 거위가 줄어드는 구간을 따로 측정했습니다. 거위의 크기, 아래 콘텐츠의 위치, 애니메이션의 재생 시간과 중간 장면을 나란히 비교해 기존 연출이 유지되는지도 확인했습니다.

측정 항목기존 height 모션transform 모션
모션 관찰 구간 CLS0.1040.000

transform으로 옮긴 구현에서는 관찰한 구간의 레이아웃 이동이 기록되지 않았습니다.

로컬 앱을 390×844 크기의 Chromium에서 실행하고, 거위 영역이 나타난 뒤 0.2~4.2초 구간을 CLS의 세션 윈도 규칙으로 측정했습니다.

성능 측정: 브라우저 작업 시간도 줄었다

CLS 변화와 함께 브라우저의 작업 시간도 확인하기 위해 모션 구간을 프로파일링했습니다. 이 측정은 모션 구현을 바꾸던 단계에 진행했습니다. 로컬 Next.js 개발 환경과 390×844 크기의 Chrome에서 축소 시작 이후 1초 구간을 측정했으며, 전후 각각 두 번 실행한 중앙값은 다음과 같습니다.

측정 항목변경 전변경 후
Layout 실행 횟수46.5회4회
Layout 누적 시간4.77ms0.48ms
Script 누적 시간227.65ms40.00ms
Style 재계산 누적 시간11.56ms20.62ms
TaskDuration 증가량300.84ms115.83ms

Style 재계산 시간은 늘었지만 Layout과 Script 작업 시간은 줄었습니다. 같은 1초 구간에서 메인 스레드가 작업을 수행한 누적 시간인 TaskDuration도 300.84ms에서 115.83ms로 약 61.5% 감소했습니다. 이번 측정에서는 기존 연출을 유지하면서 CLS와 브라우저의 작업 부담을 함께 낮출 수 있었습니다.

운영에서도 낮아진 CLS

로컬에서 확인한 변화가 실제 사용자 화면에서도 이어지는지 확인하기 위해, 2026년 11월 4일 10:05에 운영에 배포한 뒤 데이터독을 다시 살펴봤습니다. 배포 전후의 추이를 한 화면에 놓고 보니 차이가 드러났습니다.

배포 전후의 실제 데이터독 대시보드. 10시 5분 배포 이후 인앱 화면의 5분 단위 CLS P75가 전반적으로 낮아졌다.

2026년 11월 4일 07:00–15:07, 한국 시간 기준입니다. 5분 단위 P75의 추이이며, 배포 당일의 중간 관찰 화면입니다.

같은 서비스·운영 환경·인앱 경로에서 CLS가 측정된 Android 뷰를 집계했습니다. 화면에 보이는 5분 단위 추이와 별도로, 각 비교 구간 전체의 P75와 P90을 계산한 결과입니다.

측정 항목배포 전배포 후
CLS 측정 뷰 수113152
CLS P750.2440.020
CLS P900.3640.047

배포 전은 11월 4일 07:00–10:00, 배포 후는 10:15–16:54입니다. 조회 시점의 데이터 지연을 고려해 최근 10분은 제외했습니다.

로컬의 특정 모션 구간에서 확인했던 CLS 감소가 배포 후 운영 표본에서도 이어졌습니다. 14:17에는 다른 변경도 추가로 배포됐지만, 그 이전에 시작한 94뷰의 P75도 0.015로 낮았습니다. 여러 변경이 반영된 기간이므로, 개별 변경의 효과를 분리하기보다 배포 전후의 운영 추이를 확인했습니다.

배포 후 152뷰 중 3뷰에서는 CLS가 0.25를 넘었고, 가장 큰 값은 0.690이었습니다. 전체적으로 낮은 값이 이어지는 가운데 일부 큰 이동은 남아 있어, 24시간 동안 같은 조건으로 추이를 더 살펴보고 있습니다.

같은 움직임인데 transform은 왜 CLS에서 제외될까?

브라우저의 작업량이 달라지는 이유는 구현 차이로 설명할 수 있었습니다. 더 살펴보고 싶었던 것은 사용자 경험 지표인 CLS도 이 차이를 구분하는 이유였습니다.

WICG 설명서의 Transform Changes 절은 제외 이유로 세 가지를 듭니다. transform은 주변 콘텐츠를 리플로우시키지 않고, 부드러운 애니메이션에 흔히 쓰이며, 레이아웃 계산·스크립트 실행과 별도의 스레드에서 하드웨어 가속 합성으로 처리하기 쉽다는 점입니다. transform 자체에 따른 이동을 제외하며, 동시에 다른 이유로 레이아웃이 바뀌면 그 이동은 여전히 측정됩니다. 설계 배경 원문

Google의 설명에 따르면, 잘 만든 애니메이션은 사용자가 상태 변화를 이해하는 데 도움을 줄 수 있습니다. 미션 완료를 보여주고 다음 콘텐츠로 시선을 안내하려던 거위의 움직임도 같은 맥락이었습니다. 애니메이션과 전환 설명

WICG 설명서는 이런 제외 기준을 모든 상황에서 잘 작동한다고 보장할 수는 없는 휴리스틱으로 설명합니다. 부드러운 캐러셀도 left로 애니메이션하면 CLS가 높게 나올 수 있고, transform으로 바꾸면 이를 피할 수 있다는 예시를 듭니다. 한계 설명 원문

이를 읽고 나니 CLS가 사용자의 예상이나 불편함을 직접 판별하는 대신, 구현 특성을 바탕으로 사용자 경험에 미칠 영향을 가늠하려 한다는 점을 이해할 수 있었습니다.

따라서 transform을 썼다는 이유만으로 좋은 UX가 보장되지는 않습니다. 예고 없이 버튼을 순간이동시키면 CLS에 잡히지 않더라도 사용자는 불편할 수 있습니다. 반대로 이해를 돕는 연출도 구현 방식에 따라 점수에 영향을 줄 수 있습니다.

마치며

사용자의 다음 행동을 돕는 움직임이 사용자 경험 지표를 악화시킨다는 점은 처음에는 모순처럼 느껴졌습니다. CLS가 어떤 움직임을 포함하고 제외하는지, 그 기준에 어떤 가정이 있는지 살펴보고 나서야 이 상황을 이해할 수 있었습니다.

거위가 줄어드는 연출에는 미션 완료를 보여주고 다음 콘텐츠로 시선을 안내하려는 목적이 있었습니다. 그 목적을 기준으로 화면을 비교하고, 구현을 바꾼 효과는 CLS와 프로파일링으로 확인했습니다. 기존 연출을 유지하면서 모션 구간의 레이아웃 이동과 브라우저의 작업 시간을 줄일 수 있었습니다.

성능 지표에는 좋은 사용자 경험에 대한 가정이 담겨 있습니다. 그 가정을 제품의 맥락과 함께 살펴보면, 수치가 어떤 문제를 드러내는지, 어떤 경험은 점수만으로 설명하기 어려운지 구분할 수 있습니다. CLS의 설계 의도를 살펴본 것도 그 판단의 기준을 넓히는 과정이었습니다.

전체 보기