본문 바로가기
TIL/Code States

Code States 12일차 - CSS 중급

by 죠르띠에 2021. 8. 3.

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 구성하기

대부분의 경우 콘텐츠의 흐름은 좌에서 우, 위에서 아래로 흐른다. CSS로 화면을 구분할 때에는 수직분할과 수평분할을 차례대로 적용하여 콘텐츠의 흐름을 따라 작업을 진행한다.

  1. [수직분할] 화면을 수직으로 구분하여, 콘텐츠가 가로로 배치될 수 있도록 요소를 배치한다.
  2. [수평분할] 분할된 각각의 요소를 수평으로 구분하여, 내부 콘텐츠가 세로로 배치될 수 있도록 요소를 배치한다.
    • 수평으로 구분된 요소에 height 속성을 추가하면, 수평분할을 보다 직관적으로 할 수 있다.

 

레이아웃 리셋

HTML 문서는 기본적인 스타일을 가지고 있다. 때때로 HTML 문서가 갖는 기본 스타일이, 레이아웃을 잡는 데 방해가 되기도 한다.

  • 박스의 시작을 정확히 (0,0)의 위치에서 시작하고 싶은데, <body> 태그가 가진 기본 스타일에 약간의 여백이 있다.
  • width, height 계산이 여백을 포함하지 않아 계산에 어려움이 있다. (이전 유닛을 통해 박스 크기 측정 기준(box-sizing)에 대해 학습한 내용이다.)
  • 브라우저(크롬, 사파리 등)마다 여백이나 글꼴과 같은 기본 스타일이 조금씩 다르다.

이러한 수요에 따라 초기화(리셋)을 위한 다양한 라이브러리(Normalize.css)가 등장했지만, 사실 굳이 라이브러리를 사용할 필요는 없으며, 위에 언급한 문제를 해결할 몇 줄의 코드를 적용시키면, 기본 스타일링을 제거하여 디자인한 대로 레이아웃을 구현할 수 있다.


Flexbox로 레이아웃 잡기

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

 

display : flex 분석하기

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

<!-- "display: flex"를 적용시키는 예시를 위해 작성한 HTML 코드 -->
<div id="outer">
  <div class="box">box1</div>
  <div class="box">box2</div>
  <div class="box">box3</div>
</div>

 

/* HTML의 div 요소를 선택하여, 부모요소에 "display: flex"를 적용한 예시 */
#outer {
  display: flex;
  border: 1px dotted red;
  padding: 10px;
}

.box {
  border: 1px solid green;
  padding: 10px;
}

 

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

flex: <grow> <shrink> <basis>

이 순서와 기본값은 반드시 기억하세요. *"flex: grow shrink basis", "flex: 0 1 auto"*

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

flex-grow: 0;
flex-shrink: 1;
flex-basis: auto;

flex 속성의 하위 속성

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

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

.target {
  flex: 1 1 auto;
}

 

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

.box {
  flex: 1 1 auto;
}

 

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

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

.target {
  /* flex 값을 지정하지 않음 */
}

 

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

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

 

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

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

 

콘텐츠 수평 정렬 (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

와이어프레임 설계 및 목업 구현

와이어프레임 (Wireframe)

웹 또는 앱을 개발할 때 레이아웃의 뼈대를 그리는 단계를 와이어프레임이라고 한다. 와이어프레임은 말 그대로 "와이어로 설계된 모양"을 의미하며, 단순한 선이나, 도형으로 웹이나 앱의 인터페이스를 시각적으로 묘사한 것이다. 와이어프레임은 아주 단순하게, 레이아웃과 제품의 구조를 보여주는 용도이다. 전환 효과나, 애니메이션, 사용자 테스트같은 스타일링 요소나 UX(사용자 경험, User Experience)를 판단하는 것이 아니다.

목업(Mock-up)

대부분의 산업에서 목업은 실물 크기의 모형을 뜻한다. 실물 제품이 없는 무형의 웹 또는 앱은 어떻게 목업을 만들까? 웹 또는 앱을 제품이라고 할 때, 목업은 실제 제품이 작동하는 모습과 동일하게 HTML 문서를 작성한다. 예를 들어, 트윗 작성자, 트윗 내용, 작성한 날짜 등을 HTML 문서 내에 하드코딩하는 방식이다.