이번내용은 리액트에 스타일을 줄 수 있는 방법들이다
단순히 css파일로 이나 인라인태그로 스타일을 주는 게 아니라
css를 좀 더 편하게 작성하고 유동적으로 적용할 수 있는 툴을 배워보자
sass 를 만들어줄 리액트 프로젝트 폴더 위치에서 설치해 준다
sass 설치방법
C:\Users\사용자폴더\Desktop\react\StyledComponent> npm install node-sass@8
cmd에서 cd로 설치할 폴더로 이동해 준 뒤에 npm install node-sass@8을 해준다
@8은 버전인데 설치되어 있는 Node.js의 버전에 따라 설치해주면 된다. 나의 버전은 v18.12.1이다
Node.js의 버전을 확인하는 방법은 터미널에 node -v를 입력해 주면 확인이 가능하다
styled-components 설치방법
위와 똑같이 사용할 프로젝트폴더의 위치로 이동한 뒤에
npm install --save styled-components를 입력해 주면 된다.
설치가 잘되었는지 확인하는 방법은 프로젝트 폴더의 package.json에 들어가면 dependencies에 들어가 있는 걸 볼 수 있다.
SaSS--Syntactically Awesome Style Sheets
css작성을 간단하게 해 주고 변수선언이 간편하고 함수처럼 스타일을 적용시켜 줄 수도 있다.
Sass는 CSS 전처리기(Preprocessor)라고도 부른다
CSS가 만들어지기 전에 이런저런 일들을 먼저 처리해 주기 때문
일반 html에서 쓰려면 sass를 작성하고 컴파일해서 css로 바꿔주는 과정이 필요한데
리액트에서 쓰는 node-sass는 그런 과정이 필요 없이 작성한 sass를 바로 적용할 수 있다.
SassComponent.js
import React from 'react';
import './SassComponent.scss'
const SassComponent = () => {
return (
<div className='SassComponent'>
<div className='box red'></div>
<div className='box orange'></div>
<div className='box yellow'></div>
<div className='box green'></div>
<div className='box blue'></div>
<div className='box indigo'></div>
<div className='box violet'></div>
</div>
);
};
export default SassComponent;
스타일을 적용시켜 줄 컴포넌트를 만들어줬다 스타일을 줄 클래스도 만들어주고
만들어질 scss를 import 시켜줬다.
SassComponent.scss
//변수 사용하기
$red : #fa5252;
$orange : #fd7e14;
$yellow : #fcc419;
$green : #40c057;
$blue : #339af0;
$indigo : #5c7cfa;
$violet : #7950f2;
@mixin square($size){
$calculate: 32px * $size;
width: $calculate;
height: $calculate;
}
.SassComponent {
display: flex;
.box{
background-color: red;
cursor: pointer;
transition: 0.3s;
&.red{
background: $red;
@include square(1);
}
&.orange{
background: $orange;
@include square(2);
}
&.yellow{
background: $yellow;
@include square(3);
}
&.green{
background: $green;
@include square(4);
}
&.blue{
background: $blue;
@include square(5);
}
&.indigo{
background: $indigo;
@include square(6);
}
&.violet{
background: $violet;
@include square(7);
}
&:hover{
background: black;
}
}
}
@mixin ) mixin(믹스인)은 함수와 비슷한 동작을 하는 문법
CSS 스타일 시트에서 반복적으로 재사용할 CSS 스타일 그룹 선언을 정의하는 기능을 해준다.
@mixin으로 만들고 @include로 호출해서 사용 파라미터를 넣어줄 수도 있다.
위 구문에서는 파라미터로 숫자를 받아서 스타일크기가 숫자배수가 되도록 만들어줬다.
Sass는 하위요소를 안쪽으로 들여 써서 한 번에 작성해 줄 수 있다
$로 변수를 만들어서 값을 저장할 수 있다.
. SassComponet 안에 있는. box클래스를 들여서 써주고 &. violet =. box.violet과 같은 역할을 해준다
& 는 자기 자신을 의미한다.
완성화면)
Styled-components
styled-components는 style이 적용된 Component를 직접 생성하기 때문에, 스타일링을 위한 코드 사용량이 줄어드는 효과가 있습니다. 또 key value의 형태가 아닌 css의 문법을 그대로 사용하기 때문에
기존 css의 사용법보다 가독성도 높습니다.
사용법
import "./styles.css";
import styled from "styled-components";
const Circle = styled.div`
width: 50px;
height: 50px;
background: black;
border-radius: 50%;
`;
export default function App() {
return (
<div className="App">
<Circle />
</div>
);
}
스타일이 적용된 컴포넌트를 만들어준다고 생각하면 이해하기가 조금 쉽다
컴포넌트이기 때문에 props전달도 가능하다 , CSS사용
import styled,{css} from 'styled-components';
const CircleDiv = styled.div`
width:50px;
height:50px;
background: ${props=> props.color || 'black'}; props.color가 있으면 적용 없으면 black
border-radius:50%;
${props => props.big && //props.big이 true이면 별도의 css구문 실행
css`
width:150px;
height:150px;
`
}
`;
function Circle() {
return (
<div>
<CircleDiv color='blue'/>
<CircleDiv color='red' big/>
<CircleDiv/>
</div>
);
}
export default Circle;
여러 줄의 CSS 코드를 조건부로 보여주고 싶다면 css를 사용해야합니다. css 를 불러와서 사용을 해야
그 스타일 내부에서도 다른 props를 조회할 수 있습니다.
CircleDiv에 props를 주면 위의 컴포넌트선언부에서 props를 받아서 조건문에 사용해서 적용해 준다.
ThemeProvider
색상 코드를 지닌 변수를 Button.js 에서 선언을 하는 대신에 ThemeProvider라는 기능을 사용하여 styled-components로 만드는 모든 컴포넌트에서 조회하여 사용할 수 있는 전역적인 값을 설정해 보겠습니다.
<ThemeProvider theme={{
palette:{
blue:'#228be6',
gray:'#495057',
pink:'#f06595'
}
}}>
</ThemeProvider>
ThemeProvider 내부에 렌더링 된 styled-components로 만든 컴포넌트에서
palette를 조회하여 사용할 수 있습니다
props.theme.pallete.blue 이런 식으로 값에 접근이 가능하다.
예제)
좀 긴 코드라 차근차근 만들어서 보여주겠다..
import styled, { css } from "styled-components";
const AppBlock = styled.div`
width: 512px;
margin: 0 auto;
margin-top: 4em;
border: 1px solid black;
padding: 1em;
`;
export default function App() {
return (
<AppBlock>
<div></div>
</AppBlock>
);
}
AppBlock이라는 div styled-component를 만들어준다.
이제 저 빈 상자 안에 넣어줄 버튼컴포넌트를 만들어 준다
ButtonTotal.js
import React from "react";
import styled, { css } from "styled-components";
const ButtonTotal = ({ children }) => {
const StyledButton = styled.button`
/*공통스타일*/
display: inline-flex;
outline: none;
border: none;
border-radius: 4px;
color: white;
font-weight: bold;
cursor: pointer;
padding: 1em;
margin: 10px;
/*크기*/
font-size: 1em;
/*효과*/
&:hover {
background: #1c7ed6;
}
`;
return <StyledButton>{children}</StyledButton>;
};
export default ButtonTotal;
styledButton을 만들어서 마운트시켜줬다. App.js에서 태그사이글자를
props.children으로 받아서 내용을 넣어준다.
import styled, { css } from "styled-components";
import ButtonTotal from './ButtonTotal'
const AppBlock = styled.div`
width: 512px;
margin: 0 auto;
margin-top: 4em;
border: 1px solid black;
padding: 1em;
`;
export default function App() {
return (
<AppBlock>
<div>
<ButtonTotal>Button</ButtonTotal>
</div>
</AppBlock>
);
}
ButtonTotal을 import 해서 마운트 시켜준다 Button글자를 props로 보내준다.
이제 이 버튼을 여러 개 만들어주고 각각 props를 줘서 크기와 색을 다르게 해 준다.
우선은 크기부터 변경해 보자.
App.js
import styled, { css } from "styled-components";
import ButtonTotal from "./ButtonTotal";
const AppBlock = styled.div`
width: 512px;
margin: 0 auto;
margin-top: 4em;
border: 1px solid black;
padding: 1em;
`;
export default function App() {
return (
<AppBlock>
<div>
<ButtonTotal size="large">Button</ButtonTotal>
<ButtonTotal>Button</ButtonTotal>
<ButtonTotal size="small">Button</ButtonTotal>
</div>
<div>
<ButtonTotal size="large">Button</ButtonTotal>
<ButtonTotal>Button</ButtonTotal>
<ButtonTotal size="small">Button</ButtonTotal>
</div>
<div>
<ButtonTotal size="large">Button</ButtonTotal>
<ButtonTotal>Button</ButtonTotal>
<ButtonTotal size="small">Button</ButtonTotal>
</div>
</AppBlock>
);
}
App에서 props로 size를 보내준다 size props가 없는 컴포넌트는
ButtonTotal에서 size props 디폴트값을 medium으로 준다
ButtonTotal.js
import React from "react";
import styled, { css } from "styled-components";
const ButtonTotal = ({ children, size }) => {
const StyledButton = styled.button`
/*공통스타일*/
display: inline-flex;
outline: none;
border: none;
border-radius: 4px;
color: white;
font-weight: bold;
cursor: pointer;
padding: 1em;
margin: 10px;
/*크기*/
font-size: 1em;
/*조건별크기*/
${(props) => {
return (
props.size === "large" &&
css`
height: 3.5em;
font-size: 1.5em;
width: 40%;
`
);
}}
${(props) => {
return (
props.size === "medium" &&
css`
height: 2.25em;
font-size: 1em;
`
);
}}
${(props) => {
return (
props.size === "small" &&
css`
height: 1.5em;
font-size: 0.75em;
`
);
}}
/*효과*/
&:hover {
background: #1c7ed6;
}
`;
return <StyledButton size={size}>{children}</StyledButton>;
};
ButtonTotal.defaultProps = {
size: "medium"
};
export default ButtonTotal;
Props를 app에서 ButtonTotal로 보내주면 ButtonTotal > StyledButton으로 보내주고
StyledButton에서는 그걸 받아서 조건으로 props.size와 텍스트가 일치하면
css 구문을 적용시켜 주는 방식이다.
이제 색상을 각각 다르게 적용해 주겠다. 여기서는 ThemeProvider을 이용해 주겠다.
App.js
import styled, { ThemeProvider } from "styled-components";
import ButtonTotal from "./ButtonTotal";
const AppBlock = styled.div`
width: 512px;
margin: 0 auto;
margin-top: 4em;
border: 1px solid black;
padding: 1em;
`;
export default function App() {
return (
<ThemeProvider
theme={{
palette: {
blue: "#228be6",
gray: "#495057",
pink: "#f06595"
}
}}
>
<AppBlock>
<div>
<ButtonTotal size="large">Button</ButtonTotal>
<ButtonTotal>Button</ButtonTotal>
<ButtonTotal size="small">Button</ButtonTotal>
</div>
<div>
<ButtonTotal size="large" color="pink">
Button
</ButtonTotal>
<ButtonTotal color="pink">Button</ButtonTotal>
<ButtonTotal size="small" color="pink">
Button
</ButtonTotal>
</div>
<div>
<ButtonTotal size="large" color="gray">
Button
</ButtonTotal>
<ButtonTotal color="gray">Button</ButtonTotal>
<ButtonTotal size="small" color="gray">
Button
</ButtonTotal>
</div>
</AppBlock>
</ThemeProvider>
);
}
ThemeProvider를 import 해주고 theme객체를 만들어주었다
ThemeProvider컴포넌트 내부에 있는 컴포넌트들은 props로 값에 접근이 가능하다.
어떤 색을 줄지 알려주기 위해 color를 props로 보내준다.
import React from "react";
import styled, { css } from "styled-components";
const ButtonTotal = ({ children, size, color, ...rest }) => {
const StyledButton = styled.button`
/*공통스타일*/
display: inline-flex;
outline: none;
border: none;
border-radius: 4px;
color: white;
font-weight: bold;
cursor: pointer;
padding: 2em;
margin: 10px;
/*크기*/
font-size: 1em;
/* 조건별색깔 */
${({ theme, color }) => {
const selectcolor = theme.palette[color];
return css`
background: ${selectcolor};
`;
}}
/*조건별크기*/
${(props) => {
return (
props.size === "large" &&
css`
height: 3.5em;
font-size: 1.5em;
width: 40%;
`
);
}}
${(props) => {
return (
props.size === "medium" &&
css`
height: 2.25em;
font-size: 1em;
`
);
}}
${(props) => {
return (
props.size === "small" &&
css`
height: 1.5em;
font-size: 0.75em;
`
);
}}
/*효과*/
&:hover {
background: #1c7ed6;
}
`;
return (
<StyledButton size={size} color={color} {...rest}>
{children}
</StyledButton>
);
};
ButtonTotal.defaultProps = {
size: "medium",
color: "blue"
};
export default ButtonTotal;
color props를 못 받은 컴포넌트는 default로 blue를 준다.
color props를 받아서 보내주고 themeprovider는... rest로 받아서 보내준다.
/* 조건별색깔 */
${({ theme, color }) => {
const selectcolor = theme.palette[color];
return css`
background: ${selectcolor};
`;
}}
이 부분에서 받아서 theme.palette 값에 color로 접근한 다음 나온 값을 selectcolor 에저장하고
selectcolor를 백그라운드값으로 적용하는 구문을 반환해 준다.
조금 바꾼 부분이 있는데 ButtonTotal.js에서 스타일컴포넌트 만드는 부분을
ButtonTotal컴포넌트 부분 바깥으로 빼줘야 한다.
안쪽에 넣어서 썼더니 스타일이 계속 참조된다 그랬나? 새로 스타일을 만들어줘야 된다는 경고문이 떠서
바깥으로 꺼내줬더니 해결되었다.
한 번에 이해하기는 조금 어려운 부분 이긴 한데 값을 전달받고 쓰는 방법이 조금 어려운 거지 조건문이나 css자체는 이미 다해봤던 익숙한 내용들이라 익숙해지기만 하면 사용하는 데에 크게 문제는 없을 것 같다.
'프론트엔드 정복기 > 리액트' 카테고리의 다른 글
[React]15 리액트 성능 최적화(useMemo) (0) | 2023.01.12 |
---|---|
[React]14 styled-component part2 (2) | 2023.01.12 |
[React]12 Hooks (useState,useEffect,useRef,useContext) (0) | 2023.01.11 |
[React] 11 Hooks( useEffect,useRef ) (0) | 2023.01.11 |
[React] 10 리액트 style,모듈형연습 (0) | 2023.01.10 |