우리가 잘 알고 있는 웹 사이트를 방문해 보면 각 요소의 위치가 웹사이트의 목적에 맞게 배치된 것을 볼 수 있습니다.
이와 같이 각각의 요소를 목적에 맞게 배치하는 것을 레이아웃 이라고 합니다.
웹 개발자에게 웹 사이트에 목적에 맞게 화면을 만드는 것은 즉 레이아웃은 자바스크립트에 대해 배우는 만큼 중요합니다.
웹 또는 애플리케이션을 개발할 때 레이아웃의 뼈대를 그리는 단계를 와이어프레임이라고 합니다.
와이어프레임은 말 그대로 "와이어로 설계된 모양"을 의미하며, 단순한 선이나, 도형으로 웹이나 앱의 인턴페이스를 시각적으로 묘사한것입니다.
와이어프레임은 아주 단순하게 레이아웃과 제품의 구조를 보여주는 용도이며, 전환 효과나, 애니메이션, 사용자 테스트 같은 스타일링 요소나 UX를 판단하는 것이 아닙니다.
대부분의 산업에서 목업은 실물 크기의 모형을 뜻합니다.
실물 제품이 없는 무형의 웹 또는 앱은 어떻게 목업을 만들까요?
웹. 또는 앱을 제품이라고 할 때, 목업은 실제 제품이 작동되는 모습과 동일하게 HTML 문서를 작성합니다.
예를들어 트윗작성자, 트윗내용, 작성한 날짜 등을 HTML 문서내에 하드코딩하는 방식입니다.
하드코딩이란, 구구단같은 프로그램을 만들 시 자바스크립트를 사용한다면 변수를 사용하여 손쉽게 만들어 낼 수 있습니다. 하지만 HTML에서는 변수를 이용할 수 없기 때문에 하나하나 입력해야 하는데 이것을 하드코딩이라고 합니다.
와이어프레임과 목업을 작성하는 단계를 건너뛰고, Javascript로 동작하는 웹을 만들고 싶을 수 있습니다.
그러나 와이어프레임과 목업을 작성하는 단계를 진행하지 않으면 자바스크립트로 적용한 완성본이 어떤 형태를 가질지 상상하기 어렵기때문에 시행착오를 줄이기 위해 해보는것이 좋습니다.
이러한 작업은 마치 설계도 없이 건물을 짓는 것과 같습니다.
HTML 문서는 기본적인 스타일을 가지고 있습니다. 때때로 HTML 문서가 갖는 기본 스타일이, 레이아웃을 잡는 데 방해가 되기도 합니다. 어떤 사례가 있는지 찾아볼까요?
박스의 시작을 정확히 (0,0)의 위치에서 시작하고 싶은데, body 요소가 가진 기본 스타일에 약간의 여백이 있습니다.
width, height 계산이 여백을 포함하지 않아 계산에 어려움이 있습니다. (이전 유닛을 통해 박스 크기 측정 기준(box-sizing)에 대해 학습한 내용입니다.)
브라우저(크롬, 사파리 등)마다 여백이나 글꼴과 같은 기본 스타일이 조금씩 다릅니다.
이러한 수요에 따라 초기화(리셋)를 위한 다양한 라이브러리(Normalize.css)가 등장했지만, 사실 굳이 라이브러리를 사용할 필요는 없으며, 위에 언급한 문제를 해결할 몇 줄의 코드를 적용시키면, 기본 스타일링을 제거하여 디자인한 대로 레이아웃을 구현할 수 있습니다.
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
}
Flex(Flexible)는 "잘 구부러지는, 유연한"이라는 뜻입니다. Flexbox로 레이아웃을 구성한다는 것은, 박스를 유연하게 늘리거나 줄여 레이아웃을 잡는 방법입니다.
display: flex는 부모 박스 요소에 적용해, 자식 박스의 방향과 크기를 결정하는 레이아웃 구성 방법입니다.
<main>
<div>box1</div>
<div>box2</div>
<div>box3</div>
</main>
이런식의 코드가 있는경우 각 요소들이 잘보이도록 css로
main {
border: 1px dotted red;
}
div {
border: 1px solid green;
}
* {
margin: 10px;
padding: 10px;
}
메인요소에는 빨간색 점선, div 요소들에는 초록색 실선으로 테두리를 설정해 주고, 전체적으로 margin과 padding도 10px씩 주겠습니다.
이 상태에서 부모 요소인 main 요소에 display: flex 속성을 적용하면
위 사진처럼 div 요소들이 왼쪽부터 가로로 정렬된 것과 내용만큼의 공간을 차지하는것을 확인할 수 있습니다.
이처럼 Flexbox 속성들을 활용하면 요소의 정렬, 요소가 차지하는 공간을 설정해 줄 수 있습니다.
flex-direction 속성은 부모 요소에 설정해 주는 속성으로, 자식 요소들을 정렬할 정렬 축을 정합니다. 아무 설정도 해주지 않으면 기본적으로 가로 정렬을 합니다.
main {
display: flex;
**flex-direction : row;**
}
/* 부모 요소인 main에 작성하여 자식 요소인 div들을 정렬할 축을 정합니다. */
flex-wrap 속성은 하위 요소들의 크기가 상위 요소의 크기를 넘으면 자동 줄 바꿈을 할 것인지 정합니다. 설정해 주지 않으면 줄 바꿈을 하지 않습니다.
main {
display: flex;
**flex-wrap : nowrap;**
}
/* 부모 요소인 main에 작성하여 자식 요소인 div들의 줄 바꿈을 어떻게 할지 정합니다. */
justify-content 속성은 자식 요소들을 축의 수평 방향으로 어떻게 정렬할 것인지 정합니다. 요소들이 가로로 정렬되어 있다면 가로 방향으론 어떻게 정렬할 것인지, 세로로 정렬되어 있다면 세로 방향으론 어떻게 정렬할 것인지 정하는 속성입니다.
주요 속성값으로는 flex-start , flex-end, center, space-between, space-around 이 있습니다. 각 속성값의 특성이 잘 드러날 수 있도록 자식 요소의 크기를 동일하게 설정해 놓았습니다. 각 속성값이 축 방향에 따라 요소들을 어떻게 정렬시키는지 눈으로 확인해 보세요.
flex-direction : row 인 경우 ↔
flex-direction : column 인 경우 ↕️
align-items 속성은 자식 요소들을 축의 수직 방향으로 어떻게 정렬할 것인지 정합니다. 요소들이 가로로 정렬되어 있다면 세로 방향으론 어떻게 정렬할 것인지, 세로로 정렬되어 있다면 가로 방향으론 어떻게 정렬할 것인지 정하는 속성입니다.
주요 속성값으로는 stretch , flex-start , flex-end , center , baseline 이 있습니다. 이번에는 각 속성값의 특징이 명확하게 드러날 수 있도록 자식 요소의 글씨 크기를 각각 다르게 설정해 놓았습니다. 각 속성값이 축 방향에 따라 요소들을 어떻게 정렬시키는지 눈으로 확인해 보세요.
flex-direction : row 인 경우 ↕️
flex-direction : column 인 경우 ↔
flex 속성에는 세 가지 값을 지정해 줄 수 있습니다. 각 값이 의미하는 것은 다음과 같습니다.
flex: <grow(팽창 지수)> <shrink(수축 지수)> <basis(기본 크기)>
grow(팽창 지수)는 요소의 크기가 늘어나야 할 때 얼마나 늘어날 것인지, shrink(수축 지수)는 요소의 크기가 줄어들어야 할 때 얼마나 줄어들 것인지, basis(기본 크기)는 늘어나고 줄어드는 것과 상관없이 요소의 기본 크기는 얼마인지를 의미합니다. 각 값이 어떻게 작용하는지는 잠시 후 살펴보겠습니다.
자식 요소에 flex 속성을 따로 설정해 주지 않으면 다음과 같은 기본값이 적용되며, 왼쪽에서부터 오른쪽으로 콘텐츠의 크기만큼 배치됩니다.
flex: 0 1 auto;
이 순서와 기본값은 반드시 기억해 주세요. flex: grow shrink basis, flex: 0 1 auto
꼭 flex 속성 안에 세 가지 값을 한 번에 설정해 줄 필요 없이, 다음과 같이 각 값을 따로 지정해 줄 수 있습니다.
flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
grow(팽창 지수)는 요소의 크기가 늘어나야 할 때 얼마나 늘어날 것인지를 의미한다고 했습니다. 어떤 의미인지 알아보기 위해서 챕터 2-1에서 사용했던 HTML에서 자식
<main>
<div id="box1" class="box">box1</div>
<div id="box2" class="box">box2</div>
<div id="box3" class="box">box3</div>
</main>
flex 속성을 설정하기 전의 모습입니다. grow의 기본 값인 0은 빈 공간이 있어도 늘어나지 않음을 의미합니다. 따라서 빈 공간이 있음에도 박스들이 늘어나지 않습니다. 그럼 grow의 값을 변경하며 어떤 변화가 생기는지 확인해 봅시다.
우선 box1만 flex-grow : 1로 설정해 보겠습니다. flex-grow의 기본값은 0이므로 나머지 박스는 flex-grow : 0인 상태입니다.
이번에는 box2도 flex-grow : 1로 설정해 보겠습니다. box3만 flex-grow : 0인 상태입니다.
box3도 flex-grow : 1로 설정해 보겠습니다. 세 박스 모두 flex-grow : 1인 상태입니다.
어떤 느낌인지 감이 오시나요? grow(팽창 지수)는 정렬축 방향으로 빈 공간이 있을 때, 각 자식 요소들이 얼마나 늘어나서 남는 공간을 차지할 것인지 비율을 정하는 것이라고 생각하면 이해하기 쉽습니다.
즉, 첫 번째 예시에서 grow는 box1 : box2 : box3 = 1 : 0 : 0 이므로 box1이 모든 공간을 차지하고,
두 번째 예시에서 grow는 box1 : box2 : box3 = 1 : 1 : 0 이므로 box1과 box2가 1:1로 공간을 나눠 가지고,
세 번째 예시에서 grow는 box1 : box2 : box3 = 1 : 1 : 1 이므로 세 박스가 1:1:1로 공간을 나눠 가진 것입니다.
이처럼 팽창지수는 자식 요소의 grow값 / 자식 요소들의 grow값의 총합의 비율로 빈 공간을 가져갑니다.
팽창지수의 절대적 크기가 아닌 총합에서의 비율로 빈 공간을 차지하게 되는 것이죠.
shrink(수축 지수)는 grow와 반대로, 설정한 비율만큼 박스 크기가 작아집니다. 비율이 클수록 더 많이 줄어드는 것이죠. 그러나 flex-grow 속성과 flex-shrink 속성을 함께 사용하는 일은 추천하지 않습니다.
비율로 레이아웃을 지정할 경우 flex-grow 속성 또는 flex: grow 1 auto와 같이 grow 속성에 변화를 주는 방식을 권장합니다. flex-shrink 속성은 width나 이후 설명할 flex-basis속성에 따른 비율이므로 실제 크기를 예측하기가 어렵기 때문입니다. flex-grow 속성으로 비율을 변경하는 경우, flex-shrink 속성은 기본값인 1로 두어도 무방합니다.
basis(기본 크기)는 자식 박스가 flex-grow나 flex-shrink에 의해 늘어나거나 줄어들기 전에 가지는 기본 크기입니다. flex-grow가 0일 때, basis 크기를 지정하면 그 크기는 유지됩니다.
grow는 0 : 1 : 1로 설정하고, box1에 flex-basis : 50px로 설정해 보겠습니다.
box1의 크기가 늘어나거나 줄어들지 않고 50px을 유지하는 것을 확인할 수 있습니다.
flex-grow 속성의 값이 0인 경우에만 flex-basis 속성의 값이 유지됩니다.
display 속성에 flex가 적용된 컨테이너 내부에 존재하는 자식 박스는 경우에 따라, basis로 설정된 크기가 항상 유지되는 것은 아닙니다.
flex-grow 속성의 값이 양수일 경우, 늘어나면서 flex-basis 속성에 적용한 값보다 커질 수도 있습니다. 실제 레이아웃을 구현하면서 막히는 경우에는, 다음의 원리를 참고할 수 있습니다.
width와 flex-basis를 동시에 적용하는 경우, flex-basis가 우선됩니다.
콘텐츠가 많아 자식 박스가 넘치는 경우, width가 정확한 크기를 보장하지 않습니다.
(flex-basis를 사용하지 않는다면) 콘텐츠가 많아 자식 박스가 넘치는 경우를 대비해, width 대신 max-width를 쓸 수 있습니다.