본문 바로가기

WINK-(Web & App)/React.js 스터디

[2025 1학기 React.js 스터디] 이서준 #5주차

반응형

!!!!!!!!!!!!!!! 왜 나만 이런 고통을 겪어야 하는 거야 !!!!!!!!!!!!!!!

01. Sass

Sass는 CSS의 단점을 보완하기 위해 만든 CSS 전처리기라고 한다.

보통 CSS를 사용하다보면 단순 반복되는 부분이 많은 등, 불편함이 느껴지기 마련인데, Sass는 이 부분을 거의 완전히 해소시켜주는 확장된 스타일시트 언어이다.

쉽게 말해서, 복잡한 작업을 간단하게 하고 재활용성을 높여주고 가독성 부분에서 이점이 있다고 생각하면 될 것 같다.

Sass에는 Sass와 Scss가 있다.

Sass보다 Scss가 CSS와의 호환성이 더 좋다.

제일 큰 특징은

Sass - 들여 쓰기 + 줄 바꿈 형식

Scss - 중괄호 + 세미콜론 형식

보통 scss 문법이 더 많이 사용되므로, 여기선 .scss 확장자로 스타일을 작성하겠다네요

초기 설정

react 프로젝트를 만들고, 해당 프로젝트 디렉토리에 node-sass라는 라이브러리를 설치한다.

$ cd styling-with-sass
$ yarn add node-sass

이 라이브러리는 Sass를 CSS로 변환해주는 역할을 한다.

기본 scss 코드

$blue: #228be6; // 이런식으로 스타일 파일에서 사용할 수 있는 변수를 선언할 수 있음

.Button {
  display: inline-flex;
  color: white;
  font-weight: bold;
  outline: none;
  border-radius: 4px;
  border: none;
  cursor: pointer;

  height: 2.25rem;
  padding-left: 1rem;
  padding-right: 1rem;
  font-size: 1rem;

  background: $blue; // 주석 사용
  &:hover {
    background: lighten($blue, 10%); // 색상 10% 밝게 -> 함수 사용
  }

  &:active {
    background: darken($blue, 10%); // 색상 10% 어둡게
  }
}

이렇게 scss를 사용하면 기존 css에서 사용하지 못했던 문법들을 사용할 수 있다.

  • 변수 선언 ( $blue )
  • 함수 사용 ( lighten(), darken() )

의도치 못한 오류 !!!!!!!!!!!!

아니 코드 따라쳤는데 오류가 갑자기 나더라구요 근데 아무리 봐도 코드에 틀린 점이 없는데 오류가 나길래.. 찾아봤습니다.

일단 핵심 오류 메시지는 이렇다.

binding.node is not a valid Win32 application
// node-sass가 설치된 바이너리(binding.node)가 현재 시스템에서 실행되지 않음. 주로 Node.js 버전 불일치 또는 설치 중 오류 때문임.
TypeError: Cannot read properties of undefined (reading 'replace')
// 이는 보통 resolve-url-loader가 처리할 SCSS 내 경로 관련 정보가 누락됐을 때 발생함. 종속성 충돌 가능성 있음.

해결 방법

위 오류는 node-sass가 요즘 권장되지 않고, 자주 에러가 난다. 따라서 sass(Dart Sass)를 사용하는 걸 권장한단다.

npm uninstall node-sass
npm install sass

이래 했더니 해결됐음

🚨 .scss 파일에서 사용하는 &. 는 현재 선택자에 클래스명을 붙일 때 사용되는 문법이다.

즉, &는 부모 선택자(현재 선택자)를 참조한다는 의미이다.

버튼 사이즈 조정하기

우선 버튼 크기를 동적으로 설정하도록 구현한다.

import React from 'react';
import './Button.scss';

function Button({ children, size }) {
  return <button className={['Button', size].join(' ')}>{children}</button>;
}

Button.defaultProps = {
  size: 'medium'
};

export default Button;

여기서 CSS 클래스 이름을 동적으로 넣으려면 이렇게 설정한다.

className={['Button', size].join(' ')} // 1번
className={`Button ${size}`} // 2번

근데 조건부로 CSS 클래스를 넣어주고 싶을 때 classnames 라이브러리를 사용하는 것이 더 편하다.

→ 함수의 인자에 문자열, 배열, 객체 등을 전달하여 손쉽게 문자열을 조합할 수 있다.

의도치 못한 오류 !!!!!!!!!!!! - 2

