[실무 기록] 렌더링 차단(Render‑blocking) 줄이려고 preconnect / preload를 썼는데… 진짜 뭐가 좋아지나?

2026. 3. 6. 00:14·FrontEnd/web

[실무 기록] 렌더링 차단(Render‑blocking) 줄이려고 preconnect / preload를 썼는데… 진짜 뭐가 좋아지나?

Lighthouse 돌리면 가끔 꼭 뜨는 애들이 있다.

  • Eliminate render‑blocking resources
    (참고: Chrome 공식 문서) → https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources
  • Preconnect to required origins
    (리소스 힌트 개념) → https://web.dev/learn/performance/resource-hints

대충 "CSS가 렌더링 막고 있어요" "외부 도메인 연결을 미리 하세요" 이런 뜻인데, 막상 적용하려고 보면 헷갈린다.

  • preconnect는 정확히 뭘 미리 하는 거지?
  • preload는 그냥 빨리 받는 거 맞나?
  • 비동기 CSS 로딩하면 좋다는데, 왜 CLS가 늘 수 있다는 거지?

오늘은 이걸 지표(FCP/LCP/TBT/SI/CLS) 까지 연결해서 정리해본다.

 

그리고 한줄요약.

  • FCP: "첫 콘텐츠(텍스트/이미지 등)가 화면에 처음 찍히는 순간."
  • LCP: "첫 화면에서 제일 큰 콘텐츠(대개 히어로 이미지/큰 제목)가 다 그려진 순간."
  • SI: "화면이 얼마나 빨리 ‘채워져 보이는지’를 점수로 본 것."
  • TBT: "JS 같은 긴 작업 때문에 클릭/스크롤이 막혀 있던 시간의 합."
  • CLS: "로딩 중 요소가 툭툭 밀리며 레이아웃이 흔들린 정도."
  • render-blocking(CSS): "CSS가 준비되기 전엔 화면을 못 그려서, 첫 화면(FCP/LCP)이 늦어지는 현상."
  • preconnect: "외부 도메인(DNS/TCP/TLS) 연결을 미리 열어놔서, 나중 요청이 덜 기다리게 하는 것(주로 FCP/LCP/SI에 도움)."
  • preload: "곧 쓸 리소스를 ‘이거 먼저 받아’라고 선언해서 다운로드를 앞당기는 것(주로 FCP/LCP/SI에 도움)."
  • 비동기 CSS 로딩(preload+onload / media=print): "CSS 적용을 뒤로 미뤄 렌더 차단을 피하는 꼼수인데, 늦게 적용되면 화면이 바뀌어 CLS가 늘 수 있음."

 


결론부터: preconnect / preload가 "어느 지표에" 좋은가

먼저 지표 정의는 공식 문서 링크를 걸어두고 시작.

  • FCP(First Contentful Paint) 설명 → https://web.dev/articles/fcp
  • LCP(Largest Contentful Paint) 설명 → https://web.dev/articles/lcp
  • TBT(Total Blocking Time) 설명 → https://web.dev/articles/tbt
  • SI(Speed Index) 설명(Chrome 공식) → https://developer.chrome.com/docs/lighthouse/performance/speed-index
  • CLS(Cumulative Layout Shift) 설명 → https://web.dev/articles/cls

그리고 실무적으로 정리하면 이렇다.

preconnect가 보통 이득 보는 곳

  • 외부 도메인 연결(DNS/TCP/TLS)을 미리 해서 "대기시간"을 줄임
  • 그래서 대체로 FCP / LCP / SI에 유리한 편
  • TBT는 주로 JS 긴 작업이 원인이라 preconnect로는 크게 안 바뀜

출처:https://web.dev/articles/preconnect-and-dns-prefetch?hl=ko

preload가 보통 이득 보는 곳

  • "곧 필요할 리소스"를 head에서 먼저 다운로드하도록 힌트를 줌
  • 잘 맞으면 FCP / LCP / SI 개선 여지가 큼
  • 단, preload는 스펙을 제대로 맞춰야 한다(특히 as, crossorigin)
    • MDN 공식 문서: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload

비동기 CSS 로딩 트릭은 양날의 검

  • 렌더링 차단을 회피해서 FCP가 좋아질 수 있음
  • 대신 CSS 적용이 늦어지면 "스타일이 나중에 붙으면서 화면이 움직여" CLS가 늘 수 있음
  • CLS 최적화 가이드: https://web.dev/articles/optimize-cls

렌더링 차단(Render‑blocking)이 왜 생기냐

Chrome 문서에서 딱 한 줄로 정리해준다.

  • render‑blocking audit 설명: https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources

