AD JB Toolbox 01

CSS 강좌 / 이미지와 동영상 크기·비율 맞추기

이미지와 동영상을 원래 비율로 줄이려면 폭을 제한하고 높이는 자동으로 계산하게 합니다. 썸네일처럼 일정한 표시 비율이 필요하면 aspect-ratio로 영역을 정하고 object-fit으로 원본을 채우거나 전체가 보이게 맞춥니다. 영역의 비율과 그 안에 들어가는 영상의 비율은 서로 다른 값일 수 있습니다.

원본 크기와 화면의 표시 크기 구분하기

원본이 400×300이면 비율은 4:3입니다. 표시 폭이 288px이고 같은 비율을 유지하면 표시 높이는 216px입니다. HTML의 width와 height는 이미지의 크기·비율 정보를 제공하고, CSS는 페이지에서 표시할 크기를 조절합니다. HTML의 크기 속성을 지우는 것으로 문제를 해결하기보다 CSS에서 어떤 값을 덮어쓰는지 확인하세요.

img { max-width: 100%; height: auto; }
/* 폭이 작은 원본을 억지로 키우지 않고 부모에 맞춰 줄입니다. */

max-width: 100%는 부모보다 넓어지는 것을 막는 상한이며 작은 원본을 무조건 늘리지 않습니다. width: 100%는 부모 폭을 채우는 지정이므로 원본보다 확대될 수 있습니다. 사진의 선명도와 다운로드 크기는 별도 문제입니다. CSS로 작게 보여도 큰 파일을 내려받을 수 있고, srcset·sizes를 쓰면 브라우저가 후보 중 이미지를 선택하므로 화면의 표시 크기와 실제 선택된 파일을 구분해서 확인해야 합니다.

aspect-ratio는 크기 계산의 비율을 정하기

aspect-ratio: 16 / 9는 가로 16에 세로 9의 비율을 크기 계산에 사용하게 합니다. 가로가 288px이면 세로는 162px입니다. 적어도 한쪽 크기가 자동이어야 비율에 따른 계산이 가능하며, 폭과 높이를 모두 고정하면 이 속성을 넣어도 그 고정 크기가 우선합니다. MDN의 aspect-ratio 크기 계산 조건도 확인할 수 있습니다.

.thumbnail { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }

Flex 배치의 기본 교차축 늘림은 같은 줄의 이미지 높이를 맞출 수 있습니다. 원본 비율이 다른 이미지를 나란히 놓으면서 높이를 자동으로 계산하려면 부모의 align-items: flex-start나 해당 아이템의 align-self도 함께 확인하세요. 높이만 auto로 바꾼 뒤 비율이 그대로라고 느껴질 때는 부모의 정렬 규칙이 원인일 수 있습니다.

실습에서는 box-sizing을 border-box로 통일합니다. 테두리나 안쪽 여백을 추가하면 크기와 비율을 어느 상자 기준으로 측정하는지도 중요해집니다. 아래 비교 예제의 이미지에는 이를 혼동하지 않도록 테두리와 안쪽 여백을 넣지 않았습니다.

cover와 contain의 차이, 잘리는 위치 정하기

속성값 원본 비율 표시 영역 내용
fill 영역에 맞게 늘어날 수 있음 채움 원본에 따라 왜곡 가능
cover 유지 빈 공간 없이 채움 비율이 다르면 일부가 잘림
contain 유지 전체가 들어가도록 맞춤 비율이 다르면 빈 공간이 남음

4:3 원본을 16:9 영역에 cover로 넣으면 같은 폭 기준에서 위아래가 잘립니다. 가운데 정렬이면 위쪽과 아래쪽을 나누어 자르고, object-position: center top이면 위쪽을 보존하고 아래쪽을 더 자릅니다. 인물의 얼굴이나 제품의 중요한 부분이 가장자리에 있다면 cover를 선택한 뒤 잘리는 위치까지 확인해야 합니다.

다음 그림은 동일한 실습 원본을 원본 비율, cover, contain, 위쪽 정렬 cover로 표시한 결과입니다. 녹색 띠와 붉은 띠가 남는지, 빈 공간이 생기는지를 비교하세요. 가운데 원은 이 예제에서 잘리는 구간을 피하므로 띠가 더 분명한 확인 기준입니다.

같은 4대 3 그림을 원본 비율, 16대 9 cover, contain, 위쪽 정렬 cover로 표시한 비교

전체 예제: 같은 그림으로 네 가지 결과 비교하기