import React from "react";
import classNames from "classnames";
import "./Button.scss";

function Button({ children, size }) {
  return <button className={classNames("Button", size)}>{children}</button>;
}

Button.defaultProps = {
  size: "small",
};

export default Button;

Button.js를 다음과 같이 구성했는데, defaultProps 부분이 적용이 되지 않는 것을 발견했다.

왜 그런지 살펴보니, 전에 정리했던 것과 같은 이유였다.

  • defaultProps는 함수형 컴포넌트에서 더 이상 권장되지 않는다.
  • 대신 매개변수 기본값을 사용하는 것이 표준이다.

이렇대서 매개변수 기본값을 주는 것으로 변경했더니

잘 적용이 되었습니다.

& + & 는 무엇인가

강의자료에서는 &+&가 의미하는 것이 .Button + .Button이라고 하고, 함께 있다면 우측에 있는 버튼에 여백을 설정한 것이라고 하는데, 이해가 잘 되지 않았다.

그래서 찾아봤는데,

& + &는 SCSS에서 형제 선택자인 +를 활용할 때 쓰는 문법이다.

  • & : 현재 선택자 ( ex: .Button )
  • +: 바로 다음에 오는 형제 요소를 선택
  • & + &: 같은 클래스가 바로 연속해서 두 번 나올 때 두 번째 요소에만 적용된다.

이렇기 때문에, 버튼 두개가 연속으로 나오면, 우측에 있는 버튼 ( 두번째 요소 )에만 margin이 적용되어서 여백이 생기는 것이다.

그럼 이걸 언제 쓰냐

  • 버튼 사이에 간격을 줄 때
  • 같은 컴포넌트가 인접하게 반복될 때 스타일을 차별화
  • ex: 토글 버튼, 필터 버튼 그룹, 태그 리스트 등

색상 설정하기

 

색상을 관리하는 코드를 이렇게 만들었을 때, 반복되는 코드가 많아지는 문제점이 생기는데,

아까와 말했듯이 scss는 css와 달리 재사용성이 높다.

Sass의 mixin이라는 기능을 사용해서 쉽게 재사용할 수 있다.

@mixin button-color($color) {
  background: $color;
  &:hover {
    background: lighten($color, 10%);
  }
  &:active {
    background: darken($color, 10%);
  }
}

outline 옵션 만들기

outline 이라는 옵션을 주면 버튼에서 테두리만 보여지도록 설정하기

<button className={classNames('Button', size, color, { outline })}>
      {children}
    </button>

이 코드에서 outline 값을 props로 받아와서 객체 안에 집어 넣은 다음 classNames()에 포함시켜줬는데, 이렇게 하면 실제로는 아래와 같이 해석된다.

{ outline : outline }

즉, outline 값이 true일 경우에만 “outline”이라는 클래스 이름이 추가된다.

outline을 객체로 전달해야 하는 이유는 outline이 조건부 클래스이기 때문이다.

→ true 일 때만 클래스 붙이고, false일 때는 빼려고 이렇게 하는 거임

→ classNames 라이브러리의 유용한 문법 패턴이다.

전체 너비 차지하는 옵션

이번에는 fullWidth라는 옵션이 있으면 버튼이 전체 너비를 차지하도록 구현

→ 구현 방식은 outline과 유사

&.fullWidth {
    width: 100%;
    justify-content: center;
    & + & {
      margin-left: 0;
      margin-top: 1rem;
    }
  }

들었던 의문점

Button.scss 파일에서, outline은 @mixin에 들어가고 fullWidth는 Button 클래스에 정의되는 것이 궁금했는데, 간단히 말해 outline은 버튼 색상에 따라 다르게 동작하기 때문에, 색상 스타일과 연결되기에 @mixin 안에 위치하는 것이고, fulllWidth은 색상과 무관하기에 별도로 관리하는 것이다.

알쓸신잡

그리고 위와 같이 코드를 쳤는데도 텍스트가 제대로 정렬되지 않았는데, 찾아보니까 line-height를 height와 같은 값으로 주면 텍스트가 정확히 수직 중앙에 위치한다는 것을 알게 되었고 적용하니 예쁘게 바뀌었다.

 

…rest props 전달하기

컴포넌트에 onClick이랑 onMouseMove와 같은 이벤트들을 매번 넣어주는 것은 귀찮기 때문에, 이러한 문제를 해결해줄 수 있는 문법으로 spread와 rest가 있다.

