JS Library/React

Sass

원2 2022. 8. 1. 11:19
728x90
반응형

리액트 컴포넌트 스타일링

 

Sass 는 CSS  pre-processer 

 

두가지의 확장자가 있음

 

.sass / .scss

 

보통 .scss 문법이 더 많이 사용된다.

 

솔직히 걍 JSP에 사용하는 부트스트랩처럼

antd 나 머터리얼 mui 같은 프론드엔드 프레임워크를 쓰는게 정신건강에 좋긴한데

기본적은것은 알고 가야할거 같아서 배워본다.

 

.sass

$font-stack:    Helvetica, sans-serif
$primary-color: #333

body
  font: 100% $font-stack
  color: $primary-color

 

.scss

$font-stack:    Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}

 

 

새 프로젝트를 만들고 node-sass 라이브러리를 설치하자

node-sass 는 sass를 CSS 로 변환해주는 역할을 함

$ npx create-react-app 프로젝트명

$ yarn add node-sass

 

 

Button 컴포넌트 만들기

src 디렉토리에 components 디렉토리를 생성하고 Button 컴포넌ㅌ를 만들자

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

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

export default Button;

 

같은 componets 에 Button.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 {
    // 색상, 10% 밝게
    background: lighten($blue, 10%);
  }

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

$blue 처럼 변수를 선언 할 수도 있고

ligthen(), darken() 처럼 함수를 사용 할 수도 있음

 

 

App components 에서 사용해보자

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

function App() {
  return (
    <div className="App">
      <div className="buttons">
        <Button>BUTTON</Button>
      </div>
    </div>
  );
}

export default App;

 

App.css >>> App.scss  변경

.App {
  text-align: center;
  width: 512px;
  margin: 0 auto;
  margin-top: 4rem;
  border: 1px solid black;
  padding: 1rem;
}

그럼 이런 찐따같은 버튼이 나온다 ㅇㅇ..

 

버튼 사이즈 조정하기

버튼 크기에 large, medium, small 를 설정해보자

Button.js 에서 defalutProps 를 사용해서 size 의 기본값을 medium 으로 설정, 이 값을 button의 className에 넣자

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

function Button({children, size}) {
    // 1번 방법
    return <button className={['Button', size].join(' ')}>{children}</button>
    // 2번 방법
    return <button className={`Button${size}`}>{children}</button>
}

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

export default Button;

className 에 CSS 클래스 이름을 동적으로 넣으려면 1번과 2번방법이 있다.

개인적으론 2번이 좋은듯

 

그치만 조건부로 CSS 클래스를 넣어주고 싶을때 문자열을 직접 조합하는것 보단

classnames 라이브러리를 사용하는것이 좋다

 

classNames 를 사용하면 조건부 스타일링을 할 때 함수의 인자에 문자열, 배열, 객체 등을 전달해서 쉽게 문자열 조합가능

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
classNames(['foo', 'bar']); // => 'foo bar'

// 동시에 여러개의 타입으로 받아올 수 도 있습니다.
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'

// false, null, 0, undefined 는 무시됩니다.
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

 

프로젝트에 설치

$ yarn add classnames

안된다면 아래걸로(난 이걸로함)

$ npm install classnames

아니면 

yarn remove node-sass
yarn add sass

 

Button.js 에 적용

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

function Button({children, size}) {
    // 1번 방법
    return <button className={['Button', size].join(' ')}>{children}</button>;
    // 2번 방법
    return <button className={`Button${size}`}>{children}</button>;
    // classnames
    return <button className={classNames('Button', size)}>{children}</button>;

}

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

export default Button;

props 로 받은 값이 button 태그의 className 로 전달이 될 것임

 

Button.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 {
    // 색상, 10% 밝게
    background: lighten($blue, 10%);
  }

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

  // 사이즈 관리
  &.large {
    height: 3rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1.25rem;
  }

  &.medium {
    height: 2.25rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1rem;
  }

  &.small {
    height: 1.75rem;
    font-size: 0.875rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }
}

추가설명 :: 

.Button {
  &.large {

  }
}
// 위의코드가 의미하는 것
.Button.large {

}

 

 

Aps.js 에서 버튼 2개를 추가로 렌더링하고 size 값을 설정해보자

import logo from './logo.svg';
import './App.scss';
import Button from "./components/Button";

function App() {
  return (
      <div className="App">
        <div className="buttons">
          <Button size="large">Button</Button>
          <Button>Button</Button>
          <Button size="small">Button</Button>
        </div>
      </div>
  );
}

export default App;

짠 버튼 찐따 3형제 완성

 

