Styled-components 가이드
부수 기본 개념
Template Literal
문자열 안에 특정 자바스크립트 값을 넣어서 조합을 할때 쉽게 해줄수 있는 방법 (backtick사용)
const name = 'react';
const message = `hello ${name}`;
console.log(message);
// "hello react"
문자열이 아닌 object를 사용하였을시에는 다르다.
const object = {a : 1};
const text = `${object}`;
console.log(text);
// "[object Object]"
함수경우에도 함수 문자열형태그 그대로 들어가진다.
const fn = () => true
const msg = `${fn}`;
console.log(msg);
// "() => true"
favoriteColors () 대신 `` 를 사용하면?
const red = '빨간색';
const blue = '파란색';
function favoriteColors(texts, ...values) {
console.log(texts);
console.log(values);
}
favoriteColors `제가 좋아하는 색은 ${red}과 ${blue}입니다.`
favoriteColors () 대신 `` 를 사용하면? 2
const red = '빨간색';
const blue = '파란색';
function favoriteColors(texts, ...values) {
return texts.reduce((result, text, i) =>
`${result}${text}${values[i] ? `<b>${values[i]}</b>` : ''}' , '');
}
favoriteColors `제가 좋아하는 색은 ${red}과 ${blue}입니다.`
//제가 좋아하는 색은 <b>빨간색</b>과 <b>파란색</b> 입니다.
이런 ``backtick으로 styled component를 사용한다
const Circle = styled.div`
width : 5px;
height : 5px;
background : balck;
border-radius: 50%;
`;
function App() {
return <Circle />;
}
export default App;
Text
결과 ->
styled-components 문법을 backtick으로 감싸고 있는 상태에서
부모를 template Literal방식으로 가져온다
const Circle = styled.div`
width : 5px;
height : 5px;
background : ${props => props.color};
border-radius: 50%;
`;
function App() {
return <Circle color="blue" />;
}
export default App;
결과 ->
huge값이 ture라면 다음과같이...
const Circle = styled.div`
width : 5px;
height : 5px;
background : ${props => props.color};
border-radius: 50%;
${props =>
props.huge &&
`
width : 10px;
height : 10px;
`}
`;
function App() {
return <Circle color="blue" huge />;
}
export default App;
하지만 template Literal 안에 또다른 부모를 호출할순 없다...그렇다면?
styled-components에서 제공하는 css를 사용해보자
import styled, { css } from 'styled-components';
const Circle = styled.div`
width : 5px;
height : 5px;
background : ${props => props.color};
border-radius: 50%;
${props =>
props.huge &&
css`
${props .....}
width : 10px;
height : 10px;
`}
`;
function App() {
return <Circle color="blue" huge />;
}
export default App;
Styled-components 이름지정
객체의 이름을 생성할시( 스타일 컴포넌트)
앞글자는 꼭 대문자여야합니다.
const Buttons = styled(Button)`
width : ${props => props.theme.buttonWidth};
margin : ${props => props.theme.buttonMargin};
`;
//success
const PlusButton = styled(Buttons)``;
//error
const minusButton = styled(Buttons)``;
minusButton 과같이 컴포넌트를 생성한다면 오류발생입니다.
(스타일컴포넌트가 아닌 원래 컴포넌트 생성시 주의사항)
속성값 입력시에는 '' or "" 를 감싸지 않는다
const Buttons = styled(Button)`
width : 10px;
margin : 5px 10px 10px 50px;
background-color : red;
`;
//success
const PlusButton = styled(Buttons)``;
//error
const minusButton = styled(Buttons)``;
스타일 컴포넌트 생성시
ex)
const DeleteButton = styled.div`
background-color : "red";
`;
현재 프로젝트에서는 Ant Design을 통한 UI Framework를 사용중입니다.
1.기본 UI 요소를 정할시 다음과 같은 방법으로
스타일 변수를 다음과 같은 방법으로 생성 합니다.
html 요소(위에 예제에서는 div)를 styled하는 styled-components 라이브러리를 이용하여 다음과같이 생성합니다.
*생성 이름은 꼭 맨앞이 대문자여야만 합니다.
ex)
import {Button, Modal, Select, Table} from "antd";
...
const DeleteButton = styled(Button)`
background-color : "red";
`;
2. UI(ant design과 같은경우)FrameWork 수정시에는
다음과 같이 설정합니다.
antDesign의 Button UI를 styled-components를 적용해 다음과 같이
설정하여줍니다.
ex)
import {Button, Modal, Select, Table} from "antd";
...
const Buttons = styled(Button)`
margin-left : 10px;
`;
const ExcelDownButton = styled(Buttons)`
margin-left : 30px;
`;
3. 비슷하거나 겹치는 스타일 설정에대한 컴포넌트를
생성할시에 다음과 같이 정의합니다.
생성한 스타일 컴포넌트 변수를
매개변수로서 다시 styled에 주입하여 생성합니다.
이때 추가로 입력할 스타일 요소가 있다면 추가가 가능합니다.
ex)
import {Button, Modal, Select, Table} from "antd";
...
export const borderProps = props => css`
${props.borderBottom && `border-bottom: ${props.borderWidth || "1px"} solid ${color.border}`};
${props.borderTop && `border-top: ${props.borderWidth || "1px"} solid ${color.border}`};
${props.borderLeft && `border-left: ${props.borderWidth || "1px"} solid ${color.border}`};
${props.borderRight && `border-right: ${props.borderWidth || "1px"} solid ${color.border}`};
`;
4.별도의 파일로 분류하여 사용을 할 상황이면
다음과 같이 진행한다.
css ` ... ` 는 styled-components가 제공하는 기능으로 ...에대한 요소들을 css기능으로 묶어 props로 전달하는 기능이다.
스타일 컴포넌트 안에 집어넣을때는 Template Literal방식으로 넣는다.
ex) ${borderProps}
import styled from "styled-components";
import {Layout} from "antd";
const {Header} = Layout;
export const IndexLayout = styled.div`
display:grid;
grid-template-columns: 100% auto;
grid-template-rows: 60px auto;
width : 100%;
height : 100%
`;
export const DexiLogo = styled.img`
width : 32px;
height : 32px;
line-Height : 60px;
margin : 4px 15px 4px 0px;
`;
export const TopHeader = styled(Header)`
grid-column-start:1;
grid-column-end:4;
flex-direction:row;
flex: 0 0 auto;
`;
export const TopRightMenu = styled.div`
margin-top : 7px;
float : right;
`;
export default IndexLayout;
5.스타일 컴포넌츠 파일분리
스타일드 컴포넌트들을 export시켜
다음과같이 불러와 사용하였다.
import {DexiLogo, TopHeader, TopRightMenu} from '../../IndexLayout';
....
<TopHeader>
<DexiLogo>
......
</DexiLogo>
<TopRightMenu>
......
</TopRightMenu>
</TopHeader>
export 시킨 컴포넌트를 import 하여 사용하였다.
themeProvider 같은 전역으로 공통된 부분이 아닌 일부분에 필요한 스타일 컴포넌츠를 사용할때 파일을 분리해야한다면 이런 방법을 사용한다.
글로벌 변수 ( themeProvider 사용할시)
상위 컴포넌츠에 다음 예제와 같이 사용합니다.
ex)
const theme = {
buttonWidth : "50px",
buttonMargin : "5px"
// 이런식으로 전체 컴포넌트에 넣어줄 것들 생성
};
<ThemeProvider theme={theme}>
<IndexPage/>
</ThemeProvider>
많은컴포넌트에 공통으로 사용하는 스타일에 주로 사용합니다.
const theme 파일을 별도의 파일로 분류하는 것은 자유입니다.
store 저장소 mobx 사용시에
수시로 변하는 value를 적용하여 theme를 변화줄수 있습니다.
@inject('commonStore')
@observer
class App extends Component<any, any> {
render() {
const {commonStore} = this.props;
const theme ={
main : commonStore.getColor
};
return (
<Layout>
<ThemeProvider theme={theme}>
<IndexPage/>
</ThemeProvider>
</Layout>
);
}
commonStore.getColor(mobx)로 변한 value류가 다시 ThemeProvider를 타고
값을 전역에 전달합니다.
themeprovider를 다음과같이 로드하여 사용합니다.
ex)
const Buttons = styled(Button)`
width : ${props => props.theme.buttonWidth};
margin : ${props => props.theme.buttonMargin};
`;
여러 컴포넌트에서 일괄적으로 변경해야 할시
const theme의 요소에서 한번만 수정해주면 여러 반복요소를 줄일수 있습니다.
ex)
//예로 Button 컴포넌트를 만들고 부모값으로 보낼 size를 설정
<Button size="small">Button</Button>
<Button size="large">Button</Button>
<Button size="default">Button</Button>
부모로 받는 값에따라 변해야하는경우 (조건에 따른 설정)
ex)
const sizeStyles = css`
${props => props.size === 'large' &&
css`
height : 10px;
font-size: 8px;
`}
${props => props.size === 'default' &&
css`
height : 8px;
font-size: 5px;
`}
${props => props.size === 'small' &&
css`
height : 5px;
font-size: 3px;
`}
`;
const StyledButton = styled.button`
/*...공통스타일*/
/*템플레이트 리터럴*/
${sizeStyles}
`;
통상방법
ex)
const sizes = {
large: {
height : '10px',
fontSize: '8px'
},
default: {
height : '7px',
fontSize : '5px'
},
small: {
height : '5px',
fontSize : '3px'
}
};
const sizeStyles = css`
${({ size }) => css`
height : ${sizes[size].height};
font-size : ${sizes[size].fontSize};
`}
`;
const StyledButton = styled.button`
/*...공통스타일*/
/*템플레이트 리터럴*/
${sizeStyles}
`;
적용방법
예제 같은 경우도 Store저장소의 값의 변화에따라 달라질수 있으므로
size value에 mobx 값을 받도록 하였다.
ex)
//예로 Button 컴포넌트를 만들고 부모값으로 보낼 size를 설정
<Button size="small">Button</Button>
<Button size="large">Button</Button>
<Button size="default">Button</Button>
ex)
//예로 Button 컴포넌트를 만들고 부모값으로 보낼 size를 설정
<Button size={commonStore.getFontSize}>Button</Button>
<Button size="large">Button</Button>
<Button size="default">Button</Button>
const Buttons = styled(Button)`
width : ${props => props.theme.buttonWidth};
margin : ${props => props.theme.buttonMargin};
`;
//success
const PlusButton = styled(Buttons)``;
//error
const minusButton = styled(Buttons)``;
위와같이 컴포넌트를 상속하는것 보다는
const Buttons = css`
width : ${props => props.theme.buttonWidth};
margin : ${props => props.theme.buttonMargin};
`;
const PlusButton = styled.button`
${Buttons}
`;
const MinusButton = styled.button`
${Buttons}
`;
css를 분리 적용하는쪽을 주로 사용하였다.
const Buttons = styled(Button)`
width : ${props => props.theme.buttonWidth};
margin : ${props => props.theme.buttonMargin};
`;
//success
const PlusButton = styled(Buttons)``;
//error
const minusButton = styled(Buttons)``;
타입스크립트 적용시.
스크립트상에서 사용하는 언어이기때문에
타입지정이 필요할 수 있습니다.
ex)
import styledComponents from 'styled-components'
import styledComponentsTS from 'styled-components-ts'
export interface MyImageProps {
size: number
borderColor?: string
borderSize?: number
}
const MyImage = styledComponentsTS<MyImageProps>(styledComponents.img) `
width: ${props => props.size}px;
height: ${props => props.size}px;
border: ${props => props.borderSize || '4px'} solid ${props => props.borderColor || 'black'}
`
<MyImage size={300} borderColor="blue" borderSize={10} />
MyImage 에 대한 속성타입지정은 사실상 ts파일에 따로 분류하여 설정합니다.