이 문법은 주로 배열과 객체, 함수의 파라미터, 인자를 다룰 때 사용하는데, 컴포넌트에도 사용할 수 있다.

 

이렇게 …rest를 사용해서 우리가 지정한 props를 제외한 값들을 rest라는 객체의 모아주고, <button> 태그에 {…rest}를 해주면, rest 안에 있는 객체 안에 있는 값들을 모두 <button> 태그에 설정을 해준다.

그래서, 만약 App.js에서 사용한 가장 첫번째 버튼에 onClick을 설정해준다면,

이런식으로 실행한 후 버튼을 클릭했을 때 onClick이 잘 호출되고 값이 잘 나오는 것을 확인할 수 있다.

  • 컴포넌트가 어떤 props를 받을 지 확실치는 않지만 그대로 다른 컴포넌트 또는 HTML 태그에 전달을 해주어야 하는 상황에는 …rest 문법을 활용하면 된다.
  • …rest문법은 Sass가 아니라 js/react 문법이기에 잘 쓰면 좋다

…rest와 …spread의 차이

둘 다 JS의 전개 연산자 (…)을 사용한다.

그러나 차이점이 있는데,

…rest - “나머지를 모을 때”

함수 파라미터나 구조 분해에서 사용한다.

function logAll(first, ...rest) {
  console.log(first); // 첫 번째 인자
  console.log(rest);  // 나머지 인자들 배열
}
logAll(1, 2, 3, 4); // → first: 1, rest: [2, 3, 4]

…spread - “펼칠 때”

객체나 배열을 복사하거나 병합할 때 사용

// 복사
const base = { a: 1, b: 2 };
const more = { ...base, c: 3 };
// more: { a: 1, b: 2, c: 3 }

//병합
const arr = [1, 2];
const newArr = [...arr, 3, 4]; 
// newArr: [1, 2, 3, 4]

CSS Module

리액트 프로젝트에서 컴포넌트를 스타일링할 때, CSS Module이라는 기술을 사용하면 CSS 클래스가 중첩되는 것을 방지할 수 있다.

CRA로 만든 프로젝트에서 CSS Module을 사용할 때는, CSS 파일의 확장자를 .module.css로 하면 된다.

리액트 컴포넌트 파일에서 CSS 파일을 불러올 때 클래스 이름들이 모두 고유해진다.

import React from "react";
import styles from "./Box.module.css";

function Box() {
  return <div className={styles.Box}>{styles.Box}</div>;
}

export default Box;

클래스 이름에 대하여 고유한 이름들이 만들어지기 때문에, 실수로 CSS 클래스 이름이 다른 관계없는 곳에서 사용한 CSS 클래스 이름과 중복되는 일에 대하여 걱정 할 필요가 없다.

CSS 클래스 네이밍 규칙을 만들고 따르기 싫다면, CSS Module을 사용하면 된단다.

커스텀 체크박스 만들기

label 태그

input이 아닌 텍스트 부분을 선택했는데도 값이 바뀌는데, 이는 해당 내용을 label 태그로 감싸주었기 때문이다.

<label>
        <input type="checkbox" checked={checked} {...rest} />
        <div>{checked ? "체크됨" : "체크 안됨"}</div>
</label>

react-icons 라이브러리

  • Font Awesome, Ionicons, Material Design Icons 등의 아이콘들을 컴포넌트 형태로 쉽게 사용할 수 있다.
<div>{checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}</div>

체크박스 부분을 이렇게 수정하면, 텍스트 대신 아이콘이 나타나게 된다.

CheckBox.module.css - 왜 중복될 일이 없는가

정리를 하다가, CheckBox.module.css 코드 작성 부분에서

CSS Module을 작성할 때는 CSS 클래스 이름이 다른 곳에서 사용되는 CSS 클래스 이름과 중복될 일이 없기 때문에 짧고 흔한 이름을 사용해도 상관이 없다는 것을 보고, 이해가 쉽게 되지 않아 찾아보았습니다..

그 이유는 이제 CSS Module이 클래스 이름을 자동으로 “로컬 스코프”로 바꿔주기 때문이다.

일반 CSS의 문제점 - 전역 범위

일반적으로 CSS 클래스는 전역이다.

따라서 두 파일에서 .icon을 각각 정의하면, 후자가 앞의 스타일을 덮어써버린다.

따라서 스타일 충돌이 발생할 수도 있다.

