styled-components는 CSR로 작동하기 때문에 SSR인 next-js에서는 styled이 적용되도록 따로 설정이 필요합니다.
(설정을 하지 않으면 스타일이 적용되기 전에 렌더가 되어 화면이 보이는 현상이 나타납니다..🤦🏻♀️)
1. 설치
npm i styled-components
npm i -D @types/styled-components babel-plugin-styled-components
2. next.js에서 사용하도록 설정하기
1) .babelrc 생성
{
"presets": ["next/babel"],
"plugins": [
[
"styled-components",
{
"ssr": true, // SSR을 위한 설정
"fileName": true, // 코드가 포함된 파일명을 알려줌.
"displayName": true, // 클래스명에 컴포넌트 이름을 붙임
"pure": true // 사용되지 않는 속성 제거
}
]
]
}
2) _document.tsx 파일에 코드 추가 (next.js에서 제시한 예시)
import Document, { Html,Head,Main,NextScript,DocumentContext} from 'next/document';
import { ServerStyleSheet } from 'styled-components';
class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: [initialProps.styles, sheet.getStyleElement()],
};
} finally {
sheet.seal();
}
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
3. styled-components 세팅
1) 기본 css 파일 삭제
2) styled-components 파일 생성 (src > styles)
npm i styled-reset
// customReset.ts
import { css } from "styled-components";
export const customReset = css`
*,
html,
*:before,
*:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
* {
outline: none;
cursor: default;
}
*:focus {
outline: none;
}
html,body,div,span,dl,dt,dd,h1,h2,h3,h4,h5,h6,p,form,fieldset,legend,input,select,
textarea,table,col,colgroup,thead,tfoot,tbody,th,td,button {
margin: 0;
padding: 0;
color: ${({ theme }) => theme.color.dark};
font-family: "Pretendard Variable";
border: 0;
}
body {
background: #fff;
color: ${({ theme }) => theme.color.dark};
font-size: 16px;
font-weight: 400;
line-height: 1;
overflow-x: hidden;
overflow-y: overlay;
}
ul,ol,li {
margin: 0;
padding: 0;
list-style: none;
}
em,address {
font-style: normal;
}
img {
font-size: 0;
line-height: 0;
border: 0 none;
}
caption {
overflow: hidden;
width: 0;
height: 0;
font-size: 0;
line-height: 0;
}
table {
border-spacing: 0;
border-collapse: collapse;
}
th,td {
text-align: left;
vertical-align: middle;
padding: 10px 20px;
word-break: keep-all;
}
a {
text-decoration: none;
color: ${({ theme }) => theme.color.dark};
line-height: 1;
cursor: pointer;
}
a:hover,a:focus,a:active {
text-decoration: none;
}
a:visited {
color: ${({ theme }) => theme.color.dark};
}
button {
border: 0 none;
background-color: transparent;
cursor: pointer;
}
/* IE - input close button delete */
input::-ms-clear {
display: none;
}
/* RESET - chrome input background sky set */
input:-webkit-autofill {
-webkit-box-shadow: 0 0 0 0;
box-shadow: 0 0 0 0;
-webkit-text-fill-color: #848484;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
transition: background-color 5000s ease-in-out 0s;
}
p,span,h1,h2,h3,h4,h5,h6 {
word-break: keep-all;
}
b {
font-weight: 600 !important;
}
textarea {
resize: none;
}
`;
// globalStyles.ts
import { createGlobalStyle } from "styled-components";
import reset from "styled-reset";
import { customReset } from "./customReset";
const GlobalStyle = createGlobalStyle`
${reset};
${customReset};
`;
export default GlobalStyle;
// theme.ts
import { DefaultTheme } from "styled-components";
const color = {
main: "#14DBBA,
gray: "#5D5D5D",
dark: "#242424",
};
const layout = {
contentWidth: "1280px",
};
export const theme: DefaultTheme = { color, layout };
// mixin.ts
import { css } from "styled-components";
export const scroll = css`
::-webkit-scrollbar {
width: 5px;
height: 5px;
-webkit-overflow-scrolling: auto;
}
::-webkit-scrollbar-track {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
border-radius: 4px;
background-color: #e0e0e0;
}
::-webkit-scrollbar-button {
width: 0;
height: 0;
}
`;
export const textEllipsis = css`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;
3) styled-components 설정하기
컴포넌트 내에서 전반적으로 globalstyle을 적용하고, theme을 사용할 수 있도록 처리합니다.
// _app.tsx
import type { AppProps } from 'next/app';
import { ThemeProvider } from 'styled-components';
import Layout from '../components/common/Layout';
import GlobalStyle from '../styles/globalStyles';
import { theme } from '../styles/theme';
export default function App({ Component, pageProps }: AppProps) {
return (
<ThemeProvider theme={theme}>
<GlobalStyle />
<Layout>
<Component {...pageProps} />
</Layout>
</ThemeProvider>
);
}
https://github.com/vercel/next.js/tree/canary/examples/with-styled-components
반응형
'Web > React & Next.js' 카테고리의 다른 글
React | Kakao Map Api를 사용하여 주소로 지도 그리기 (0) | 2023.05.14 |
---|---|
Next.js 에서 Next/Image를 사용하여 이미지 처리하기 (0) | 2023.02.16 |
Next.js | Next.js + typescript 초기 세팅 (next 13) (0) | 2023.02.14 |
React | web3를 사용하여 메타마스크(Metamask) BSC 네트워크 변경 및 추가하기 (0) | 2023.01.25 |
React | axios interceptors header에 token값 설정&추가하기, 삭제하기 (0) | 2023.01.17 |