특히 CSS는 기본적으로 렌더링을 막는다. 그래서 <link rel="stylesheet">가 무거우면 첫 화면이 느려진다.

비critical CSS를 늦추는 방법은 web.dev에 패턴별로 정리돼 있음.

  • Defer non‑critical CSS: https://web.dev/articles/defer-non-critical-css

preconnect: "연결을 미리 따두는" 힌트

내가 이해한 방식은 이거다.

"어차피 저 도메인에서 받을 건데 DNS/TCP/TLS handshake 미리 좀 해둘게."

 

개념 정리는 여기서 제일 깔끔하다.

  • Resource hints (web.dev): https://web.dev/learn/performance/resource-hints

폰트는 crossorigin이 중요함 (진짜 자주 놓침)

질문에 준 코드:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com">

폰트 같은 리소스는 "anonymous mode / CORS" 케이스가 엮일 수 있어서 crossorigin이 빠지면 연결 재사용이 잘 안 될 수 있다.

  • MDN 가이드: https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/dns-prefetch

그래서 보통 이렇게 권장한다.

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

preload: "이 리소스, 곧 필요하니까 먼저 받아둬"

preload는 역할이 더 직관적이다.

  • head에서 "이거 곧 쓸 거야"라고 브라우저에 선언해서
  • 렌더링 파이프라인보다 먼저 다운로드/캐시에 태워놓는 개념

MDN이 이걸 꽤 자세히 정리해 둠. (예시 포함)

  • rel=preload (MDN): https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload

여기서 제일 중요한 포인트는:

  • as="style", as="font" 같은 타입을 정확히 써야 함
  • 폰트처럼 CORS가 필요한 리소스는 crossorigin도 맞춰야 함
    • link 요소 참고: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link

지금 쓰는 패턴들: 차이 / 언제 쓰면 좋은지 / 단점(특히 CLS)

질문에 준 코드가 3종류라서, 실무 관점으로 나눠서 정리해본다.


1) preload + onload로 rel=stylesheet 바꾸기 (비동기 CSS)

<link 
    rel="preload" 
    href="style.css" 
    as="style"
    onload="this.onload=null;this.rel='stylesheet'"
>
<noscript><link rel="stylesheet" href="style.css"></noscript>

이 패턴은 web.dev “non‑critical CSS defer” 글에서 대표적으로 다룬다.

  • https://web.dev/articles/defer-non-critical-css

장점

  • "비critical CSS"라면 렌더링 차단을 줄여서 FCP 개선에 도움이 될 수 있음

단점 (여기서 CLS가 터진다)

  • CSS 적용이 "나중에" 되면, 화면이 처음에는 기본 스타일로 보이다가 뒤늦게 스타일이 붙으면서 요소 위치/높이가 변할 수 있음
  • 그 변동이 곧 CLS로 잡힌다.
    • CLS 설명: https://web.dev/articles/cls
    • CLS 최적화: https://web.dev/articles/optimize-cls

그래서 내 결론:

  • 이 패턴은 "아래쪽 섹션 / 탭 / 모달 / 부가 UI" 같이 비critical에만 쓰는 게 안전하다.
  • 헤더/히어로/첫 화면 레이아웃을 결정하는 CSS에 쓰면 CLS가 늘 확률이 높다.

2) media="print" → onload에 media="all" (비동기 stylesheet)

<link rel="stylesheet" href="...owl.carousel.min.css" media="print" onload="this.media='all'">

이것도 결국 "초기 렌더링 차단"을 피하려는 변형이다.

  • 스타일 적용이 늦어지면 FOUC/레이아웃 변동이 생길 수 있고
  • 그 결과 CLS로 이어질 수 있다.
    • CLS 최적화 문서: https://web.dev/articles/optimize-cls

3) Google Fonts에 preload + stylesheet를 같이 걸기 (중복/우선순위 점검 필요)

<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?...&display=swap">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?...&display=swap">

이 조합은 "의도는 좋은데" 실무에서 네트워크 중복/우선순위 경쟁이 생길 수 있어서 꼭 Network 탭에서 확인하는 게 좋다.

  • MDN preload 문서: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload

또 폰트는 display=swap 때문에 텍스트가 빨리 보이는 대신, 폰트가 늦게 오면 글자 폭/줄높이가 바뀌면서 CLS가 생길 수 있다.

  • CLS 원인/대응: https://web.dev/articles/optimize-cls

"그럼 실무에서 어떻게 하라는 건데" (내 기준 체크리스트)

preconnect

  • 초반에 바로 필요한 외부 도메인만(보통 1~3개)
  • 폰트 도메인은 crossorigin 포함
    • https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/dns-prefetch