CSS Module의 특징: 자동으로 고유화

CSS Module을 쓰면 컴파일 시 클래스 이름이 자동으로 유일한 이름으로 바뀐다.

예시

/* Button.module.css */
.icon {
  width: 16px;
}
import styles from './Button.module.css';

<div className={styles.icon}>...</div>

실제 브라우저에서는

<div class="Button_icon__x38z4">...</div>

이처럼 .icon이 위와 같이 변경되면서 다른 컴포넌트와 이름이 절대 안 겹치게 처리된다.

 

확인해보면 위와 같이 고유한 클래스 이름이 만들어진 것을 볼 수 있다.

CSS Module을 사용할 때는 styles.icon - 이런 식으로 객체 안에 있는 값을 조회해야 하는데, 만약 클래스 이름에 -가 들어가있다면 다음과 같이 사용해야한다.

styles['my-class']

그리고, 만약에 여러개가 있다면 다음과 같이 작성해야한다.

${styles.one} ${styles.two}

// 조건부 스타일링
${styles.one} ${condition ? styles.two : ''}

classnames 라이브러리에서는 bind 기능이 있는데, 이 기능을 사용하면 CSS Module을 조금 더 편하게 사용할 수 있다.

classnames의 bind 기능을 사용하면, CSS 클래스 이름을 지정해 줄 때 cx(’클래스 이름’)과 같은 형식으로 편하게 사용할 수 있습니다. 여러개의 CSS 클래스를 사용해야하거나, 조건부 스타일링을 할 때 사용하면 좋다.

styled-components

styled-components라는 인기있는 라이브러리였는데, 지원 종료한다는 소식이 있는 것 같아 emotion을 사용하고 있는데, 어쨋든 문법은 비슷하니 스타일드 컴포넌트로 정리해보겠습니다.

Tagged Template Literal

styled-components를 사용하기 전에 Tagged Template Literal이라는 문법에 대하여 짚고 넘어가면,

styled-components가 내부적으로 어떻게 작동하는지 이해 할 수 있다.

Template Literal을 사용할 때, ${} 안에 일반 문자열 / 숫자가 아닌 객체 또는 함수를 넣는다면

const object = { a: 1 };
const text = `${object}`
console.log(text);
// "[object Object]"

const fn = () => true
const msg = `${fn}`;
console.log(msg);
// "() => true"

만약 Template Literal을 사용하면서도, 그 내부에 넣은 JS 값을 조회하고 싶을 땐 Tagged Template Literal 문법을 사용할 수 있다.

const red = '빨간색';
const blue = '파란색';
function favoriteColors(texts, ...values) {
  console.log(texts);
  console.log(values);
}
favoriteColors`제가 좋아하는 색은 ${red}과 ${blue}입니다.`

그 함수가 문자열과 변수들을 가공해서 원하는 결과를 만들 수 있다.

favoriteColors`제가 좋아하는 색은 ${red}과 ${blue}입니다.`;

위처럼 함수 이름(favoriteColors)을 템플릿 리터럴 앞에 붙이면

그 함수는 다음 두 개의 인자를 받습니다.

  1. 문자 조각들 → 배열로 (texts)
  2. 중간 중간의 변수들 → 나머지 인자로 (…values)

호출되는 형태

favoriteColors(
  ["제가 좋아하는 색은 ", "과 ", "입니다."],
  "빨간색",
  "파란색"
);

가공하는 방법

function favoriteColors(texts, ...values) {
   return texts.reduce((result, text, i) =>
     `${result}${text}${values[i] ? `<b>${values[i]}</b>` : ''}`, '');
}
  • texts는 문자열 조각들 ([”제가 좋아하는 색은 “, “과 “, “입니다.”])
  • values는 변수들 ([”빨간색”, “파란색”])
  • .reduce()로 문자열과 변수들을 하나씩 합치며
  • 변수 값은 <b>값</b>로 감싸준다.

결과

"제가 좋아하는 색은 <b>빨간색</b>과 <b>파란색</b>입니다."

styled-components에서는 이런 문법을 사용해서 컴포넌트의 props를 읽어오기도 한다.

const StyledDiv = styled`
	background : ${props => props.color};
`;

Tagged Template Literal을 사용하면 만약 ${ }을 통하여 함수를 넣어줬다면, 해당 함수를 사용해줄 수도 있다.

어쨌든

예시를

