웹사이트 성능 최적화에는 어떤 방법이 있나요?

윤지영·2023년 9월 4일
0
post-thumbnail

웹사이트 성능 최적화에는 어떤 방법이 있나요?

1. 웹 사이트 로딩 최적화

서버에서 웹 페이지에 필요한 HTML, CSS, Javascript, 미디어 소스(Image, Video) 등의 리소스를 다운로드할 때의 성능

블록 차단 리소스 최적화

HTML의 파싱을 막는 CSS나 자바스크립트의 리소스를 블록 리소스라고 한다.

  • script 로드를 위한 script 태그는 DOM 생성 블로킹을 일으킬 수 있기 때문에 HTML 최하단에 배치한다.
  • script 태그에 defer나 async 속성을 명시하면 스크립트가 DOM 트리와 CSSOM 트리를 변경하지 않겠다는 의미이기 때문에 브라우저가 파싱을 멈추지 않는다. 단, 이 속성들은 브라우저 지원 범위가 한정적이므로 사용에 유의한다.
  • CSS는 렌더링 차단 리소스로, 항상 HTML 문서 최상단(head 아래)에 배치한다.
  • 특정 조건에서만 필요한 CSS는 미디어 쿼리를 사용하여 불필요한 블로킹을 방지한다.

리소스 용량 줄이기

  • css의 복잡한 셀렉터 지양하고, 공통 스타일은 클래스로 설정한다.
  • HTML 태그의 중첩을 최소화 한다.(DOM 트리가 커지는 것을 방지하는 것이 좋다.)
  • java script의 자주 사용하는 내용은 함수처리한다.
  • 만능 유틸 사용에 주의한다.
    일반적인 방식으로 가져와 사용하면 유틸 함수 전체가 포함되므로 자바스크립트 파일 용량이 커진다.
    필요한 함수만 부분적으로 가져오도록 하며 사용하지 않는 기능이 많이 포함된 라이브러리 사용은 지양한다.
//모든 유틸 함수 가져오기 (최적화 전)
import _ from 'lodash';

_.array(...);
_.object(...);

//필요한 함수만 가져오기 (최적화 후)
import array from 'lodash/array';
import object from 'lodash/fp/object';

array(...);
object(...);
  • 중복코드 및 불필요한 코드는 제거하고 공백, 주석 등도 최소화 하여 작업한다.
  • 용량이 큰 이미지는 압축을 진행한다.
  • 웹팩등을 사용하여 압축 및 난독화를 진행한다.

리소스 요청 개수 줄이기

  • 외부 스타일시트를 가져올 때 사용하는 @import 사용은 피한다 (link 태그 사용)
  • 이미지 스프라이트 사용하여 여러 번 불어와야 할 이미지를 한번만 불러오도록 한다.
  • 레이지로드
  • 번들링

2. 렌더링 성능(Rendering Performance) 개선

페이지 화면에 주요 리소스가 페이지에 그려질 때의 성능.
레이아웃을 최대한 빠르게, 최대한 적게 발생시켜야 함 => Reflow, Repaint 최소한으로 줄여야 한다.

리플로우(reflow) 와 리페인트(repaint)

리플로우와 리페인트는 요소가 시각적으로 변경되었을 때, 변화를 계산하여 화면에 그려주는 작업이다.
만약 DOM이 시각적으로 변경되면 리플로우가 발생하여 렌더트리를 재생성하고,
생성된 렌더트리를 기반으로 요소를 화면에 그리는 리페인트가 발생한다.

리플로우와 리페인트 최소화: DOM 및 스타일 변경을 최소화

js

  • 강제 동기 레이아웃 피하기 & 레이아웃 스래싱(thrashing) 피하기
    • offsetHeight, offsetTop과 같은 계산된 값을 속성으로 읽을 때 브라우저는 강제로 동기 레이아웃을 수행한다.
    • 반복문 안에서 style.width를 설정하고 box.offsetWidth를 읽어오면 for문이 반복 실행될 때마다 레이아웃이 발생한다. 반복문 밖에서 box 엘리먼트의 너비를 읽어오면 레이아웃 스래싱을 막을 수 있다.
function resizeAllParagraphs() {
  const box = document.getElementById('box');
  const paragraphs = document.querySelectorAll('.paragraph');

  for (let i = 0; i < paragraphs.length; i += 1) {
    paragraphs[i].style.width = box.offsetWidth + 'px';
  }
}
// 레이아웃 스래싱을 개선한 코드
function resizeAllParagraphs() {
  const box = document.getElementById('box');
  const paragraphs = document.querySelectorAll('.paragraph');
  const width = box.offsetWidth;

  for (let i = 0; i < paragraphs.length; i += 1) {
    paragraphs[i].style.width = width + 'px';
  }
}

참고 : 레이아웃에 영향을 미치는 요소

  • 가능한 한 하위 노드의 DOM을 조작하고 스타일을 변경

css

  • 가능한 JS 보다는 CSS 애니메이션을 사용한다.
    브라우저는 CSS애니메이션을 처리하기 위한 성능 최적화가 더 잘 되어있다. GPU의 도움을 받을 수 있는 속성을 활용하도록 한다.(애니메이션 기능을 오로지 GPU에게 맡긴다는 것은 기하 구조를 계산하고 그려주는 reflow/repaint 과정을 CPU에서 거칠 필요가 없다는 의미)

  • 애니메이션으로 요소의 위치를 변경할 경우, 주변 요소(형제, 부모, 자식)의 위치도 변경되어 리플로우가 여러 번 발생하게 되므로 애니메이션이 적용된 요소의 position을 absolute나 fixed로 설정하여 주변 요소에 영향을 주지 않도록 하자.

