display: flex는 나란히 놓을 요소들의 부모에 줍니다. 그러면 그 부모의 직계 자식(항목)만 한 줄에 나란히 놓이고, 자식 안에 든 손자는 그대로입니다.
레시피 카드의 요리 이름 h2는 블록이라 한 줄을 통째로 차지하고, 옆에 두고 싶은 배지 '한식'은 그 아래 줄로 밀립니다. 머리글의 사이트 이름과 내비게이션도 두 줄로 쌓입니다. 일반 흐름은 블록을 위에서 아래로 쌓기만 하기 때문입니다.
둘을 한 줄에 두려면 놓는 방식을 바꿔야 합니다. 그 방식이 flex(flexbox — 항목을 한 방향으로 늘어놓고 자리를 나누는 배치)입니다. 그런데 display: flex를 어느 요소에 주느냐에 따라 나란해지는 것이 달라집니다.
이 레슨에서는 flex가 닿는 범위, flex를 줄 요소를 나무에서 고르는 법, 나란히 놓이지 않을 때 찾는 곳을 봅니다.
이 단원을 마치면 레시피 노트의 머리글을 한 줄로, 카드 제목과 배지를 양 끝으로, 후기 폼의 칸 둘을 한 줄로 놓을 수 있습니다. 이 단원(한 줄로 나란히: flex)을 이미 안다면 단원 연습 문제부터 풀고 틀린 레슨만 보세요. 건너뛸지 볼 때는 힌트를 펴지 않고 풉니다.
그림 준비 중
1부모에 display: flex — 직계 자식이 한 줄로
카드의 제목 묶음 div에는 요리 이름 h2와 배지 span이 들어 있습니다. 이 둘을 나란히 놓으려면 둘을 담은 div에 display: flex를 줍니다. 제목의 위아래 바깥 여백은 10단원의 레시피 카드처럼 지워 두었습니다.
<div class="recipe-card-head">
<h2>떡볶이</h2>
<span class="badge">한식</span>
</div>
.recipe-card-head {
display: flex;
}
h2 {
margin: 0;
}.recipe-card-head의 줄 수1.badge의displayblock
이름과 배지가 한 줄에 섰습니다. 잰 값의 '줄 수'는 보이는 자식이 몇 줄에 놓였는지 센 값입니다 — display: flex를 지우면 2입니다.
브라우저 규칙 7. 놓는 방식(일반 흐름 · flex · grid)은 부모가 정하고 직계 자식에게만 닿습니다 — 자식은 그 방식 안에서 제 몫(늘어남 · 차지할 칸)만 정합니다. 부모가
display: flex면 직계 자식이 그 규칙으로 놓입니다.
div·span과 블록·인라인에서 본 앞 절반(일반 흐름에서 블록은 쌓이고 인라인은 흐른다)에 이어지는 문장입니다. grid는 13단원에서 봅니다.
display: flex를 준 부모의 직계 자식을 항목(flex item)이라고 부릅니다. 부모는 자료에 따라 flex 컨테이너(flex container)라고 부릅니다. 인라인이던 배지 span도 항목이 되자 display가 block으로 바뀌었습니다. 항목은 블록 · 인라인이 아니라 부모의 flex 규칙을 따라 놓입니다.
2손자는 그대로 — 나란히 놓을 것들의 부모를 고른다
카드 전체 li에 display: flex를 주면 무엇이 나란해질까요? li의 직계 자식은 제목 묶음 div와 조리 시간 p 둘뿐입니다.
<li class="recipe-card">
<div class="recipe-card-head">
<h2>떡볶이</h2>
<span>한식</span>
</div>
<p>조리 20분</p>
</li>
.recipe-card {
display: flex;
}
.recipe-card h2,
.recipe-card p {
margin: 0;
}.recipe-card의 줄 수1.recipe-card-head의 줄 수2.recipe-card span의displayinline
제목 묶음과 조리 시간은 나란히 섰지만, 묶음 안의 이름과 배지는 그대로 두 줄입니다. 배지는 li의 손자라 li의 flex가 닿지 않고, display도 inline 그대로입니다.
그래서 flex를 줄 요소는 이 차례로 고릅니다.
- 나란히 놓을 요소를 먼저 찾습니다 — 이름
h2와 배지span. - 요소 나무에서 그 둘을 바로 담은 요소를 찾습니다 —
div.recipe-card-head. - 그 요소에
display: flex를 줍니다.
부모 안의 부모에도 따로 줄 수 있습니다. 머리글을 한 줄로 놓고 그 안의 nav도 링크를 한 줄로 놓으려면 header와 nav에 저마다 display: flex를 줍니다. flex가 손자에게 전해진 것이 아니라, 부모 둘이 저마다 제 자식을 놓는 것입니다.
3나란히 놓이지 않을 때 — 찾는 차례 다섯째
브라우저 기본 스타일과 Styles 창의 '안 먹을 때 찾는 차례'를 넷째(알아들었나 · 이겼나)까지 지났는데도 화면이 그대로면, 상자 네 겹에서 더한 다섯째 상자 · 배치를 봅니다. flex가 안 먹을 때 배치에서 볼 곳은 하나입니다 — display: flex를 준 요소가 나란히 놓을 요소들의 부모인가(브라우저 규칙 7).
- Elements 패널에서
display: flex가 든 요소의 줄 끝에는flex라는 작은 표시가 붙습니다. 그 줄을 펼쳐, 바로 한 겹 안의 자식이 나란히 놓을 요소인지 봅니다. - 그 요소를 골라 Computed 창의
display가flex인지 봅니다. 규칙이 졌거나 버려졌으면 여기에 다른 값이 보입니다.
예제
레시피 노트의 머리글입니다. 머리글 header에 display: flex를 줬습니다. 결과 화면을 펴기 전에, 사이트 이름과 링크 둘이 어떻게 놓일지 먼저 적어 보세요.
<header class="site-header">
<a href="index.html">
레시피 노트
</a>
<nav>
<a href="index.html">
레시피 목록
</a>
<a href="kimchi.html">
김치볶음밥
</a>
</nav>
</header>
.site-header {
display: flex;
}
결과 화면 보기
.site-header의 줄 수1.site-header > a의displayblocknav a의displayinline
셋이 한 줄에 섰습니다. 사이트 이름 a와 nav는 머리글의 항목이라 나란히 놓였고, 항목 사이 줄바꿈은 그려지지 않아 둘이 빈틈없이 붙었습니다. nav 안 두 링크는 머리글의 손자라 인라인 그대로 — 그 사이 빈칸 한 칸은 인라인 사이의 줄바꿈이 그린 것입니다.
이름과 내비게이션을 양 끝으로 떼는 일은 주축 정렬에서 합니다.
자주 틀리는 곳
틀린 생각: display: flex를 주면 그 안의 모든 요소가 나란히 놓인다.
flex를 준 요소 안이 모두 가로로 바뀔 것 같습니다(flex가 후손까지라는 생각).
<div class="a">
<div>가</div>
<div class="b">
<div>나</div>
<div>다</div>
</div>
</div>
.a {
display: flex;
}.a의 줄 수1.b의 줄 수2
'가'와 .b는 한 줄에 섰지만, .b 안의 '나' · '다'는 그대로 쌓였습니다.
맞는 규칙: flex는 직계 자식에게만 닿습니다. 손자를 나란히 놓으려면 그 손자의 부모(.b)에도 display: flex를 줍니다(브라우저 규칙 7).
틀린 생각: 나란히 놓을 요소에 저마다 display: flex를 준다.
이름과 배지를 옆으로 보내고 싶으니, 그 둘에게 flex를 주면 될 것 같습니다.
<div class="recipe-card-head">
<h2>떡볶이</h2>
<span class="badge">한식</span>
</div>
h2,
.badge {
display: flex;
}
h2 {
margin: 0;
}.recipe-card-head의 줄 수2.badge의displayflex
이름과 배지는 그대로 두 줄이고, 배지는 오히려 한 줄을 통째로 차지했습니다. flex를 받은 h2와 배지는 제 안의 글을 놓는 부모가 되었을 뿐, 저 자신은 블록처럼 쌓입니다.
맞는 규칙: display: flex는 받은 요소의 자식을 놓습니다. 나란히 놓을 요소들이 아니라 그 둘을 담은 부모에 줍니다(브라우저 규칙 7).
틀린 생각: flex 항목 사이에도 HTML의 줄바꿈이 빈칸 한 칸을 만든다.
인라인 사이의 줄바꿈은 빈칸 한 칸으로 그려지니, 항목 사이도 그럴 것 같습니다.
<div class="tags">
<span>밥</span>
<span>김치</span>
</div>
.tags {
display: flex;
}
.tags span {
width: 40px;
}.tags span:first-child의 오른쪽 끝48px.tags span:last-child의 왼쪽 자리48px
첫 항목이 끝난 자리(48px)에서 둘째 항목이 바로 시작합니다. 둘 사이에 빈칸이 없습니다.
맞는 규칙: 항목 사이처럼 빈칸만 있는 글은 그려지지 않습니다(브라우저 규칙 2). 블록과 인라인 display에서 본 인라인 블록 사이의 틈도 flex로 놓으면 생기지 않습니다. 항목 사이를 띄우려면 부모에 gap을 줍니다(gap과 flex: 1).
확인 문제
1. 예제 CSS의 선택자 .site-header를 nav로 바꿨습니다. 결과 화면에서 사이트 이름과 링크 둘은 어떻게 놓일까요?
<header class="site-header">
<a href="index.html">
레시피 노트
</a>
<nav>
<a href="index.html">
레시피 목록
</a>
<a href="kimchi.html">
김치볶음밥
</a>
</nav>
</header>
nav {
display: flex;
}
- ① 두 줄 — 위에 '레시피 노트', 아래에 링크 둘이 붙어서 한 줄
- ② 한 줄 — 사이트 이름 옆에 링크 둘
- ③ 세 줄 — 사이트 이름, 링크, 링크가 한 줄씩
힌트
이제 display: flex를 받은 요소는 어느 것인지, 그 요소의 직계 자식은 무엇인지 나무에서 찾습니다.
정답
① — 위에 '레시피 노트', 아래 줄에 링크 둘이 붙어서 섭니다.
.site-header의 줄 수2nav의 줄 수1nav a의displayblock
nav의 직계 자식인 링크 둘이 항목이 되어 한 줄에 섰습니다. 항목 사이 줄바꿈은 그려지지 않아 두 링크가 붙었습니다(브라우저 규칙 2).- 머리글은 이제 flex가 아니라 일반 흐름이라, 블록
nav가 사이트 이름 아래 새 줄에서 시작합니다(브라우저 규칙 7). - ②는 flex를 받은
nav자신이 옆으로 간다고 본 것입니다. flex는 받은 요소의 자식을 놓습니다. - ③은 항목의
display가block이 되니 쌓인다고 본 것입니다. 항목은 블록처럼 쌓이지 않고 부모의 flex 규칙으로 놓입니다.
2. 재료 줄의 이름과 양을 한 줄에 놓으려 합니다. ____ 자리에 알맞은 선택자를 쓰세요.
<ul class="ingredient-list">
<li>
<p>밥</p>
<p>2공기</p>
</li>
</ul>
____ {
display: flex;
}
힌트
나란히 놓을 두 요소를 먼저 찾고, 나무에서 그 둘을 바로 담은 요소를 찾습니다.
정답
li — .ingredient-list li로 써도 됩니다.
<ul class="ingredient-list">
<li>
<p>밥</p>
<p>2공기</p>
</li>
</ul>
.ingredient-list li {
display: flex;
}.ingredient-list li의 줄 수1
나란히 놓을 것은 '밥'과 '2공기'의 p 둘이고, 둘을 바로 담은 부모는 li입니다.
.ingredient-list(ul)에 주면 ul의 자식인 li가 항목이 되어, li 안의 두 p는 그대로 쌓입니다. p에 주면 저마다 제 안의 글만 놓습니다.
3. 동아리 공지를 이렇게 썼습니다. 결과 화면에는 어떻게 보일까요?
<div class="notice">
<p>동아리 공지</p>
<ul>
<li>10월 20일</li>
<li>3층 동아리방</li>
</ul>
</div>
.notice {
display: flex;
}
- ① 한 줄 — '동아리 공지 10월 20일 3층 동아리방'
- ② '동아리 공지' 옆에 목록이 서고, 목록의 두 줄은 위아래로
- ③ 그대로 세 줄 — 공지, 날짜, 장소가 위아래로
힌트
나무를 그려 display: flex가 걸린 요소에 표시하고, 요소마다 무엇 안에 드는지 적어 보세요.
힌트 둘
flex는 display: flex를 준 요소의 직계 자식만 나란히 놓습니다. .notice의 직계 자식이 무엇무엇인지 세고, 날짜와 장소는 누구의 자식인지 봅니다.
정답
② — '동아리 공지' 옆에 목록이 서고, 날짜와 장소는 목록 안에서 위아래로 놓입니다.
.notice의 줄 수1ul의 줄 수2
.notice의 항목은p와ul둘이라 둘이 나란히 섭니다. 날짜와 장소의li는ul의 자식, 곧.notice의 손자라 그대로 쌓입니다(브라우저 규칙 7).- ①은 flex가 그 안의 모든 요소를 나란히 놓는다고 본 것입니다(flex가 후손까지라는 생각).
- ③은
display: flex가 블록을 나란히 놓지 못한다고 본 것입니다. 항목은 블록이어도 한 줄에 섭니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
hello.html의 body 안을 2절 카드 코드로 바꾸고, style 요소 안에 2절 CSS를 넣어 저장 · 새로고침합니다. 그다음 .recipe-card 규칙의 display: flex를 손자인 배지에게 줘 봅니다 — 선택자를 .recipe-card span으로 바꿔 저장 · 새로고침하면, 배지만 제 줄을 통째로 차지하고 제목 옆으로 오지 않습니다. 마지막으로 선택자를 .recipe-card-head로 바꾸면 배지가 이름 옆에 섭니다. Elements 패널에서 flex 표시가 붙는 줄도 함께 봅니다.
파일을 만들고 여는 법은 준비: VS Code와 작업 폴더에 있습니다.