이미지 및 미디어가 레이아웃 이동을 일으키는 이유 (및 해결 방법)

이미지, 비디오, iframe, 반응형 이미지 및 미디어 임베드에서 CLS를 방지하기 위한 완벽한 가이드

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-04-08

이미지 및 미디어가 레이아웃 이동을 일으키는 이유 (및 해결 방법)

2025 Web Almanac은 제가 현장에서 계속 보아온 것을 수치로 보여줍니다. 모바일 페이지의 62%가 명시적인 너비(width)와 높이(height)가 없는 이미지를 하나 이상 포함하고 있습니다. 이로 인해 크기가 지정되지 않은 미디어는 웹에서 Cumulative Layout Shift의 가장 큰 원인이 됩니다. 그리고 이러한 이동(shift)은 2019년부터 존재해 온 기술로 모두 예방할 수 있습니다.

마지막 검토: Arjen Karel (2026년 3월)

브라우저는 이미지의 크기를 알지 못합니다

이미지로 인해 발생하는 모든 레이아웃 이동은 한 가지 이유로 귀결됩니다. 이미지가 로드되기 전에 브라우저는 얼마나 많은 공간을 확보해야 하는지 알지 못합니다.

브라우저가 크기가 없는 <img> 태그를 발견하면, 이미지 크기를 알 때까지 멈추지 않습니다. 대신 0x0 픽셀의 공간만 예약합니다. 그런 다음 이미지가 다운로드되면 브라우저가 레이아웃을 다시 계산하고 이미지 아래의 모든 요소가 아래로 밀려납니다. 그 밀려남이 바로 CLS입니다.

width와 height가 레이아웃 이동을 방지하는 방법

레이아웃 이동에 대한 유일한 해결책은 적절한 공간을 예약하는 것입니다. 가장 쉬운 방법은 이미지의 올바른(고유한) 너비와 높이를 설정하는 것입니다. 2019년과 2020년에 모든 주요 브라우저에서 widthheight 속성의 작동 방식을 변경하는 기능이 출시되었습니다. 이제 브라우저는 이미지가 다운로드되기 전에 이 속성을 사용하여 종횡비(aspect ratio)를 계산합니다.

다음과 같이 작성하면:

<img src="hero.jpg" width="800" height="450" alt="설명">

브라우저는 내부적으로 다음을 생성합니다:

img[Attributes Style] {
    aspect-ratio: auto 800 / 450;
}

반응형 이미지의 경우 다음 CSS를 추가합니다:

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

브라우저는 크기를 계산하기 위해 전체 이미지 파일을 다운로드할 필요가 없습니다. 브라우저는 비율을 알고 있으며 수직 공간을 확보합니다. CSS는 컨테이너 안에 맞추는(containment) 최종적인 역할을 합니다. height: auto는 비율에서 높이를 계산합니다. max-width: 100%는 이미지가 컨테이너를 벗어나는 것을 방지합니다.

해결책을 무효화하는 것들

width 및 height 속만 있으면 이미지로 인한 레이아웃 이동을 방지할 수 있습니다. 하지만 크기와 CSS를 설정하더라도 이러한 작업을 무효화하고 이미지에서 레이아웃 이동을 유발하는 몇 가지 일반적인 패턴이 여전히 존재합니다.

CSS에서의 width:auto

이것은 제가 가장 많이 보는 것이자 디버깅 시간을 가장 많이 낭비하는 원인입니다. 개발자는 모든 이미지에 widthheight를 설정하고 HTML에서 모든 것을 올바르게 수행하지만 CSS 파일 어딘가에 이미지에 대한 추가적인 width:auto가 존재합니다.

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

문제는 width: auto입니다. 브라우저의 내부 비율이 CSS 우선순위에서 가장 낮기 때문에, 어떤 규칙이든 이를 덮어씁니다. width: auto는 브라우저가 높이를 계산하는 데 사용하던 너비를 제거합니다. 두 크기 모두 알 수 없게 됩니다. 이미지는 파일이 다운로드되고 최종 크기를 알 때까지 0x0으로 렌더링됩니다.

CSS에서 aspect-ratio를 설정해도 이 문제는 해결되지 않습니다. width: auto가 설정되면 브라우저는 처음에 너비를 0으로 취급합니다. 0에서 계산된 종횡비는 여전히 0x0을 생성합니다.

