css 최적화

구글 라이트하우스를 통해 css 최적화에 대한 오류와 기법들이 보고된다.

기본 전제

css 최적화에는 두 가지 기본 전제가 있다.

  1. unused css 제거
  2. render-blocking resources제거

unused css 제거

css는 페이지 렌더링을 차단하는 리소스이기 떄문에 사용되지 않는 css는 브라우저가 스타일을 계산하는데에 잠재적으로 더 많은 시간을 소비하게 만든다.

render-blocking resorces 제거

브라우저가 외부 리소스를 다운로드 하고 파싱하는 동안 페이지 콘텐츠를 파싱하거나 렌더링하지 않기 때문에 페이지 표시 속도 저하의 원인이다.

Unused CSS는 render blocking을 가중하는 요인이다.

render blocking resources

렌더 블로킹 리소스 표시 조건:

  • defer , async 속성이 없는 <head> 요소의 <script>태그
  • mdeia 속성과 값이 없는 <link rel='stylesheet'>태그

script의 여러 속성

  • async
    병렬 다운로드, 즉 스크립트를 다운로드 하면서 웹페이지를 해석한다.
    다운이 끝나면 즉시 실행한다.
  • defer
    병렬 다운로드, 즉 스크립트를 다운로드 하면서 웹페이지를 해석한다.
    그 후 다운로드가 끝나면 웹페이지가 그려지고 DOM이 들어왔을 때 실행한다.

script 개선방안

  1. 필수 스크립트는 head에 <script>형식을 작성한다.
  2. 기타 스크립트는 </body> 종료 태그 직전에 선언한다.
  3. 마지막에 파싱해도 문제가 없다면 defer속성을 사용한다.
  4. 가능한 빠른 시점에 실행이 필요하면 async속성을 사용한다.

css 의 여러 속성

css에 media속성이 없거나 값이 all이면 렌더 차단 리소스이다.

media 속성을 통해 특정 조건에서만 css를 해석하도록 처리하였기 떄문에 render blok resource로 파악되지 않는다.

따라서 반응형 웹 개발시에는 해상도 구간별로 별도의 css를 작성 후 여기에 media 쿼리 구문을 적용하여 개발하면 성능을 개선할 수 있다.

css 개선방안

  • 반응형 웹인 경우 해상도 구간 별로 css 파일을 분리하고 media 속성으로 분기하기
1
2
3
4
5
6
7
<link href="*.css" rel="stylesheet" media=" (max-width:639) " />
<link
href="*.css"
rel="stylesheet"
media=" (max-width:639) and (max-width:960)"
/>
<link href="*.css" rel="stylesheet" media=" (max-width:961) " />
  • 필수 스타일은 페이지의 <head><style> 형식으로 작성하기
1
2
3
<style>
/*필수 스타일*/
</style>
  • 지연 스타일은 <link rel="preload"> 속성으로 병렬 로딩 후 지연 적용하기
    당장 필요하지 않은 css의 경우 병렬로 로딩을 한 후 늦게 화면이 되도록 지연 적용하기

    병렬로 로딩하다가 로딩이 끝나면 onload이벤트를 이용하여 rel을 stylesheet로 적용하여 화면에 적용된다.
    중요하지 않은 CSS 연기

    1
    2
    3
    4
    5
    6
    <link
    rel="preload"
    as="style"
    href="x.css"
    onload="this.onload=null;this.rel='stylesheet'"
    />

LCP(Largest Contentful Paint)

가장 큰 덩어리 콘텐츠를 2.5초 이내에 로딩시켜야 한다.

LCP 개선 사례

  1. 라이브러리 의존도 줄이기
    사용하려는 기능 외에 많은 기능을 포함하고 있기 떄문에 FCP를 늦출 확률이 높다.
    ex)jquery lodash,normalize

    https://youmightnotneed.com을 통해 라이브러리 대신 사용할 수 있는 바닐라 js를 찾을 수 있다.

  2. 사용하지 않는 css 제거
    normalize나 reset과 같이 잘 사용하지 않는 css를 과감하게 버려야한다.

  3. preconnect/preload
    웹 폰트를 preconnect하여 url에 미리 연결하고 바로 다운받을 수 있게 도와준다.
    또한 css를 preload하여 렌더링을 차단하지 않고 css를 로드한다.

    1
    2
    3
    4
    5
    6
    7
    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link
    rel="preload"
    as="style"
    href="x.css"
    onload="this.onload=null;this.rel='stylesheet'"
    />

