DAY 013. 코드스테이츠 3주차 - CSS (레이아웃과 CSS Selector)

슈레더·2021년 6월 30일
0

코드스테이츠

목록 보기
13/25
post-thumbnail

CSS Selector

CSS Selector란?

CSS 선택자(CSS Selector)는 스타일을 지정하고자 하는 HTML DOM 요소를 선택할 때 사용되는 CSS 규칙

CSS Selector의 종류

셀렉터

h1 { }
div { }

전체 셀렉터

* { }

Tag 셀렉터

section, h1 { }

ID 셀렉터

#only { }

class 셀렉터

.widget { }
.center { }

attribute 셀렉터

a[href] { }
p[id="only"] { }
p[class~="out"] { }
p[class|="out"] { }
section[id^="sect"] { }
div[class$="2"] { }
div[class*="w"] { }

후손 셀렉터

header h1 {}

자식 셀렉터

header > p { }

인접 형제 셀렉터

section + p { }

형제 셀렉터

section ~ p { }

가상 클래스

a:link { }
a:visited { }
a:hover { }
a:active { }
a:focus { }

요소 상태 셀렉터

input:checked + span { }
input:enabled + span { }
input:disabled + span { }

구조 가상 클래스 셀렉터

p:first-child { }
ul > li:last-child { }
ul > li:nth-child(2n) { }
section > p:nth-child(2n+1) { }
ul > li:first-child { }
li:last-child { }
div > div:nth-child(4) { }
div:nth-last-child(2) { }
section > p:nth-last-child(2n + 1) { }
p:first-of-type { }
div:last-of-type { }
ul:nth-of-type(2) { }
p:nth-last-of-type(1) { }

부정 셀렉터

input:not([type="password"]) { }
div:not(:nth-of-type(2)) { }

정합성 확인 셀렉터

input[type="text"]:valid { }
input[type="text"]:invalid { }

레이아웃

레이아웃 리셋

HTML 문서는 기본적인 스타일을 가지고 있다.
하지만 각 브라우저마다 여백 및 글꼴 스타일이 조금씩 다르고 body 태그 기본 스타일에
약간의 여백이 있다.
그래서 아래의 몇 줄을 추가해서 레이아웃을 리셋 시켜주어야 한다.

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

HTML 구성하기

VSCode와 비슷한 레이아웃을 만들고 싶다고 가정할 때,

실제 VS Code의 레이아웃을 분석해 큰 틀에서 추상화하면, 다음과 같이 영역을 나눌 수 있다.

CSS로 화면을 구분할 때에는 수직분할과 수평분할을 차례로 적용한다.
HTML 문서를 통해 레이아웃을 작성하면, 다음과 같이 구성할 수 있다.

<div id="container">
  <div class="col w10">
    <div class="icon">아이콘 1</div>
    <div class="icon">아이콘 2</div>
    <div class="icon">아이콘 3</div>
  </div>
  <div class="col w20">
    <div class="row h40">영역1</div>
    <div class="row h40">영역2</div>
    <div class="row h20">영역3</div>
  </div>
  <div class="col w70">
    <div class="row h80">영역4</div>
    <div class="row h20">영역5</div>
  </div>
</div>
  • 참고: 클래스 이름으로 지정된 w10, w20, w70, 또는 h20, h40, h80을 CSS로 구현하면, 다음과 같다.
.w70 { width: 70%; }
.h40 { height: 40%; }

이렇게 클래스 이름과 구현을 1:1로 일치시켜 아주 작은 단위로 CSS를 작성 기법을 Atomic CSS 방법론이라고 한다.
클래스 이름을 선언하는 방법에 대한 이야기는 아래 링크에서 확인할 수 있다.
CSS Architcture: Atomic CSS

Flexbox로 레이아웃 잡기

flex(flexible)는 "잘 구부러지는, 유연한"이라는 뜻이다. flexbox로 레이아웃을 구성한다는 것은, 박스를 유연하게 늘리거나 줄여 레이아웃을 잡는 방법이다.

display: flex 분석하기

부모 박스요소에 display: flex를 적용해, 자식 박스의 방향과 크기를 결정하는 레이아웃 구성방법이다.
기본값으로, display: flex가 적용된 부모 박스의 자식 요소는 왼쪽부터 차례대로 이어 배치된다.

<div id="outer">
  <div class="box">box1</div>
  <div class="box">box2</div>
  <div class="box">box3</div>
</div>
  • "display: flex"를 적용시키는 예시를 위해 작성한 HTML 코드
#outer {
  display: flex;
  border: 1px dotted red;
  padding: 10px;
}

.box {
  border: 1px solid green;
  padding: 10px;
}
  • HTML의 div 요소를 선택하여, 부모요소에 "display: flex"를 적용한 예시

  • "display: flex"가 적용된 빨간 박스 내의 자식요소는 왼쪽부터 차례대로 배치된다.

Flex 요소에 방향 지정하기 (flex-direction)