이 문제를 발견하기 어렵게 만드는 것은 브라우저 캐싱입니다. 이미지가 브라우저 캐시에 있는 경우 실제 크기를 즉시 사용할 수 있으며 이동이 발생하지 않습니다. 저는 수십 개의 클라이언트 사이트에서 이 문제를 디버깅했으며 항상 개발자의 컴퓨터에 캐시되어 있었습니다.

해결 방법:

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

width: auto를 제거하세요. height: automax-width: 100%만 유지하세요. 이것은 web.dev에서 권장하는 패턴입니다.

빠른 확인: 이미지를 마우스 오른쪽 버튼으로 클릭하고 검사한 다음, 계산된 스타일을 살펴보세요. width: auto가 보인다면 그것이 문제입니다. 전체 설명은 자동 크기 조정 이미지로 인한 레이아웃 이동 수정을 참조하세요.

잘못된 이미지 크기

내부적으로 생성된 종횡비가 기억나시나요? 여기서 약간 기술적인 내용이 나옵니다. auto 키워드는 브라우저에게 "이 비율을 자리 표시자로 사용하되, 실제 이미지가 로드되면 실제 크기로 전환하라"고 지시합니다. 잘못된 값을 설정하면(16:9 이미지에 width="4" height="3"), 브라우저는 처음에 4:3 공간을 예약한 다음, 이미지가 로드될 때 16:9로 수정합니다. 그 수정이 바로 레이아웃 이동입니다. 항상 이미지의 실제 픽셀 크기를 사용하세요.

CSS aspect-ratio가 더 나은 선택일 때

width/height 속성이 기본 접근 방식이며 항상 최선의 접근 방식이지만 때로는 CMS에서 이미지 크기를 추가하지 못하게 할 수도 있습니다(생각보다 자주 발생하는 일입니다!). 이 경우 CSS 종횡비를 사용하여 확보할 공간의 크기를 제어할 수 있습니다. 예를 들어, 히어로 이미지에 .hero 클래스가 있는 경우 다음과 같이 공간을 예약할 수 있습니다:

img.hero {
    aspect-ratio: 16 / 9;
    width: 100%;
}

모든 최신 브라우저(Chrome 88+, Firefox 87+, Safari 15+)에서 작동하며 이미지나 비디오뿐만 아니라 모든 요소에 적용할 수 있습니다.

비디오, iframe 및 SVG

비디오

동일한 문제, 동일한 해결책입니다. 비디오 해상도에 맞게 너비와 높이를 설정하세요:

<video src="demo.mp4" width="1280" height="720" autoplay muted loop></video>

CSS에 height: auto; max-width: 100%;를 추가하세요. 한 가지 주의할 점은: 포스터 이미지가 아닌 비디오 해상도에 맞춰 크기를 설정하세요. 둘이 다르면 재생이 시작될 때 이동이 발생합니다.

Iframes

이미지와 달리 iframe은 해당 속성에서 종횡비를 계산하지 않습니다. 명시적인 크기가 없으면 기본적으로 300x150 픽셀로 설정됩니다. 대부분의 임베드에서 이는 잘못된 것입니다. iframe의 경우 다음과 같이 종횡비를 설정하는 것이 가장 좋습니다:

.responsive-iframe {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
}

더 나은 방법은 iframe을 아예 로드하지 않는 것입니다. 저는 수년 전부터 YouTube, Vimeo, Google Maps 및 소셜 임베드의 경우 페이지 로드 시 iframe을 로드하지 않습니다. 올바른 종횡비의 정적 자리 표시자 이미지를 표시하세요. iframe이 표시되어야 할 때 JavaScript가 이를 실제 iframe으로 교체합니다. 이 교체로 인한 이동은 사용자 입력 후 500ms 이내에 발생하며 설계상 CLS에서 제외됩니다.

구현 세부 정보는 완벽한 YouTube 임베드PageSpeed를 잃지 않는 Google Maps를 참조하세요.

SVGs

<img>를 통해 로드된 SVG는 래스터 이미지와 마찬가지로 태그에 너비와 높이가 필요합니다. 인라인 <svg> 요소는 CSS aspect-ratio가 있는 viewBox가 필요합니다. 둘 다 없으면 기본적으로 300x150으로 설정됩니다.

반응형 이미지

모든 srcset 소스에서 동일한 비율 유지