요즘같은 더운날에 붙어있으면 어지러우니까 떨어지게 해주자

Button.scss > .Button {} 에 아래코드를 추가

  // & + & 가 의미 하는것 => .Button + .Button / 같이 있다면? 여백설정
  & + & {
    margin-left: 1rem;
  }

거리두기 on

 

이제 버튼의 색상을 설정해보자

Button.scss

// 선언
$blue: #228be6;
$grape: #cc5de8;
$teal:#38d9a9;

.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 {
    // 색상, 10% 밝게
    background: lighten($blue, 10%);
  }

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

  // 사이즈 관리
  &.large {
    height: 3rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1.25rem;
  }

  &.medium {
    height: 2.25rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1rem;
  }

  &.small {
    height: 1.75rem;
    font-size: 0.875rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }

  // & + & 가 의미 하는것 => .Button + .Button / 같이 있다면? 여백설정
  & + & {
    margin-left: 1rem;
  }

  // 색상 관리
  &.grape {
    background: $grape;

    &:hover {
      background: lighten($grape, 10%);
    }

    &:active {
      background: darken($grape, 10%);
    }
  }

  &.teal {
    background: $teal;

    &:hover {
      background: lighten($teal, 10%);
    }

    &:active {
      background: darken($teal, 10%);
    }
  }
}

이렇게 해줬는데 반복되는 코드는 정리해주고 싶은 기분이 든다

  // 반복되는 코드들
  background: $blue;
  &:hover {
    // 색상, 10% 밝게
    background: lighten($blue, 10%);
  }

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

    &:hover {
      background: lighten($grape, 10%);
    }

    &:active {
      background: darken($grape, 10%);
    }
  }

  &.teal {
    background: $teal;

    &:hover {
      background: lighten($teal, 10%);
    }

    &:active {
      background: darken($teal, 10%);
    }
  }

그럼 mixin 라는 기능을 사용해서 재사용 해주자

주의 :::: mixin 에 문제가 많다고 판단된다는 react 공식 문서에 글이 있는것을 확인.

https://ko.reactjs.org/blog/2016/07/13/mixins-considered-harmful.html

 

Mixins Considered Harmful – React Blog

“How do I share the code between several components?” is one of the first questions that people ask when they learn React. Our answer has always been to use component composition for code reuse. You can define a component and use it in several other co

ko.reactjs.org

 

재사용한 Button.scss

// 선언
$blue: #228be6;
$grape: #cc5de8;
$teal: #38d9a9;

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

.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;

  // 사이즈 관리
  &.large {
    height: 3rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1.25rem;
  }

  &.medium {
    height: 2.25rem;
    padding-left: 1rem;
    padding-right: 1rem;
    font-size: 1rem;
  }

  &.small {
    height: 1.75rem;
    font-size: 0.875rem;
    padding-left: 1rem;
    padding-right: 1rem;
  }

  // & + & 가 의미 하는것 => .Button + .Button / 같이 있다면? 여백설정
  & + & {
    margin-left: 1rem;
  }

  &.blue {
    @include button-color($blue);
  }

  &.grape {
    @include button-color($grape);
  }

  &.teal {
    @include button-color($teal);
  }
}

 

 

App.js 에서 코드가 잘 되었는지 확인해보자

import './App.scss';
import Button from "./components/Button";

function App() {
  return (
      <div className="App">
        <div className="buttons">
          <Button size="large">Button</Button>
          <Button>Button</Button>
          <Button size="small">Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="grape">Button</Button>
          <Button color="grape">Button</Button>
          <Button size="small" color="grape">Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="teal">Button</Button>
          <Button color="teal">Button</Button>
          <Button size="small" color="teal">Button</Button>
        </div>
      </div>
  );
}

export default App;

짠 형형색색의 찐따 버튼 모음

또 붙어있으니까 떼어주도록 하자

App.scss

.App {
  text-align: center;
  width: 512px;
  margin: 0 auto;
  margin-top: 4rem;
  border: 1px solid black;
  padding: 1rem;
  .buttons + .buttons {
    margin-top: 1rem;
  }

}

outline 옵션 설정

이번에는 색상을 테두리에만 줘보자

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

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

Button.defaultProps = {
    size: 'medium',
    color: 'blue'
};

export default Button;

outline을 classNames에 넣어주고

해당 outline 클래스가 있다면( true) 아웃라인으로 처리 되는 코드를 짜면 끝

 

Button.scss

