CSS flex와 selector

1. 레이아웃

Atomic CSS 방법론
1:1로 클래스 이름과 구현을 일치시켜 아주 작은 단위로 CSS를 작성하는 기법

맨 처음 레이아웃을 리셋해주어야 한다
body태그의 default 여백, 브라우저마다의 차이(글꼴, 여백 등)가 있으므로!

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
}

2. flex

  • 부모 요소에 display: flex;, 자식 요소에 flex: grow, shrink, basis 적용
  • 위 설정이 된 경우, 자식 요소는 왼쪽부터 차례대로 배치된다.
  1. flex-direction : row(default), column;
  2. flex(default) : 0 1 auto;

❗️flex 하위 속성

flex : grow(팽창 지수) shrink(수축 지수) basis(기본 크기)
grow, shrink는 단위가 없고 비율에 따라 달라지는 값이다.

1. grow
예를 들어 grow === 1 이라면,
n개의 자식요소가 있고 grow의 총 합이 n일 때, 길이 1/n을 적용한다.

.box {
  flex: 1 1 auto;
}

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

위의 경우를 예시로 확인해보자.
display: flex가 적용된 부모요소인 outer가 있고, flex-grow가 각각 1, 2로 적용된 자식요소인 box과 target이 있다.
총 grow의 합은 1*2 + 2 = 4인데, box는 1/4씩 차지하고 target은 2/4를 차지하는 것을 확인할 수 있다.

만약 모든 자식 박스의 flex-grow 속성이 0보다 큰 값을 동일하게 가진다면, 가로 길이는 모두 동일하다. (그 값이 무엇이든 상관없이!)
만약 임의의 A 박스를 제외한 모든 박스가 flex-grow를 0으로 가지면 A박스는 이 외 박스가 찌부된 상태(가로 길이가 없는 상태)로 나머지 영역을 모두 차지하게 된다.


2. shrink
웬만하면 기본값으로 사용하자! grow만으로 비율을 변경할 수 있을 뿐더러, 실제 크기를 예측하기 힘들어진다!


3. basis
grow 속성이 0일 때 고정되는 크기!

c.f. 레이아웃이 내맘대로 안될 때 참고하자

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

3. 정렬

  • main axis(flex-direction), cross axis(main과 수직되는 방향)

Justify-content

  • main axis 기준, 일반적으로 수평 정렬
  • 수평으로 정렬하고자 하는 박스의 부모 박스에 적용해야한다!
  • 속성값 옵션 flex-start, flex-end, center, space-between

align-items

  • main axis 기준, 일반적으로 수직 정렬
  • 수평으로 정렬하고자 하는 박스의 부모 박스에 적용해야한다!
  • 속성값 옵션 flex-start, flex-end, center, stretch

4. Selector