srcset의 모든 이미지는 동일한 종횡비를 공유해야 합니다. 그렇다면 <img>에 하나의 너비/높이 세트만으로 충분합니다:

<img
    src="hero-800.jpg"
    srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1200.jpg 1200w"
    sizes="(max-width: 600px) 100vw, 800px"
    width="800" height="450"
    alt="히어로 이미지">

800:450은 세 가지 변형 모두에서 동일한 비율입니다. 브라우저가 어느 것을 선택하든 예약된 공간은 올바릅니다. 다른 비율이 필요한 경우 대신 <source> 요소와 함께 <picture>를 사용하세요.

아트 디렉션: 브레이크포인트별로 다른 비율

서로 다른 뷰포트 너비에서 다른 크롭을 제공할 때는 <picture> 요소를 사용해야 합니다. 각 <source>widthheight를 설정하세요:

<picture>
    <source
        media="(max-width: 799px)"
        srcset="hero-mobile.jpg"
        width="480" height="600">
    <source
        media="(min-width: 800px)"
        srcset="hero-desktop.jpg"
        width="1200" height="400">
    <img
        src="hero-desktop.jpg"
        width="1200" height="400"
        alt="제품 히어로 이미지">
</picture>

Chrome과 Safari는 활성화된 <source>에서 올바른 크기를 선택합니다. Firefox는 그렇지 않습니다(bug 1694741). 항상 <img>의 폴백(fallback) 크기를 사용합니다. 해결 방법: CSS 미디어 쿼리와 브레이크포인트를 일치시키세요.

picture img {
    width: 100%;
    height: auto;
}
@media (max-width: 799px) {
    picture img {
        aspect-ratio: 480 / 600;
    }
}
@media (min-width: 800px) {
    picture img {
        aspect-ratio: 1200 / 400;
    }
}

모든 크롭이 동일한 비율을 공유한다면 Firefox 버그는 문제가 되지 않습니다.

고정 컨테이너, 캐러셀 및 컨테인먼트(containment)

고정 크기 컨테이너를 위한 object-fit

모든 카드의 높이는 같지만 이미지의 비율이 다른 제품 카드 그리드. 컨테이너를 고정하고 이미지가 이를 채우도록 합니다:

.product-image {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    object-position: center;
}
<img
    src="product.jpg"
    width="400" height="600"
    class="product-image"
    alt="제품명">

이미지가 로드되기 전에 크기가 고정됩니다. 이는 CSS 배경 이미지도 대체합니다. 배경 이미지는 지연 로딩할 수 없고, 프리로드 스캐너가 이를 찾지 못하며, fetchpriority를 사용할 수 없습니다. object-fit: cover가 지정된 <img>는 이러한 모든 제어 기능을 제공합니다.

캐러셀

left, width 또는 margin을 애니메이션하는 슬라이드 전환은 레이아웃 재계산을 트리거합니다. 자동 재생(autoplay)은 사용자 입력이 아니기 때문에 모든 이동이 CLS에 계산됩니다. 고정된 종횡비를 가진 컨테이너로 고정하세요. 대신 transform: translateX()를 사용하여 애니메이션하세요. Transform은 GPU에서 실행되며 레이아웃을 절대 트리거하지 않습니다.

제어할 수 없는 임베드를 위한 컨테인먼트

광고 슬롯, 타사 위젯, 사용자 생성 콘텐츠. 렌더링되는 내용을 제어할 수 없으며 잘라낼(clip) 수도 없습니다. 현실적인 목표는 이동을 제거하는 것이 아니라 최소화하는 것입니다.

공간을 예약하는 것으로 시작하세요:

.ad-slot {
    min-height: 250px;
    contain: layout style;
}

min-height는 큰 효과를 냅니다. 광고가 250px 이하로 로드되면 이동이 없습니다. 300px로 로드되면 0에서 300px로 이동하는 대신 50px만 이동합니다. 그 차이가 중요합니다.

contain: layout은 다른 역할을 합니다. 컨테이너가 커지는 것을 막지는 않습니다. 내부에서 일어나는 일을 격리합니다. 광고 네트워크가 자체 콘텐츠를 리플로우(iframe 크기 조정, 새 요소 주입, 내부 레이아웃 재계산)하는 스크립트를 주입할 때, 이러한 재계산은 컨테이너 내부에 머뭅니다. 컨테인먼트가 없으면 광고 내부의 모든 리플로우가 전체 페이지의 레이아웃 재계산을 트리거합니다. 컨테인먼트가 있으면 브라우저는 상자 외부의 모든 것을 건너뜁니다. 이로 인해 광고가 로드되는 동안 페이지의 응답성이 향상됩니다.