@mixin button-color($color) {
  background: $color;
  &:hover {
    background: lighten($color, 10%);
  }
  &:active {
    background: darken($color, 10%);
  }
  &.outline {
    color: $color;
    background: none;
    border: 1px solid $color;
    &:hover {
      background: $color;
      color: white;
    }
  }
}

 

mixin으로 처리를 해놨기 때문에 outline 만 추가해주면 된다!

 

App에 outline 클래스 추가해주면?

import './App.scss';
import Button from "./components/Button";

function App() {
  return (
      <div className="App">
        <div className="buttons">
          <Button size="large">Button</Button>
          <Button>Button</Button>
          <Button size="small">Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="grape">Button</Button>
          <Button color="grape">Button</Button>
          <Button size="small" color="grape">Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="teal">Button</Button>
          <Button color="teal">Button</Button>
          <Button size="small" color="teal">Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="blue" outline>Button</Button>
          <Button color="teal" color="grape" outline>Button</Button>
          <Button size="small" color="teal" outline>Button</Button>
        </div>
      </div>
  );
}

export default App;

 

 

전체 너비 차지 옵션

이번엔 fullWidth 라는 옵션이 있으면 너비 전체를 차지하게 만들자 outline 과 똑같음

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

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

Button.defaultProps = {
    size: 'medium',
    color: 'blue'
};

export default Button;

fullWidth 설정 후

 

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

추가하고

app 에서 fullWidth 넣어주면?

<div className="buttons">
  <Button size="large" color="blue" fullWidth>Button</Button>
  <Button color="teal" color="grape" fullWidth>Button</Button>
  <Button size="small" color="teal" fullWidth>Button</Button>
</div>

크기별로 너비를 채웠따!

 

 

...rest props 전달

특정한 이벤트를 설정해주고 싶을때!

예를들어 onClick

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

function Button({children, size, color, outline, fullWidth, onClick}) {
    return (
        <button className={classNames('Button', size, color, {outline, fullWidth})}
                onClick={onClick}
        >
            {children}
        </button>
    );
}

Button.defaultProps = {
    size: 'medium',
    color: 'blue'
};

export default Button;

여기서 하나의 이벤트 더 추가? 

onMouseMove

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

function Button({children, size, color, outline, fullWidth, onClick, onMouseMove}) {
    return (
        <button className={classNames('Button', size, color, {outline, fullWidth})}
                onClick={onClick}
                onMouseMove={onMouseMove}
        >
            {children}
        </button>
    );
}

Button.defaultProps = {
    size: 'medium',
    color: 'blue'
};

export default Button;

 

... 하나씩 추가하기는 너무 번거롭다!

 

그럴때 ...spread 를 쓰자.

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

function Button({children, size, color, outline, fullWidth, ...rest}) {
    return (
        <button className={classNames('Button', size, color, {outline, fullWidth})}
                {...rest}
        >
            {children}
        </button>
    );
}

Button.defaultProps = {
    size: 'medium',
    color: 'blue'
};

export default Button;

이렇게하면 끝이다.

...rest 가 우리가 지정한 props 를 제외한 값들을 rest 객체에 모아주고

해당 태크에 {...rest} 를 해주면 객체 안에 있는 값들을 모두 태그에 설정해줌

첫번째 버튼에 onClick () => log 를 설정하면 ?

import './App.scss';
import Button from "./components/Button";

function App() {
  return (
      <div className="App">
        <div className="buttons">
          <Button size="large" onClick={() => console.log("클릭하셨소?")}>Button</Button>
          <Button>Button</Button>
          <Button size="small">Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="grape">Button</Button>
          <Button color="grape">Button</Button>
          <Button size="small" color="grape">Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="teal">Button</Button>
          <Button color="teal">Button</Button>
          <Button size="small" color="teal">Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="blue" outline>Button</Button>
          <Button color="teal" color="grape" outline>Button</Button>
          <Button size="small" color="teal" outline>Button</Button>
        </div>
        <div className="buttons">
          <Button size="large" color="blue" fullWidth>Button</Button>
          <Button color="teal" color="grape" fullWidth>Button</Button>
          <Button size="small" color="teal" fullWidth>Button</Button>
        </div>
      </div>
  );
}

export default App;

이렇게 딱 뜬다. wow

 

오늘도 화이팅

출처-

https://react.vlpt.us/styling/01-sass.html

728x90
반응형

'JS Library > React' 카테고리의 다른 글

styled-components  (0) 2022.08.02
react-icons link  (0) 2022.08.01
CSS Module  (0) 2022.08.01
useReducer 요청 상태 관리  (0) 2022.06.09
API 연동하기, axios  (0) 2022.06.09
Immer 라이브러리  (0) 2022.05.26