flexbox(Flexible Box Module)은 웹 디자인 및 웹 개발에서 사용되는 레이아웃 모델 중 하나로 flexbox 내의 아이템 간 공간 배분과 정렬 기능을 제공하기 위한 1차원 레이아웃 모델입니다. flex(flexbox)는 요소의 중앙 정렬, block 요소들의 가로 정렬 등 다양한 레이아웃을 편하게 구현하는 것을 가능하게 합니다.
💡
flex와 flexbox는 뭐가 다른가요?
CSS에서의 flex속성은 하나의flex-item(자식)이 자신의 flex- container(부모)가 차지하는 공간에 맞추기 위해 크기를 조절하는 속성이며 flex-grow, flex-shrink, flex-basic의 단축 속성입니다.
책에서 소개하고자 하는 내용은 CSS 레이아웃 중 하나인 flexbox에 대해서 다룹니다. flexbox를 적용하기 위해선 컨테이너의 display 속성에 flex 혹은 inline-flex 사용이 요구되기 때문에 편의상 flexbox를 flex로 지칭하도록 하겠습니다.
이 css 속성을 통해 기본적으로 아이템들은 가로로 배치가 되고 너비 값은 아이템 자신의 컨텐츠만큼 차지하게 되고 높이 값은 컨테이너의 높이 값 만큼 차지하게 됩니다. 아이템들이 inline-block 처럼 배치가 된다고 볼 수 있습니다.
그렇다면 display: flex 와 display: inline-flex의 차이는 무엇일까요?
간단하게 설명하자면 display: flex로 지정된 컨테이너들은 block요소와 같은 성향을 가지며 display: inline-flex로 지정된 컨테이너들은 inline요소와 같은 성향을 가지게 됩니다.
컨테이너에 다양한 플렉스 속성을 통해 다음과 같이 아이템을 제어할 수 있습니다.
flex-direction : 플렉스 아이템의 배치 방향을 설정합니다.
flex-wrap : 플렉스 아이템을 여러 줄 배치합니다.
flex-flow : 플렉스 아이템의 배치 방향과 여러 줄 배치를 한 번에 설정합니다.
justify-content : 주축 방향으로 다양하게 플렉스 아이템을 배치합니다.
align-items : 교차축 방향으로 다양하게 플렉스 아이템을 배치합니다.
뒤에서 하나씩 살펴보도록 하겠습니다.
flex-direction
flex-direction속성은 컨테이너의 아이템을 배치할 때 사용할 주축 및 방향을 지정합니다.
flex-direction 속성을 따로 지정하지 않았을 때의 기본값은 row(행) 방향입니다. 즉 아이템들이 수평으로 배치가 됩니다. 아이템들을 수직으로 배치하고 싶을 때에는 flex-direction: column을 명시적으로 지정해 주어야 합니다. 또한 기본적으로 아이템들은 왼쪽에서 오른쪽으로 배치가 됩니다. 아이템들의 배치 방향을 반대로 바꾸고 싶다면 flex-direction: row-reverse을 지정해 주어야 합니다.
flex-direction: row-reverse : row와 동일하게 동작하지만 주축의 시작점과 끝점이 반대로 위치됩니다. 아이템들이 수평축(오른쪽에서 왼쪽)으로 배치됩니다.
flex-direction: column : 주축이 수직 방향입니다. 컨테이너의 아이템이 수직축(위에서 아래)으로 배치됩니다.
flex-direction: column-reverse : column과 동일하게 동작하지만 수직축의 시작점과 끝점이 반대로 위치됩니다. 아이템들이 수직축(아래에서 위로)으로 배치됩니다.
💡
접근성 고려 사항
flex-direction 속성에 row-reverse 또는 column-reverse 값을 사용하면 DOM 구조와 그 시각적 표현에 차이가 생깁니다. 이는 스크린 리더 등 접근성 기술을 사용하는 사용자들에게 잘못된 정보를 전달할 가능성이 생깁니다.
flex-wrap
flex-wrap 속성은 아이템들을 한 줄로 배치되게 할지, 컨테이너의 가능한 영역 내에서 벗어나지 않고 여러행으로 나누어 배치할지 결정하는 속성입니다. flex-wrap 속성을 따로 지정하지 않으면 기본값 flex-wrap: nowrap으로 지정됩니다.
flex-wrap: nowrap : 기본 설정값으로 컨테이너의 영역을 벗어나더라도 아이템들을 한 줄로 배치합니다.
아이템들 크기를 고정 값으로 설정해놓아도 flex-shrink 값을 설정하지 않았으면 초기값 1로 설정되어 아이템들이 컨테이너의 크기에 맞춰 일정 비율 줄어들지만,
flex-shrink을 0으로 설정하면 설정한 아이템들의 크기가 고정되어 컨테이너 안에 한 줄로 배치됩니다.
flex-wrap: wrap : 아이템들이 컨테이너 영역보다 클 때 컨테이너의 영역 내에 한 줄로 배치되지 못하는 상황이 있습니다. 그때 여러 행의 걸쳐 배치되게 하는 속성입니다. 여러행으로 배치되었을 때 각각의 행은 하나의 컨테이너라고 생각해야 합니다. 공간 배분은 해당 행에서만 이루어지며 다른 행은 영향을 받지 않기 때문입니다.
flex-direction: row 일 때 main axis(주축)이 컨테이너의 왼쪽에서 시작하는 가로 축이므로 아이템들이 컨테이너의 가로 영역을 넘게 되면 다음 줄(위에서 아래)로 정렬되게 됩니다.
flex-direction: column 일 때 main axis(주축)이 컨테이너의 위쪽에서 시작하는 세로 축이므로 아이템들이 컨테이너의 세로 영역을 넘게 되면 다음 줄(좌에서 우)로 정렬되게 됩니다.
flex-wrap: wrap-reverse : wrap속성과 동일하지만, 아이템들이 나열되는 시작점과 끝점이 반대가 됩니다. 예시를 보면 더욱 쉽게 이해할 수 있습니다.
flex-wrap: wrap 일 때는 아이템들이 컨테이너의 가로 영역을 넘게 되면 위에서 아래로 줄이 바뀌어 정렬되었습니다. flex-wrap: wrap-reverse는 반대로 아래에서부터 시작하여 위로 줄이 바뀌게 됩니다.
main axis이 column 일 때도 마찬가지로 초반 한 줄까지는 flex-wrap: wrap 속성과 동일합니다. 하지만 아이템이 컨테이너의 세로 영역을 넘게 되면 flex-wrap: wrap 속성에서는 좌에서 우로 줄이 바뀌어 정렬되었던 것에 반해 flex-wrap: wrap-reverse는 오른쪽에서부터 시작하여 왼쪽으로 줄이 바뀌게 됩니다.
flex-flow : column wrap 속성값으로 아이템들이 컨테이너 영역보다 클 때 한 줄로 배치되지 못하고 다음 행으로 배치됩니다.
flex-flow : row-reverse wrap 속성값으로 아이템의 배치 방향이 오른쪽에서 왼쪽으로 바뀌었고 아이템들이 컨테이너 영역보다 클 때 다음행에 오른쪽에서 왼쪽으로 배치됩니다.
이 외에도 ‘row wrap-reverse’, ‘column wrap’ 등등 다른 속성값들을 넣어서 실습해 보시면 어떻게 동작하는지 알 수 있을 것입니다.
justify-content
컨테이너에서 flex-direction 속성 값으로 인해 정해진 주축을 기준으로 컨테이너의 아이템들을 어떻게 정렬할 것인지를 정의합니다. 예를 들어 flex-direction의 값이 column이라면 위에서 아래 방향으로의 정렬을 정합니다. 기본적으로는 flex-direction 속성의 기본값은 row이므로 따로 지정하지 않으면 컨테이너의 가로 방향으로 정렬을 정의합니다.
justify-content 속성 값은 다음과 같습니다.
justify-content : flex-start : 컨테이너의 아이템들이 주축의 시작 부분부터 밀착되어 정렬됩니다. 따로 속성 값을 지정해 주지 않으면 기본값으로 들어가는 값입니다.
align-items : center : 컨테이너의 아이템들이 교차축의 중앙에 정렬됩니다.
align-content
flex-wrap : wrap 상태에서 아이템들이 2줄 이상이 되었을 때 아이템들의 교차축 방향으로 어떻게 정렬할 것인지 정하는 속성입니다. flex-wrap : nowrap 상태에서는 아무 효과도 없습니다. align-content 속성 값은 다음과 같습니다.
align-content : stretch
align-content : flex-start
align-content : flex-end
align-content : center
align-content : space-between
align-content : space-around
align-content : space-evenly
4.1.4 flex item
아이템들에게 플렉스 속성을 적용하면 아이템의 배치, 크기, 정렬 등을 제어할 수 있습니다.
아이템에 다양한 아이템 속성을 통해 다음과 같은 아이템을 제어할 수 있습니다.
flex-basis : 아이템의 초기 크기 설정합니다.
flex-grow : 아이템이 부모 컨테이너에 남은 공간을 얼마나 차지할지 설정합니다.
flex-shrink : 아이템이 부모 컨테이너의 공간보다 클 때 얼마큼 줄어들지 설정합니다.
뒤에서 하나씩 살펴보도록 하겠습니다.
flex-basis
flex-basis는 아이템들의 기본 크기를 지정합니다. flex-direction 속성값이 row일 때는 너비 값을, column일 때는 높이값를 지정합니다.
💡
auto값을 가지지 않는 flex-basis 와 width(flex-direction 값이 column인 경우 height )값을 동시에 적용하는 경우 flex-basis 값이 우선 적용됩니다.
flex-basis의 속성값으로는 fill, max-content, min-content, fit-content 같은 content 키워드를 사용하거나 <’width’> 값을 나타내는 단위를 사용합니다. 기본값은 auto입니다.
flex-basis값을 따로 지정해 주지 않을 때에 기본값 auto는 해당 아이템의 width값을 사용합니다. width 값을 따로 지정해 주지 않았다면 아이템의 크기는 컨텐츠의 크기입니다.
.item {
flex-basis: 150px;
}
flex-basis값을 150px로 주었을 때, ‘flex’ 와 ‘love’ 아이템은 150px로 늘어나고 ‘flexbox hi’ 아이템은 기존에 150px보다 컸으므로 그대로 유지됩니다.
content : 컨테이너의 아이템의 컨텐츠 크기에 따라 자동으로 크기가 바뀝니다.
💡
flex-basis의 속성값 content는 flex-basis와 width, height 속성을 전부 auto로 설정한 것과 동일하게 작동합니다.
flex-grow
flex-grow는 아이템들이 컨테이너 안에서의 할당 가능한 공간을 어떻게 분배할지를 결정합니다. 각각의 아이템들이 flex-grow 값을 갖는다면 컨테이너 안에서 할당 가능한 공간을 flex-grow 값의 비율만큼을 가지게 됩니다. flex-grow의 속성값으로는 숫자 값이 들어가고 기본값은 0입니다. 기본값이 0이기 때문에 따로 적용하기 전까지는 아이템들은 컨텐츠 만큼의 크기를 가지게 되거나 flex-basis값만큼의 크기를 가집니다.
모든 아이템들이 동일한 flex-grow값을 갖는다면 컨테이너 안에서 동일한 공간을 할당받습니다.
.item {
flex-grow : 1;
/* flex-grow : 0; 기본값 */
}
이번에는 각각의 아이템들에게 flex-grow 값을 1:2:1 비율로 설정하여 컨테이너의 남은 공간을 나누어 가지도록 해보겠습니다.
flex-shrink는 아이템의 크기를 고정시키거나 축소할 때 사용하는 속성입니다. 기본적으로 flex-shrink 속성의 기본값은 1이므로 아이템들의 크기가 컨테이너의 크기보다 큰 경우 아이템의 크기가 줄어듭니다. 속성값을 0으로 지정해 주면 아이템들의 크기가 컨테이너의 크기보다 커도 줄어들지 않습니다.
flex-grow는 컨테이너의 남은 공간을 아이템들이 어떻게 분배할지 정하는 속성이라면 flex-shrink는 컨테이너 안에서 아이템들이 컨테이너가 줄어들었을 때 아이템들이 얼마큼 줄어들지를 결정하는 속성입니다. flex-grow의 반대개념이라고 할 수 있겠습니다.
💡
flex-shrink는 컨테이너에 flex-wrap: wrap 속성이 부여된 경우 작동하지 않습니다.
4.2 Grid 레이아웃
4.2.1 Grid 개념
Grid 레이아웃은 식당 내부의 테이블을 배치하는 것과 비슷한 원리로 작동합니다. 식당에는 여러 크기와 모양의 테이블이 있으며, 각 테이블을 일정한 간격과 패턴에 따라 배치할 수 있습니다. 필요에 따라 특정 테이블에 더 많은 공간을 주거나, 작은 테이블을 여러 개 묶어 큰 테이블처럼 보이도록 조절할 수도 있습니다. 이와 같이, Grid 레이아웃은 콘텐츠와 요소를 규칙적으로 배치하고 정렬하는 데 사용되며, 반응형 웹 디자인에 매우 유용합니다.
Grid는 웹 페이지의 요소를 격자(그리드) 형태로 정렬하고 배치하는 데 사용되는 기술입니다. Flex와의 주요 차이점은 Flex는 1차원의 한 방향 레이아웃 시스템인 반면, Grid는 2차원의 두 방향(x축, y축) 레이아웃 시스템을 제공한다는 것입니다. 이러한 이유로 Grid는 Flex보다 더 복잡한 레이아웃 표현이 가능합니다.
Grid 역시 Flex와 마찬가지로 container와 item 개념을 사용하여 웹 페이지의 구성 요소를 조합하고 정렬합니다.
부모 요소인 div.container를 Grid Container(그리드 컨테이너)라고 부르고, 자식 요소인 div.item을 Grid Item(그리드 아이템)이라고 부릅니다. 그리드 컨테이너는 그리드의 영향을 받는 영역을 나타내고, 그리드 아이템은 이 영역 내에서 설정에 따라 배치되는 요소를 나타냅니다.
그리드 컨테이너 (Grid Container)
그리드 레이아웃을 적용하는 전체 영역입니다. 일반적으로는 <div> 요소나 다른 블록 수준 요소가 그리드 컨테이너 역할을 합니다.
그리드 셀 (Grid Cell)
그리드 컨테이너 내에서 그리드 아이템이 배치되는 개별 셀입니다. 셀은 행과 열의 교차점에 해당하며, 그리드 아이템은 이러한 셀에 위치하게 됩니다.
그리드 아이템 (Grid Item)
그리드 컨테이너의 자식 요소로, 그리드 레이아웃 내에서 배치되는 콘텐츠입니다
그리드 트랙 (Grid Track)
그리드 레이아웃에서 행 또는 열을 나타내는 요소입니다. 그리드 컨테이너 내에서 행과 열을 만들어 내는 구성 요소이며, 이를 통해 그리드 아이템을 배치합니다.
그리드 라인 (Grid Line)
그리드 셀을 구분하는 선입니다. 가로로는 수평 그리드 라인, 세로로는 수직 그리드 라인이 있습니다. 그리드 아이템은 이러한 그리드 라인 사이에 배치됩니다.
그리드 넘버 (Grid Number)
그리드 라인의 각 번호이며, 그리드 넘버는 행과 열을 구분하고 정확한 위치를 나타내는 데 도움을 줍니다.
그리드 갭 (Grid Gap)
그리드 셀 사이의 간격으로, 행과 열 간의 간격을 나타냅니다. 그리드 갭을 설정하여 그리드 아이템 사이의 간격을 지정할 수 있습니다.
그리드 영역 (Grid Area)
여러 그리드 셀이 결합된 영역을 나타냅니다. 그리드 아이템은 하나 이상의 그리드 셀을 차지하고, 이를 통해 그리드 영역을 형성합니다.
💡
크롬의 개발자 도구에는 그리드 레이아웃을 명확하게 시각화하는 기능이 있습니다. 개발자 도구를 열고 그림과 같이 표시된 영역을 클릭하면 이를 확인할 수 있습니다.
4.2.2 Grid Container
display 속성
그리드 레이아웃을 만들 때, 먼저 그리드를 적용할 가장 바깥 영역을 그리드 컨테이너로 지정해야 합니다. 이를 위해 컨테이너 요소에 display: grid나 display: inline-grid를 선언하는 것으로 시작합니다.
display: grid는 컨테이너 내부의 요소를 블록(block) 요소로 배치합니다. 이미 블록 요소인 경우, 이 속성을 지정했을 때는 아무런 변화가 없습니다.
display: inline-grid는 컨테이너 내부의 요소를 인라인(inline) 요소로 배치합니다. 그리드 컨테이너는 텍스트 흐름 내에서 정렬되므로 다른 인라인 요소와 같은 줄에 배치됩니다.
그리드는 플렉스와 마찬가지로, 컨테이너에 적용하는 속성과 아이템에 적용하는 속성으로 나눌 수 있습니다. 그리드 컨테이너 내에서 열과 행의 크기와 개수를 지정하기 위해서 grid-template-columns 속성과 grid-template-rows 속성을 사용합니다. 열과 행의 크기를 조절하기 위해 px, 백분율(%), em 등과 같은 고정 크기 값뿐만 아니라, repeat() 함수, 상대적인 크기를 나타내는 fr(fraction), 자동 크기를 나타내는 auto 등의 단위를 사용하여 크기를 지정할 수 있습니다.
위의 예시에서 첫 번째 열은 1/6, 두 번째 열은 1/3, 세 번째 열은 1/2의 너비를 가지게 됩니다. 그리고 두 개의 행을 만들어 첫 번째와 두 번째 행은 200px 높이를 가지게 됩니다.
fr(fraction)
열과 행의 크기를 지정할 때, 픽셀(px) 단위를 이용하면 크기가 고정되어 있기 때문에 반응형으로 동작하지 않습니다. 그래서 그리드 레이아웃에서는 상대적인 크기 조절이 가능한 fr(fraction) 단위를 주로 사용합니다. fr은 사용할 수 있는 공간에 대한 비율을 의미합니다. 요소 간의 비율을 조절하여 컨테이너의 크기에 맞게 공평하게 분할하여 일관된 레이아웃을 유지하는 데 도움을 줍니다. 이 단위는 그리드 컨테이너 안에서만 사용되며, 상황에 따라 유연하게 레이아웃을 제어하는 데 유용합니다.
예를 들어, 3개의 열을 너비가 동일한 1:1:1의 비율로 만든다면 다음과 같이 지정할 수 있습니다.
grid-template-columns: 1fr 1fr 1fr;
또한, 고정 크기와 가변 크기를 섞어 쓸 수도 있습니다. 예를 들어, 다음과 같이 지정하면 왼쪽 첫 번째 열은 100px로 고정되고, 나머지 두 번째와 세 번째 열은 1:2의 비율로 유연하게 조절됩니다.
grid-template-columns: 100px 1fr 2fr;
repeat 함수
px이나 fr 단위를 사용하면 똑같은 값을 여러 번 반복하는 일이 발생합니다. 이때, 그리드 레이아웃에 내장된 repeat() 함수를 사용하면 반복하는 값을 간결하게 정의할 수 있어 코드의 가독성을 향상시키고 유지 보수를 쉽게 할 수 있습니다.
repeat(반복 횟수, 반복 값);
첫 번째 인자는 생성할 그리드의 행이나 열의 개수를 나타내는 반복 횟수이고, 두 번째 인자는 각 그리드의 행이나 열의 크기를 정의하는 반복할 값을 지정합니다.
이러한 repeat() 함수를 이해하기 위해 몇 가지 예제들을 통해 알아보겠습니다.
grid-template-columns: repeat(3, 200px);
위 예제는 100px 크기의 column을 3개 배치할 때 100px을 3번 사용하는데, 즉 repeat(3, 100px)은 100px 100px 100px과 같습니다.
위 예제는 1fr과 2fr 크기를 번갈아가면서 column을 4번 반복하고, 1fr 크기의 row를 2번 반복하여 생성합니다. 따라서, 총 8개의 열과 2개의 행이 생성됩니다.
minmax()
minmax() 함수를 사용하면 그리드 아이템의 너비나 높이를 고정하지 않고, 최소 크기와 최대 크기 사이에서 자동으로 조절할 수 있습니다.
minmax(최솟값, 최댓값)
이 함수는 두 개의 인자를 받으며, 첫 번째 인자는 최소 크기를 나타내고 두 번째 인자는 최대 크기를 나타냅니다. 이렇게 설정하면 그리드 아이템은 최솟값보다 크거나 같고, 최댓값보다 작거나 같은 크기 범위 내에서 그리드 아이템의 크기를 유연하게 조절할 수 있게 해줍니다. 이 함수를 이용하면 다양한 화면의 크기와 레이아웃에 대응하기 위한 반응형 디자인을 구현할 수 있습니다.
grid-template-columns: minmax(100px, 1fr);
위 예제는 열의 크기를 최소 100px로 하고, 사용 가능한 공간이 추가로 있을 경우 1fr 크기까지 늘릴 수 있게 합니다.
auto-fill과 auto-fit
repeat 함수와 함께 사용되는 auto-fill 및 auto-fit 키워드는 그리드 아이템의 배치에 유용한 속성 값입니다. 이들은 반복 횟수를 고정하지 않고, 그리드 컨테이너의 너비나 높이에 따라 최대한 많은 셀을 배치하고 싶을 때 사용됩니다. 특히 행과 열의 아이템 개수가 명확하지 않은 경우에 유용하게 사용됩니다.
auto-fill: 그리드 아이템이 사용할 수 있는 공간을 모두 채울 때까지 반복됩니다. 그리드 컨테이너에 가능한 한 많은 그리드 행 또는 열을 생성하려고 시도하며, 그리드 아이템이 부족한 경우에는 빈 공간이 남게 됩니다.
auto-fit: auto-fill과 비슷하지만, 셀의 길이를 나눠서 길이를 딱 맞게 설정해 그리드 아이템과 함께 비어 있는 공간도 고려하여 열 또는 행의 수를 결정합니다. 따라서 그리드 내 아이템이 적더라도 남는 공간 없이 채우려고 합니다.
auto-fill과 auto-fit의 주요 차이점은 그리드 컨테이너가 행 또는 열에 모든 아이템을 수용하고 남는 공간이 있을 때 발생합니다. auto-fill은 사용할 수 있는 공간을 채우는 역할을 하지만, 비어 있는 공간을 남겨둘 수 있습니다. auto-fit은 비어 있는 공간을 최대한 활용하여 남는 공간 없이 그리드를 채우기 위해 조절합니다. 이러한 키워드를 사용하면 다양한 화면 크기와 콘텐츠 양에 대응하는 반응형 그리드 레이아웃을 만들 수 있습니다.
column-gap, row-gap, gap
그리드 레이아웃에서 각 그리드 아이템 사이의 간격을 설정하는 데 gap 속성을 사용합니다.
span
행과 열을 병합할 때 span 키워드를 사용합니다. span의 사전적 의미는 ‘한 뼘’ 또는 ‘~을 채우다’의 의미를 가지고 있습니다. 그리드 아이템이 현재 위치에서 n 개의 그리드 행 또는 열을 차지하도록 지정합니다. span 값을 사용하면 그리드 아이템의 위치와 크기를 보다 유연하게 설정할 수 있습니다.
grid-template-areas & grid-area
앞에서 살펴본 그리드 라인은 시작 번호와 끝 번호를 일일이 지정해서 레이아웃을 만들어야 했습니다. 하지만 grid-template-areas을 사용하면 그리드 레이아웃이 어떻게 배치되는지 한눈에 파악하기 쉽고 코드도 더 간결해집니다.
grid-area 속성을 이용하여 각 그리드 아이템 영역에 이름을 지정하고, grid-template-areas 속성을 사용해 아이템을 어떻게 배치할지 지정합니다. 각 아이템 영역을 공백으로 구분하고, 만약 아이템 영역을 비워 두려면 해당 자리에 마침표(.)를 넣으면 됩니다. 한 줄에 들어갈 영역을 큰따옴표(“ ”)로 묶어주고, 각 줄마다 줄 바꿈을 하면 그리드 레이아웃을 한눈에 볼 수 있습니다.
grid-template-areas와 grid-area를 사용할 때 주의할 점은 모든 상황에서 유용하지는 않을 수 있습니다. 만약 그리드 레이아웃이 매우 복잡하거나 각 그리드 아이템을 독립적으로 제어해야 할 때는 grid-column-start, grid-column-end, grid-row-start, grid-row-end 속성을 사용하는 것이 더 유용할 수 있습니다. 따라서 어떤 속성을 선택할지는 프로젝트의 요구사항과 복잡성에 따라 달라질 수 있으므로 적절한 선택을 하는 것이 중요합니다.
align-self & justify-self
플렉스 박스 레이아웃에서 살펴보았던 align-self 또는 justify-self 속성을 사용하여 그리드 레이아웃의 항목을 정렬할 수 있습니다.
start
그리드 아이템을 컨테이너의 시작(위쪽) 부분에 정렬합니다.
center
그리드 아이템을 수직 중앙에 정렬합니다.
end
그리드 아이템을 컨테이너의 끝(아래쪽) 부분에 정렬합니다.
stretch
그리드 아이템을 수직으로 늘려 컨테이너에 맞춥니다.
start
그리드 아이템을 컨테이너의 시작(왼쪽) 부분에 정렬합니다.
center
그리드 아이템을 수평 중앙에 정렬합니다.
end
그리드 아이템을 컨테이너의 끝(오른쪽) 부분에 정렬합니다.
stretch
그리드 아이템을 수평으로 늘려 컨테이너에 맞춥니다.
place-self
align-self와 justify-self를 같이 쓸 수 있는 단축 속성입니다. align-self, justify-self의 순서로 작성하고, 하나의 값만 쓰면 두 속성 모두에 적용됩니다.
.item {
place-self: start center;
}
order
order 속성은 플렉스와 마찬가지로 각 그리드 아이템의 배치 순서를 지정하는 데 사용되는 속성입니다. 이 속성은 그리드 아이템의 순서를 나타내는 정수 값으로 설정하며, 작은 숫자일수록 먼저 배치됩니다. order 속성을 사용하면 HTML 구조와 상관없이 원하는 순서로 아이템을 배치할 수 있어 그리드 레이아웃을 더 유연하게 제어할 수 있습니다. 예를 들어, 모바일 레이아웃에서는 사이드바를 위로 올리고 본문을 아래로 내릴 수 있습니다. 또한, 특정 그리드 아이템을 시각적으로 더 강조하거나 다른 아이템보다 우선시하고 싶을 때 order 속성을 사용합니다.
order 속성은 그리드 레이아웃을 유연하게 만들어 시각적 디자인을 개선할 때 유용하지만, 의미적인 구조를 훼손하지 않고 신중하게 사용해야 합니다. 이 속성은 아이템의 시각적인 순서를 변경하는 것이지 HTML 자체의 구조를 변경하는 것은 아니므로, 웹 접근성 측면에서 주의가 필요합니다. 시각장애인분들이 사용하는 스크린 리더로 화면을 읽을 때, order를 이용해 순서를 바꾼다 해도 의미적인 구조가 변경되지는 않습니다. 따라서 order 속성을 사용할 때에는 접근성을 고려하여 의미적인 구조를 유지하면서 시각적 디자인을 조정하는 것이 중요합니다.
z-index
position 속성에서 봤던 z-index 속성을 그리드 레이아웃에서도 사용할 수 있습니다. 그리드 내에서는 position 속성을 사용하지 않고도 그리드 아이템이 화면에 보이는 우선순위를 설정할 수 있습니다. 예를 들어, 그리드 아이템 중 하나가 모달 팝업 또는 드롭다운 메뉴인 경우, 이러한 팝업이 다른 아이템 위에 나타나야 할 때 z-index를 사용할 수 있습니다. 또한, 그리드 내에 중첩된 그리드가 있는 경우 z-index를 사용하여 중첩된 그리드 아이템의 쌓임 순서를 조절할 수 있습니다. 이를 통해 그리드 레이아웃 내에서도 화면 요소들의 표시 순서를 조절하여 원하는 시각적 효과를 얻을 수 있습니다.
z-index 속성은 그리드 레이아웃에서 그리드 아이템의 쌓임 순서를 조절하는 데 유용하지만, 과도한 사용은 복잡성을 증가시킬 수 있으므로 필요한 경우에만 사용하는 것이 좋습니다.
grid 단축 속성
grid-template-xxx과 grid-auto-xxx의 단축 속성입니다. grid-template-rows, grid-template-columns, grid-template-areas grid-auto-rows, grid-auto-columns, grid-auto-flow를 사용할 수 있습니다. 슬래시(/)는 보통 행의 값 / 열의 값을 분리하는 용도로 쓰입니다.
이미지는 웹 사이트에서 효과적으로 커뮤니케이션을 하는 데 있어서 핵심적인 역할을 수행합니다. 웹 페이지의 시각적인 콘텐츠 중 하나로, 이미지의 품질과 성능은 사용자 경험을 크게 좌우합니다. 특히, 모바일 디바이스와 데스크톱 환경에서 사용되는 다양한 화면 크기와 해상도에 대응하려면 이미지 반응형 처리가 필수적입니다.
이미지 반응형 처리는 웹 페이지의 빠른 로딩 속도, 데이터 사용량 최적화, 그리고 다양한 환경에서 최상의 시각적 품질을 보장하는 데 도움을 줍니다. 이를 위해서는 이미지를 효과적으로 선택하고 관리하는 기술들이 필요합니다. 이번 장에서는 이미지 반응형 웹 디자인을 위한 핵심 기술에 대해 살펴보겠습니다.
4.3.1 이미지 포맷 선택
이미지 포맷 선택하기에 앞서 아래 5가지의 상황을 고려하여 선택하여야 합니다.
용도: 이미지가 어떤 용도로 사용되는지 고려합니다. 사진, 로고, 아이콘 등 다양한 용도에 맞는 포맷을 선택합니다.
화질 요구: 화질이 중요한 경우에는 손실 압축이 적용된 JPEG나 PNG를 사용하고, 더 높은 화질이 필요한 경우에는 AVIF와 같은 고화질 포맷을 고려합니다.
파일 크기: 대역폭 제한이나 페이지 로딩 시간을 고려하여 파일 크기를 최적화합니다.
투명도 및 애니메이션: 투명한 배경이나 애니메이션을 지원해야 하는 경우에는 PNG 또는 WebP와 같은 포맷을 고려합니다.
브라우저 호환성: 대상 브라우저에서 지원하는 이미지 포맷을 고려하여 선택합니다.
JPEG (Joint Photographic Experts Group)
장점: 손실 압축을 사용하므로 파일 크기를 줄이고 화질을 유지할 수 있습니다.
단점: 투명한 배경을 지원하지 않으며, 비손실 압축은 제공하지 않습니다.
용도: 사진 및 복잡한 이미지에 적합합니다.
PNG (Portable Network Graphics)
장점: 비손실 압축을 사용하여 높은 화질 유지하고 투명한 영역 및 알파 채널 지원합니다.
단점: JPEG에 비해 파일 크기가 큰 경우가 있습니다.
용도: 일반 이미지 및 그래픽에 적합하고 투명한 배경을 지원합니다.
GIF (Graphics Interchange Format)
장점: 애니메이션 및 반복 이미지를 지원합니다.
단점: 색상 제한이 있고, 비손실 압축을 제공하지 않습니다.
용도: 간단한 애니메이션 및 간단한 그래픽에 적합합니다.
SVG (Scalable Vector Graphics)
장점: 크기가 조절 가능하며, 해상도에 영향을 받지 않습니다. 텍스트 기반 형식이므로 파일 크기가 작습니다.
단점: 복잡한 비트맵 이미지에는 적합하지 않습니다.
용도: 벡터 그래픽 및 아이콘에 적합합니다.
WebP
장점: 작은 파일 크기와 높은 화질 제공하고 투명한 배경 및 애니메이션 지원 가능합니다.
단점: 모든 브라우저에서 지원하지는 않을 수 있습니다.
용도: Google에서 개발한 형식으로, JPEG 및 PNG 대체용으로 사용 가능합니다.
AVIF (AV1 Image File Format)
장점: 최신 비손실 압축 형식으로, 작은 파일 크기와 높은 화질을 제공합니다.
단점: 모든 브라우저에서 지원하지는 않을 수 있습니다.
용도: 고화질 이미지에 적합한 최신 형식입니다.
이미지 : flaticon.com
💡
비손실 압축(Lossless Compression)은 데이터를 압축하고 다시 복원할 때 원본 데이터를 완벽하게 복구할 수 있는 압축 방식을 의미합니다. 이 방식은 원본 데이터의 모든 정보를 보존하므로, 이미지나 오디오, 텍스트 파일 등에서 중요한 정보가 손실되지 않도록 하는 데 사용됩니다.
alt: 대체 텍스트를 제공하는 속성으로, 이미지가 로드되지 않거나 스크린 리더가 페이지를 읽어줄 때 사용됩니다.
src 속성은 이미지 경로 확인을 위해 필수로 작성되어야 합니다.
이제 불러온 이미지를 다양한 화면 크기에 맞게 변화하는 반응형 이미지로 만들어보겠습니다.
img {
max-width: 100%; /* 이미지 최대 너비 설정 */
height: auto;
}
이미지 태그에 max-width값을 100%로 지정하여 이미지의 최대 너비를 화면에 맞게 조절합니다. 이로 인해 이미지의 너비가 부모 요소의 너비와 같아지거나 작아질 수는 있지만, 부모 요소의 너비보다 크게 확대되지는 않습니다. 또한 height값을 auto로 주어 이미지의 가로 세로 비율을 유지할 수 있도록 합니다.
max-width: 요소의 최대 너비를 설정하여 속성의 크기가 지정 값보다 커지는 것을 방지합니다.
height: 이미지의 높이를 지정합니다. 값을 auto로 줄 경우 세로는 이미지의 비율에 맞게 자동으로 조절됩니다.
화면 크기가 변화함에 따라 이미지도 반응하도록 하는 코드를 작성해 보았습니다. 여기서 이미지 크기를 좀 더 세밀하게 적용할 수는 없을까요? 아래 코드를 살펴봅시다.
/* 기본 이미지 스타일 */
img {
width: 100%;
height: auto;
}
/* 미디어 쿼리를 사용하여 화면 크기에 따라 이미지 크기 조절 */
@media (max-width: 768px) {
.image-container img {
width: 50%; /* 화면 너비가 768px 이하일 때 이미지 크기를 50%로 줄임 */
}
}
위 코드는 미디어 쿼리를 사용하여 특정한 화면 너비에 따라 이미지 크기가 변화하도록 만든 예제입니다. 화면 너비가 768px 이하일 때 이미지 크기를 50%로 줄이도록 합니다. 이렇게 앞에서 배운 미디어 쿼리를 활용하면 더 세밀한 크기 조정이 가능합니다.
반응형 웹에서 이미지를 적용할 때는 크기와 함께 해상도 또한 고려할 수 있어야 합니다. 이미지 태그 내에는 반응형 이미지를 위해 크기와 해상도에 대해 고려할 수 있는 두 가지 속성이 있습니다. 이에 대해 자세히 알아보겠습니다.
첫 번째는 srcset 속성입니다. 동일한 이미지를 다양한 해상도의 버전으로 제시하여 선택하도록 합니다. 예제 코드에서는 srcset에 세 가지 선택 사항을 제시합니다.
image-small.jpg 300w: 뷰포트 너비가 300px 이하일 때 image-small.jpg 사용
image-medium.jpg 600w: 뷰포트 너비가 600px 이하일 때 image-medium.jpg 사용
image-large.jpg 1200w: 뷰포트 너비가 1200px 이하일 때 image-large.jpg 사용
두 번째는 sizes 속성입니다. 이 속성에서는 미디어 쿼리를 통해 특정 미디어 조건에 따라 차지하는 이미지 크기 값을 지정합니다. srcset에서 제공한 이미지 후보들의 사용 규칙을 정의하는 것이기 때문에, srcset 없이 단독으로는 사용할 수 없습니다. 예제 코드는 아래와 같이 정의합니다.
(max-width: 600px) 100vw: 화면 너비가 600px 이하일 때 이미지 크기를 100%로 설정
(max-width: 1200px) 50vw: 화면 너비가 1200px 이하일 때 이미지 크기를 50%로 설정
25vw: 그 외에는 25%로 설정
srcset, sizes 속성을 이용하여 <img> 태그 안에서 반응형 이미지를 구현할 수 있는 방법에 대해 알아보았습니다. 브라우저는 이제 화면의 너비, 해상도, 이미지의 크기 등을 고려하여 환경에 따라 최적의 이미지를 나타낼 것입니다.
srcset: 여러 해상도의 이미지 버전을 나열합니다.
이미지 파일 이름, 공백, 고유 픽셀 너비로 이루어졌으며 고유 픽셀 너비는 w단위를 사용합니다.
sizes: 각 미디어 조건에 따라 이미지가 화면을 얼마나 차지할지 나열합니다.
미디어 조건문, 공백, 차지할 너비 값으로 작성하며 px, em 또는 vw를 사용해야 합니다.
💡
w서술자는 이미지의 해상도를 나타내는 데 사용되는 단위로, 원본 이미지의 픽셀 너비(width)를 알려줍니다. 예를 들어 300w는 이미지의 픽셀 너비가 300px 임을 의미하고, 600w는 이미지의 픽셀 너비가 600px 임을 나타냅니다.
<picture> 태그는 여러 환경에 따라 다른 이미지를 표시하려는 경우에 사용하는 태그입니다. <picture> 태그 내에 다양한 구성 요소들을 활용하여 화면 크기에 따른 다양한 이미지를 구현할 수 있습니다. 예제와 함께 구성 요소들을 살펴보겠습니다.
<img> 태그에서는 <source> 태그에서 설정한 조건에 맞는 이미지가 없을 경우에 사용될 기본 이미지를 지정합니다.
<picture> 태그 내의 두 가지 요소를 알아보았으니, 이제 예제 코드를 다시 한번 확인해 봅시다.
max-width: 600px: 화면 너비가 600px 이하일 때 image-small.jpg 사용
max-width: 1200px: 화면 너비가 1200px 이하일 때 image-medium.jpg 사용
화면 너비가 1200px 초과일 때 image-default.jpg 사용 (기본 이미지 적용)
반응형 웹 이미지는 다양한 기기와 화면 크기에 대응하여 최적의 사용자 경험을 제공합니다. 이미지의 크기와 해상도를 조정하여 로딩 속도를 개선하고, 사용자가 편리하게 이용할 수 있도록 도움을 줍니다. 따라서 반응형 웹 디자인 프로젝트에서는 적절한 반응형 이미지 전략을 구축하여 모든 사용자에게 일관된 시각적 경험을 제공해야 합니다.
4.4 미디어
오디오, 비디오, 애니메이션과 같은 다양한 미디어 형식은 사용자와의 감성적인 연결을 강화하고, 정보의 전달력을 높여줍니다. 미디어 콘텐츠가 다양한 화면 크기와 해상도에서 최적의 경험을 제공하기 위해서는 반응형 처리가 필수적입니다.
HTML 내에서 직접적으로 미디어의 반응형 처리를 할 수 있는 태그는 제한적이지만, 기본 미디어 삽입 태그와 CSS의 조합을 통해 효과적인 반응형 미디어를 구현할 수 있습니다. 이번에는 이러한 접근 방식과 함께 미디어의 반응형 처리를 위한 핵심 전략을 알아보겠습니다.
4.4.1 미디어 포맷 선택
MP4 (H.264 codec)
장점: MP4는 효율적인 압축률과 높은 호환성을 가진 동영상 포맷입니다. 대부분의 웹 브라우저와 디바이스에서 지원되며, 고품질의 비디오를 제공합니다.
단점: 특허권 문제로 인해 일부 오픈 소스 프로젝트에서 사용이 제한될 수 있습니다.
용도: 웹 스트리밍 서비스(YouTube 등), 멀티미디어 콘텐츠 배포 등 다양한 웹 기반 비디오 콘텐츠에 널리 사용됩니다.
WebM (VP8/VP9 codec)
장점: WebM은 Google이 개발한 오픈 소스 동영상 포맷으로서 라이센스 문제가 없으며, 고효율의 압축률을 가지고 있습니다.
단점: 아직 모든 브라우저에서 완벽하게 지원되지 않아 호환성 문제를 겪을 수 있습니다.
용도: 웹 기반 비디오 스트리밍 서비스에 주로 사용되며 HTML5기반의 게임 및 앱에서도 많이 활용됩니다.
Ogg (Theora codec)
장점: Ogg Theora는 오픈 소스 동영상 포맷으로서 라이센스 문제가 없습니다.
단점: 압축률과 비디오 품질 면에서 MP4나 WebM보다 상대적으로 낮으며 일부 브라우저(옛 버전의 Internet Explorer 등)에서 지원하지 않아 호환성 문제를 겪을 수 있습니다.
용도: 인터넷 방송, 게임 사운드 클립 등 다양한 멀티미디어 콘텐츠에 사용됩니다.
이미지 : flaticon.com
4.4.2 미디어 태그
<video> 태그는 웹 페이지에 비디오를 직접 삽입하고 싶을 때 사용합니다. 비디오와 관련된 또 다른 태그인 <iframe>과는 용도, 사용 방법 등의 차이가 있습니다. 이 차이는 <video> 태그를 살펴본 후 알아보도록 하겠습니다. 아래의 예제를 통해 비디오 태그의 구성 요소들을 확인해 봅시다.
예제 코드에서는 위와 같은 속성을 이용해서 “video.mp4”라는 비디오 파일을 임베드 합니다. 이 비디오는 너비 320px, 높이 240px의 크기로 삽입되며, controls 속성을 통해 표준 비디오 컨트롤(재생, 일시정지, 볼륨 조절, 전체 화면 등)이 비디오 아래에 표시됩니다.
이러한 방식으로 <video> 태그를 사용하면 웹 페이지에 비디오를 쉽게 삽입할 수 있습니다. 여기서 더 나아가 다양한 브라우저에서의 호환성을 고려한 태그로 발전시켜보겠습니다.
위 코드에서는 <video> 태그 내에 <source> 태그를 사용하였습니다. 모든 웹 브라우저가 동일한 비디오 포맷을 지원하지는 않습니다. 예를 들어, 일부 브라우저는 MP4를 지원하지만 WebM을 지원하지 않을 수 있고, 반대의 경우도 있습니다. <source> 태그를 사용하면 여러 비디오 포맷을 지정하여 브라우저가 자동으로 지원하는 포맷을 선택하게 할 수 있습니다.
하지만 width, height 값을 고정 값으로 넣어주게 되면 반응형 처리가 되지 않는다는 사실을 아실 것입니다. 그럼 이제 <video> 태그로 삽입한 비디오를 반응형 비디오로 만들어보겠습니다.
padding-bottom: 56.25%: 16:9의 종횡비를 나타내며, 이를 통해 비디오는 항상 16:9의 비율을 유지
height: 0: 컨테이너의 높이를 0으로 설정하여 실제 높이는 ‘padding-bottom’에서만 조절 가능
width: 100%, height: 100%: 비디오의 크기를 컨테이너 크기에 맞게 조절
이 예제를 사용하면 브라우저 너비에 따라 크기가 자동으로 조절되면서, 동시에 16:9 종횡비를 유지하는 반응형 비디오를 구현할 수 있습니다.
<iframe> 태그는 <video> 태그와 달리 직접 비디오를 삽입하기 위한 태그는 아닙니다. 이는 웹 페이지 내에 다른 웹 페이지나 외부 콘텐츠를 삽입할 때 사용됩니다. YouTube, Vimeo와 같은 비디오 호스팅 서비스에서 제공하는 임베딩 코드는 주로 <iframe>을 사용합니다.
srcdoc: iframe의 내용을 직접 명시 (iframe 내부에 표시될 HTML 문자열)
allowfullscreen: iframe 내에서 전체 화면 모드를 허용
loading: iframe의 로딩 전략을 지정
예제의 코드에서는 ‘https://www.example.com’ 주소의 웹 페이지를 로드하도록 설정되어 있습니다. 이 iframe은 loading="lazy" 속성을 통해 로드됩니다. 사용자가 페이지를 스크롤 하여 iframe 영역에 접근하기 전까지는 로드되지 않습니다. 이는 웹 페이지의 초기 로딩 속도를 빠르게 하기 위한 전략입니다.
<iframe> 태그의 경우 사용 시 주의사항이 있습니다. 이전에 <iframe> 을 이용해서 문제가 된 사례가 있습니다. 사례 중 일부로 설명드리도록 하겠습니다.
보안이 문제가 된 사례
XSS 공격 (크로스 사이트 스크립팅)으로 해커들이 iframe을 이용하여 웹 페이지에 악의적인 코드를 넣어 다른 웹사이트를 가장한 후 사용자의 정보를 훔치거나 다른 해킹 시도를 시도한 적이 있습니다.
클릭재킹 공격으로 iframe을 사용하여 사용자가 의도하지 않은 클릭을 유도하고 악의적인 동작을 유도하는 사례도 있었습니다.
웹 접근성이 문제가 된 사례
iframe을 사용한 웹사이트는 스크린 리더와 같은 보조 기술을 사용하는 사용자에게 접근하기 어려운 경우가 있어서, 웹 접근성을 준수하기 어려웠습니다.
검색 엔진 최적화(SEO)가 문제 된 사례
iframe 안의 콘텐츠는 검색 엔진에서 색인화되지 않거나 적절하게 표시되지 않을 수 있어서, 웹페이지의 SEO에 부정적인 영향을 미친 경우가 있습니다.
모바일 호환성이 문제 된 사례
iframe은 모바일 기기에서 화면 크기에 맞게 자동으로 조절되지 않아서, 모바일 환경에서 사용자 경험을 저해하는 문제가 있었습니다.
위와 같은 내용을 잘 기억해서 iframe 태그를 활용하는 것이 중요합니다!
💡
iframe은 웹 페이지 내에서 다른 웹 페이지나 콘텐츠를 효과적으로 임베드 하는 강력한 도구입니다. 보안 취약성에 대한 우려가 있지만, 이러한 취약성을 신중하게 고려하고 적절하게 사용한다면, 사용자에게 다양한 콘텐츠와 기능을 제공하는 웹 사이트를 구현하는 데 큰 도움이 될 것입니다.
미디어 콘텐츠를 임베드 하는 경우에는 <iframe> 대신 특화된 도구들이 종종 사용됩니다. YouTube IFrame Player API가 그런 예입니다.
YouTube IFrame Player API는 YouTube 동영상을 웹 페이지에 임베드하고 제어하기 위한 JavaScript 라이브러리입니다. 이 API를 통해 개발자들은 프로그래밍 방식으로 비디오의 재생, 일시정지, 정지 및 볼륨 조절과 같은 작업을 수행할 수 있습니다. 따라서 <iframe>만으로는 어려울 수 있는 고급 제어 기능을 활용할 수 있게 됩니다.
또한 IFrame Player API를 활용하여 반응형 디자인에 맞춘 비디오 플레이어 구현도 가능합니다. CSS와 함께 적절히 활용하면 화면 크기에 따라 자동으로 크기가 조정되는 YouTube 비디오 플레이어를 만들 수 있습니다.
IFrame Player API를 사용하여 YouTube 동영상을 자동으로 크기 조정하는 방법을 JavaScript를 사용해서 구현해 보도록 하겠습니다. 동영상을 재생할 HTML 요소와 API 키가 필요합니다.
<script>
// IFrame Player API를 비동기로 로드합니다.
const tag = document.createElement('script');
tag.src = 'https://www.youtube.com/iframe_api';
const firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
/*
여기까지 IFrame Player API를 비동기 로드 한다는 의미로 해당 코드를 사용하지 않는다면
html코드에서 script를 이용해서 import 해야 합니다.
*/
let player; // YouTube 동영상 플레이어 객체
// API 로드 후 호출될 함수
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '720', // 동영상 플레이어의 높이
width: '1280', // 동영상 플레이어의 너비
videoId: 'M7lc1UVf-VE', // 재생할 동영상의 고유 ID
playerVars: {
autoplay: 1, // 자동 재생 여부
controls: 1, // 동영상 컨트롤러 표시 여부
modestbranding: 1, // YouTube 로고 표시 여부
showinfo: 0, // 동영상 정보 표시 여부
loop: 1 // 반복 재생 여부
},
events: {
'onReady': onPlayerReady
}
});
}
// 동영상 플레이어가 준비되면 호출되는 함수
function onPlayerReady(event) {
// 동영상 플레이어 크기를 자동으로 조정
const aspectRatio = 16 / 9; // 원하는 가로:세로 비율
const playerElement = document.getElementById('player');
const containerWidth = playerElement.offsetWidth;
const newHeight = containerWidth / aspectRatio;
// 플레이어 크기 조정
player.setSize(containerWidth, newHeight);
}
</script>
videoId 항목에 재생할 동영상의 고유 ID를 넣어 줍니다. YouTube 영상을 선택하여 주소를 확인하면 다음과 같이 고유 ID를 확인할 수 있습니다.