image-ratio.html로 저장해 여세요. 원본 그림을 파일 안에 SVG 데이터로 포함했으므로 외부 이미지는 필요 없습니다. 각 그림의 width와 height 속성은 원본의 400×300 정보를 유지하고, CSS로 화면 크기와 표시 비율을 정합니다.

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>image-ratio.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 65rem); margin-inline: auto; padding: 1rem; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }
.sample { width: min(100%, 18rem); margin: 0; }
.sample img { display: block; width: 100%; height: auto; background: #e2e2e2; }
.sample p { margin: .5rem 0 0; } .cover, .contain { aspect-ratio: 16 / 9; }
.cover { object-fit: cover; } .contain { object-fit: contain; }
.top { object-position: center top; }
</style>
</head>
<body>
<main><h1>같은 그림의 크기와 잘림 비교</h1><div class="gallery"><div class="sample"><img class="" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="위쪽 녹색 띠, 아래쪽 붉은 띠와 가운데 주황색 원"><p>원본 4:3</p></div>
<div class="sample"><img class="cover" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="위쪽 녹색 띠, 아래쪽 붉은 띠와 가운데 주황색 원"><p>16:9 cover, 가운데</p></div>
<div class="sample"><img class="contain" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="위쪽 녹색 띠, 아래쪽 붉은 띠와 가운데 주황색 원"><p>16:9 contain</p></div>
<div class="sample"><img class="cover top" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="위쪽 녹색 띠, 아래쪽 붉은 띠와 가운데 주황색 원"><p>16:9 cover, 위쪽</p></div>
</div></main>
</body>
</html>
  1. 넓은 화면에서 각 그림의 폭이 18rem에 제한되는지 확인합니다. 루트 글꼴 16px에서는 폭 288px이며 원본은 높이 216px, 나머지 16:9 영역은 높이 162px입니다.
  2. .sample img의 height만 300px로 바꿉니다. 16:9 비율이 적용되어도 고정 높이 때문에 영역이 288×300px이 되는 것을 확인한 뒤 auto로 복구합니다.
  3. .gallery의 align-items만 stretch로 바꿉니다. 같은 줄의 래퍼 높이는 같아지지만 래퍼 안의 이미지 비율은 유지되는지 확인하고 flex-start로 되돌립니다. 이 예제에서 Flex 아이템은 이미지가 아닌 sample 래퍼입니다. 이미지를 직접 Flex 아이템으로 놓는 구성에서는 자동 높이가 늘어날 수 있으므로 정렬까지 확인해야 합니다.
  4. .top의 object-position만 center bottom으로 바꿉니다. 이번에는 붉은 띠가 남고 녹색 띠가 잘리는지 확인한 뒤 center top으로 복구합니다.

예제의 SVG는 자체적으로 도형의 비율을 유지하는 특성도 있습니다. 이미지 요소의 표시 영역이 잘못되어 빈 공간이 생겨도 원이 반드시 찌그러지는 것은 아닙니다. 눈으로 도형만 보는 대신 개발자 도구에서 img 요소의 폭과 높이를 함께 확인하세요.

동영상도 표시 영역과 원본 비율을 나누어 지정하기

아래 실습은 이 강의를 위해 만든 400×300 무음 영상을 16:9 영역 안에 contain으로 표시합니다. 영상에는 음성·자막 정보가 없고 주황색 원의 이동만 있어, 위아래 또는 양옆 공간과 재생 조작을 확인하는 데 사용합니다. 실습용 WebM 동영상 파일의 주소를 예제에 넣었습니다. 네트워크가 없는 환경에서는 이 파일을 내려받아 HTML과 같은 폴더에 두고 source 주소를 파일 이름으로 바꾸세요.

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>video-ratio.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 34rem); margin-inline: auto; padding: 1rem; }
video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; background: #111; }
</style>
</head>
<body>
<main><h1>동영상의 표시 비율</h1>
<p id="video-description">파란 바탕에서 주황색 원이 움직이는 무음 실습 영상입니다. 재생 버튼으로 시작하고 일시 정지해 비율을 비교하세요.</p>
<video controls preload="metadata" width="400" height="300" aria-describedby="video-description">
  <source src="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm" type="video/webm">
  <a href="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm">실습 동영상 파일 내려받기</a>
</video></main>
</body>
</html>

controls는 사용자가 재생·정지 등 브라우저 조작을 사용할 수 있게 하고, preload="metadata"는 재생 전에 메타정보를 읽도록 요청하는 힌트입니다. 실제 다운로드 방식은 브라우저가 결정합니다. autoplay를 넣지 않았으므로 재생 버튼을 눌러 확인하세요. object-fit만 cover로 바꾸면 영역은 그대로이고 위아래 내용이 잘리는 차이를 볼 수 있습니다. 확인 후 contain으로 복구합니다.

