Thumbnail

5분

웹 사이트 성능(4) - Core web vitals, CLS

Core Web Vitals 중 3개 중 하나인 CLS에 대해 알아보도록 하겠습니다. - https://web.dev/cls

페이지에서 갑자기 바뀌는 부분으로 인해 갑작스레 링크를 클릭하거나 읽던 부분을 놓지는 경우가 있지 않으신가요? 이러한 부분을 수치로 측정함으로써 사용자 경험을 보장하도록 하는데 쓰이는 지표가 CLS(Cumulative Layout Shift, 누적 레이아웃 이동) 입니다.

CLS(Cumulative Layout Shift, 누적 레이아웃 이동)는 사용자가 예상하지 못한 레이아웃 경험을 수량화하여 시각적 안정성을 측정할 때 중요한 사용자 중심 메트릭입니다.

사용자 중심 메트릭 4가지 중 쾌적함과 관련이 있습니다.

예상하지 못한 이동은 일반적으로 리소스가 비동기로 로드되거나 DOM 요소가 기존 콘텐츠 위의 페이지에 동적으로 추가되기 떄문에 발생합니다.

  • 예측하지 못한 크기의 이미지나 동영상
  • 예측한 크기보다 크거나 작게 렌더링되는 글꼴
  • 동적으로 크기가 조정되는 광고, 위젯
  • ...등등

위와 같은 원인이 될 수 있습니다.

이러한 것이 더욱 큰 문제가 되는 이유는 사이트에서 개발했던 기능이 사용자가 경험하는 방식과 상당히 다를 수 있다는 점입니다.

대부분 커스텀 콘텐츠나 외부 콘텐츠는 운영 환경에서 개발 환경과 동일하게 작동하지 않습니다. 테스트 이미지는 이미 개발자의 브라우저 캐시에 존재하며, 로컬에서 실행되는 API 호출은 너무 빨라 눈에 띄지 않는 경우가 많이 때문입니다.

CLS(누적 레이아웃 이동) 메트릭은 실제 사용자에게 이러한 일이 발생하는 빈도를 측정하여 이 문제를 해결하는데 도움을 줍니다.

Core Web Vitals 3가지 메트릭 중 하나라는 것은 큰 의미를 가집니다. 웹 페이지 성능을 측정할 때 가장 중요한 지표 3가지 중 하나라는 것이죠.

CLS

Cumulative Layout Shift: 누적 레이아웃 이동 CLS는 페이지의 전체 수명 동안 발생하는 예기치 않은 모든 레이아웃 이동에 대한 가장 큰 Layout Shift Burst Scores(레이아웃 이동 버스트 Scores) 를 뜻합니다.

cls

우선 레이아웃 이동이라는 말은 어떤 뜻 일까요?

레이아웃 이동은 시각적 요소가 렌더링된 프레임에서 다음 프레임으로 위치를 변경할 때마다 발생합니다.

세션 윈도우(Session Window) 로 알려진 레이아웃 이동 버스트(Layout Shift Score Burst) 는 하나 이상의 레이아웃 이동이 빠르게 연속해서 이루어지는 경우를 뜻합니다. (이 때 각 레이아웃 이동 간격은 1초 미만이며, 총 기간은 최대 5초입니다.)

가장 큰 Layout Shift Burst Scores 는 해당 기간 내 모든 레이아웃 이동에 대해 누적 점수가 최대인 세션 윈도우 입니다.

https://storage.googleapis.com/web-dev-assets/better-layout-shift-metric/session-window.webm

위 영상은 세션 윈도우의 예시입니다. 최대 5초로 구간이 만들어지며 파란색 막대는 레이아웃 이동의 점수를 나타냅니다.

이전 CLS는 페이지의 전체 수명 동안 발생한 모든 레이아웃 이동 점수의 합계를 측정했습니다. 2021년 6월 세션 윈도우라는 개념을 도입하고, CLS 지표 측정방식을 변경했습니다. - https://web.dev/evolving-cls/