preload

  • LCP 후보(히어로 이미지/폰트/핵심 CSS)가 늦게 발견되는 구조면 효과가 큼
  • 무조건 많이 거는 게 아니라 "진짜 빨리 필요하고 큰 것"만
  • 타입(as)과 CORS(crossorigin)는 스펙대로 정확히
    • https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload

비동기 CSS는 "비 critical만"

  • web.dev도 목표를 "critical은 유지, non‑critical만 defer"로 잡고 설명한다.
    • https://web.dev/articles/defer-non-critical-css
  • 첫 화면 레이아웃/타이포에 걸린 CSS를 늦추면 CLS가 늘 가능성 높음
    • https://web.dev/articles/optimize-cls

적용 후 "진짜 좋아졌나" 확인 방법

  1. Lighthouse Opportunities에서 render‑blocking 리소스가 실제로 FCP에 영향을 주는지 확인
    • https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources
  1. Network 탭에서
    • preload가 중복 요청을 만들지
    • preconnect 남발로 연결이 과하게 열리지 않는지
  1. CLS 디버깅
    • "늦게 적용된 CSS/폰트 때문에 화면이 흔들리는지"를 먼저 잡아야 함
    • Layout shift 디버깅 문서: https://web.dev/articles/debug-layout-shifts

참고 링크(공식 문서 위주)

  • Eliminate render‑blocking resources (Chrome/Lighthouse)
    • https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources
  • Defer non‑critical CSS (web.dev)
    • https://web.dev/articles/defer-non-critical-css
  • Resource hints (preconnect/dns-prefetch/preload) (web.dev)
    • https://web.dev/learn/performance/resource-hints
  • rel=preload (MDN)
    • https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload
  • dns-prefetch / preconnect 주의점(crossorigin 관련) (MDN)
    • https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/dns-prefetch
  • FCP / LCP / TBT / CLS (web.dev)
    • https://web.dev/articles/fcp
    • https://web.dev/articles/lcp
    • https://web.dev/articles/tbt
    • https://web.dev/articles/cls
  • Speed Index (Chrome)
    • https://developer.chrome.com/docs/lighthouse/performance/speed-index
저작자표시 비영리 변경금지 (새창열림)

'FrontEnd > web' 카테고리의 다른 글

브라우저 리소스 요청 과 캐싱 프로세스 흐름  (0) 2026.03.10
[실무 기록] 브라우저 캐시와 CORS 에러  (0) 2026.03.06
[실무 기록] (2탄) macOS에서 adb가 "개발자 신원을 확인할 수 없습니다"로 막혀 Chrome Inspect가 또 안 될 때  (0) 2026.03.05
[실무 기록] <link rel="stylesheet">로 CSS 불러오는데 간헐적으로 CORS 에러가 나던 이유 (해결: crossorigin 제거)  (1) 2026.01.13
[실무 기록] Chrome Inspect에서 Pending authentication만 뜨고 안드로이드 디버깅이 안 될 때  (0) 2026.01.12
'FrontEnd/web' 카테고리의 다른 글
  • 브라우저 리소스 요청 과 캐싱 프로세스 흐름
  • [실무 기록] 브라우저 캐시와 CORS 에러
  • [실무 기록] (2탄) macOS에서 adb가 "개발자 신원을 확인할 수 없습니다"로 막혀 Chrome Inspect가 또 안 될 때
  • [실무 기록] <link rel="stylesheet">로 CSS 불러오는데 간헐적으로 CORS 에러가 나던 이유 (해결: crossorigin 제거)
프론트엔드 개발자 jbeat
프론트엔드 개발자 jbeat
프론트엔드 개발자 블로그인데 일상도 쪼그으믐
  • 프론트엔드 개발자 jbeat
    jbeat 님의 블로그
    프론트엔드 개발자 jbeat
  • 전체
    오늘
    어제
    • 분류 전체보기 (44)
      • FrontEnd (43)
        • TypeScript (6)
        • JavaScript (18)
        • Next.js (3)
        • React (1)
        • Testing (2)
        • Third Party (1)
        • web (10)
        • Tooling (1)
        • coding test (0)
        • A.I (1)
      • 일상 (1)
        • wedding (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    이터러블
    타입스크립트
    yjs
    playwright
    WebSocket
    배열
    Android
    omit
    컬렉션
    고차함수
    preconnect
    CrossOrigin
    pick
    TypeScript
    Next.js
    javascript
    코테
    주니어
    CRDT
    Utility
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
프론트엔드 개발자 jbeat
[실무 기록] 렌더링 차단(Render‑blocking) 줄이려고 preconnect / preload를 썼는데… 진짜 뭐가 좋아지나?
상단으로

티스토리툴바