📝

9. 스타일 적용하기

 

1. styled-components

 
styled-components 설치하기
// with npm npm install --save styled-components // with yarn yarn add styled-components
 

1) 글로벌 스타일 만들기

글로벌 스타일은 styled-components가 제공하는 createGlobalStyle() 함수를 사용합니다. 먼저 crateGlobalStyle() 함수를 사용하여 전역 스타일 컴포넌트를 생성합니다.
App.js(현재 최상위 컴포넌트) 상단에 추가해주면 모든 하위 컴포넌트에 스타일이 적용됩니다.
import React from "react"; import ReactDOM from 'react-dom'; import { createGlobalStyle } from "styled-components"; import Example from "./Components/Example"; const GlobalStyle = createGlobalStyle` span { color : red; font-size : 12px; } `; const App = () => ( <React.Fragment> <GlobalStyle /> <h1>Hi, I'm an app!</h1> <h2>Hi, I'm an app!</h2> <span>글귀 3</span> <Example /> </React.Fragment> ); export default App;
src / app.js
const Example = () => { return ( <> <span>글귀 1</span> <span>글귀 2</span> </> ); }; export default Example;
src / Components / Example.jsx
 

2) Reset css

Reset css는 styled-reset이라는 패키지를 다운받은 뒤 styled-reset이 제공하는 reset을 아래와 같이 글로벌 CSS에다가 적용합니다.
styled-reset 설치하기
npm i styled-reset
 
글로벌 스타일에 styled-reset 적용하기
import React from "react"; import ReactDOM from 'react-dom'; import { createGlobalStyle } from "styled-components"; import reset from "styled-reset"; import Example from "./Components/Example"; const GlobalStyle = createGlobalStyle` ${reset}; a{ text-decoration : none; color : inherit; } button{ border : none; cursor : pointer; } * { box-sizing: border-box; } `; const App = () => ( <React.Fragment> <GlobalStyle /> <h1>Hi, I'm an app!</h1> <h2>Hi, I'm an app!</h2> <span>글귀 3</span> <Example /> </React.Fragment> ); export default App;
src / app.js
const Example = () => { return ( <> <span>글귀 1</span> <span>글귀 2</span> </> ); }; export default Example;
src / Components / Example.jsx
 

3) styled-components를 사용한 스타일 적용

 
styled-components로 스타일을 적용할 때는 styled-components에서 제공하는 styled를 사용합니다.
인라인으로 스타일을 적용할때와 다르게 기존 CSS에서 사용하는 케밥 표기법(하이픈 표기법)으로 프로퍼티를 작성하면 됩니다.
const 변수명 = styled.태그명` background-color : red; `
 
import React from "react"; import styled from "styled-components"; const ContentDiv = styled.div` margin: 40px; `; const ContentH2 = styled.h2` width: 200px; margin: 0 auto; text-align: center; `; const App = () => { return ( <ContentDiv> <ContentH2>Q&A</ContentH2> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos excepturi corrupti quo blanditiis! Adipisci amet corporis ipsum odio minima aliquid quisquam! Dignissimos natus laborum qui veritatis quaerat eaque! Nemo, ullam. </p> </ContentDiv> ); }; export default App;
src / app.js
 
notion imagenotion image
 
import React from "react"; import styled from "styled-components"; const ContentDiv = styled.div` margin: 40px; `; const ContentH2 = styled.h2` width: 200px; margin: 0 auto; text-align: center; color:red; `; const App = () => { return ( <ContentDiv> <ContentH2>Q&A</ContentH2> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos excepturi corrupti quo blanditiis! Adipisci amet corporis ipsum odio minima aliquid quisquam! Dignissimos natus laborum qui veritatis quaerat eaque! Nemo, ullam. </p> <Hello/> </ContentDiv> ); }; function Hello(){ return <h2>hello world</h2> } export default App;

4) props에 따른 조건부 스타일

props를 사용해서 조건에 따라 스타일을 적용해줄 수 있습니다. 문자열 리터럴 안에 자바스크립트 코드를 넣을 때 $를 사용하듯이 ${} 안에 코드를 입력해주면 됩니다.
import React from "react"; import styled from "styled-components"; const ContentDiv = styled.div` margin: 40px; `; const ContentH2 = styled.h2` color: ${(props) => (props.name === 'hello'? `red` : `black`)}; width: 200px; margin: 0 auto; text-align: center; `; const App = () => { return ( <ContentDiv> <ContentH2 name="hello">Q&A</ContentH2> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos excepturi corrupti quo blanditiis! Adipisci amet corporis ipsum odio minima aliquid quisquam! Dignissimos natus laborum qui veritatis quaerat eaque! Nemo, ullam. </p> </ContentDiv> ); }; export default App;
App.js
 