Evloving CLS

우리는 매우 좋은 피드백을 많이 받았고 대규모 분석을 완료하여 메트릭에 적용할 변경 사항을 최종 결정했습니다. 최소 1초 간격이 있고, 최대 5초 구간을 가진 세션 윈도우 지표입니다.

기존 CLS 점수 방식에 대한 많은 피드백이 있었습니다. CLS 측정항목이 오래 열려있는 웹페이지를 측정하는 데는 부적절하며 점수가 낮은 페이지에 불이익을 준다는 피드백을 받았습니다.

기존 지표 점수는 전체 페이지 수명 동안 발생한 모든 레이아웃 이동 점수를 합계하였기 때문에 웹페이지가 오래 열려있을 수록 점수는 무제한으로 합산됩니다. 또한 무한 스크롤로 인한 레이아웃 이동이 발생하는 경우 마찬가지로 의도한 것과는 다른 불이익을 받을 수 있습니다.

이러한 점을 피드백을 받고 세션 윈도우라는 옵션을 도입하였습니다.

최소 1초 Gap을 가지고, 최대 5초 구간을 가진 윈도우를 도입하여 CLS를 측정하는 방식을 바꾸었습니다.

왜 세션 윈도우인가요?

점수가 무제한으로 증가하지 않는 것을 보장하면서 레이아웃 변화를 그룹화할 수 있는 윈도우 전략을 검토하였습니다. 그리고 가장 직관적으로 그룹화하기 때문에 세셩 윈도우 전략을 개발자들이 압도적으로 선호했습니다.

왜 세션 최대 시간이 필요한가요?

2가지 옵션이 있었습니다.

  • 윈도우간 5초 Gap, 구간 상한이 없는 윈도우들 모두에 대한 평균 점수
  • 윈도우간 1초 Gap, 구간 상한 5초를 가진 윈도우들 중에서 최대 점수

session-time.png

분석을 진행하는 도중에 위와 같은 레이아웃 이동 패턴을 가진 많은 URL이 있었습니다.

만약 평균 점수를 이용한다면 다음과 같은 문제가 발생할 수 있습니다.

세션 윈도우2에서 아주 작은 레이아웃 이동이 있습니다. 그러나 개발자가 작은 레이아웃 변경을 수정하면 어떻게 될까요? 세션 윈도우2에서는 레이아웃 이동이 발생하지 않아 세션 윈도우1만으로 평균 계산을 하게 됩니다. 그렇게 되면 페이지 점수가 기존 수정하지 않았을 때부터 거의 2배 가까지 증가하게 됩니다.

레이아웃 변경을 수정했는데 점수가 높아진다면 혼라스러울 것입니다. 사용자 경험은 약간 더 좋지만 점수는 매우 나빠졌다는 걸 알게된다면 말이죠.

평균에 대한 이 문제 때문에 더 작고 제한이 있는 최대 세션 윈도우를 선택하고 진행하기로 결정했습니다.

따라서 위의 예에서는 세션 창 2는 무시되고 세션 창 1의 레이아웃 이동 합계만 보고될 것입니다.

왜 최대 구간이 5초로 설정되어있나요?

여러 창 크기를 평가하고 다음과 같은 결과를 냈습니다.

  • 더 작은 구간을 가진 윈도우인 경우 느린 페이지 로드와 사용자 상호 작용에 대한 느린 응답으로 인해 구간 내에 레이아웃 변화가 적어지고 여러 번 바뀌어 더 높은 점수를 받게 될 수 있습니다. 즉, 속도가 느린 페이지가 CLS에 보상하지 않도록 창을 충분히 크게 유지하여야 했습니다.
  • 작은 레이아웃 이동이 계속되는 일부 페이지가 있습니다. 예를 들어, 스포츠 점수 페이지같은 경우 각 점수가 업데이트될 때마다 조금씩 바뀌게 됩니다. 이러한 변화는 성가실 수 있지만 크게 영향을 미치지 않는 경우입니다. 그래서 이러한 유형의 레이아웃 변경에 대해 창에 제한을 두어 확인을 해야 했습니다.

