HTML 요소들은 CSS의 영향을 받기 전부터 이미 자신만의 자연스러운 크기를 가지고 있습니다. 가장 직관적인 예가 바로 이미지입니다. 이미지 파일은 그 자체로 크기 정보를 포함하고 있는데, 이를 본질적 크기(intrinsic size)라고 부릅니다. 이 크기는 우리가 CSS로 적용하는 포맷팅이 아니라, 이미지 파일 자체에 의해 결정됩니다.
이미지를 페이지에 배치하고 <img> 태그의 속성이나 CSS를 사용해 너비나 높이를 변경하지 않는다면, 이미지는 자신의 본질적 크기 그대로 화면에 표시됩니다. 아래 예제에서는 이미지 파일에 정의된 실제 크기 범위를 여러분이 눈으로 직접 확인할 수 있도록 테두리(border)를 그려 넣었습니다.
<img
alt="star"
src="https://mdn.github.io/shared-assets/images/examples/big-star.png" />
img {
border: 5px solid darkblue;
}
반면, 텅 빈 <div> 요소는 자기 자신의 크기를 전혀 갖지 않습니다. 만약 HTML에 내용물이 없는 <div>를 추가하고 위의 이미지처럼 테두리를 주게 되면, 화면에는 그저 일직선의 선만 보일 것입니다. 이것은 테두리가 위아래로 겹쳐진(collapsed) 상태로, 이 상자를 벌려서 열어줄 내용물(content)이 없기 때문입니다.
아래 예제를 보면, 이 선(빈 div의 테두리)이 컨테이너의 전체 너비를 차지하고 있는 것을 볼 수 있습니다. <div>는 블록 레벨(block-level) 요소이기 때문이죠. (이제 블록 레벨의 특징은 슬슬 익숙해지셨을 겁니다!) 하지만 내용물이 없기 때문에 높이(블록 방향의 크기)는 0입니다.
<div class="box"></div>
.box {
border: 5px solid darkblue;
}
위 예제의 빈 요소 안에 텍스트를 한 번 추가해 보세요. 내용물이 생기면서 요소의 높이가 내용물에 맞춰 늘어나 테두리가 열리는 것을 볼 수 있을 것입니다. 이것 또한 요소의 본질적 크기(intrinsic size)입니다. 요소의 크기가 그 '내용물(content)'에 의해 결정된 것이죠.
💡 강사의 실무 팁!
내용물이 없으면 높이가 0이 되어 사라지는 현상 때문에 초보자분들이 "어? 분명히div를 넣었는데 화면에 안 보여요!"라며 당황하는 경우가 많습니다. 내용물이 없을 때 박스 형태를 유지하려면 반드시 다음 섹션에서 배울 명시적 크기(extrinsic size), 즉 고정된height나min-height를 주어야 합니다.
물론 우리는 디자인에 맞춰 요소들에 특정한 크기를 부여할 수도 있습니다. 이렇게 요소에 크기를 지정하여 억지로 맞추게 되면(그리고 내용물은 그 지정된 크기 안에 들어가야만 하죠), 이를 명시적 크기(extrinsic size)라고 부릅니다.
다음 예제에서는 두 개의 <div>에 구체적인 width와 height 값을 주었습니다. 이제 이 상자들은 안에 어떤 내용물이 들어가든 무조건 그 크기를 유지하게 됩니다.
오른쪽 <div>를 보면 알 수 있듯이, 억지로 높이를 고정해 버리면 요소 안에 들어갈 내용물이 너무 많을 경우 상자 밖으로 내용물이 넘쳐흐르는 오버플로우(overflow) 현상이 발생할 수 있습니다. (오버플로우를 다루는 방법은 이어지는 다른 레슨에서 더 자세히 배우게 됩니다.)
<div class="wrapper">
<div class="box"></div>
<div class="box">
These boxes both have a height set, this box has content in it which will
need more space than the assigned height, and so we get overflow.
</div>
</div>
body {
font: 1.2em sans-serif;
}
.wrapper {
display: flex;
}
.wrapper > * {
margin: 20px;
}
.box {
border: 5px solid darkblue;
height: 100px;
width: 200px;
}
이렇게 길이(px 등)나 백분율(%)로 요소의 '높이'를 고정해버리면 오버플로우 문제가 발생하기 때문에, 웹 개발을 할 때는 요소의 크기를 고정하는 일을 매우 신중하게 처리해야 합니다.
💡 강사의 실무 팁!
그래서 실무에서는 요소의height를 고정된 픽셀(px)로 지정하는 것을 최대한 지양합니다! 내용물에 따라 상자가 자연스럽게 늘어나도록 내버려 두거나, 정 최소 높이가 필요하다면height대신min-height를 사용하는 것이 반응형 웹(Responsive Web) 디자인의 핵심 원칙입니다.
여러 면에서 백분율(percentages)은 길이 단위와 비슷하게 작동합니다. 값과 단위 레슨에서 설명했듯이, 종종 길이 단위(px, em 등)와 서로 바꿔가며 사용할 수 있죠.
하지만 백분율을 사용할 때는 '무엇의 백분율인가?'를 정확히 알아야 합니다. 다른 컨테이너 안에 들어있는 자식 상자에게 백분율로 width를 주게 되면, 그 크기는 부모 컨테이너 너비의 백분율로 계산됩니다.
<div class="container">
<div class="box">I have a percentage width.</div>
</div>
body {
font: 1.2em sans-serif;
}
.box {
border: 5px solid darkblue;
width: 50%;
}
위의 경우 box 클래스를 가진 <div>가 백분율이 없을 때는 블록 레벨 요소라서 사용 가능한 공간의 100%를 꽉 채우겠지만, 너비를 50%로 주었기 때문에 원래 채울 수 있었던 공간의 절반만 차지하게 됩니다.
위 예제를 이렇게 수정해 보면서 확인해 보세요:
1. box <div>의 width: 50%; 코드를 지워보세요. 기본적으로 100% 너비를 차지하는지 확인할 수 있습니다.
2. 지웠던 width: 50%; 코드를 다시 원래대로 되돌리세요.
3. 이번에는 container <div> (부모 상자)의 width를 50%로 줘보세요. box <div>의 너비가 더 작아지는 것을 볼 수 있을 겁니다. 왜냐하면 이제 줄어든 부모 너비의 50%로 계산되기 때문이죠!
margin이나 padding을 백분율(%)로 설정할 때는 아주 이상한(strange) 현상을 목격하게 될 것입니다.
아래 예제에서 박스 하나에 margin 10%와 padding 10%를 주었습니다. 결과를 보면, 박스의 상/하 패딩과 마진 크기가 좌/우 패딩과 마진 크기와 완벽하게 동일합니다.
<div class="box">I have margin and padding set to 10% on all sides.</div>
body {
font: 1.2em sans-serif;
}
.box {
border: 5px solid darkblue;
width: 200px;
margin: 10%;
padding: 10%;
}
보통 "상/하 마진이나 패딩은 요소 '높이(height)'의 10%가 되고, 좌/우 마진이나 패딩은 요소 '너비(width)'의 10%가 되겠지?"라고 기대하기 쉽습니다. 하지만 절대 그렇지 않습니다!
백분율로 마진과 패딩을 설정하면, 그 값은 부모 컨테이너(containing block)의 가로 크기(inline size, 너비)를 기준으로 계산됩니다! (우리가 사용하는 언어가 가로 쓰기 방식일 때 기준)
즉, 위 예제에서 상하좌우 모든 마진과 패딩은 "부모 너비의 10%"로 동일하게 계산됩니다. 그래서 박스 사방에 완전히 동일한 크기의 여백을 만들 수 있는 것이죠. 백분율을 사용할 때 이 사실을 꼭 기억해 두세요!
💡 강사의 실무 팁! (단골 면접 질문)
"padding-top: 100% 를 주면 크기가 어떻게 되나요?" 이 질문은 프론트엔드 기술 면접에 정말 단골로 나옵니다! 정답은 "부모 요소의 너비와 동일한 크기가 됩니다." 입니다.
과거에는 이 기법(Padding Hack)을 이용해서 유튜브 영상 등을 16:9 비율로 반응형 렌더링할 때 밥 먹듯이 썼었어요. (지금은aspect-ratio라는 좋은 속성이 생겨서 잘 안 쓰지만, 원리는 꼭 알고 계셔야 합니다!)
우리는 요소에 고정된 크기를 주는 것 외에도, CSS를 통해 최소(minimum) 크기나 최대(maximum) 크기를 설정할 수도 있습니다.
예를 들어, 내용물의 양이 계속 변할 수 있는 박스가 있는데, 내용이 적더라도 "최소한 이 정도 높이는 유지했으면 좋겠다" 싶다면 min-height 속성을 사용할 수 있습니다. 이렇게 하면 박스는 항상 최소 높이를 유지하다가, 내용물이 그 최소 높이 공간을 넘어설 만큼 많아지면 내용물에 맞춰 자연스럽게 더 길어집니다.
다음 예제에는 두 개의 박스가 있고, 둘 다 min-height가 100픽셀로 설정되어 있습니다. 왼쪽 박스는 내용물이 적어 딱 100픽셀 높이로 나오지만, 오른쪽 박스는 내용물이 많아 100픽셀 이상의 공간이 필요하기 때문에 100픽셀을 넘어서 쑥 늘어난 것을 볼 수 있습니다.
<div class="wrapper">
<div class="box"></div>
<div class="box">
These boxes both have a min-height set. This box has content in it, which
will need more space than the assigned height, and so it grows from the
minimum.
</div>
</div>
body {
font: 1.2em sans-serif;
}
.wrapper {
display: flex;
align-items: flex-start;
}
.wrapper > * {
margin: 20px;
}
.box {
border: 5px solid darkblue;
min-height: 100px;
width: 200px;
}
이 방법은 양이 불규칙한 내용물을 다룰 때 앞서 본 무서운 오버플로우(overflow) 현상을 피하기 위해 매우매우 유용합니다!
💡 강사의 실무 팁!
실무에서 컨텐츠가 적을 때 웹 페이지 푸터(Footer, 화면 맨 밑 영역)가 붕 뜨는 걸 막기 위해main { min-height: 100vh; }(또는 calc 이용) 방식을 정말 많이 사용합니다. "아무리 내용이 없어도 최소한 화면 높이만큼은 차지해라!" 라는 명령이죠.
max-width on images)max-width가 가장 흔하게 쓰이는 곳은 바로 이미지 축소입니다. 이미지가 가진 본질적 크기(원본 크기)보다 화면 공간이 작을 때 이미지가 화면에 맞게 쪼그라들게 하면서도, 절대 원본 크기보다 더 커지지는 않게(화질이 깨지지 않게) 만들고 싶을 때 사용하죠.
예를 들어, 이미지에 width: 100%를 주면 어떻게 될까요? 만약 이미지를 감싸는 컨테이너가 원본 이미지보다 훨씬 크다면, 이미지가 억지로 100%까지 쫙 늘어나서 화질이 왕창 깨지고 픽셀이 도드라져(pixelated) 보일 것입니다.
하지만 대신 max-width: 100%를 사용하면? 컨테이너가 원본보다 크더라도 이미지는 억지로 늘어나지 않고 선명한 원본 크기를 유지합니다. 반대로 컨테이너가 좁아지면 거기에 맞춰 예쁘게 축소되죠.
아래 예제에는 똑같은 이미지가 세 번 삽입되어 있습니다:
width: 100%가 주어졌습니다. 이미지를 감싸고 있는 컨테이너가 원본 이미지보다 더 넓기 때문에, 컨테이너 너비에 맞추기 위해 강제로 늘어났습니다. 화질이 깨져 보이죠?max-width: 100%가 주어졌습니다. 그래서 컨테이너를 가득 채우기 위해 억지로 찢어지듯 늘어나지 않았습니다.mini-box), 그 안에 max-width: 100%를 가진 이미지를 넣었습니다. 박스 크기에 맞춰 이미지가 얌전하게 축소된 것을 볼 수 있습니다.<div class="wrapper">
<div class="box">
<img
alt="star"
class="width"
src="https://mdn.github.io/shared-assets/images/examples/big-star.png" />
</div>
<div class="box">
<img
alt="star"
class="max"
src="https://mdn.github.io/shared-assets/images/examples/big-star.png" />
</div>
<div class="mini-box">
<img
alt="star"
class="max"
src="https://mdn.github.io/shared-assets/images/examples/big-star.png" />
</div>
</div>
.wrapper {
display: flex;
align-items: flex-start;
}
.wrapper > * {
margin: 20px;
}
.box,
.mini-box {
border: 5px solid darkblue;
}
.box {
width: 200px;
}
.mini-box {
width: 30px;
}
.width {
width: 100%;
}
.max {
max-width: 100%;
}
이 기술은 이미지를 반응형(responsive)으로 만들기 위해 필수적으로 사용됩니다. 화면이 작은 모바일 기기에서 볼 때 이미지가 예쁘게 축소되게 만들어 주거든요.
하지만 주의할 점이 있습니다! 모바일에서 이미지를 축소해서 보여준다고 해서, 애초에 엄청나게 용량이 큰 고화질 이미지를 로드해서 브라우저가 축소하게 만들면 안 됩니다. 디자인에서 필요로 하는 최대 크기에 딱 맞춰서 최적화된 이미지를 사용해야 해요. 무식하게 큰 이미지를 다운로드하게 만들면 웹사이트 속도가 끔찍하게 느려지고, 데이터 요금 폭탄을 맞은 사용자들의 원망을 사게 될 것입니다!
💡 강사의 실무 팁!
실무에서 사용하는 모든 스타일 초기화 파일(Reset CSS)에는 항상 이 코드가 들어갑니다.
img, video { max-width: 100%; height: auto; display: block; }
반응형 웹을 만들기 위한 이미지 세팅의 '성배(Holy Grail)'와도 같은 코드니 눈에 콕 박아두세요!
뷰포트(Viewport)란, 여러분이 웹 사이트를 볼 때 사용하는 브라우저의 '실제로 눈에 보이는 화면 영역'을 뜻합니다. 그리고 이 뷰포트 역시 크기를 가지고 있죠.
CSS에는 이 뷰포트의 크기와 직접적으로 연관된 특별한 단위가 있습니다. 바로 뷰포트 너비(viewport width)를 뜻하는 vw와, 뷰포트 높이(viewport height)를 뜻하는 vh입니다. 이 단위들을 사용하면 사용자의 뷰포트 크기에 비례하여 요소의 크기를 잴 수 있습니다.
1vh는 뷰포트 높이의 1%와 같습니다.1vw는 뷰포트 너비의 1%와 같습니다.이 단위들은 박스 크기를 잡을 때도 유용하지만, 텍스트 크기를 화면에 비례하게 맞출 때도 아주 요긴합니다. 아래 예제에는 20vw 너비와 20vh 높이를 가진 박스가 있습니다. 그리고 그 안에는 알파벳 A가 들어있는데, 글자 크기(font-size)에 10vh를 주었습니다.
<div class="box">A</div>
body {
font-family: sans-serif;
}
.box {
border: 5px solid darkblue;
width: 20vw;
height: 20vh;
font-size: 10vh;
}
이제 여러분이 브라우저 창의 크기를 마우스로 잡고 늘렸다 줄였다 해보세요. vh와 vw 값을 변경하면 박스와 폰트 크기가 바뀌고, 뷰포트 크기를 변경하면 그에 맞춰 박스와 폰트 크기가 실시간으로 고무줄처럼 반응하여 커졌다 작아졌다 할 것입니다!
디자인을 할 때 뷰포트 기준 크기 조절은 꽤 매력적입니다. 예를 들어, 사용자가 스크롤을 내리기 전 맨 처음 화면에 꽉 차는 풀스크린 배너를 띄우고 싶다면, 그 영역의 높이를 100vh로 주면 됩니다. 그러면 브라우저 높이의 100%를 정확히 채우기 때문에, 나머지 내용들은 스크롤을 내려야만 볼 수 있게 깔끔하게 밀려 내려갑니다.
💡 강사의 실무 팁! (고급 기술)
모바일 브라우저(Safari, Chrome 등)에서100vh를 사용하면 맨 밑의 주소창이나 툴바 메뉴 때문에 화면이 가려져서 묘하게 스크롤이 생기는 버그 아닌 버그를 겪게 될 겁니다!
이를 해결하기 위해 최근 CSS에는dvh(동적 뷰포트 높이),svh(최소 뷰포트 높이),lvh(최대 뷰포트 높이) 라는 신규 단위가 추가되었습니다. 실무에서는 모바일 100% 풀화면을 잡을 때height: 100dvh;를 많이 사용한다는 점, 나중에 꼭 기억해 두세요!
이번 레슨에서는 웹에서 사물의 크기를 다룰 때 마주칠 수 있는 핵심적인 개념들을 쭉 훑어보았습니다. 나중에 CSS 레이아웃(CSS Layout)을 본격적으로 다루게 되면, 이 크기 지정 개념들이 다양한 레이아웃 기법을 정복하는 데 아주 중요한 밑거름이 될 것입니다. 그러니 다음 단계로 넘어가기 전에 확실히 이해하고 가는 것이 좋습니다.