notion imagenotion image

2. module.css

기본 세팅 코드
import React from "react"; import Question from "./Components/Question"; const App = () => { return ( <> <nav className="box"> <ul> <li id="detail" className="text"> 상세정보 </li> <li id="qa" className="text"> Q&A </li> <li id="review" className="text"> Review </li> </ul> </nav> <Question /> </> ); }; export default App;
src/ app.js
import React from "react"; // import "./Question.css"; const Question = () => { return ( <div class="box"> <h2 class="text">Q&A</h2> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos excepturi corrupti quo blanditiis! Adipisci amet corporis ipsum odio minima aliquid quisquam! Dignissimos natus laborum qui veritatis quaerat eaque! Nemo, ullam. </p> </div> ); }; export default Question;
src / Components / Question.jsx
 
처음 Create-react-app을 설치하면 볼 수 있는 CSS 파일과 JS파일입니다.
index.js에 index.css를 import 하게되면 전역으로 CSS가 적용됩니다. App.js에 App.css를 import하게 되면 App 컴포넌트에 들어있는 모든 컴포넌트에 적용됩니다.
notion imagenotion image
부모컴포넌트에서 import한 css는 자식까지 자동으로 적용되고, 자식컴포넌트에 새로 css를 적용하게 되면 부모의 스타일은 무시되고 자식컴포넌트에 import된 스타일이 적용됩니다.
 
💡
태그는 가능하지만 클래스는 가능하지 않은데요. 클래스가 부모와 자식이 겹치는 것을 방지하기 위해서 그렇습니다. module.css를 사용하면 class명에 고유값을 추가해주어서 겹치지 않도록 합니다.
 
div { margin: 40px; background: blanchedalmond; } h2 { width: 200px; margin: 0 auto; text-align: center; color: Red; }
src / App.css
import "./App.css";
src / App.js
div { background: pink; } h2 { width: 200px; margin: 0 auto; text-align: center; color: lemonchiffon; }
src / Components / Question.css
import "./Question.css";
src / Components / Question.jsx
 
결과 :
notion imagenotion image
그러면 태그에 클래스 이름을 넣어주고 CSS에서 클래스 이름을 선택한 뒤 스타일을 적용하게되면 어떻게 될까요?

1) 일반 CSS일 때

App.js에 일반 css를 import하였습니다. 아래와 같이 스타일이 잘 적용되서 나옵니다.
.box { margin: 40px; background: blanchedalmond; } .text { width: 200px; margin: 0 auto; text-align: center; color: Red; }
src / app.css
import "./App.css";
src / app.js
notion imagenotion image
 
이번에는 Question.jsx에 스타일을 Question.jsx에 import해보겠습니다.
.box { background: pink; } .text { width: 200px; margin: 0 auto; text-align: center; color: lemonchiffon; }
src / Components / Question.css
import "./Question.css";
src / Components / Question.jsx
notion imagenotion image
자식 컴포넌트에서 import한 CSS가 적용되지 않는 것을 볼 수 있습니다. 이때 CSS 파일 이름에 .css를 module.css로 바꿔주면 됩니다.
 

2) module.css일 때

Question.css 파일명을 Question.module.css 로 바꿔봅시다.
Question.jsx에는 {styles.클래스명} 으로 바꿔줄게요
import React from "react"; import styles from "./Question.module.css"; const Question = () => { return ( <div className={styles.box}> <h2 className={styles.text}>Q&A</h2> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos excepturi corrupti quo blanditiis! Adipisci amet corporis ipsum odio minima aliquid quisquam! Dignissimos natus laborum qui veritatis quaerat eaque! Nemo, ullam. </p> </div> ); }; export default Question;
notion imagenotion image
 
App.css와 App.module.css도 바꿔줄게요
import React from "react"; import styles from "./App.module.css"; import Question from "./Components/Question"; const App = () => { return ( <> <nav className={styles.box}> <ul> <li id="detail" className={styles.text}> 상세정보 </li> <li id="qa" className={styles.text}> Q&A </li> <li id="review" className={styles.text}> Review </li> </ul> </nav> <Question /> </> ); }; export default App;
notion imagenotion image
 
클래스 이름이 컴포넌트별로 겹치지 않도록 클래스 명을 지정해주지않고 module을 파일명에 추가해준뒤 styles.클래스명 으로 해준다면 아래 개발자도구에서처럼 클래스명이 겹치지 않도록 처리해줍니다.
  • nav와 div 모두 box라는 style을 받고 있지만 이름이 다릅니다.