flexbox는 박스가 수직으로 분할되는 것이 기본값이다. 그러나 방향을 설정해주면, 수평으로도 분할할 수 있다. flex-direction 속성은 부모 박스요소에 적용한다. 자식 박스에 특별한 속성을 주지 않아도, 부모 요소에 의해 자식 요소가 영향을 받는다. 주요 속성은 다음과 같다.

  • row (기본값)
  • column

※주의※
display 속성에 flex를 적용하는 것은 부모 요소에 적용한다. (display: flex)
자식 요소는 flex라는 속성에 값을 적용한다. (flex: 0 1 auto)

grow(팽창 지수), shrink(수축 지수), basis(기본 크기)

자식 박스에 어떠한 속성도 주지 않으면, 왼쪽에서부터 오른쪽으로 콘텐츠의 크기만큼 배치된다. 자식 요소의 flex 속성을 추가하지 않으면, 다음과 같은 기본값이 적용된다.

flex: 0 1 auto;
  • 자식요소에 flex 속성을 추가하지 않으면 적용되는 기본값

flex 속성에 적용되는 세 가지 영역은, margin이나 padding에서 띄어쓰기를 기준으로 의미하는 바가 구분되는 것과 동일하다. 그러나, flex 속성에 적용되는 세 가지는 기본 크기를 바탕으로 필요에 따라 늘리거나 줄일 수 있는 값이 적용된다. 각각의 값이 의미하는 것은 다음과 같다.

flex: <grow> <shrink> <basis>
  • flex 속성에 적용되는 세 가지 값의 종류

margin이나 padding에서 상하좌우 각 방향을 따로 지정할 수 있었던 것처럼, flex에 적용되는 grow, shrink, basis도 각 값을 따로 지정할 수 있다.

flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;
  • flex에 입력되는 세 속성을 따로 입력할 수도 있다.

grow, shrink 속성은 단위가 없고, 비율에 따라 결과가 달라진다. 부모 박스 안에 n개의 자식 박스가 있다고 가정해보자. 각 자식 박스가 갖는 grow값의 총 합이 n이라면, grow 속성의 값을 1로 설정하는 것은 1/n 가로 또는 세로길이를 적용한다는 의미다. grow 속성의 값을 2로 지정하면, 2/n의 길이를 의미한다. HTML 파일을 다음과 같이 변경하고, 첫 번째 자식 박스에 target 클래스를 추가한 다음, 여러가지 방식으로 접근해보자.

<div id="outer">
  <div class="box target">.box.target</div>
  <div class="box">.box</div>
  <div class="box">.box</div>
</div>
  • html 파일에서, 자식 박스 요소 중 첫 번째 자식 박스 요소에 target 클래스를 추가한다.

flex 속성의 하위 속성

grow: 자식 박스는 얼마나 늘어날 수 있을까?

target 클래스에서, flex-grow 속성의 값을 1로 변경한다. target 클래스를 가지고 있는 첫 번째 자식박스는, 부모 박스의 가로 길이 중에서 남은 빈 영역만큼 늘어난다. 위 설명대로라면 전체 자식요소가 가진 grow 값의 합은 1+0+0 = 1이므로, target 클래스를 가지고 있는 자식 박스의 가로 크기는 1/1 = 100% 다. 그러나 다른 자식 박스 안에 이미 콘텐츠가 존재하므로, 다른 자식 박스안의 콘텐츠가 담긴 길이를 제외한 나머지 가로 길이가 target 클래스를 가진 자식박스의 가로 길이다.

.target {
  flex: 1 1 auto;
}
  • target 클래스에 flex-grow 속성의 값을 1로 설정
  • target 클래스에만 flex-grow 속성에 1을 적용한 경우

box 클래스의 flex-grow는 기본값인 0이다. 만약 box 클래스의 flex-grow 속성에 값을 1로 설정하면, 모든 박스가 늘어나려고(grow) 한다. 결과적으로 모든 박스가 동일한 비율로 가로 길이가 늘어난다. (총 grow 값 1+1+1, 각 박스는 1/3씩 크기를 가짐)

.box {
  flex: 1 1 auto;
}
  • box 클래스의 flex-grow 속성의 값을 1로 설정
  • box 클래스의 flex-grow 속성에 1을 적용한 경우

flex-grow 속성에 적용하는 값은 비율을 의미한다. 모든 자식 박스의 flex-grow 속성이 0보다 큰 값을 동일하게 가지는 경우, 각 박스의 가로 길이는 동일한 비율을 가진다. 다음 코드는 전부 같은 모양으로 렌더링된다.

.box {
  flex: 1 1 auto;
  /*
  flex: 2 1 auto;
  flex: 3 1 auto;
  flex: 4 1 auto;
  */
}

.target {
  /* flex 값을 지정하지 않음 */
}
  • 모든 자식 박스에 flex-grow 속성의 값을 동일하게 적용하면, 모든 자식 요소의 flex-grow 속성의 값을 1로 설정한 것과 같다.