object-fit은 img·video 같은 대체 요소의 내용을 맞추는 속성입니다. 외부 영상을 넣는 iframe에는 같은 효과가 없으므로 래퍼의 비율을 정하고 iframe이 래퍼를 채우게 만드는 별도 구성이 필요합니다. 음성으로 내용을 전달하는 영상에는 이 무음 예제와 달리 자막 등 필요한 대체 정보를 준비해야 합니다. 적용 범위는 MDN의 object-fit 설명, 재생 속성은 MDN의 video 요소 설명에서 확인할 수 있습니다.

같은 카테고리의 다른 글
CSS 강좌 / 넘치는 콘텐츠와 긴 문자열 처리하기

CSS 강좌 / 넘치는 콘텐츠와 긴 문자열 처리하기

같은 내용에 visible·hidden·auto·scroll을 적용해 넘침 처리를 비교합니다. 긴 URL 줄바꿈과 실제 말줄임표 예제를 실행하고, 원문 보존과 키보드 스크롤을 함께 확인합니다.

CSS 강좌 / ul, ol 가운데 정렬하는 방법

CSS 강좌 / ul, ol 가운데 정렬하는 방법

목록 자체가 아니라 목록 안의 내용만 가운데 정렬할 때는 text-align 속성을 사용합니다. 목록 요소 자체를 가운데 정렬할 때는 margin 속성을 사용합니다. 만약 요소의 내용에 맞게 자동으로 크기가 정해지게 하고 싶으면 display 속성을 사용합니다.

CSS / Tutorial / 마름모 만드는 방법

CSS / Tutorial / 마름모 만드는 방법

CSS로 삼각형을 만들 수 있다면 마름모는 쉽게 만들 수 있습니다. 삼각형을 두 개 붙이면 마름모가 되기 때문입니다. 마름모는 네 변의 길이가 같은 사각형이므로, 이등변삼각형 두 개를 붙이며 됩니다.

CSS 강좌 / 상속(inheritance)

CSS 강좌 / 상속(inheritance)

CSS 속성은 상속하는 속성과 상속하지 않는 속성이 있습니다. 상속하는 속성은 자식 요소에 영향을 미칩니다. 상속하지 않는 속성은 자식 요소에 영향을 미치지 않습니다.

CSS 강좌 / 표와 셀의 크기 조절하기

CSS 강좌 / 표와 셀의 크기 조절하기

표의 자동·고정 레이아웃, 30:70 열 너비, 긴 문자열의 영향을 같은 데이터로 비교합니다. 모바일 가로 스크롤과 키보드 이동을 확인하고 말줄임 원문을 보존하는 방법을 설명합니다.

CSS / Tutorial / 마우스 호버 효과 / 텍스트 나오게 하는 방법

CSS / Tutorial / 마우스 호버 효과 / 텍스트 나오게 하는 방법

CSS로 특정 요소에 마우스를 올렸을 때 보이지 않던 특정 요소가 보이게 할 수 있습니다. 아래는 문단에 마우스를 올렸을 때 div 요소가 나오게 하는 예제입니다. div 요소 안에 텍스트가 있지만, 텍스트가 아닌 이미지 등 다른 것도 가능합니다.

CSS 강좌 / display와 기본 배치 흐름 이해하기

CSS 강좌 / display와 기본 배치 흐름 이해하기

block·inline·inline-block의 줄바꿈과 크기 적용을 같은 요소로 비교합니다. display: none과 visibility: hidden의 공간 차이, 인라인 이미지의 크기 예외를 실행하며 확인합니다.

CSS 강좌 / 유동적인 크기로 반응형 레이아웃 시작하기

CSS 강좌 / 유동적인 크기로 반응형 레이아웃 시작하기

본문의 최대 폭, min()·clamp(), 카드와 이미지의 유동 크기를 비교합니다. 전체 예제와 긴 문자열 실습으로 좁은 공간에서도 내용을 유지하는 방법을 배웁니다.

CSS 강좌 / 작은 학습 사이트를 반응형으로 꾸미는 종합 실습

CSS 강좌 / 작은 학습 사이트를 반응형으로 꾸미는 종합 실습

작은 학습 사이트를 공통 스타일·Flexbox 헤더·유동 제목·Grid 카드 순서로 완성합니다. 전체 파일과 반응형·초점·긴 내용·움직임 감소 점검 방법을 제공합니다.

CSS 강좌 / 큰 스타일시트 정리하기: 파일 구성·중첩·레이어

CSS 강좌 / 큰 스타일시트 정리하기: 파일 구성·중첩·레이어

역할별 CSS 파일 연결과 네이티브 중첩, 캐스케이드 레이어를 실행 가능한 작은 프로젝트로 익힙니다. 선택자 충돌을 비교하고 원래 설정으로 복원하는 실습을 제공합니다.