flex에서 항목이 늘어서는 방향을 주축(main axis), 그와 직각인 방향을 교차축(cross axis)이라고 부릅니다. flex-direction으로 늘어서는 방향을 바꾸면 두 축이 함께 돌고, 축을 따라 자리를 정하는 정렬 속성의 방향도 함께 바뀝니다.
라벨과 입력 칸은 가로보다 위아래로 놓는 편이 읽기 쉽습니다. flex로 항목을 세로로 세울 수 있는데, 그다음 가운데로 모으려고 하면 엉뚱한 방향으로 움직이기 쉽습니다. 정렬 속성은 가로 · 세로가 아니라 축을 맡기 때문입니다.
이 레슨에서는 늘어서는 방향을 정하는 flex-direction, 정렬 속성이 맡는 축, 보이는 차례만 바꾸는 값을 봅니다.
그림 준비 중
1주축은 항목이 늘어서는 방향 — flex-direction
flex-direction을 적지 않으면 처음 값 row라, 항목이 왼쪽에서 오른쪽으로 늘어섭니다. column이면 위에서 아래로 늘어섭니다.
<div class="box">
<div>가</div>
<div>나</div>
<div>다</div>
</div>
.box {
display: flex;
flex-direction: column;
}
.box div {
width: 40px;
height: 40px;
}.box의flex-directioncolumn.box의 줄 수3
세 항목이 세 줄로 섰습니다. 블록이 쌓인 것과 모양은 같지만, 이제 셋은 flex 항목이라 주축을 따라 자리를 나눠 받습니다.
flex-direction | 늘어서는 방향 | 주축 | 교차축 |
|---|---|---|---|
row(처음 값) | 왼쪽 → 오른쪽 | 가로 | 세로 |
column | 위 → 아래 | 세로 | 가로 |
row-reverse | 오른쪽 → 왼쪽 | 가로 | 세로 |
column-reverse | 아래 → 위 | 세로 | 가로 |
row-reverse · column-reverse는 보이는 차례만 거꾸로 그립니다. 항목 하나의 자리를 옮기는 order도 같습니다. 요소 나무의 차례는 그대로라, 화면 읽기 프로그램이 읽는 차례와 Tab이 옮겨 가는 차례도 HTML 차례 그대로입니다(키보드로 다니기). 그래서 이 과목은 보이는 차례가 필요하면 HTML 차례부터 맞춥니다.
2정렬 이름은 축을 따라간다
정렬 속성 둘은 저마다 한 축을 맡습니다. justify-content는 주축, align-items는 교차축에서 항목의 자리를 정합니다. 값은 다음 두 레슨에서 하나씩 보고, 여기서는 center(가운데)만 씁니다.
| 속성 | 맡는 축 | row | column |
|---|---|---|---|
justify-content | 주축 | 가로 | 세로 |
align-items | 교차축 | 세로 | 가로 |
column으로 세운 항목을 가로 가운데로 모으려면, 가로가 교차축이니 align-items를 씁니다.
<div class="box">
<div>가</div>
<div>나</div>
<div>다</div>
</div>
.box {
display: flex;
flex-direction: column;
align-items: center;
width: 200px;
height: 160px;
}
.box div {
width: 40px;
height: 40px;
}.box div의 왼쪽 자리88px.box div의 위 자리8px
'가'가 너비 200px 상자의 가로 가운데(왼쪽에서 80px)로 왔고, 위 자리는 그대로입니다. 같은 자리에 justify-content: center를 쓰면 주축인 세로로 움직입니다.
주축으로 움직이려면 그 방향에 남는 자리가 있어야 합니다. 이 상자는 높이가 160px이고 항목 셋이 120px이라 세로로 40px이 남습니다. 높이를 정하지 않으면 상자가 항목 높이만큼만 커져 세로로 남는 자리가 없습니다.
예제
후기 폼의 이름 칸입니다. 라벨 아래에 입력 칸이 오도록 묶음 .field를 column으로 세웠습니다.
<div class="field">
<label for="nick">이름</label>
<input
id="nick"
name="nick"
/>
</div>
.field {
display: flex;
flex-direction: column;
width: 240px;
}.field의 줄 수2label의displayblockinput의 너비240px
라벨과 입력 칸이 두 줄로 섰습니다. 입력 칸은 너비를 적지 않았는데 묶음 너비 240px만큼 늘었습니다 — column에서는 가로가 교차축이고, 교차축 정렬의 처음 값이 항목을 그 축으로 늘이기 때문입니다. 이 늘이기는 교차축 정렬에서 봅니다.
자주 틀리는 곳
틀린 생각: justify-content는 가로, align-items는 세로를 맡는다.
row에서 늘 그렇게 쓰다 보면, 이름 자체가 가로 · 세로를 뜻한다고 외우게 됩니다.
<nav>
<a href="index.html">
레시피 목록
</a>
<a href="kimchi.html">
김치볶음밥
</a>
</nav>
nav {
display: flex;
flex-direction: column;
align-items: center;
height: 120px;
}nav a의 위 자리8px
세로 가운데로 내리려고 align-items: center를 줬는데, 링크는 위 끝(8px)에 그대로이고 가로 가운데로 갔습니다.
맞는 규칙: 정렬 속성은 축을 맡습니다 — justify-content는 주축, align-items는 교차축. column이면 주축이 세로라, 세로 가운데는 justify-content: center입니다(브라우저 규칙 7).
틀린 생각: column에서 justify-content: center를 주면 언제나 세로 가운데로 온다.
예제의 이름 칸에 justify-content: center를 더해 봅니다.
<div class="field">
<label for="nick">이름</label>
<input
id="nick"
name="nick"
/>
</div>
.field {
display: flex;
flex-direction: column;
justify-content: center;
width: 240px;
}label의 위 자리8px
라벨은 맨 위(8px) 그대로입니다. 묶음 높이를 정하지 않아 묶음이 두 항목 높이만큼만 커졌고, 세로로 나눌 자리가 없습니다.
맞는 규칙: 정렬은 남는 자리를 옮기는 일입니다. column에서 세로로 움직이려면 부모에 항목보다 큰 높이가 있어야 합니다.
틀린 생각: row-reverse로 뒤집으면 HTML 차례도 바뀐다.
화면에 '다음'이 왼쪽, '이전'이 오른쪽으로 보이니, 키보드도 그 차례로 옮겨 갈 것 같습니다.
<div class="pager">
<a href="japchae.html">이전</a>
<a href="kimchi.html">다음</a>
</div>
.pager {
display: flex;
flex-direction: row-reverse;
width: 200px;
}.pager a의 오른쪽 끝208px- 지금 포커스의 읽는 이름이전
'이전'은 상자 오른쪽 끝(208px)에 그려졌지만, Tab을 한 번 누르면 '이전'으로 갑니다. 눈은 왼쪽에서 오른쪽으로 '다음 → 이전'을 읽는데, 포커스는 '이전'에서 '다음'으로 — 오른쪽에서 왼쪽으로 거꾸로 움직입니다.
맞는 규칙: row-reverse · column-reverse · order는 그리는 차례만 바꿉니다. 읽는 차례와 Tab 차례는 나무의 차례(HTML 차례) 그대로라, 보이는 차례가 필요하면 HTML 차례를 바꿉니다(브라우저 규칙 2 · 3).
확인 문제
1. 예제 CSS에서 .field의 width: 240px을 width: 160px로 바꿨습니다. 입력 칸의 너비는 얼마가 될까요?
<div class="field">
<label for="nick">이름</label>
<input
id="nick"
name="nick"
/>
</div>
.field {
display: flex;
flex-direction: column;
width: 160px;
}
- ① 160px
- ② 240px 그대로
- ③ 라벨의 너비만큼
힌트
column에서 교차축은 어느 방향인지 먼저 적고, 입력 칸이 그 방향으로 무엇에 맞춰 늘었는지 봅니다.
정답
① 160px
input의 너비160px
column에서 교차축은 가로입니다. 입력 칸은 처음 값의 늘이기로 교차축, 곧 가로로 묶음 너비만큼 늘어납니다. 묶음이 160px이면 입력 칸도 160px입니다(브라우저 규칙 7).- ②는 240px이 입력 칸에 적힌 값이라고 본 것입니다. 240px은 묶음의 너비였습니다.
- ③은 라벨과 같은 줄에 맞춰진다고 본 것입니다. 라벨과 입력 칸은 다른 줄의 항목이고, 둘 다 묶음 너비에 맞춰집니다.
2. 후기 폼의 별점 칸도 라벨 아래에 고르는 칸이 오게 하려 합니다. ____ 자리에 알맞은 값을 쓰세요.
<div class="field">
<label for="star">별점</label>
<select id="star" name="star">
<option>5</option>
<option>4</option>
</select>
</div>
.field {
display: flex;
flex-direction: ____;
}
힌트
항목이 늘어설 방향을 먼저 정하고, 그 방향의 값 이름을 표에서 찾습니다.
정답
column
.field {
display: flex;
flex-direction: column;
}위에서 아래로 늘어서는 값은 column입니다. row(처음 값)면 라벨 옆에 고르는 칸이 섭니다.
3. 여행 일정 링크 셋을 이렇게 놓았습니다. 결과 화면에서 왼쪽부터 무엇이 보이고, Tab을 처음 누르면 어느 링크로 갈까요?
<div class="trip">
<a href="day1.html">1일</a>
<a href="day2.html">2일</a>
<a href="day3.html">3일</a>
</div>
.trip {
display: flex;
flex-direction: row-reverse;
width: 200px;
}
- ① '3일 2일 1일'로 보이고,
Tab은 '1일'로 간다 - ② '3일 2일 1일'로 보이고,
Tab은 '3일'로 간다 - ③ '1일 2일 3일'로 보이고,
Tab은 '1일'로 간다
힌트
그리는 차례와 나무의 차례를 따로 적고, Tab이 둘 가운데 어느 차례를 따르는지 봅니다.
정답
① — 화면은 '3일 2일 1일'이고, Tab은 '1일'로 갑니다.
.trip a의 오른쪽 끝208px- 지금 포커스의 읽는 이름1일
row-reverse는 오른쪽에서 왼쪽으로 늘어서게 그려, HTML 첫 링크 '1일'이 상자 오른쪽 끝(208px)에 놓입니다.Tab차례는 나무의 차례라 HTML 첫 링크 '1일'부터입니다(브라우저 규칙 2 · 3).- ②는
Tab도 보이는 차례를 따른다고 본 것입니다. ③은row-reverse가 차례를 바꾸지 않는다고 본 것입니다 — 그리는 차례는 바뀝니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
hello.html의 body 안을 2절 상자 코드로, style 요소 안을 2절 CSS로 바꿔 저장 · 새로고침합니다. flex-direction: column을 지워 처음 값 row로 돌아가면, 같은 align-items: center가 이번에는 세 항목을 상자의 세로 가운데로 옮깁니다. 축이 돌자 같은 속성이 맡는 방향이 바뀐 것입니다.
파일을 만들고 여는 법은 준비: VS Code와 작업 폴더에 있습니다.