box 클래스의 flex-grow 속성에는 1을 그대로 두고, target 클래스의 flex-grow 속성의 값을 변경해보자. target 클래스를 가지고 있는 자식 박스는, 다른 자식 박스와의 비율만큼 크기가 더 커진다.

.box {
  flex: 1 1 auto;
}

/* 
 * 자식 박스가 총 세개인데, target만 2의 비율을 가집니다.
 * 2(target) + 1(box2) + 1(box3) = 4 이므로,
 * target의 비율은 50% 입니다.
 */
.target {
  flex: 2 1 auto;
}
  • target 클래스의 flex-grow 속성을 2로 설정

target 클래스에 적용된 flex-grow 속성의 값이 1, box 클래스에 적용된 flex-grow 속성의 값이이 1일 경우, grow가 적용된 전체 값은 1+1+1 = 3이다. 따라서, 각 자식 박스의 가로 길이는 1/3의 길이를 가진다.

  • 모든 자식 박스의 flex-grow 속성에 같은 값을 설정한 경우

target 클래스의 flex-grow 속성의 값이 2, box 클래스의 flex-grow 속성의 값이 1일 경우, grow가 적용된 전체 값은 2+1+1 = 4이다. 따라서, target 클래스를 가지지 못한 나머지 자식 박스는 1/4의 길이를 가진다.

  • target 클래스의 flex-grow 속성에만 2를 적용하고, box 클래스의 glex-grow 속성은 1로 설정한 경우

shrink: 자식 박스는 얼마나 줄어들 수 있을까?

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 크기를 지정하면 그 크기는 유지된다.

<div id="outer">
  <div class="left">메뉴</div>
  <div class="right">본문</div>
</div>
  • HTML 파일에 작성된 메뉴와 본문이라는 두 가지 자식 박스
/* grow를 0으로 설정해줘야 100px 이상으로 늘어나지 않습니다. */
.left {
  flex: 0 1 100px;
}

/* 우측 박스는 grow를 1로 설정해 나머지 공간을 채워줍시다 */
.right {
  flex: 1 1 auto;
}
  • 왼쪽 메뉴 박스는 크기를 유지해야 하므로 flex-basis 속성에 100px을 적용한다.
  • 오른쪽 본문 박스는 flex-basis 속성이 auto로 설정되어 flex-grow 속성의 영향을 받는다.

  • flex-grow 속성에 동일한 값을 입력한 박스

flex-grow 속성의 값이 0인 경우에만 flex-basis 속성의 값이 유지된다. diplay 속성에 flex가 적용된 컨테이너 내부에 존재하는 자식 박스는 경우에 따라, basis로 설정된 크기가 항상 유지되는 것은 아니다. flex-grow 속성의 값이 1 이상인 경우, flex-basis 속성에 적용한 값보다 커질 수도 있다. 실제 레이아웃을 구현하면서 막히는 경우에는, 다음의 원리를 참고할 수 있다.

  • widthflex-basis를 동시에 적용하는 경우, flex-basis가 우선됩니다.
  • 콘텐츠가 많아 자식 박스가 넘치는 경우, width가 정확한 크기를 보장하지 않습니다.
  • (flex-basis를 사용하지 않는다면) 콘텐츠가 많아 자식 박스가 넘치는 경우를 대비해, width 대신 max-width를 쓸 수 있습니다.

콘텐츠 정렬 방법

Flexbox를 원하는 대로 제어하기 위해서는 axis(축)의 개념에 대한 이해가 필요하다.
axis는 main axis 와 cross axis로 구분한다.

main axis은 flex-direction 속성에 의해서 결정된다.
flex-direction의 기본 값인 row 인 상태일 때 main axis 는 가로축이 된다.

cross axis는 여러 개의 main axis와 수직을 이루는 방향이다. main axis가 가로일 때 cross axis는 세로가 된다.

이 axis들을 기준으로 정렬할 수 있는 속성들에 justify-contentalign-items 가 있다.
justify-content 속성은 main axis를 기준으로 정렬하며, align-items 속성은 cross axis를 기준으로 정렬한다.

flex-direction 속성의 값을 column 으로 준다면 main axis과 cross axis는 서로 바뀐다.

이어지는 내용은 flex-directionrow 인 상태, 즉 main axis가 가로인 상태를 기준으로 설명하는 내용이다.

콘텐츠 수평 정렬 (justify-content)

부모 박스에 justify-content 속성을 적용하면, 자식 박스를 수평으로 정렬할 수 있다. 다음은 justify-content 속성의 값이 될 수 있는 주요 옵션이다.

  • flex-start
  • flex-end
  • center
  • space-between

콘텐츠 수직 정렬 (align-items)

부모 박스에 align-items 속성을 적용하면, 자식 박스를 수직으로 정렬할 수 있다. 다음은 align-items 속성의 값이 될 수 있는 주요 옵션이다.

  • flex-start
  • flex-end
  • center
  • stretch
profile
shreder0804

0개의 댓글