다양한 창 크기를 비교한 결과 5초가 창 크기의 적절한 제한이라는 결론을 내렸습니다.

CLS 측정

우수한 사용자 경험을 제공하려면 사이트의 CLS 점수는 0.1 이하여야 합니다.

레이아웃 이동

레이아웃 이동은 Layout Instability API가 정의하는 것으로, 뷰포트 내의 가시적 요소가 두 프레임 사이에서 시작 위치가 변경될 때마다 layout-shift 항목을 보고합니다. 그리고 이러한 요소는 unstable elements로 간주됩니다.

레이아웃 이동은 기존 요소가 시작 위치를 변경할 때만 발생합니다.

새로운 Element가 DOM에 추가되거나 기존 Element 크기가 변경으로 인해 다른 Element의 시작 위치가 변경되지 않는 한 레이아웃 이동으로 간주되지 않습니다.

레이아웃 이동 점수

layout shift score = impact fraction _ distance fraction 레이아웃 이동 점수 = 영향 _ 거리

레이아웃 이동 점수는 해당 움직임에 대한 영향도와 거리라는 두 가지 측정값을 사용해 계산합니다.

다음 2가지 예시를 통해 점수가 어떤 방식으로 보이는지 확인할 수 있습니다.

  • Element 이동
  • Element 추가

예시: Element 이동

Impact fraction(영향분율)

영향분율은 불안정 Element가 두 프레임 사이 뷰포트 영역에 미치는 영향을 측정합니다. Impace fraction = 영향을 받은 뷰포트 / 전체 뷰포트

impact-fraction

위 이미지에서 한 프레임에서 뷰포트의 50%를 차지하는 Element가 있습니다.

다음 프레임에서는 뷰포트 높이의 25%만큼 아래로 이동합니다. (빨간색 점선 박스는 두 프레임에서 가시 영역을 합친 영역입니다.)

이 경우 영향을 받은 뷰포트는 전체 뷰포트의 75%이므로 Impact fraction은 0.75 입니다.

Distance fraction(거리분율)

거리분율은 뷰포트를 기준으로 불안정 Element가 이동한 거리를 측정합니다. Distance fraction = 수평 또는 수직으로 이동한 최대 거리 / 뷰포트의 가장 큰 치수(너비 또는 높이 중 더 큰 값)

distance-fraction

예시: Element 추가

기존 Element에 콘텐츠를 추가하면 레이아웃 이동 점수에 어떤 영향을 미치는지 확인해보겠습니다.

예시1

example1

Click Me! 버튼이 회색 Panel 맨 아래에 추가되어 녹색 Panel을 아래로 밀어냅니다.(부분적으로 뷰포트 밖으로도 밀어냅니다.)

이 예시에서 회색 Panel은 시작 위치가 변경되지 않으므로 불안정 Element가 아닙니다. Click Me! 버튼도 기존 DOM에 없었으므로 시작 위치도 변경되지 않습니다.

녹색 Panel의 경우 시작 위치는 변경되었지만 부분적으로 뷰포트 밖으로 이동되었으며 영향분율을 계산할 때 보이지 않는 영역은 고려되지 않습니다.

그래서 녹색 Panel(불안정 Element)의 영향분율은 첫 번째 프레임의 영역과 동일합니다.(뷰포트의 50%, 빨간색 점선박스). 그러므로 영향분율은 0.5 입니다.

거리분율은 보라색 화살표를 보면 녹색 Panel은 뷰포트의 약 14%만큼 아래로 이동하였으므로 거리분율은 0.14 입니다.

따라서 레이아웃 이동 점수는 0.5 * 0.14 = 0.07 입니다.

예시2

example2

첫 번째 프레임에서 동물에 대한 API 요청의 4가지 결과가 알파벳 순으로 정렬되어 있습니다. 두 번째 프레임에서는 더 많은 동물들이 목록에 추가됩니다.