LCP를 head에서 preload로 로딩하여 성능을 개선할 수 있다.

  1. feature detection

type과 media라는 조건을 붙여서 최적화한다.

1
2
3
4
5
6
<picture>
<source srcset="small.avif" type="image/avif" media=" (max-width:640px)" />
<source srcset="small.avif" type="image/avif" />
<source srcset="small.webp" type="image/webp" media=" (max-width:640px)" />
<source srcset="small.webp" type="image/webp" />
</picture>
  1. Image Loading / Decoding

loading="lazy"는 뷰포트 안에 들어오지 않으면 로딩을 하지 않는다.

또한 decoding="async"는 화면에 다른 요소를 렌더링하는 걸 중단하지 않고 다른 요소를 먼저 표시하고 이미지를 나중에 표시하는 기법이다.

1
<img src="example.jpg" loading="lazy" decoding="async" />

CLS(Cumulative Layout Shift)

누적 배치 변경이라고 하며 이미 배치가 끝난 컨텐츠의 위치가 바뀌는 상황이다.

0부터 1까지의 범위를 가지고 있으며 0.1 이내로 단축하는 것이 좋다.

CLS 유발 요인

  1. 치수를 알 수 없는 이미지 로딩.
  2. 동적으로 추가된 DOM.
  3. 웹 폰트 swap 페인팅(FOIT/FOUT)

CLS 해결방법

  1. 자리표시자
    동적으로 추가하는 컨텐츠에 들어올 영역에 자리 표시자를 미리 띄워놓고 이미지가 들어오지 않더라도 그 영역을 다른 요소가 침범하지 않도록 막아놓는다.

    • 최소크기를 지정하기

    이미지나 영상이 로딩될 영역의 최소크기를 지정한다.

    1
    2
    3
    4
    .heroBanner {
    min-height: 100px;
    background: silver;
    }
  2. 이미지/ 영상 요소에 비율 힌트 제공

    • img태그에 width와 height값의 비율을 제공하기
      css로 이미지의 크기를 설정할 수 있다고 하더라도 img 태그에 제공 해주는 것이 좋다.
    1
    2
    <img src="..." width="800" height="534" alt />
    <!-- + max-width:100%; height:auto; -->
    • aspect-ratio
      aspect-ratio는 비율을 고정하는 속성인데 아직 많이 지원되지는 않는다.

    • 영상 종횡비 유지하기(padding)
      padding 속성에 %를 주어 부모요소를 기준으로 하게 하여 비율을 유지하게 해준다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    .utube {
    position: relative;
    padding-top: 56.25%;
    }
    .utube__iframe {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    }
  3. 웹폰트 대체 글꼴 지정하기

텍스트 영역의 높이가 늘어나면서 CLS가 발생한다.
비슷한 특징을 갖는 대체 글꼴을 사용하여 바뀌지 않도록 해야한다.

1
2
3
* {
font-family: "Noto Sans KR", Verdana, sans-serif;
}
  1. 애니메이션 적용 시 transform 사용.

reset,normalize

대부분의 초기화 스타일은 쓸모 없거나 덮어쓰는 코드가 대부분이다.

이는 unusedcss를 증가시킨다.

reset.css 최적화하기

1
2
3
4
5
6
7
8
9
10
11
12
body {
margin: 0;
overflow-wrap: break-word;
}
:lang(ko) {
word-break: keep-all;
}

img {
max-width: 100%;
height: auto;
}

클래스 속성이 들어간 요소들에만 reset.css를 적용한다.

링크

1
2
3
[class]{
...
}

선택자 최적화

선택자를 많이 중첩시키지 않는 것이 중요하다.

댓글