[엘리스 sw 엔지니어 트랙] 52일차 CSS-in-JS, Felxbox

오경찬·2022년 7월 15일
0

수업 52일차

이론

  • css module: 하나의 css module 파일 안에 작성한 스타일은 하나의 파일 namespaace로 관리, 두단어 이상 camelCase로 지음
    CSS-in-JS: 별도의 CSS 파일을 만들지 않고 하나의 컴포넌트 파일 안에서 스타일 작성
    CSS Box Model : CSS layout의 기본이 되는 모델
    static: position의 default 값으로, element는 normal flow를 따라 위치함.
    relative: normal flow를 따라 위치하되, 자기 자신에 상대적으로 위치함
    absolute: normal flow에서 벗어나 가장 가까운 ancestor에 상대적으로 위치함
    fixed: normal flow를 벗어나 viewport에 상대적으로 위치함
    sticky: normal flow에 따라 위치하되, 가장 가까운 sxrolling ancestor에 상대적으로 위치함
    Sass: 모듈, 믹스인, nested style, 변수, 조건문, 반복문 등의 기능으로 CSS를 프로그래밍 언어적으로 활용하도록 확장.
    CSS Flexbox Model: HTML element를 하나의 상자로 간주하고, 그안에서 어떻게 내부 item을 배열할 것인가를 스타일 하는 모델
    styled-components: 자바스크립트 파일 안에 스타일을 정의하고, React컴포넌트 처럼 활용

CSS-in-JS

  • JavaScript 안에 css를 넣어, component 위주의 컨셉
    • scss, css는 js와 따로 파일을 두면서 다양한 컴포넌트에서 사용하거나 nested 개념도 쓰면서 다양한
      스타일 의존성이 생겼다.
    • 의존성이 생기면 하나를 고치면 여러 케이스가 변경되어 확인할 작업과 고려할 작업이 많아진다.
  • 대표적으로 styled-components, emotion.js 가 있다.

styled-components

CSS code를 component와 함께 작성할 수 있는 대표적인 library이다.
dynamic styling이 가능하다.
props로 넘겨주면서 adapting 가능
또한, Style을 확장시키거나 기존처럼 media query, nesting도 가능하다.

import React from 'react';
import styled from 'styled-components';


interface ButtonProps {
  label: string;
}

function RoundButton({label}: ButtonProps) {
  // code
  // ...
  
  return <ButtonStyle label={label}> This is button component </ButtonStyle>;
}

const ButtonStyle = styled.button<ButtonProps>`
  color: turquoise;
  label: ${props => props.label || ""};
`;

Tagged Template Literal

Styled Component에서 쓰이는 문법의 원리는 Tagged Template Literal이라는 문법이다.
백틱(``)을 이용해서 template literal을 표현한다.

// syntax
tag `
  string text ${expression} string text
`
// 이 때 tag는 함수라고 한다.

예시로 다음처럼 사용할 수 있으며 console.log로 호출하면 expression과 문자열이 분리된다.

var person = 'NAME';
var age = 20;

function tag(strings, personExp, ageExp) {
  console.log(strings, personExp, ageExp);
}

tag`Person ${person} is a ${age}`;
// [['Person', ' is a ', ''], 'NAME', 20]

그래서 styled component는 위 문법을 이용해서 각 tag마다 function을 실행한다고 생각할 수 있다.

emotion.js

css prop을 쓰는 것이 emotion의 주요 특징이다.

import React from 'react';
import styled from '@emotion/styled';
import { css } from '@emotion/react';

interface ButtonProps {
  label: string;
  color: string;
  primary: boolean;
}

function Button({ label, color }: ButtonProps) {
  const handleClick = () => {
    alert('Clicked button!');
  };
  return (
    <button
      css={css`
        padding: 32px;
        font-size: 24px;
        color: ${color};
        font-weight: bold;
        background-color: green;
        &:hover {
          background-color: green;
        }
      `}
      onClick={handleClick}
    >
      ${label}
    </button>
  );
}

export default Button;

styled prop으로 styled components 처럼도 사용할 수 있다.

import React from 'react';
import styled from '@emotion/styled'

interface ButtonProps {
  label: string;
}

function RoundButton({label}: ButtonProps) {
  // code
  // ...
  
  return <ButtonStyle label={label}> This is button component </ButtonStyle>;
}

const ButtonStyle = styled.button<ButtonProps>`
  color: turquoise;
  label: ${props => props.label || ""};
`;

두 특성을 통해 string style, object style 방식을 모두 사용 가능하다.

Flexbox

flexbox는 뷰포트나 요소의 크기가 불명확하거나 동적으로 변할 때에도 효율적으로 요소를 배치, 정렬, 분산할 수 있는 방법을 제공하는 CSS3의 새로운 레이아웃 방식이다. flexbox의 장점을 한 마디로 표현하면 '복잡한 계산 없이 요소의 크기와 순서를 유연하게 배치할 수 있다' 라고 할 수 있다. 정렬, 방향, 순서, 크기 등을 유연하게 조절할 수 있기 때문에 별도의 분기 처리를 줄일 수 있고, CSS만으로 다양한 레이아웃을 구현할 수 있다.

Flexbox 만들기

.flex_container {
    display: flex;
}

display를 부모요소에 flex속성을 선언해서 사용한다.

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

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

  • row (기본값)
  • column

-> 반드시 알아두자 : grow(팽창 지수), shrink(수축 지수), basis(기본 크기)
자식 박스에 어떠한 속성도 주지 않으면, 왼쪽에서부터 오른쪽으로 콘텐츠의 크기만큼 배치된다. 자식 요소의 flex 속성을 추가하지 않으면, 다음과 같은 기본값이 적용된다.

flex: 0 1 auto;

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

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

grow

아래의 target 클래스에서, flex-grow 속성의 값을 1로 변경하면 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씩 크기를 가짐)

shrink

shrink는 grow와 반대로, 설정한 비율만큼 박스 크기가 작아진다. 그러나 flex-grow 속성과 flex-shrink 속성을 함께 사용하는 일은 추천하지 않습니다. 비율로 레이아웃을 지정할 경우 flex-grow 속성 또는 flex: 1 auto와 같이 grow 속성에 변화를 주는 방식을 권장한다. flex-shrink 속성은 width나 이후 설명할 flex-basis 속성에 따른 비율이므로 실제 크기를 예측하기가 어렵기 때문이다. flex-grow 속성으로 비율을 변경하는 경우, flex-shrink 속성은 기본값인 1로 두어도 무방하다.

실제 레이아웃을 하면서 여러 어려움이 있을때는 다음 원리를 생각해보자.

  • 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 는 가로축이 됩니다.

콘텐츠 수평 정렬 (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
코린이 입니당 :)

0개의 댓글