React

[REACT] React - .css .scss 사용

Hwan'ss 2019. 8. 13. 16:50

<리액터를 다루는 기술 10장을 활용한 예제>

- 책에 나와 있는 sass의 환경설정은 지금 버전이 바뀌어 지원을 하지 않고 있기 때문에 아래와 같이 환경설정해서 사용하면 된다.

 

1. .css .scss 사용을 위한 기본 설정

 

.css .scss 등 스타일링에 필요한 라이브러리

npm install node-sass --save
npm install open-color --save
npm install sass-loader --save
npm install classnames --save

 

index.css가 실질적으로 백그라운드에 영향을 준다. 

.scss를 사용 하기 위해서는 index.js 파일에서 import를 변경시켜 주어야 한다.

.scss로 변경하더라도 .css 확장자명을 설정 변경없이 사용이 가능하다.

index.css의 확장자를 index.scss 로 변경해 주어야 한다.

변경을 하고 index.scss의 내용도 scss의 문법으로 변경해 주어야 한다.

 

* 컴파일 하다가 Error 발생시 모듈을 지웠다가 다시 깔아보기.

* npm install node-sass 설치시 에러가 발생하면 Visual C++ 관련 빌드툴이 깔려있지 않은 경우이다. vs를 설치하고 npm install windows-build-tools를 실행하면 된다.

Ex01. 컴포넌트의 백그라운드 색깔 지정

// App.js

import React, { Component } from 'react';

// Cpp에서 classname을 통해 접근을 하기 위해서 import
import classNames from 'classnames/bind';
import b from './B.scss'

class App extends Component {
  render() {
    return (
      <div>
        <Bpp/>
        <Cpp/>
      </div>
    );
  }
}

const Bpp = () => {
  return (
    <div className={'RedBox'}>
      콩콩이
    </div>
  );
};

const Cpp = () => {
  const bx = classNames.bind(b);
  return (
    <div className={bx('GreenBox')}>
      댕댕이
    </div>
  );
};

export default App;

Ex01 실행결과

Ex02. PageTamplate 구현

// App.js

import React, { Component } from 'react';

// Cpp에서 classname을 통해 접근을 하기 위해서 import
import classNames from 'classnames/bind';
import pageTamlate from './PageTamplate.scss'

class App extends Component {
  render() {
    return (
      <div>
        <Fpp/>
      </div>
    );
  }
}

// PageTamplate(Fpp)
class Fpp extends Component {
  render() {
    const cx = classNames.bind(pageTamlate);;
    return (
      <div className={cx("page-template")}>
        <h1>일정관리</h1>
        <div className={cx("content")}>
          안녕하세요.
        </div>
      </div>
    );
  }
}

export default App;
// PageTamplate.scss

.page-template {
    margin-top: 5rem;
    margin-left: auto;
    margin-right: auto;
    width: 500px;
    background: white;
    // 그림자를 띄워줍니다.
    box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
    padding-top: 2rem;
  
    // 브라우저의 크기가 768px 미만으로 됐을 땐,
    @media(max-width: 768px) {
      margin-top: 1rem;
      width: calc(100% - 2rem); // 양 옆에 1rem의 여백을 남기고 꽉 채워줍니다.
    }
    h1 {
      text-align: center;
      font-size: 4rem;
      font-weight: 300;
      margin: 0;
    }
    .content {
      margin-top: 2rem;
    }
  }
  

Ex02 실행결과

Ex03. TodoInput 구현

// App.js

import React, { Component } from 'react';

// Cpp에서 classname을 통해 접근을 하기 위해서 import
import classNames from 'classnames/bind';
import todoinput from './TodoInput.scss'

class App extends Component {
  render() {
    return (
      <div>
        <Gpp/>
      </div>
    );
  }
}

// TodoInput(Gpp)
const Gpp = () => {
  const cx = classNames.bind(todoinput)
  return (
    <div className={cx('todo-input')}>
      <input value='여기에 입력' onChange={() => { }}></input>
      <div className={cx('add-button')}>추가</div>
    </div>
  );
};

export default App;
// TodoInput.scss

@import '~open-color/open-color';