notion imagenotion image
 
module.css를 사용할 때 주의할 점은 적용하고자 하는 컴포넌트 이름반드시 일치시켜줘야합니다.예를들어 Detail.jsx 파일에만 적용해주고 싶은 module.css의 파일명은 Detail.module.css여야합니다.

미션! (조건에 따른 컴포넌트 렌더링 복습)

리엑트페이지처럼 문서를 클릭했을 때, 자습서를 클릭했을 때, 블로그를 클릭했을 때, 커뮤니티를 클릭했을 때 각각의 페이지가 보여지게 만들어주세요.
(URL이 어떻게 변하는지 알고 싶다면 Router 챕터로 이동해주세요.)
notion imagenotion image
힌트코드
import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; ReactDOM.render(<App />, document.getElementById("root"));
src / index.js
import React, { useState } from "react"; import { createGlobalStyle } from "styled-components"; import reset from "styled-reset"; import Nav from "./Components/Nav"; import ContentsContainer from "./Components/ContentsContainer"; const GlobalStyle = createGlobalStyle` ${reset}; a{ text-decoration : none; color : inherit; } button{ border : none; cursor : pointer; } * { box-sizing: border-box; } `; const App = () => { const [listName, setListName] = useState("detail"); const checkId = (e) => { setListName(e.target.id); console.log(e.target.id); }; return ( <> <GlobalStyle /> <Nav changeState={checkId} stateValue={listName} /> <ContentsContainer listName={listName} /> </> ); }; export default App;
src / app.js
import Detail from "./Detail"; import Question from "./Question"; import Review from "./Review"; const ContentsContainer = ({ listName }) => { if (listName === "detail") { return <Detail />; } else if (listName === "qa") { return <Question />; } else if (listName === "review") { return <Review />; } }; export default ContentsContainer;
src/ Components / ContentsContainer.jsx
import React from "react"; import styled from "styled-components"; const ProductNavUl = styled.ul` display: flex; list-style: none; `; const ProductNavLi = styled.li` color: ${(props) => (props.listName === props.id ? `red` : `black`)}; cursor: pointer; & + li { margin-left: 20px; } &::after { display: block; content: ""; height: 2px; width: 100%; background-color: ${(props) => props.listName === props.id ? `red` : `transparent`}; margin-top: 4px; }`; function NavBar({ changeState, stateValue }) { return ( <> <nav> <ProductNavUl> <ProductNavLi id="detail" onClick={changeState} listName={stateValue}> 상세정보 </ProductNavLi> <ProductNavLi id="qa" onClick={changeState} listName={stateValue}> Q&A </ProductNavLi> <ProductNavLi id="review" onClick={changeState} listName={stateValue}> Review </ProductNavLi> </ProductNavUl> </nav> </> ); } export default NavBar;
src / Components / Nav.jsx
import React from "react"; import styled from "styled-components"; const ContentDiv = styled.div` margin: 40px; `; const ContentH2 = styled.h2` width: 200px; margin: 0 auto; text-align: center; `; const Detail = () => { return ( <ContentDiv> <ContentH2>Detail</ContentH2> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos excepturi corrupti quo blanditiis! Adipisci amet corporis ipsum odio minima aliquid quisquam! Dignissimos natus laborum qui veritatis quaerat eaque! Nemo, ullam. </p> </ContentDiv> ); }; export default Detail;
src / Components / Detail.jsx
import React from "react"; import styled from "styled-components"; const ContentDiv = styled.div` margin: 40px; `; const ContentH2 = styled.h2` width: 200px; margin: 0 auto; text-align: center; `; const Question= () => { return ( <ContentDiv> <ContentH2>Detail</ContentH2> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos excepturi corrupti quo blanditiis! Adipisci amet corporis ipsum odio minima aliquid quisquam! Dignissimos natus laborum qui veritatis quaerat eaque! Nemo, ullam. </p> </ContentDiv> ); }; export default Question;
src / Components / Question.jsx
import React from "react"; import styled from "styled-components"; const ContentDiv = styled.div` margin: 40px; `; const ContentH2 = styled.h2` width: 200px; margin: 0 auto; text-align: center; `; const Review = () => { return ( <ContentDiv> <ContentH2>Detail</ContentH2> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos excepturi corrupti quo blanditiis! Adipisci amet corporis ipsum odio minima aliquid quisquam! Dignissimos natus laborum qui veritatis quaerat eaque! Nemo, ullam. </p> </ContentDiv> ); }; export default Review;
src / Components / Review.jsx