[실무 기록] 렌더링 차단(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로는 크게 안 바뀜

preload가 보통 이득 보는 곳
- "곧 필요할 리소스"를 head에서 먼저 다운로드하도록 힌트를 줌
- 잘 맞으면 FCP / LCP / SI 개선 여지가 큼
- 단, preload는 스펙을 제대로 맞춰야 한다(특히
as,crossorigin)
비동기 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이 빠지면 연결 재사용이 잘 안 될 수 있다.
그래서 보통 이렇게 권장한다.
<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도 맞춰야 함
지금 쓰는 패턴들: 차이 / 언제 쓰면 좋은지 / 단점(특히 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” 글에서 대표적으로 다룬다.
장점
- "비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 탭에서 확인하는 게 좋다.
또 폰트는 display=swap 때문에 텍스트가 빨리 보이는 대신, 폰트가 늦게 오면 글자 폭/줄높이가 바뀌면서 CLS가 생길 수 있다.
- CLS 원인/대응: https://web.dev/articles/optimize-cls
"그럼 실무에서 어떻게 하라는 건데" (내 기준 체크리스트)
preconnect
- 초반에 바로 필요한 외부 도메인만(보통 1~3개)
- 폰트 도메인은
crossorigin포함
preload
- LCP 후보(히어로 이미지/폰트/핵심 CSS)가 늦게 발견되는 구조면 효과가 큼
- 무조건 많이 거는 게 아니라 "진짜 빨리 필요하고 큰 것"만
- 타입(
as)과 CORS(crossorigin)는 스펙대로 정확히
비동기 CSS는 "비 critical만"
- web.dev도 목표를 "critical은 유지, non‑critical만 defer"로 잡고 설명한다.
- 첫 화면 레이아웃/타이포에 걸린 CSS를 늦추면 CLS가 늘 가능성 높음
적용 후 "진짜 좋아졌나" 확인 방법
- Lighthouse Opportunities에서 render‑blocking 리소스가 실제로 FCP에 영향을 주는지 확인
- Network 탭에서
- preload가 중복 요청을 만들지
- preconnect 남발로 연결이 과하게 열리지 않는지
- CLS 디버깅
- "늦게 적용된 CSS/폰트 때문에 화면이 흔들리는지"를 먼저 잡아야 함
- Layout shift 디버깅 문서: https://web.dev/articles/debug-layout-shifts
참고 링크(공식 문서 위주)
- Eliminate render‑blocking resources (Chrome/Lighthouse)
- Defer non‑critical CSS (web.dev)
- Resource hints (preconnect/dns-prefetch/preload) (web.dev)
- rel=preload (MDN)
- dns-prefetch / preconnect 주의점(crossorigin 관련) (MDN)
- FCP / LCP / TBT / CLS (web.dev)
- Speed Index (Chrome)
'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 |