.todo-input {
  border-top: 1px solid $oc-gray-2;
  border-bottom: 1px solid $oc-gray-2;
  // 손쉬운 레이아웃 설정을 위하여 flex를 사용합니다.
  display: flex;
  padding: 1rem;
  input {
    // 인풋의 기본 스타일을 지우고 새 스타일을 정의합니다.
    flex: 1; // 부모 엘리먼트에서 add-button을 제외한 나머지 공간을 차지합니다.
    font-size: 1.1rem;
    outline: none;
    border: none;
    background: transparent;
    border-bottom: 1px solid $oc-gray-4;
    &:focus {
      border-bottom: 1px solid $oc-cyan-6;
    }
  }
  .add-button {
    width: 5rem;
    height: 2rem;
    margin-left: 1rem;
    border: 1px solid $oc-green-7;
    color: $oc-green-7;
    font-weight: 500;
    font-size: 1.1rem;
    display: flex;
    // 내용을 가운데에 정렬시킵니다.
    align-items: center;
    justify-content: center;
    cursor: pointer;
    &:hover {
      background: $oc-green-7;
      color: white;
    }
    &:active {
      background: $oc-green-8;
    }
  }
}

Ex03 실행결과

Ex04. PageTamplate에 TodoInput 추가하는 3가지 방법

import React, { Component } from 'react';

// Cpp에서 classname을 통해 접근을 하기 위해서 import
import classNames from 'classnames/bind';
import todoinput from './TodoInput.scss'

class App extends Component {
  render() {
    return (
      <div>
        {/* pageTamplate안에 todoinput 포함시키기 */}
        {/* 첫번째 방법, Hpp 컴포넌트 자체에 Gpp 포함하기 */}
        <Hpp/>

        {/* Ipp에서 Gpp 컴포넌트를 children으로 받기 */}
        <Ipp>
          <Gpp/>
        </Ipp>

        {/* Jpp에서 Gpp 컴포넌트를 props로 받기 */}
        <Jpp>
          <Gpp/>
        </Jpp>
      </div>
    );
  }
}

// TodoInput(Gpp)
const Gpp = () => {
  const cx = classNames.bind(todoinput)
  return (
    <div className={cx('todo-input')}>
      <input value='여기에 입력' onChange={() => { }}></input>
      <div className={cx('add-button')}>추가</div>
    </div>
  );
};

// PageTamplate(Hpp)에 직접 TodoInput(Gpp) 추가
class Hpp extends Component {
  render() {
    const cx = classNames.bind(todoinput);;
    return (
      <div className={cx("page-template")}>
        <h1>일정관리</h1>
        <div className={cx("content")}>
          <Gpp />
        </div>
      </div>
    );
  }
}
// PageTamplate(Ipp)에서 children 사용하여 하위 태그 받음
const Ipp = ({ children }) => {
  const cx = classNames.bind(todoinput)
  return (
    <div className={cx('page-template')}>
      <h1>일정관리</h1>
      <div className={cx('content')}>
        {children}
      </div>
    </div>
  );
};

// PageTamplate(Jpp)에서 전달받은 props 사용
class Jpp extends Component {
  render() {
    const cx = classNames.bind(todoinput)
    return (
      <div className={cx('page-template')}>
        <h1>일정관리</h1>
        <div className={cx('content')}>
          {/* props로 받는다. */}
          {this.props.children}
        </div>
      </div>
    );
  }
}

export default App;
// TodoInput.scss

@import '~open-color/open-color';

.todo-input {
  border-top: 1px solid $oc-gray-2;
  border-bottom: 1px solid $oc-gray-2;
  // 손쉬운 레이아웃 설정을 위하여 flex를 사용합니다.
  display: flex;
  padding: 1rem;
  input {
    // 인풋의 기본 스타일을 지우고 새 스타일을 정의합니다.
    flex: 1; // 부모 엘리먼트에서 add-button을 제외한 나머지 공간을 차지합니다.
    font-size: 1.1rem;
    outline: none;
    border: none;
    background: transparent;
    border-bottom: 1px solid $oc-gray-4;
    &:focus {
      border-bottom: 1px solid $oc-cyan-6;
    }
  }
  .add-button {
    width: 5rem;
    height: 2rem;
    margin-left: 1rem;
    border: 1px solid $oc-green-7;
    color: $oc-green-7;
    font-weight: 500;
    font-size: 1.1rem;
    display: flex;
    // 내용을 가운데에 정렬시킵니다.
    align-items: center;
    justify-content: center;
    cursor: pointer;
    &:hover {
      background: $oc-green-7;
      color: white;
    }
    &:active {
      background: $oc-green-8;
    }
  }
}