contain: style은 CSS 카운터 및 기타 스타일의 부작용이 외부로 유출되는 것을 방지합니다. 저렴한 보험과도 같습니다.

min-height 값의 경우 광고 제공업체의 가장 일반적인 크리에이티브 크기를 확인하고 노출의 대부분을 커버하는 크기를 선택하세요. 광고의 90%가 250px이고 10%가 300px인 경우 250px로 설정하고 가끔 발생하는 작은 이동은 감수하세요. 300px로 설정하면 더 작은 광고가 로드될 때 페이지 로드의 90%에서 50px의 빈 공간이 축소됩니다. 이 축소 역시 레이아웃 이동입니다.

광고에 대한 완벽한 답은 없습니다. 목표는 가장 많은 페이지 로드에서 가능한 한 가장 작은 이동을 발생시키는 것입니다.

이미지 CLS를 찾는 방법

일반적인 브라우징 조건에서는 이미지 CLS를 발견할 수 없습니다. 브라우저 캐시에 이전 방문의 크기가 이미 있으므로 이동이 발생하지 않습니다. 실제 사용자가 보는 것을 보려면 DevTools(F12)를 열고 네트워크 탭으로 이동하여 "캐시 사용 중지"를 선택하세요. 캐시는 DevTools가 열려 있는 동안에만 비활성화됩니다. 또는 시크릿 창을 사용하세요.

Real User Monitoring

CoreDash 또는 다른 RUM 도구로 시작하세요. CLS 어트리뷰션 데이터는 어떤 요소가 이동했는지 정확히 보여줍니다. CLS로 이동하여 어트리뷰션 요소 표를 확인하세요. 이미지로 필터링하면 레이아웃 이동의 영향을 받는 모든 이미지 요소가 영향도 순으로 정렬되어 표시됩니다.

Chrome DevTools

네트워크 탭에서 캐시를 비활성화하고, Slow 4G로 스로틀링하고, 스크린샷을 활성화하고, 다시 로드하세요. 시각적인 흔들림을 주시하세요. 그런 다음 성능 패널을 열고 "Layout Shift" 항목을 찾으세요. 이동을 클릭하면 노드, 점수, 최근 사용자 입력이 있었는지 여부를 볼 수 있습니다.

Core Web Vitals Visualizer

Core Web Vitals Visualizer 확장 프로그램은 모든 레이아웃 이동을 색상이 있는 오버레이로 강조 표시합니다. 성능 패널을 열기 전 첫 번째 단계로 이것을 사용합니다. 확장 프로그램이 활성화된 상태에서 다시 로드하면 무엇이 움직였는지 정확히 볼 수 있습니다.

빠른 CLS 수정 체크리스트

요소 CLS 원인 해결 방법
<img> width/height 누락 widthheight를 추가하고 CSS에서 height: auto; max-width: 100%;를 사용하세요
<img> 크기를 덮어쓰는 CSS width: auto width: auto를 제거하고 height: auto만 유지하세요
<img> 잘못된 width/height 값 이미지의 실제 픽셀 크기를 사용하세요
<video> width/height 누락 비디오 해상도에 일치하는 widthheight를 추가하세요
<iframe> 기본 300x150 CSS aspect-ratio: 16 / 9; width: 100%; 또는 파사드(facade) 패턴을 사용하세요
<picture> 소스당 다른 비율 (Firefox 버그) <source>에 width/height를 설정하고 CSS 미디어 쿼리 폴백을 추가하세요
<img srcset> srcset에 섞인 비율 모든 소스에 대해 동일한 비율을 사용하고 <img>에 width/height를 설정하세요
JS 지연 로딩(lazy loading) 비율이 잘못된 1x1 자리 표시자 네이티브 loading="lazy"를 사용하거나 자리 표시자 비율을 맞추세요
캐러셀(Carousel) 자동 재생(Autoplay) + 레이아웃을 트리거하는 전환 고정 종횡비 컨테이너; 전환을 위해 transform을 사용하세요
SVG 내장된 크기 없음 <img>에 width/height를 지정하거나 viewBox + CSS aspect-ratio를 사용하세요
광고 슬롯 / 임베드 알 수 없는 크기 min-height + contain: layout style