🔴 Reflow를 발생시키는 속성

position / width / height / margin / padding / display / top / left / right / bottom / box-sizing / background-color / border-color / text-align / border / border-width / font-family / float / font-size / font-weight / line-height / vertical-align / white-space / word-wrap / text-overflow / text-shadow

🔴 Repaint를 발생시키는 속성

color / border-style / visibility / background / background-image / background-position / background-repeat / background-size / text-decoration / outline / outline-style / outline-color / outline-width / border-radius / box-shadow

💚 둘 다 발생시키지 않는 속성

opacity / transform / cursor / z-index

  • transform 과 opacity속성은 리플로우, 리페인트가 일어나지 않는다.
    top, bottom, left, right, width, height 보다 transform을,
    visibility / display 보다 opacitiy를 사용하는 것이 성능 개선에 좋다.

html

  • tag안에 직접 지정하는 Inline style을 사용하지 않는다.
    웹페이지가 그려지는 과정 중 Layout에 영향을 미쳐 추가 Reflow가 발생한다.

  • 복잡한 DOM Tree를 지양한다.
    DOM Tree가 커질수록 Rendering 속도가 느려지기 때문에 불필요한 요소는 제거한다.

    경험

    퍼블리셔로 근무할 때 각 개발팀이 관리하는 모든 페이지의 랜딩속도를 개선하라는 지시가 있었다.
    단기간 내에 수많은 사업군의 모든 페이지를 수정해야 했기에 어떤 방식이 가장 빠르고 효율적일지 고민을 하였고, 많은 속도 개선 방법이 있었지만, 이미지와 영상이 많은 이벤트페이지 특성 상 가장 효율적인 방법은 이미지에 'lazy load'를 적용하는것이라 판단하여 (1)이미지에 lazyload 적용 (2)중복 코드 / 미사용 코드 제거 (3)이미지 압축 순으로 랜딩속도 개선 작업을 진행하였다.

lazy load를 적용하였음에도 개선되지 않은 페이지들은 주로 아래 3가지 경우가 대다수였다.

1) 용량이 너무 큰 메인이미지를 포함한 페이지(jpg/gif)
2) 자동 재생이 포함된 영상 콘텐츠가 포함된 페이지
3) 페이지 진입 시 자동 재생이 적용된 동영상 팝업이 뜨는 경우

위의 세 가지 사항 모두 개발팀 내에서 독단적으로 수정할 수 없는 사항들이라 기획팀, 디자인팀과의 협의가 필요했다.

해결책

1 용량이 큰 gif 이미지 대신 css 애니메이션으로 구현하였다.
2) 처음부터 재생되고 있던 영상을 정지상태로 두고, 유저들이 해당 영상단에 진입했을 때 자동재생 되도록 스크롤 이벤트를 추가하였다.
3)...자동 재생되는 동영상 팝업이 매출과 즉결된다 판단하여 영상 배너가 포함된 페이지들은 랜딩 속도 개선 기준을 완화하겠다는 지시가 내려왔다.

느낀점

화려한 이미지와 영상들을 통한 정보 전달도 중요하지만 결국 속도가 느리고, 사용자 경험을 해치는 웹페이지라면 사용자에게 외면받을 수 밖에 없다고 생각한다. 기획단계에서부터 기획자-디자이너-개발자 간의 충분한 조율을 통해 사용자 경험에 대해 충분히 고민 한 뒤 페이지 제작이 되는 것이 중요함을 체감하였다.
또한 '프론트엔드 개발자'로서 작업 시 효율적인 코드 작성을 통해 리소스 최적화와 렌더링 성능을 최적화 할 수 있도록 다방면으로 고민해보는 것이 좋겠다.

동일 페이지 레이지로드 적용 전

요청 22/32 | 5.6 MB/5.7 MB 전송됨 | 5.5 MB | 5.9 MB 리소스/완료: 842밀리초
DOMContentLoaded: 790밀리초| 로드: 849밀리초
레이지로드 적용 전

동일 페이지 레이지로드 적용 후

요청 7/18 | 2.8 MB/2.9 MB 전송됨 | 2.8 MB/3.0 MB 리소스 |완료: 249밀리초
|DOMContentLoaded: 286밀리초/| 로드: 286밀리초
레이지로드 적용 후

** 참고페이지

https://ui.toast.com/fe-guide/ko_PERFORMANCE#%EB%B8%94%EB%A1%9D-%EB%A6%AC%EC%86%8C%EC%8A%A4css-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%B5%9C%EC%A0%81%ED%99%94

https://mong-blog.tistory.com/entry/%EB%A6%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EB%A6%AC%ED%8E%98%EC%9D%B8%ED%8A%B8%EC%99%80-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%A0%8C%EB%8D%94%EB%A7%81-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0

** 다음에 실습 해보기

이미지 최적화, Lazy Load & Intersection Observer API
profile
쑥쑥쑥쑥 레벨업🌱🌼🌳

0개의 댓글