Ex04 실행결과

Ex05. PageTamplate에 TodoInput 추가에 이어 TodoItem도 추가

// App.js

import React, { Component } from 'react';

// Cpp에서 classname을 통해 접근을 하기 위해서 import
import classNames from 'classnames/bind';
import todoinput from './TodoInput.scss'
import todoitem from './TodoItem.scss'

class App extends Component {
  render() {
    return (
      <div>

        {/* Ipp에서 Gpp 컴포넌트를 children으로 받기 */}
        <Ipp>
          <Gpp/>
          <Kpp/>
        </Ipp>


      </div>
    );
  }
}

// TodoInput(Gpp)
const Gpp = () => {
  const cx = classNames.bind(todoinput)
  return (
    <div className={cx('todo-input')}>
      <input value='여기에 입력' onChange={() => { }}></input>
      <div className={cx('add-button')}>추가</div>
    </div>
  );
};

// PageTamplate(Ipp)에 하위태그를 children으로 받음
const Ipp = ({ children }) => {
  const cx = classNames.bind(todoinput)
  return (
    <div className={cx('page-template')}>
      <h1>일정관리</h1>
      <div className={cx('content')}>
        {children}
      </div>
    </div>
  );
};

// TodoItem(Kpp)
class Kpp extends Component {
  render() {
    const ex = classNames.bind(todoitem)
    return (
      <div className={ex('todo-item')}>
        <input className={ex('tick')} type="checkbox" checked={true} readOnly />
        {/* <div className={ex('text')}>{this.props.children}</div> */}
        <div className={ex('text')}>일정관리하자!!!!!!!!!</div>
        <div className={ex('delete')} onClick={(e) => {
          e.stopPropagation();
        }
        }>[지우기]</div>
      </div>
    );
  }
}

export default App;
// TodoItem.scss

@import '~open-color/open-color';

.todo-item {
  padding: 1rem;
  display: flex;
  align-items: center;
  cursor: pointer;
  .tick {
    margin-right: 1rem;
  }
  .text {
    flex: 1;
    word-break: break-all;
    &.done {
      text-decoration: line-through;
    }
  }
  .delete {
    margin-left: 1rem;
    color: $oc-red-7;
    font-size: 0.8rem;
    &:hover {
      color: $oc-red-5;
      text-decoration: underline;
    }
  }
  &:nth-child(odd) {
  // 홀수 번째 엘리먼트에는 회색 배경
    background: $oc-gray-0;
  }
  &:hover {
    background: $oc-gray-1;
  }
}

.todo-item + .todo-item {
  // 컴포넌트 사이 사이에 위쪽 테두리를 설정합니다.
  border-top: 1px solid $oc-gray-1;
}

Ex05 실행결과

Ex06. .css 사용 - 버튼 디자인 하기

- css의 경우 w3school.com 등 사이트에서 끌어와서 사용하는 법 정도만 익히면 된다.

// App.js

import React, { Component } from 'react';

import './button.css'

class App extends Component {
  render() {
    return (
      <div>
        {/* w3schools.com의 css 버튼 끌어오기 */}
        <button class="button">Green</button>
        <button class="button button2">Blue</button>
        <button class="button button3">Red</button>
        <button class="button button4">Gray</button>
        <button class="button button5">Black</button>
      </div>
    );
  }
}

export default App;
// button.css

.button {
    background-color: #4CAF50; /* Green */
    border: none;
    color: white;
    padding: 15px 32px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    margin: 4px 2px;
    cursor: pointer;
  }
  
  .button2 {background-color: #008CBA;} /* Blue */
  .button3 {background-color: #f44336;} /* Red */ 
  .button4 {background-color: #e7e7e7; color: black;} /* Gray */ 
  .button5 {background-color: #555555;} /* Black */

Ex06 실행결과

 

 

2019.08.13(화)

.css .scss의 사용