-
Optimization(최적화)CS&Network 2022. 8. 4. 15:56
오늘은 웹 최적화 개념과 기법들에 대해 알아보고 정리해보려고 합니다.
최적화의 개념
최적화는 보통 주어진 조건으로 최대 효율을 낼 수 있도록 하는 것을 의미합니다.
웹 개발에서의 최적화는 무엇을 의미할까요? 바로 주어진 조건 아래에서 최대한 빠르게 화면을 표시하도록 만드는 것입니다. 이번에 알아보고자 하는 것은 바로 웹 개발 중에서도 프론트엔드 단에서 할 수 있는 최적화 방법입니다. 본격적으로 최적화 방법에 대해서 알아보기 전에, 웹 개발에서 최적화가 왜 필요한지, 그 필요성에 대해서 먼저 알아봅시다.
최적화의 필요성 및 효과
1. 이탈률 감소
웹 개발에서의 최적화는 화면을 최대한 빠른 속도로 표시하게 하는 것이라고 했습니다. 이는 최적화가 잘되지 않은 웹 페이지는 화면 로딩에 시간이 걸린다는 뜻으로도 볼 수 있습니다. 화면을 불러오는 시간이 길어지면 사용자가 페이지를 이탈할 확률이 높아집니다. 여기서 이탈이란 방문자가 웹 사이트의 첫 페이지에서 아무런 상호작용도 하지 않고 종료하는 것을 의미합니다. 여러분도 한 번쯤은 화면 로딩을 기다리다가 그냥 창을 꺼버린 경험이 있으실 겁니다.
구글의 조사 결과에 따르면 페이지 로드가 3초 이상 걸리면 53%의 사용자가 사이트를 이탈한다고 합니다. 또한 페이지 로드 시간이 길어지면 사이트 방문자가 이탈률이 폭발적으로 증가한다고 합니다. 열심히 만든 웹 사이트가 로딩이 느리다는 이유로 사용자가 이탈하게 된다면 정말 속상한 일입니다. 하지만 반대로, 웹 사이트의 성능 최적화를 통해 페이지 로딩 속도를 줄이면, 사용자의 이탈률을 효과적으로 줄일 수 있다는 의미이기도 합니다. 여기서 최적화의 필요성을 엿볼 수 있습니다.
2. 전환율 증가
이탈률이 줄어들면, 전환율이 높아질 확률도 커집니다. 여기서 전환율이란, 웹 사이트를 방문한 사용자 중 회원가입, 상품 구매, 게시글 조회, 다운로드 등의 행위를 한 방문자의 비율을 의미합니다. 너무나 당연한 이야기입니다. 화면이 로딩되느라 제대로 뜨지도 않는 상태에서는 회원 가입은 고사하고 버튼 하나 클릭하는 것도 불가능하기 때문입니다. 물론 화면이 제대로 표시된다고 해도 방문자를 실제 서비스 이용자로 전환하게 하는 일은 어려운 일입니다. 하지만 이탈해버린 사용자의 전환율은 0%입니다. 전환율을 늘려 서비스 사용자를 늘리기 위해서는 이탈률을 줄여야 합니다.
3. 수익 증대
빠른 웹 사이트 로딩 속도는 수익 증대까지 이어질 수 있습니다. 이탈률 감소, 전환율 증가는 트래픽 증대 및 회원 수 증가로 이어지고, 이는 곧 수익 증대를 의미합니다. 실제로 로딩 속도가 1초 빨라졌을 때 아마존 판매량은 1%, 구글 검색량은 0.2%, 월마트의 전환율은 2% 증가했다고 합니다. 퍼센티지로 보면 크지 않아 보이지만, 이 수치를 돈으로 환산하면 각각 68억 달러, 4억 5천만 달러, 2억 4천400만 달러의 매출 증가라고 합니다. 1초 차이로 어마어마한 수익이 왔다 갔다 하는 것입니다. 꼭 아마존이나 월마트처럼 규모가 크지 않은 서비스라도, 로딩 속도의 차이는 이처럼 유의미한 수익 차이를 낼 수 있습니다.
4. 사용자 경험(UX) 향상
최적화는 효과적인 UX 개선 수단입니다. 페이지 로딩이 빠를수록 UX는 향상되기 때문에 이미 페이지 로드 속도가 빠른 편이라고 해도 최적화를 통해 UX가 더욱 향상할 수 있습니다. 만약 로딩이 오래 걸릴 경우, 스피너, 프로그레스 바, 스켈레톤과 같이 로딩 중임을 알려주는 UI를 먼저 표시하여 방문자가 조금 더 인내심을 갖고 기다리게 하는 방법도 있습니다. 하지만 이러한 방법은 최적화를 통해 페이지 로드 속도 자체를 최대한 빠르게 하는 것보다 UX에 좋다고 볼 수는 없습니다. 또한 방문자의 체류 시간이 좀 더 늘어날 뿐, 페이지 로드 속도가 개선되지 않는다면 이탈률 개선까지 이어지기는 어렵습니다. 따라서 이탈률 감소와 UX 향상 효과를 동시에 보기 위해서는 웹 사이트 성능 최적화를 진행하는 것이 가장 좋습니다.
그럼 이제 최적화의 구체적 방법에 대해 알아보겠습니다.
HTML, CSS 코드 최적화하기
화면을 렌더링할 때는 HTML 파일과 CSS 파일이 필요합니다. HTML 파일은 DOM 트리를, CSS 파일은 CSSOM 트리를 만들고 두 트리를 결합하여 렌더링할 때 사용하게 됩니다. 이 두 트리 중에서 하나라도 변경되면 리렌더링을 유발하는데, 이때 트리의 크기가 크고 복잡할수록 더 많은 계산이 필요하기 때문에 리렌더링에 소모되는 시간도 길어집니다. 따라서 HTML, CSS 코드를 최적화함으로써 렌더링 성능을 향상시킬 수 있습니다.
1. HTML 최적화 방법
(1) DOM 트리 가볍게 만들기
DOM 트리가 깊을수록, 자식 요소가 많을수록 DOM 트리의 복잡도는 커집니다. 복잡도가 클 수록 DOM 트리가 변경되었을 때 계산해야 하는 것도 많아집니다. HTML 요소들의 관계를 잘 살펴보고, 불필요하게 깊이를 증가시키는 요소가 있다면 삭제하세요.
(2) 인라인 스타일 사용하지 않기
인라인 스타일은 개별 요소에 스타일 속성을 작성해주는 것이기 때문에, 클래스로 묶어서 한 번에 작성해도 될 스타일 속성을 중복으로 작성하게 되는 경우가 생깁니다. 이처럼 불필요한 코드 중복은 가독성을 떨어뜨릴 뿐 아니라 파일 크기를 증가시킵니다. 또한 CSS 파일을 따로 작성하면 단 한 번의 리플로우만 발생하는 것과 달리, 인라인 스타일은 리플로우를 계속해서 발생시켜 렌더링 완료 시점을 늦춥니다. 애초에 인라인 스타일은 웹 표준에 맞지 않으므로 지양해야 합니다.
2. CSS 최적화 방법
(1) 사용하지 않는 CSS 제거하기
CSS 파일의 모든 코드의 분석이 끝난 후에 CSSOM 트리가 생성됩니다. 그만큼 불필요한 CSS 코드가 있다면 CSSOM 트리의 완성이 늦어집니다. 따라서 사용하지 않는 CSS 코드가 있다면 제거하는 것이 좋습니다. 보통 해당 CSS 코드를 사용하던 요소를 삭제하면서 CSS 코드만 남게 되는 경우가 많습니다. 요소를 삭제할 일이 생기면, CSS 코드만 남지는 않는지 확인하고 함께 삭제하면 이런 상황을 방지할 수 있습니다.
(2) 간결한 셀렉터 사용하기
셀렉터가 복잡할수록 스타일 계산과 레이아웃에 시간을 더 많이 소모하게 됩니다. 따라서 최대한 간결한 CSS 셀렉터를 사용하는 것이 좋습니다.
리소스 로딩 최적화하기
HTML 파일에서 JavaScript 파일을 불러올 땐 <script> 요소를, CSS 파일을 불러올 땐 <link> 요소를 사용하게 됩니다. 이때 파일을 불러오는 위치가 어디인가에 따라서 렌더링 완료 시점이 달라질 수 있습니다.
1. CSS 파일 불러오기
화면을 렌더링할 때는 DOM 트리와 CSSOM 트리가 필요하다고 했습니다. DOM 트리는 HTML 코드를 한 줄 한 줄 읽으면서 순차적으로 구성할 수 있지만, CSSOM 트리는 CSS 코드를 모두 해석해야 구성할 수 있습니다. 따라서 CSSOM 트리를 가능한 빠르게 구성할 수 있도록 HTML 문서 최상단에 배치하는 것이 좋습니다.
2. JavaScript 파일 불러오기
JavaScript는 DOM 트리와 CSSOM 트리를 동적으로 변경할 수 있습니다. HTML 코드 파싱 중에 <script> 요소를 만나는 순간 해당 스크립트가 실행되며, <script> 요소 이전까지 생성된 DOM까지만 접근할 수 있습니다. <script> 요소를 HTML 코드 중간에 넣는다면, 해당 요소 이후에 생성될 DOM을 수정하는 코드가 있는 경우에는 화면이 의도한 대로 표시되지 않게 됩니다.
또한 스크립트 실행이 완료되기 전까지 DOM 트리 생성이 중단됩니다. JavaScript 파일을 다운받아와서 사용하는 경우에는 다운로드 및 스크립트 실행이 완료될 때까지 DOM 트리 생성이 중단됩니다. DOM 트리 생성이 중단된 시간만큼 렌더링 완료 시간은 늦춰지게 됩니다. 이러한 이유로 JavaScript 파일은 DOM 트리 생성이 완료되는 시점인 HTML 문서 최하단에 배치하는 것이 좋습니다.
브라우저 이미지 최적화하기
페이지의 대부분의 용량은 HTML/CSS/JS와 같은 코드 데이터가 아닌 이미지 파일과 같은 미디어 파일이 차지합니다. (전체 페이지 용량의 약 51% 차지)그래서 이미지의 용량을 줄이거나 요청의 수를 줄이는 것을 우선적으로 고려할 시, 사용자 경험을 빠르게 개선할 수 있습니다.
1. 이미지 스프라이트
클라이언트에서 서버 요청이 증가할수록 로딩 시간은 점점 늘어납니다. 따라서 웹 페이지를 로드하는 데 필요한 서버 요청 수를 줄이기 위해 이미지 스프라이트 기법을 사용할 수 있습니다.
이미지 스프라이트 기법은 여러 개의 이미지를 모아 하나의 스프라이트 이미지로 만들고 CSS의 background-position 속성을 사용해 이미지의 일정 부분만 클래스 등으로 구분하여 사용하는 방법입니다.
하나의 이미지를 배경 이미지로 사용하되, 표시하고 싶은 부분에 맞춰 width, height, background-position 속성을 주어 아이콘을 만듭니다. 위 이미지를 보면서 CSS 속성값에따라 어떤 부분이 보이는지 확인하면서 이해해보세요.
해당 기법을 이용하면 한번의 이미지 요청으로 대부분의 개별 이미지를 사용할 수 있기 때문에 네트워크 로딩 시간을 줄일 수 있습니다. 또한, 많은 이미지 파일을 개별로 관리할 필요없이 특정 스프라이트 이미지 파일만을 관리하면 되므로 관리가 용이하다는 장점이 있습니다.
2. 아이콘 폰트 사용하기
아이콘 사용이 많을 때에는, 모든 아이콘을 이미지로 사용하는 것이 아니라 아이콘 폰트를 사용하여 용량을 줄일 수 있습니다. 대표적인 아이콘 글꼴 서비스로는 Font Awesome이 있습니다.
3. WebP 또는 AVIF 이미지 포맷 사용하기
이미지 최적화를 위해 전통적으로 사용하는 JPEG 또는 PNG 형식이 아닌 새롭게 등장한 이미지 포맷인 WebP 또는 AVIF를 사용하여 용량을 더욱 감소시킬 수 있습니다. WebP는 PNG와 비교해 26% 용량이 감소되며 JPEG와 비교했을 땐 25-35% 더 감소됩니다. AVIF는 JPEG와 비교했을 때 무려 용량의 50%가 감소되며 WebP와 비교했을 땐 20% 감소됩니다.
하지만 WebP와 AVIF 모두 비교적 최근에 등장한 이미지 포맷이기 때문에 JPEG 포맷처럼 모든 브라우저에서 호환되지 않는다는 단점이 있습니다. WebP의 경우 비교적 최근에 브라우저 지원이 되었으므로 구버전의 브라우저에서는 지원이 안될 수 있으며 Safari 브라우저에서도 지원하지 않습니다. AVIF의 경우에는 Chrome, Opera 등 소수의 브라우저만 지원하고 있습니다. (참고 - Can I use WebP?, Can I use AVIF?)
그럼 개발자가 각 브라우저의 이미지 호환성을 파악해서 이미지 파일을 분기해야 할까요? 다행히도 HTML의 <picture> 태그를 이용하면 각 브라우저의 호환에 맞도록 분기를 대체할 수 있습니다.
<picture>: img 요소의 다중 이미지 리소스(multiple image resources)를 위한 컨테이너를 정의할 때 사용한다.
다음과 같이 HTML 태그를 작성할 시, 만약 접속한 브라우저에서 <source>태그 내의 srcset에 정의한 WebP 포맷을 지원하지 않는다면 해당 <source> 태그는 무시됩니다. 이와 같은 속성을 이용하여 각 브라우저에 따라 이미지 포맷을 최적화할 수 있습니다.
캐시 사용하기
캐시는 다운로드 받은 데이터나 값을 미리 복사해 놓는 임시 장소를 뜻하며, 데이터에 접근하는 시간이 오래 걸리는 경우나 값을 다시 계산하는 시간을 절약하고 싶은 경우에 사용합니다. 캐시를 사용하면 리소스를 매번 다운로드받을 필요 없이 캐시에서 꺼내와 재사용하면 되기 때문에 네트워크 리소스는 물론 로딩 시간을 줄일 수 있습니다.
프론트엔드단에서 캐시를 사용하기 위해서는 HTTP 요청을 보낼 때 조건부 요청 헤더를 작성하여 캐시를 재사용해도 되는지 확인해주면 됩니다.
- If-Modified-Since : 캐시된 리소스의 Last-Modified 값 이후에 서버 리소스가 수정되었는지 확인하고, 수정되지 않았다면 캐시된 리소스를 사용합니다.
- If-None-Match : 캐시된 리소스의 ETag 값과 현재 서버 리소스의 ETag 값이 같은지 확인하고, 같으면 캐시된 리소스를 사용합니다.
보통 두 종류의 헤더를 동시에 사용합니다. 둘 중 하나만 사용했다가 매칭되는 응답 헤더가 없는 경우에는 재사용할 수 있는 경우에도 리소스를 다시 받아와야 하는 경우가 생길 수 있기 때문입니다.
CDN 사용하기
CDN은 콘텐츠를 좀 더 빠르고 효율적으로 제공하기 위해 설계되었습니다. 네트워크 지연(latency)은 유저와 호스팅 서버간의 물리적 거리의 한계가 존재하기 때문에 발생할 수 밖에 없습니다. 유저와 서버의 거리가 멀다면 지연(latency) 또한 늘어납니다. CDN은 이를 해결하고자 세계 곳곳에 분포한 분산된 서버에 콘텐츠를 저장합니다.
간단히 말해, CDN은 유저가 가까운 곳에 위치한 데이터 센터(서버)의 데이터를 가져옵니다. 그러므로 데이터가 전달되기 위해 거쳐야하는 서버의 갯수가 크게 줄기 때문에 로딩 속도가 빨라집니다.
지금은 CDN을 사용하는 방법을 구체적으로 알지 않아도 괜찮습니다. 추후에 CDN을 사용해보고싶다면, CloudFront, Cloudflare와 같은 CDN 서비스들에 대해서 알아보세요.
'CS&Network' 카테고리의 다른 글
RESTful System (REST API를 잘 만드는 방법) (0) 2022.09.01 Lighthouse (0) 2022.08.04 REST API란? (0) 2022.06.10 SSR vs CSR (0) 2022.06.10 AJAX 란? (0) 2022.06.10