sample`
	제목: ${props => props.title}
	내용: ${props => props.body}
`
/*
"
  제목: 안녕하세요
  내용: 내용은 내용내용 입니다.
"
*/

이렇게 했을 때

출력이 위와 같이 나옵니다.

styled-components 사용하기

const Circle = styled.div`
  width: 5rem;
  height: 5rem;
  background: black;
  border-radius: 50%;
`;

이렇게 컴포넌트를 만들 때부터 css를 설정하고 만들 수 있다.

검은 동그라미 생김

background: ${(props) => props.color || "black"};

이렇게 하면 색을 매개변수로 받아서 바꿀 수 있다.

또한 huge라는 props를 설정했을 때 크기를 더 키워서 보여주고 싶다면

${(props) =>
    props.huge &&
    css`
      width: 10rem;
      height: 10rem;
    `}

위와 같이 코드를 구성하면 된다.

이런식으로 여러 줄의 CSS 코드를 조건부로 보여주고 싶다면 css를 사용해야 한다. css를 불러와서 사용을 해야 그 스타일 내부에서도 다른 props를 조회할 수 있다.

Button 만들기

Button도 styled-components로 구현 가능하다.

const StyledButton = styled.button`
  /* 공통 스타일 */
  display: inline-flex;
  outline: none;
  border: none;
  border-radius: 4px;
  color: white;
  font-weight: bold;
  cursor: pointer;
  padding-left: 1rem;
  padding-right: 1rem;

  /* 크기 */
  height: 2.25rem;
  font-size: 1rem;
  line-height: 2.2rem;

  /* 색상 */
  background: #228be6;
  &:hover {
    background: #339af0;
  }
  &:active {
    background: #1c7ed6;
  }

  /* 기타 */
  & + & {
    margin-left: 1rem;
  }
`;

이런식으로 만들고 App.js에는 <Button> 컴포넌트만 넣어주면 된다. → 초 간 단 !

polished의 스타일 관련 유틸 함수 사용하기

Sass를 사용 할 때에는 lighten() 또는 darken()과 같은 유틸 함수를 사용하여 색상에 변화를 줄 수 있었는데, CSS in JS 에서도 비슷한 유틸 함수를 사용하고 싶다면 polished라는 라이브러리를 사용하면 된다.

polished 라이브러리를 설치한 후, 기존 색상 부분을 polished의 유틸 함수로 대체하면 된다.

 /* 색상 */
  background: #228be6;
  &:hover {
    background: ${lighten(0.1, '#228be6')};
  }
  &:active {
    background: ${darken(0.1, '#228be6')};
  }

회색, 핑크색 버튼을 만들 때는 색상 코드를 지닌 변수를 Button.js에서 선언을 하는 대신에 ThemeProvider라는 기능을 사용하여 styled-components로 만드는 모든 컴포넌트에서 조회하여 사용할 수 있는 전역적인 값을 설정할 수 있다.

function App() {
  return (
    <ThemeProvider
      theme={{
        palette: {
          blue: "#228be6",
          gray: "#495057",
          pink: "#f06595",
        },
      }}
    >
      <AppBlock>
        <Button>BUTTON</Button>
        <Button>BUTTON</Button>
      </AppBlock>
    </ThemeProvider>
  );
}

이렇게 theme을 설정하면 ThemeProvider에서 내부에 렌더링된 styled-components로 만든 컴포넌트에서 palette를 조회하여 사용할 수 있다.

${(props) => {
    const selected = props.theme.palette.blue;
    return css`
      background: ${selected};
      &:hover {
        background: ${lighten(0.1, selected)};
      }
      &:active {
        background: ${darken(0.1, selected)};
      }
    `;
  }}
  /* 기타 */
  & + & {
    margin-left: 1rem;
  }
