강사님이 운영중이신 영화관 웹사이트... 메인 요소 안 영화 정보와 사이드바로 구분된 레이아웃이 흥미롭다.
이런 페이지에서 중요한 것은 컨텐츠의 크기 변화, 또는 다양한 디바이스 너비에서도 안정적으로 유지되는 레이아웃의 설계!
천천히 만들어 가 보자. 🐢
1. 메인 영역 안에서 영화 정보와 사이드바의 구분
우선 flex box의 속성을 이용하여 컨테이너를 168px로 고정된 사이드바와, 나머지 너비를 차지하는 메인 영역으로 나눈다.
<main class="contents">
<div class="l_wrapper">
<div class="container">
<div class="container-main">MAIN</div>
<div class="container-sidebar">Side bar</div>
</div>
</div>
</main>
index.html
.container {
box-shadow: inset 0 0 30px gold;
display: flex;
gap: 24px;
min-height: 848px;
}
.container-main {
box-shadow: inset 0 0 20px purple;
flex-grow: 1;
}
.container-sidebar {
box-shadow: inset 0 0 20px pink;
width: 168px;
height: 283px;
}
style.css
1. container에 flex 속성을 주어 container-main과 container-sidebar를 flex-item으로 만든다.
2. sidebar의 너비와 높이를 지정하고, main의 flex-grow에 1 값을 주어 컨테이너의 가용공간을 main의 너비에 더해준다.
이제 컨텐츠를 채우면 될 것 같은데... 레이아웃 설계는 그리 만만치 않다.
우리는 미래의 돌발상황에도 무너지지 않는 안정적인 코드를 작성해야 한다.
그럼 flex box를 사용할때 자주 발생하는 문제와 그 해결법을 알아보자.
2-1. flex item의 너비는 컨텐츠의 양에 따라 자동으로 조정된다.
이전 코드에서 의도적으로 container-main의 컨텐츠를 늘여보았다.
그럼 해당 아이템이 컨테이너에서 차지하는 공간도 함께 늘어남에 따라 sidebar의 공간은 줄어듦을 확인할 수 있다.
근본적인 이유는 flex item의 flex-basis 속성이 초기값 auto를 가지고 있기 때문인데,
이것은 아이템의 너비가 컨텐츠 양과 함께 늘어나는 것을 의미한다.
따라서 이 문제의 해결 방법은 다음과 같다.
- container-main에 flex-basis: 0 주기
- container-sidebar에 flex-shrink: 0 주기
- container-sidebar에 min-width: 168px 주기
1번은 flex-basis 값을 0으로 만들어 container-main의 너비가 컨텐츠의 양에 영향받지 않게 하는 것이고,
2과 3번은 container-main의 너비 변화에 관계없이 container-sidebar의 너비가 변하지 않게 고정하는 방법이다.
2-2. flex item이 길이가 긴 컨텐츠(이미지, 단어)를 가지고 있을 때 flex container 외부로 오버플로우가 발생한다.
이를 해결하기 위해선 flex-basis에 대한 이해가 필요하다.
flex-basis는 flex item의 너비를 결정하는 속성이고, 앞서 말했듯 초깃값인 auto 상태에서는 컨텐츠의 크기에 따라 너비가 맞춰진다.
하지만 flex-basis의 값이 0인 경우, flex item의 너비는 0이 되지 않는데, 그 이유는 아이템의 min-width이 초깃값 auto로 컨텐츠의 크기만큼 계산되어있기 때문이다.
따라서 flex-basis: 0과 min-width: 0을 동시에 주면, flex tem는 너비가 0부터 계산되면서 flex-grow의 영향만을 받게된다.
*flex item의 경우 width: 0으로 flex-basis: 0과 min-wdith: 0을 동시에 나타낼 수 있다.
다음은 contents 그리드를 반응형으로 만드는 방법이다.
페이지 너비와 함께 아이템도 같이 줄어들다가, 특정 뷰포트(태블릿, 모바일)에서 열의 개수가 줄어들어 글을 더 읽기 쉽게 만들 수 있다.
<main class="contents">
<div class="l_wrapper">
<div class="container">
<div class="container-main">
<ul class="l_row">
<li class="l_col">
<section class="card">A</section>
</li>
<li class="l_col">
<section class="card">B</section>
</li>
<li class="l_col">
<section class="card">C</section>
</li>
</ul>
</div>
</div>
</div>
</main>
index.html
.l_row {
background-color: yellow;
display: flex;
flex-wrap: wrap;
gap: 24px
}
.l_col {
flex-basis: 320px;
flex-grow: 1;
}
.card {
color: black;
background-color: limegreen;
}
style.css
ul과 li를 이용해 레이아웃을 마크업 하고, 아이템(l_col)에 flex-grow: 1을 주면 컨테이너의 여백 공간이 같은 비율로 나누어져 아이템의 너비(flex-basis)에 더해진다. (3등분 된다.)
아이템은 320px의 basis를 가지고 있고, flex-wrap 때문에 페이지가 줄어들면 아이템이 다음 줄로 내려오게 되는데, 여기에도 flex-grow가 적용되어 아이템이 컨테이너 너비를 꽉 채우게 된다.
하지만 우리가 원하는 레이아웃은 각 아이템들의 너비가 같아야 하므로 width 속성을 사용해야 한다.
width: calc(100% / 3)는 컨테이너의 너비를 3등분 한다는 뜻이다.
여백을 위해 각 아이템에 gap: 24px를 줄 경우 아이템 너비와 gap의 합이 컨테이너 너비를 벗어나 wrap된다.
그 대신 l_col에 패딩을 주고, l_row에 그 반절만큼 네거티브 마진을 주어 시각적으로 여백이 나타나게 할 수 있다.
.l_row {
background-color: yellow;
display: flex;
flex-wrap: wrap;
row-gap: 24px;
margin: 0 -12px;
}
.l_col {
width: calc(100% / 3);
padding: 0 12px;
/* width가 padding을 포함하여 계산 */
box-sizing: border-box;
}
.card {
color: black;
background-color: limegreen;
}
style.css
이제 아이템의 개수가 늘어나더라도 너비가 컨테이너의 1/3로 고정되는 것을 확인할 수 있다.
만약 특정 아이템이 차지하는 너비 비율을 바꾸고 싶다면, 클래스를 주어 선택자 안에 width의 값을 조정하면 된다. (미디어 쿼리에도 사용하면 페이지 너비에 따라 그리드의 열 개수가 바뀌게 할 수 있다.)
보통 총 너비를 12분할하여 원하는 만큼 사용하는 12 column grid가 자주 사용된다.
.l_col_12_12 {
width: 100%;
}
.l_col_11_12 {
width: 91.66666667%;
}
.l_col_10_12 {
width: 83.33333333%;
}
.l_col_9_12 {
width: 75%;
}
.l_col_8_12 {
width: 66.66666667%;
}
.l_col_7_12 {
width: 58.33333333%;
}
.l_col_6_12 {
width: 50%;
}
.l_col_5_12 {
width: 41.66666667%;
}
.l_col_4_12 {
width: 33.33333333%;
}
.l_col_3_12 {
width: 25%;
}
.l_col_2_12 {
width: 16.66666667%;
}
.l_col_1_12 {
width: 8.33333333%;
}
'Front-end > HTML, CSS' 카테고리의 다른 글
image 사이의 여백 - 인라인 요소의 vertical-align (0) | 2024.07.27 |
---|---|
getBoundingClientRect (0) | 2024.02.04 |
HTML 특수문자표 (0) | 2024.01.26 |
grid 기본 (0) | 2024.01.17 |
flex의 align-self, align-item과 align-content의 차이 (0) | 2024.01.17 |