별도의 library 를 이용합니다.
Styled Component 라는 방식이 있는 것이고, 이것을 지원하는 다양한 library들이 있는데, 그 중에 가장 대표적인 library가 Styled Components
라고 하는 똑같은 이름의 library가 있습니다.
이와 별개로 많이 쓰이는 library가 emotion
이라는 library가 있습니다.
둘 다 같은 방식이지만 약간 사용법이 틀립니다.
Styled Components 라이브러리를 이용하여 component에 style을 적용하는 방법을 알아보겠습니다.
npx create-react-app styled-components-example
npm i styled-components
npm start
//StyledButton.jsx
import styled from 'styled-components';
const StyledButton = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
font-size: 20px;
`;
export default StyledButton;
StyledButton은 styled-components 에 의해서 스타일이 적용된 button을 가지고 있게 됩니다.
스타일을 명시하려면 템플릿 스트링을 바로 뒤에 붙여서 표현합니다. 이는 javascript에서 기본적으로 지원되는 방식입니다.
템플릿 스트링 부분은 문자열이기 때문에 css파일에서 작성할 때 처럼 오타를 잡아주지 않습니다. 이 부분을 극복하기 위해 플러그인을 사용한다거나 하지 않으면 조금 어려움이 있을 수 있습니다.
StyledButton 는 현재 스타일이 적용된 일종의 컴포넌트
입니다. 이것을 컴포넌트 처럼 다른 곳으로 가져가서 사용할 수 있습니다.
//App.js
function App() {
return (
<StyledButton>버튼</StyledButton>
);
}
실행하면 button이 출력되고, console 창에서 확인하면 아래처럼 우리가 class를 지정하지 않았음에도 class를 확인할 수 있습니다.
이제 아래처럼 style를 추가하고 html 에서 확인하면,
//StyledButton.jsx
import styled from 'styled-components';
const StyledButton = styled.button`background: transparent;`;
export default StyledButton;
head에 style 태그 한 개가 추가되었습니다.
class 이름이 bNahjN 으로 새로 만들어졌습니다.
button 태그로 가서 확인해 보면 아래처럼 같은 이름의 클래스가 추가되어 있습니다.
정리하면 Styled Components
는 클래스 이름이 다른 엘리먼트들과 겹치지 않게 관리하기 위해 style 태그로 style을 자동으로 추가해주고, 클래스 이름을 자동으로 만들어주고, 그 클래스를 컴포넌트에 자동으로 추가해줍니다.
props를 전달해서 그 props에 맞는 디자인을 보여주고 싶은 경우도 많을 것입니다.
//App.js
function App() {
return (
<StyledButton primary>버튼</StyledButton>
);
}
(참고) html문법으로서 html 태그의 속성으로 primary
이렇게 전달하면 primary={true}
와 의미가 같습니다.
primary 속성이 (true)있다면 아래의 css 속성을 적용합니다.
//StyledButton.jsx
import styled, { css } from 'styled-components';
const StyledButton = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
font-size: 20px;
${props => props.primary &&
css`
background: palevioletred;
color: white;
`}
`;
export default StyledButton;
//App.js
import StyledButton from "./components/StyledButton";
import styled from "styled-components";
const PrimaryStyledButton = styled(StyledButton)`
background: palevioletred;
color: white;
`;
function App() {
return (
<StyledButton primary>버튼</StyledButton>
<PrimaryStyledButton>버튼</PrimaryStyledButton>
);
}
사용자가 임의로 만든 style을 가져올 때에는 styled()
의 인자로 해당 컴포넌트를 인수로 넘깁니다. styled(StyledButton)
function App() {
return (
<StyledButton>버튼</StyledButton>
<StyledButton as="a" href="/">버튼</StyledButton>
);
}
두번째 버튼 태그는 이제 button 태그가 아니라 a 태그로 렌더링 됩니다. 실제로 확인해보면 button 태그가 아닌 a태그로 바뀌어 있습니다.
아래처럼 기존의 엘리먼트 뿐만 아니라 as속성에 특정 컴포넌트를 지정하여 그 컴포넌트에 StyledButton의 style을 지정할 수도 있습니다.
const UppercaseButton = (props) => <button { ... props} children={props.children.toUpperCase()} />;
function App() {
return (
<StyledButton>버튼</StyledButton>
<StyledButton as={UppercaseButton}>button</StyledButton>
);
}
const MyButton = props => <button { ... props} children={`MyButton ${props.children}`} />
const StyledMyButton = styled(MyButton)`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
font-size: 20px;
`;
function App() {
return (
<StyledButton>버튼</StyledButton>
<StyledMyButton>button</StyledMyButton>
);
}
const MyButton = props => <button { ... props} children={`MyButton ${props.children}`} />
const StyledMyButton = styled(MyButton)`
background: transparent;
border-radius: 3px;
border: 2px solid ${(props) => props.color || "palevioletred"};
color: ${(props) => props.color || "palevioletred"};
margin: 0 1em;
padding: 0.25em 1em;
font-size: 20px;
:hover {
border: 2px solid red;
}
::before {
content: "@";
}
`;
function App() {
return (
<StyledButton>버튼</StyledButton>
<StyledMyButton>button</StyledMyButton>
<StyledMyButton color="green">button</StyledMyButton>
);
}
styled의 템플릿 스트링에는
${}
안에 함수를 넣어 props에 따른 원하는 값을 반환하여 적용하는 처리를 해줄 수도 있습니다.
:hover
처리도 가능합니다.
::before
와 같은 가상선택자 등 css에서 사용가능한 속성들을 다 사용할 수 있습니다.
이처럼
Styled Components
를 사용하면 scope 오염을 방지할 수 있지만, 각각 컴포넌트 별로 style을 적용하다 보면 전역적으로 처리를 하고 싶을 때는 어려움이 있습니다.
그래서 Styled Components 에서도 global로 스타일을 적용할 수 있는 방법을 제공해줍니다.
//App.js
import styled, { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
button {
color: yellow;
}
`;
function App() {
return (
<div className="App">
<GlobalStyle />
// ...
// ...
</div>
);
}
// StyledA.jsx
import styled from "styled-components";
const StyledA = styled.a.attrs((props) => ({
target: "_BLANK",
}))`
color: ${props => props.color};
`;
export default StyledA;
attrs((props) => ({}))
attrs의 반환값으로 속성을 객체로 반환하면 컴포넌트에 props 객체가 들어온것과 같은 효과를 줄 수 있습니다.
// App.js
function App() {
return (
<StyledA href="https://google.com">태그</StyledA>
);
}
StyledA
는 href와 target 속성이 적용되어 렌더됩니다.
이제 StyledA
가 적용된 컴포넌트는 마치 디폴트로 target: "_BLANK",
속성이 적용된 엘리먼트로 사용할 수 있게 됩니다.