이미지 CLS에 대한 웹의 현황

2025 Web Almanac 수치:

  • 모바일 페이지의 62%가 크기가 지정되지 않은 이미지를 하나 이상 포함하고 있습니다. 2024년 66%에서 감소했습니다. 여전히 다수입니다.
  • 데스크톱 페이지의 65%가 크기가 지정되지 않은 이미지를 포함하고 있습니다. 69%에서 감소했습니다.
  • p75에서 데스크톱 페이지에는 크기가 지정되지 않은 이미지가 9개, 모바일에는 8개가 있습니다.
  • 크기가 지정되지 않은 이미지의 중앙값 높이: 데스크톱 111px, 모바일 98px. 문단을 이동시키기에 충분합니다.
  • 데스크톱의 72%, 모바일 오리진의 81%가 CLS를 통과했습니다. 2021년 62%에서 증가했습니다.

CLS는 지난 4년 동안 다른 어떤 Core Web Vitals보다 많이 개선되었습니다. 크기가 지정되지 않은 이미지는 여전히 가장 큰 원인입니다. 이 문제 하나만 해결해도 대부분의 사이트에서 레이아웃 이동이 사라집니다.

관련 가이드

About the author

Arjen Karel is a web performance consultant and the creator of CoreDash, a Real User Monitoring platform that tracks Core Web Vitals data across hundreds of sites. He also built the Core Web Vitals Visualizer Chrome extension. He has helped clients achieve passing Core Web Vitals scores on over 925,000 mobile URLs.


CoreDash엔 MCP가 기본 탑재.

Claude든 어떤 AI agent든 바로 연결. 지난주 화요일에 INP가 왜 튀었는지 그냥 물어보세요.

작동 방식 보기

이미지 및 미디어 CLS 관련 자주 묻는 질문

width와 height 속성이 설정되어 있는데도 이미지의 width:auto가 레이아웃 이동을 일으키는 이유는 무엇인가요?

width/height 속성에서 가져온 브라우저의 내부 종횡비는 CSS 우선순위에서 가장 낮습니다. width: auto가 이를 덮어쓰면 두 크기 모두 알 수 없게 됩니다. 이미지는 파일이 다운로드될 때까지 0x0으로 렌더링됩니다. width: auto를 제거하고 height: auto; max-width: 100%;만 유지하세요.

비디오 및 iframe 요소에도 width와 height가 필요한가요?

비디오의 경우 그렇습니다. 메커니즘이 같습니다. iframe은 다릅니다. 속성에서 비율을 계산하지 않으며 기본적으로 300x150으로 설정됩니다. CSS aspect-ratio 또는 파사드(facade) 패턴을 사용하세요.

브레이크포인트마다 종횡비가 다를 때 picture 요소의 CLS를 어떻게 방지하나요?

<source>에 width와 height를 설정하세요. Chrome과 Safari는 올바른 크기를 사용합니다. Firefox에는 항상 <img> 폴백을 사용하는 버그가 있습니다. 해결 방법으로 브레이크포인트에 맞는 올바른 aspect-ratio를 가진 CSS 미디어 쿼리를 추가하세요.

지연 로딩(lazy loading)이 레이아웃 이동을 유발하나요?

이미지에 width와 height 속성이 있다면 유발하지 않습니다. 하지만 스크롤 전 보이는(above-the-fold) 이미지를 지연 로딩하면 아무런 이점 없이 LCP가 지연됩니다. 초기 뷰포트 내의 이미지에는 loading="lazy"를 절대 사용하지 마세요.

Lighthouse에서는 양호한 CLS를 표시하는데 내 필드 데이터에는 레이아웃 이동이 표시되는 이유는 무엇인가요?

Lighthouse는 웜 브라우저(warm browser)와 빠른 네트워크 환경에서 실행됩니다. 계산된 CSS 스타일이 아닌 HTML 속성을 확인하기 때문에 width: auto 문제를 발견하지 못합니다. 항상 CrUX의 필드 데이터나 CoreDash와 같은 RUM 도구를 사용하여 CLS를 확인하세요.

이미지 및 미디어가 레이아웃 이동을 일으키는 이유 (및 해결 방법)Core Web Vitals 이미지 및 미디어가 레이아웃 이동을 일으키는 이유 (및 해결 방법)