`;

ThemeProvider로 설정한 값은 styled-components에서 props.theme으로 조회가 가능하다.

오류 - 또 defaultProps 너냐

function Button({ children, ...rest }) {
  return <StyledButton {...rest}>{children}</StyledButton>;
}

Button.defaultProps = {
  color: 'blue'
};

이렇게 defaultProps를 설정해주어 기본 색상이 blue가 되도록 설정해주었는데, 야무지게 오류가 떴다.

ERROR Passed an incorrect argument to a color function, please pass a string representation of a color.

해결은 생각보다 간단했다. 위에서 했던 것처럼 구조분해 기본값으로 color를 넘겨주면 해결되었다.

function Button({ children, color = 'blue', ...rest }) {
  return <StyledButton color={color} {...rest}>{children}</StyledButton>;
}

근데 왜 자꾸 이러는지 찾아보았는데, JS 구조 분해 방식 때문이란다.

function Button({ children, ...rest })

여기서 color는 children이 아니니까 rest에 포함되어야 하는데,

defaultProps는 props가 아예 안 들어온 경우에만 값을 설정하기 때문에 color가 구조 분해 단계에서 빠져 있으면 rest에도 안 들어가게 된다.

즉, rest.color가 undefined가 되어서 StyledButton에 전달이 안되고 theme에서 undefined 키를 찾게 되어서 undefined 색상이 lighten()으로 넘어가서 에러가 터지는 거랍니다..

 ${({ theme, color }) => {
    const selected = theme.palette[color];
    return css`
      background: ${selected};
      &:hover {
        background: ${lighten(0.1, selected)};
      }
      &:active {
        background: ${darken(0.1, selected)};
      }
    `;
  }}

비구조화 할당 문법을 사용하여 가독성을 높일 수 있다.

또한 색상 관련 코드가 길어진다면, 색상에 관련된 코드를 분리하여 사용할 수도 있다.

const colorStyles = css`
  ${({ theme, color }) => {
    const selected = theme.palette[color];
    return css`
      background: ${selected};
      &:hover {
        background: ${lighten(0.1, selected)};
      }
      &:active {
        background: ${darken(0.1, selected)};
      }
    `;
  }}
`;

const StyledButton = styled.button`
  /* 공통 스타일 */
  display: inline-flex;
  outline: none;
  border: none;
  border-radius: 4px;
  color: white;
  font-weight: bold;
  cursor: pointer;
  padding-left: 1rem;
  padding-right: 1rem;

  /* 크기 */
  height: 2.25rem;
  font-size: 1rem;

  /* 색상 */
  ${colorStyles}

  /* 기타 */
  & + & {
    margin-left: 1rem;
  }
`;

이렇게 분리해두면 나중에 유지보수를 할 때 더 편해질 수 있다.

Dialog 만들기

h3나 p를 굳이 따로 따로 컴포넌트를 만들어주지 않아도

styled-components 에서도 Nested CSS 문법을 사용할 수 있기 때문에 DialogBlock 안에 있는 h3와 p에게 특정 스타일을 줄 수 있다.

const Title = styled.h3``;
const Description = styled.p``; // 이렇게 안해도 됨

const DialogBlock = styled.div`
  h3 {}
  p {}
`;

문제

Dialog 기능을 만들었는데, 이제 코드를 똑같이 쳐도 이렇게 굉장히 못생기게 나오는 것을 확인했습니다.

코드 상의 문제를 한 번 찾아봤는데,

& + & 가 이제 fullWidthStyle 에서도 정의가 되어있고, StyledButton 마지막 부분에도 정의가 되어있는데, 이 두 부분에서 문제가 생겨서 이런 사단이 발생한 것을 확인했습니다. 그니까 이제 저 두 개는 가로로 배치되어있는 거라서

margin-left가 먹어야 하는데 먹으라는 margin-left는 안먹고

const fullWidthStyle = css`
  ${(props) =>
    props.fullWidth &&
    css`
      width: 100%;
      justify-content: center;
      & + & {
        margin-left: 0;
        margin-top: 1rem;
      }
    `}
`;

여기 부분의 코드로 작동하더라구요 근데 해결을 하지 못해서 다음에 조금 더 열심히 공부해서 해결해보도록 하겠습니다..

→ 와우 근데 밑에 스타일 덮어쓰기 사용해서 해결을 하긴 했습니다.

const ShortMarginButton = styled(Button)`
  & + & {
    margin-left: 0.5rem;
    margin-top: 0;
  }
`;

이렇게 컴포넌트 스타일 덮어쓰기를 사용해서 새로 지정해주니까

이쁘네요

 

컴포넌트 스타일 덮어쓰기

Dialog.js에서 ShortMarginButton을 만들고 기존 Button을 대체할 수 있다.

위에서 설명한 것과 같습니다.

트랜지션 구현하기

트랜지션 효과를 적용 할때는 CSS KeyFrame을 사용하며, styled-components에서 이를 사용 할 때에는 keyframes라는 유틸을 사용한다.

 

 

여기까지 하겠습니다. 굉장히 css 어렵네요

css는 왜 검색해도 답을 알려주지 않을까?

반응형