Cat은 시작위치가 변경되지 않았으므로 안정적입니다. 마찬가지로 목록에 추가된 Crocodile, Elephant, Lion, Tiger 또한 기존 DOM에 없었기 때문에 시작 위치가 변경되지 않았습니다.

Dog, Horse, Zebra 라고 표시된 항목은 모두 시작 위치가 변경되었으므로 불안정 Element입니다.

빨간색 점선 박스는 이 3가지 항목에 대한 전후 영역의 합을 나타냅니다. 이 경우 뷰포트 영역의 약 38%이므로 영향분율은 0.38 입니다.

화살표는 불안정 Element가 시작 위치에서 이동한 거리를 나타내며 Zebra 요소가 뷰포트 높이의 30% 정도로 가장 많이 이동했습니다. 따라서 거리분율은 0.3 입니다.

따라서 레이아웃 이동 점수는 0.38 * 0.3 = 0.1172 입니다.

예상된 레이아웃 이동 vs 예상치 못한 레이아웃 이동

모든 레이아웃 변경이 나쁜 것은 아닙니다. 실제로 많은 웹 페이지에서 레이아웃 변경은 자주 일어납니다.

예상치 못한 레이아웃 이동인 경우에만 나쁜 것입니다.

반면 사용하 상호 작용(링크, 버튼, 검색 등)에 대한 응답으로 발생하는 레이아웃 이동은 사용자에게 그 관계가 명확하게 보이는 한 괜찮습니다.

예를 들어, API 호출 후 요청이 완료될 때 사용자에게 좋지 않은 레이아웃 이동을 피하기 위해 로딩바를 표시하는 것은 좋은 경우입니다. 사용자가 로드되고 있다는 사실을 인지하지 못하거나 리소스가 언제 준비될지 예상하지 못하는 경우 사용자는 의도하지 않은 다른 것을 클릭하게 될 수도 있습니다.

또한 제대로 된 애니메이션, 트랜지션은 사용자에게 예상된 레이아웃 이동이라는 것을 알려주는 좋은 방법입니다. 점진적이고 자연스럽게 이동하는 콘텐츠는 사용자가 상황을 더 잘 이해하고 변경을 안내하는데 도움이 됩니다.

CSS Trasnform 속성을 사용하면 레이아웃 이동을 트리거 하지 않고 애니메이션을 적용할 수 있습니다.

  • height, width 속성을 변경하는 대신 transform: scale()를 사용하세요
  • Element를 이동 시킬 때 top, right, bottom, left 대신 transform: translate()를 사용하세요.

CLS 측정 도구

Chrome Devtools, LightHouse, PageSpeed Insights에서는 기본적으로 Core Web Vitals에 대해 보고서를 작성해줍니다.

구글 Search Console을 이용하고 계시다면 코어 웹 바이탈 항목에서 보고서를 받아볼 수 있습니다.(기본적으로

구글 web-vitals 라이브러리에서 사용할 수 있습니다.

세션 윈도우 적용에 대해서도 github wiki에서 snippet을 제공하고 있습니다.

마무리하며

구글에서 사용자 경험에서 중요한 지표로 관리하는 web-vitals 중 Core Web Vitals에 대해 겉핥기 식으로나마 확인해보았습니다.

웹 페이지 성능에 대해 알아보고자 더듬더듬 거리며 조금은 이해를 해본 것 같아요.

web vitals는 정적인 지표가 아니고 계속해서 변경되어가며 사용자 경험에 발맞추어 진화해 나갈 것으로 보입니다.

이 모든 최적화를 당장 실현할 순 없겠지만, 이러한 것이 있다는 것을 알고 추후 적용할 때 찾아볼 수 있다는 것만으로도 큰 도움이 될 수 있을 것 같습니다.

Reference

마지막 업데이트

11/14/2021


Avatar

JHSeo

배우는 것을 좋아하고 관심이 많은 웹 엔지니어 입니다. 느리더라도 꾸준하게 성장하려고 노력하는 개발자입니다.