* 전체 선택자 : 모든 요소를 낱개로 전부 선택한다
.A#B A 클래스이면서 B id를 가진 요소
태그[id='이름'] 속성 선택자 : 이름을 id로 가지고 있는 태그
태그[속성] 속성 선택자 : 속성을 가지고 있는 태그
A B 하위 선택자 : A의 하위에 있는 모든 B
A > B 자식 선택자 : A의 자식요소 중 B
A + B 형제 선택자 : A에 인접한 다음 형제요소인 B
A ~ B 형제 선택자 : A에 인접한 앞, 뒤 형제요소인 B
A:first-child : A의 첫번째 자식요소
A > B:last-child : A의 자식요소인 B 중 마지막 요소
A > B:nth-child(3) : A의 자식요소인 B 중 세번째 요소
A:first-of-type : A 요소 중 형제끼리 비교해 가장 첫번째 A 요소 (하나라면 그 요소)
A:last-of-type : A 요소 중 형제끼리 비교해 가장 마지막 A 요소 (하나라면 그 요소)
A:nth-of-type : A 요소 중 두번째 A 요소(하나라면 두번째가 아니니 X)
A:not(#이름) : A 요소 중에 이름을 id로 가지고 있는 태그를 제외하고 나머지


용어 정리

  • 와이어프레임 : 화면 단위의 레이아웃 설계하는 작업
  • 목업 : 실제품을 만들어보기 전, 실물과 비슷하게 시제품을 제작하는 작업 (기능은 없지만 외형정도)
  • 프로토타입 : 처음부터 종료까지 핵심 동작이 가능하게 구현된 데모버전
  • 하드 코딩 : 서버에서 데이터를 불러오지 않고 데이터를 코드 내부에 직접 입력하는 것

만들어보자

HTML 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>VScode</title>
    <link rel="stylesheet" href="main.css">
</head>
<body>
    <div class="container">
        <div class="col w10">
            <div class="icon"></div>
            <div class="icon"></div>
            <div class="icon"></div>
        </div>
        <div class="col w20">   
            <div class="row h40"></div>
            <div class="row h40"></div>
            <div class="row h20"></div>
        </div>
        <div class="col w70">
            <div class="row h80"></div>
            <div class="row h20"></div>
        </div>
    </div>
</body>
</html>

CSS 코드

*{
    box-sizing: border-box;
}

body{
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
}

.container{
    display: flex;
    background-color: whitesmoke;
    width: 70vw;
    min-height: 80vh;
    border: 1px solid blue;
    padding: 0.4rem;
    font-size: 0.8rem;
    column-gap: 0.4rem;
}

.col{
    display: flex;
    flex-direction: column;
    border: 1px solid red;
    padding: 0.6rem;
    row-gap: 0.4rem;
}

.w10{
    flex: 1 0 0;
}
.w20{
    flex: 2 0 0;
}
.w70{
    flex: 7 0 0;
}

.icon{
    border: 1px dotted red;
}
.icon::after{
    content: "";
    display: block;
    padding-bottom: 100%;
}

.row{
    border: 1px dotted blue;
    /* margin: 1rem; */
}

.h80{
    flex: 8 0 0;
}

.h40{
    flex: 4 0 0;
}

.h20{
    flex: 2 0 0;
}

화면의 중간에 배치하기

.container를 화면 중간에 배치하기 위해서, 부모인 body에 아래 코드를 추가하였다.

justify-content: center;
align-items: center;
height: 100vh;

세로로 배열하기

.col 내에 .row영역들을 세로로 배열하기 위해서 .col에 아래 코드를 추가하였다. (display: flex; 는 당연히!)

flex-direction: column;

정사각형 반응형으로 만들기

.icon이 화면의 가로만 줄어들더라도 정사각형 모양을 유지하기 위해서는 vw, %와 같이 부모 요소의 크기에 영향을 받는 단위는 사용할 수 없었다.

가상요소 ::after를 사용하여 아래 코드를 추가하였다.

.icon::after{
    content: "";
    display: block;
    padding-bottom: 100%;
}

❗️가상요소란, 실제로 html상에서는 없지만 가짜로 하나를 만들어주는 것이다.

내용은 없지만 (content: "";) block 요소로 만들어 부모 요소로부터 주어진 width만큼 세로 길이를 padding으로 더해주는 방식이다.

이때 padding-bottom 은 padding-top 으로 변경해도 무방하다. 어쨌든 나 자신의 안쪽 위로 여백을 늘릴 것인지, 안쪽 아래로 여백을 늘릴 것인지의 차이이기 때문이다.

.icon::after가 없을 때 컨텐츠가 없는 div 태그는 height이 없으므로 아래와 같이 나타난다.

결국 영역을 만드는 것은 .icon::after이기 때문에 박스 내에 컨텐츠가 없다면 .icon은 없어도 무방하다. 하지만 컨텐츠가 있다면 아래와 같이 영역이 구성된다.

내용이 있을 때 내용을 정사각형 중간에 유지하면서 박스 자체도 정사각형을 유지할 수 있는 방법이 무엇일지 주말에 고민해보아야겠다.

width와 height을 연결하는 엄청난 아이디어라고 생각했다. 동시에, 오늘 스프린트 리뷰에서 'CSS는 정답이 없다'는 코치님의 말도 기억이 났다.

박스 사이에 간격 할당하기

space-between을 써야하나, flex로 박스의 길이가 이미 지정되어있는데 어떻게 여백을 만들어야하지 고민했는데 아주 간단한 방법이 있었다.

column-gap: 0.4rem;
row-gap: 0.4rem;

justify-contentalign-items처럼 부모요소에 지정해주면 된다.

좋은 웹페이지 즐겨찾기