ํจ์จ์ ์ธ ์ปดํฌ๋ํธ ํ ์คํธ, ๋ฐ์ํ ๋์์ธ ๊ฐ๋ฐ, UI ํคํธ ์ ์์ ์ํ CSS @mock์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ์์๋ณด์ธ์. ์ค์ ์์ ์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐฐ์ธ ์ ์์ต๋๋ค.
CSS @mock: ํ ์คํธ ๋ฐ ๊ฐ๋ฐ์ ์ํ CSS ๋ชจํน ์ค์ฉ ๊ฐ์ด๋
๋์์์ด ๋ฐ์ ํ๋ ํ๋ก ํธ์๋ ๊ฐ๋ฐ ํ๊ฒฝ์์ ํจ์จ์ ์ธ ํ
์คํธ์ ๋น ๋ฅธ ํ๋กํ ํ์ดํ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์๋ฐ์คํฌ๋ฆฝํธ ํ
์คํธ ํ๋ ์์ํฌ๋ ๋ณดํธํ๋์์ง๋ง, CSS ์คํ์ผ์ ํจ๊ณผ์ ์ผ๋ก ๋ถ๋ฆฌํ๊ณ ํ
์คํธํด์ผ ํ ํ์์ฑ์ ์ข
์ข
๊ฐ๊ณผ๋์ด ์์ต๋๋ค. ๋ฐ๋ก ์ฌ๊ธฐ์ CSS @mock
์ด ๋ฑ์ฅํฉ๋๋ค. ์ด๋ ๊ฐ๋ฐ ์ํฌํ๋ก์ฐ๋ฅผ ๊ฐ์ํํ๊ธฐ ์ํด CSS ์คํ์ผ์ ๋ชจํนํ๋ ๊ฐ๋ ฅํ ๊ธฐ์ ์
๋๋ค(ํ์ค CSS ๊ธฐ๋ฅ์ ์๋์ง๋ง, ์ด ๊ธ์์๋ CSS ๋ชจํน์ *๊ฐ๋
*๊ณผ ์ด๋ฅผ ๋ฌ์ฑํ๋ ๋ฐฉ๋ฒ์ ํ๊ตฌํฉ๋๋ค). ์ด ์ข
ํฉ ๊ฐ์ด๋์์๋ ์ฌ๋ฌ๋ถ์ ํ๋ก ํธ์๋ ๊ฐ๋ฐ ์์ค์ ํ ๋จ๊ณ ๋์ด๊ธฐ ์ํ CSS ๋ชจํน์ ์์น, ์ค์ ์ ์ฉ ์ฌ๋ก, ๊ทธ๋ฆฌ๊ณ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ดํด๋ด
๋๋ค.
CSS ๋ชจํน์ด๋ ๋ฌด์์ธ๊ฐ?
CSS ๋ชจํน์ ํต์ฌ์ ํ ์คํธ๋ ๊ฐ๋ฐ ์ค์ ์ค์ CSS ์คํ์ผ์ ์ ์ด ๊ฐ๋ฅํ๊ณ ์์ธก ๊ฐ๋ฅํ ๋์ฒด๋ฌผ๋ก ๋ฐ๊พธ๋ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ํตํด ๋ค์์ ์ํํ ์ ์์ต๋๋ค:
- ์ปดํฌ๋ํธ ๋ถ๋ฆฌ: ์ ์ญ CSS ์คํ์ผ์ํธ์ ๋ ๋ฆฝ์ ์ผ๋ก ์ปดํฌ๋ํธ์ ์๊ฐ์ ๋์์ ํ ์คํธํฉ๋๋ค. ์ด๋ ๋จ์ ํ ์คํธ์ ์ปดํฌ๋ํธ ์ฌ์ฌ์ฉ์ฑ์ ๋ณด์ฅํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- ๋ค์ํ ์ํ ์๋ฎฌ๋ ์ด์ : ๋ณต์กํ ์ค์ ์์ด ์ปดํฌ๋ํธ๊ฐ ๋ค์ํ ์ํ(์: hover, active, disabled)์์ ์ด๋ป๊ฒ ๋ ๋๋ง๋๋์ง ์ฝ๊ฒ ํ ์คํธํฉ๋๋ค.
- ๋ฐ์ํ ๋์์ธ ์คํ: ๋ฏธ๋์ด ์ฟผ๋ฆฌ๋ฅผ ๋ชจํนํ์ฌ ๋ค์ํ ํ๋ฉด ํฌ๊ธฐ์ ํด์๋๋ฅผ ์ ์ํ๊ฒ ํ ์คํธํฉ๋๋ค.
- UI ํคํธ ๊ฐ๋ฐ: ๋ค๋ฅธ ์คํ์ผ์ ๊ฐ์ญ ์์ด UI ํคํธ์ ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํ์ฌ ๋ณด์ฌ์ค๋๋ค.
- ์๊ฐ์ ํ๊ท ํ ์คํธ ๋จ์ํ: ํ ์คํธ ์ค์ธ CSS ์คํ์ผ์ ์ ์ดํ์ฌ ์๊ฐ์ ํ๊ท ํ ์คํธ์ ๋ ธ์ด์ฆ๋ฅผ ์ค์ ๋๋ค.
ํ์ค CSS์๋ ๋ด์ฅ๋ @mock
CSS at-rule์ด ์์ง๋ง, CSS ๋ณ์, ์๋ฐ์คํฌ๋ฆฝํธ ํ
์คํธ ํ๋ ์์ํฌ, ๋น๋ ๋๊ตฌ๋ฅผ ํ์ฉํ ๋ค์ํ ๊ธฐ์ ์ ํตํด ์ด ๊ฐ๋
์ ๊ตฌํํ ์ ์์ต๋๋ค. ์ด ๋ฐฉ๋ฒ๋ค์ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ CSS๋ฅผ ๋ชจํนํด์ผ ํ๋๊ฐ?
CSS ๋ชจํน์ ์ด์ ์ ๋จ์ํ ํธ์์ฑ์ ํจ์ฌ ๋ฐ์ด๋์ต๋๋ค. ์ด๋ ๋ค์์ ๊ธฐ์ฌํฉ๋๋ค:
- ํ ์คํธ ์ฉ์ด์ฑ ์ฆ๊ฐ: CSS ๋ชจํน์ ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํ๊ณ ์๊ฐ์ ๋์์ ์ ์ดํ ์ ์๊ฒ ํ์ฌ ์คํ์ผ์ ํ ์คํธ ์ฉ์ด์ฑ์ ๋์ ๋๋ค. ์ด๋ฅผ ํตํด ๋ ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ํ ์คํธ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
- ๋ ๋น ๋ฅธ ๊ฐ๋ฐ ์ฃผ๊ธฐ: ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํ๊ณ ๋ค์ํ ์ํ๋ฅผ ์ ์ํ๊ฒ ์๋ฎฌ๋ ์ด์ ํจ์ผ๋ก์จ CSS ๋ชจํน์ ๊ฐ๋ฐ ํ๋ก์ธ์ค๋ฅผ ํฌ๊ฒ ๊ฐ์ํํฉ๋๋ค.
- ์ฝ๋ ํ์ง ํฅ์: ๋ค์ํ ์คํ์ผ์ ์ฝ๊ฒ ํ ์คํธํ๊ณ ์คํํ ์ ์๋ ๋ฅ๋ ฅ์ ๋ ๋์ ์ฝ๋ ํ์ง๊ณผ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด CSS๋ก ์ด์ด์ง๋๋ค.
- ์์กด์ฑ ๊ฐ์: CSS ๋ชจํน์ ์ปดํฌ๋ํธ ๊ฐ์ ์์กด์ฑ์ ์ค์ฌ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๊ณ ์ ์ง๋ณด์๋ฅผ ๋ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
- ํ์ ๊ฐํ: ์คํ์ผ ํ ์คํธ๋ฅผ ์ํ ๋ช ํํ๊ณ ์ ์ด๋ ํ๊ฒฝ์ ์ ๊ณตํจ์ผ๋ก์จ CSS ๋ชจํน์ ๋์์ด๋์ ๊ฐ๋ฐ์ ๊ฐ์ ๋ ๋์ ํ์ ์ ์ด์งํฉ๋๋ค.
CSS ๋ชจํน์ ์ํ ๊ธฐ์ ๋ค
CSS ๋ชจํน์ ํจ๊ณผ์ ์ผ๋ก ๊ตฌํํ๊ธฐ ์ํ ๋ช ๊ฐ์ง ์ค์ฉ์ ์ธ ๊ธฐ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
1. CSS ๋ณ์ (Custom Properties)
CSS ๋ณ์๋ ๋ฐํ์์ ์คํ์ผ์ ์ฌ์ ์ํ ์ ์๋ ๊ฐ๋ ฅํ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค. CSS ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ์คํ์ผ์ ์ ์ํ๋ฉด ํ ์คํธ๋ ๊ฐ๋ฐ ์ค์ ์ด๋ฅผ ์ฝ๊ฒ ๋ชจํนํ ์ ์์ต๋๋ค.
์์:
๋ฒํผ ์ปดํฌ๋ํธ๋ฅผ ๊ณ ๋ คํด ๋ด ์๋ค:
:root {
--button-background-color: #007bff;
--button-text-color: #fff;
--button-border-radius: 5px;
}
.button {
background-color: var(--button-background-color);
color: var(--button-text-color);
border-radius: var(--button-border-radius);
padding: 10px 20px;
border: none;
cursor: pointer;
}
ํ ์คํธ ํ๊ฒฝ(์: Jest, Mocha, Cypress ์ฌ์ฉ)์์ ์ด๋ฌํ ๋ณ์๋ฅผ ์ฌ์ ์ํ ์ ์์ต๋๋ค:
// JavaScript ํ
์คํธ
document.documentElement.style.setProperty('--button-background-color', '#ff0000'); // ๋นจ๊ฐ์
document.documentElement.style.setProperty('--button-text-color', '#000'); // ๊ฒ์์
์ด๋ ๊ฒ ํ๋ฉด ์ ์ญ ์คํ์ผ์ํธ์ ์ํฅ์ ์ฃผ์ง ์๊ณ ํ ์คํธ ๋ฒ์ ๋ด์์๋ง ๋ฒํผ์ ๋ชจ์์ด ๋นจ๊ฐ์ ๋ฐฐ๊ฒฝ์ ๊ฒ์์ ํ ์คํธ๋ก ํจ๊ณผ์ ์ผ๋ก ๋ณ๊ฒฝ๋ฉ๋๋ค.
์ฅ์ :
- ๊ตฌํ์ด ๊ฐ๋จํ๊ณ ์ง๊ด์ ์ ๋๋ค.
- ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋น๋ ๋๊ตฌ๊ฐ ํ์ ์์ต๋๋ค.
- ๋์ ์ด๋ฉฐ ๋ฐํ์ ์คํ์ผ ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํฉ๋๋ค.
๋จ์ :
- ํ๋ก์ ํธ ์ ์ฒด์์ CSS ๋ณ์๋ฅผ ์ผ๊ด๋๊ฒ ์ฌ์ฉํ๋ ค๋ฉด ์ ์คํ ๊ณํ์ด ํ์ํฉ๋๋ค.
- ๋ชจํนํ ์คํ์ผ์ ์๊ฐ ๋ง์ผ๋ฉด ์ฝ๋๊ฐ ์ฅํฉํด์ง ์ ์์ต๋๋ค.
2. CSS ๋ชจ๋๊ณผ ํจ๊ปํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ ํ๋ ์์ํฌ
์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ ํ๋ ์์ํฌ์ CSS ๋ชจ๋์ ๊ฒฐํฉํ๋ฉด CSS ๋ชจํน์ ๋ํด ๋ ๊ตฌ์กฐํ๋๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค. CSS ๋ชจ๋์ ๊ฐ ์ปดํฌ๋ํธ์ ๋ํด ๊ณ ์ ํ ํด๋์ค ์ด๋ฆ์ ์์ฑํ์ฌ ์ด๋ฆ ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ์คํ์ผ ๋ถ๋ฆฌ๋ฅผ ๋จ์ํํฉ๋๋ค.
์์:
`Button.module.css`
.button {
background-color: #007bff;
color: #fff;
border-radius: 5px;
padding: 10px 20px;
border: none;
cursor: pointer;
}
.button--primary {
background-color: #28a745; /* Green */
}
`Button.js`
import styles from './Button.module.css';
function Button({ primary, children }) {
return (
);
}
export default Button;
Jest๋ก ํ ์คํธํ๊ธฐ:
import React from 'react';
import { render, screen } from '@testing-library/react';
import Button from './Button';
// CSS ๋ชจ๋ ๋ชจํน
jest.mock('./Button.module.css', () => ({
button: 'mocked-button',
'button--primary': 'mocked-button--primary',
}));
describe('Button Component', () => {
it('renders with the default styles', () => {
render();
const buttonElement = screen.getByRole('button', { name: 'Click me' });
expect(buttonElement).toHaveClass('mocked-button');
});
it('renders with the primary styles', () => {
render();
const buttonElement = screen.getByRole('button', { name: 'Click me' });
expect(buttonElement).toHaveClass('mocked-button');
expect(buttonElement).toHaveClass('mocked-button--primary');
});
});
์ด ์์์๋ jest.mock()
์ ์ฌ์ฉํ์ฌ CSS ๋ชจ๋์ ๋ฏธ๋ฆฌ ์ ์๋ ํด๋์ค ์ด๋ฆ์ ํฌํจํ๋ ๋ชจ์ ๊ฐ์ฒด๋ก ๋์ฒดํฉ๋๋ค. ์ด๋ฅผ ํตํด ํ
์คํธ ์ค์ ์ปดํฌ๋ํธ์ ์ฌ๋ฐ๋ฅธ ํด๋์ค ์ด๋ฆ์ด ์ ์ฉ๋์๋์ง ํ์ธํ ์ ์์ต๋๋ค.
์ฅ์ :
- CSS ๋ชจ๋๋ก ์ธํ ๊ฐ๋ ฅํ ์คํ์ผ ๋ถ๋ฆฌ.
- ๋ช ํํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ํ ์คํธ ์ฝ๋.
- ์ฌ๋ฐ๋ฅธ ํด๋์ค ์ด๋ฆ์ด ์ ์ฉ๋์๋์ง ์ฝ๊ฒ ํ์ธํ ์ ์์ต๋๋ค.
๋จ์ :
- CSS ๋ชจ๋์ ์ง์ํ๋ ๋น๋ ๋๊ตฌ(์: webpack, Parcel)๊ฐ ํ์ํฉ๋๋ค.
- ์ด๊ธฐ ์ค์ ๋ฐ ๊ตฌ์ฑ์ด ํ์ํ ์ ์์ต๋๋ค.
3. ์ธ๋ผ์ธ ์คํ์ผ
์ปดํฌ๋ํธ์ ์ง์ ์ธ๋ผ์ธ ์คํ์ผ์ ์ฌ์ฉํ๋ ๊ฒ์ ํนํ ๊ธฐ๋ณธ์ ์ธ ์คํ์ผ๋ง์ ๊ฒฝ์ฐ CSS๋ฅผ ๋ชจํนํ๋ ๊ฐ๋จํ๊ณ ์ง์ ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
์์:
import React from 'react';
function Button({ primary, children, style }) {
const baseStyle = {
backgroundColor: '#007bff',
color: '#fff',
borderRadius: '5px',
padding: '10px 20px',
border: 'none',
cursor: 'pointer',
};
const primaryStyle = {
backgroundColor: '#28a745', // Green
};
const combinedStyle = {
...baseStyle,
...(primary ? primaryStyle : {}),
...style, // Allow overriding with custom styles
};
return (
);
}
export default Button;
Jest๋ก ํ ์คํธํ๊ธฐ:
import React from 'react';
import { render, screen } from '@testing-library/react';
import Button from './Button';
describe('Button Component', () => {
it('renders with custom background color', () => {
render();
const buttonElement = screen.getByRole('button', { name: 'Click me' });
expect(buttonElement).toHaveStyle({ backgroundColor: 'red' });
});
});
์ฅ์ :
- ์คํ์ผ์ ๋ํ ๊ฐ๋จํ๊ณ ์ง์ ์ ์ธ ์ ์ด.
- ์ธ๋ถ ์์กด์ฑ์ด ํ์ ์์ต๋๋ค.
- ํ ์คํธ์์ ์คํ์ผ์ ์ฝ๊ฒ ์ฌ์ ์ํ ์ ์์ต๋๋ค.
๋จ์ :
- ๊ณผ๋ํ๊ฒ ์ฌ์ฉํ๋ฉด ์ ์ง๋ณด์ํ๊ธฐ ์ด๋ ค์ด ์ฝ๋๊ฐ ๋ ์ ์์ต๋๋ค.
- ๊ด์ฌ์ฌ ๋ถ๋ฆฌ๋ฅผ ์ด์งํ์ง ์์ต๋๋ค.
- ๋ณต์กํ ์คํ์ผ๋ง ์๋๋ฆฌ์ค์๋ ์ ํฉํ์ง ์์ต๋๋ค.
4. Shadow DOM
Shadow DOM์ ์ปดํฌ๋ํธ๋ฅผ ์ํ ๋ณ๋์ DOM ํธ๋ฆฌ๋ฅผ ์์ฑํ์ฌ ์บก์ํ๋ฅผ ์ ๊ณตํฉ๋๋ค. Shadow DOM ๋ด์ ์ ์๋ ์คํ์ผ์ ๋ฐ์ผ๋ก ์์ด ๋๊ฐ์ง ์๊ณ , ๋ฉ์ธ ๋ฌธ์์ ์คํ์ผ์ Shadow DOM ์์ผ๋ก ์นจํฌํ์ง ์์ผ๋ฏ๋ก(CSS ๋ณ์์ `part` ์์ฑ์ ํตํด ๋ช ์์ ์ผ๋ก ํ์ฉํ์ง ์๋ ํ), ์ปดํฌ๋ํธ ์คํ์ผ๋ง ๋ฐ ํ ์คํธ์ ํ์ํ ๊ฒฉ๋ฆฌ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์์:
`MyComponent.js`
class MyComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' }); // ์๋์ฐ ๋ฃจํธ ์์ฑ
// ์คํ์ผ ์์ ์์ฑ
const style = document.createElement('style');
style.textContent = `
.my-component {
background-color: #f0f0f0;
padding: 10px;
}
`;
// div ์์ ์์ฑ
const div = document.createElement('div');
div.classList.add('my-component');
div.textContent = 'Hello from Shadow DOM!';
// ์๋์ฐ ๋ฃจํธ์ ์คํ์ผ๊ณผ div ์ถ๊ฐ
this.shadowRoot.appendChild(style);
this.shadowRoot.appendChild(div);
}
}
customElements.define('my-component', MyComponent);
์ด ์์์ .my-component
์ ์คํ์ผ์ Shadow DOM์ ๊ตญํ๋์ด ์ธ๋ถ ์คํ์ผ์ ์ํฅ์ ๋ฐ์ง ์์ต๋๋ค. ์ด๋ ํ
์คํธ๋ฅผ ์ํ ํ์ํ ๊ฒฉ๋ฆฌ๋ฅผ ์ ๊ณตํ๋ฉฐ, ์ฃผ๋ณ ํ๊ฒฝ์ ๊ด๊ณ์์ด ์ปดํฌ๋ํธ์ ์คํ์ผ์ด ์ผ๊ด๋๊ฒ ์ ์ง๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
์ฅ์ :
- ๋ฐ์ด๋ ์คํ์ผ ๊ฒฉ๋ฆฌ.
- ์ปดํฌ๋ํธ ์คํ์ผ๋ง์ ์บก์ํ.
- ์คํ์ผ ์ถฉ๋ ์ํ ๊ฐ์.
๋จ์ :
- Shadow DOM ๊ฐ๋ ์ ๋ํ ์ดํด๊ฐ ํ์ํฉ๋๋ค.
- ๋ค๋ฅธ ๊ธฐ์ ๋ณด๋ค ๊ตฌํ์ด ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
- ์ผ๋ถ ๊ตฌํ ๋ธ๋ผ์ฐ์ ๋ Shadow DOM์ ์์ ํ ์ง์ํ์ง ์์ ์ ์์ต๋๋ค.
5. ๋น๋ ๋๊ตฌ ๋ฐ ์ ์ฒ๋ฆฌ๊ธฐ
webpack๊ณผ ๊ฐ์ ๋น๋ ๋๊ตฌ์ Sass๋ Less์ ๊ฐ์ ์ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ ํ๊ฒฝ์ ๋ง๋ ๋ค๋ฅธ CSS ๋น๋๋ฅผ ์์ฑํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ํน์ ์คํ์ผ์ ๋ชจ์ ์คํ์ผ๋ก ๋์ฒดํ๋ "๋ชจ์" ๋น๋๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
์์:
Sass์ webpack ์ฌ์ฉ:
`button.scss`
$button-background-color: #007bff;
$button-text-color: #fff;
.button {
background-color: $button-background-color;
color: $button-text-color;
border-radius: 5px;
padding: 10px 20px;
border: none;
cursor: pointer;
}
`button.mock.scss`
$button-background-color: #ff0000; // Red
$button-text-color: #000; // Black
Webpack ๊ตฌ์ฑ:
// webpack.config.js
module.exports = {
//...
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
// ํ๊ฒฝ ๋ณ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ค๋ฅธ ๊ตฌ์ฑ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
// ์๋ฅผ ๋ค์ด, NODE_ENV ์ฌ์ฉ
sassOptions: (loaderContext) => {
const isMockBuild = process.env.NODE_ENV === 'test'; // ๋๋ ๋ค๋ฅธ ํ๊ฒฝ ๋ณ์
return {
additionalData: isMockBuild ? '@import "./button.mock.scss";' : '',
};
},
},
},
],
},
],
},
};
์ด ์ค์ ์ `sass-loader`์ `additionalData` ์ต์ ์ ์ฌ์ฉํ์ฌ ํน์ ํ๊ฒฝ ๋ณ์(์: `NODE_ENV=test`)๊ฐ ์ค์ ๋ ๊ฒฝ์ฐ ๋ชจ์ ์คํ์ผ์ ๊ฐ์ ธ์ต๋๋ค. ์ด๋ ํ ์คํธ ํ๊ฒฝ์ ์ํ ๋น๋ ํ๋ก์ธ์ค ์ค์ ๊ธฐ๋ณธ ์คํ์ผ์ ๋ชจ์ ์คํ์ผ๋ก ํจ๊ณผ์ ์ผ๋ก ์ฌ์ ์ํฉ๋๋ค.
์ฅ์ :
- ๋งค์ฐ ์ ์ฐํ๊ณ ์ฌ์ฉ์ ์ ์๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
- ๋ณต์กํ ์คํ์ผ ๋ณํ์ด ๊ฐ๋ฅํฉ๋๋ค.
- ๊ธฐ์กด ๋น๋ ํ๋ก์ธ์ค์ ํตํฉ๋ ์ ์์ต๋๋ค.
๋จ์ :
- ๋น๋ ๋๊ตฌ ๋ฐ ์ ์ฒ๋ฆฌ๊ธฐ์ ๋ํ ์ถฉ๋ถํ ์ดํด๊ฐ ํ์ํฉ๋๋ค.
- ๋ค๋ฅธ ๊ธฐ์ ๋ณด๋ค ์ค์ ์ด ๋ ๋ณต์กํ ์ ์์ต๋๋ค.
- ๋น๋ ์๊ฐ์ด ์ฝ๊ฐ ์ฆ๊ฐํ ์ ์์ต๋๋ค.
CSS ๋ชจํน์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
CSS ๋ชจํน์ ํจ๊ณผ๋ฅผ ๊ทน๋ํํ๋ ค๋ฉด ๋ค์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๊ณ ๋ คํ์ญ์์ค:
- CSS ์ํคํ ์ฒ ๊ณํ: CSS ๋ชจํน์ ๊ตฌํํ๊ธฐ ์ ์ CSS ์ํคํ ์ฒ๋ฅผ ์ ์คํ๊ฒ ๊ณํํ์ญ์์ค. ์ผ๊ด๋ ์ด๋ฆ ์ง์ ๊ท์น์ ์ฌ์ฉํ๊ณ , CSS ๋ณ์๋ฅผ ํ์ฉํ๋ฉฐ, ์คํ์ผ์ ๋ชจ๋ํํ์ญ์์ค.
- ์ปดํฌ๋ํธ ์์ค ๋ชจํน์ ์ง์ค: ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํ๊ณ ์ฌ์ฌ์ฉ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ปดํฌ๋ํธ ์์ค์์ ์คํ์ผ์ ๋ชจํนํ๋ ๊ฒ์ ์ฐ์ ์ํ์ญ์์ค.
- ๊ฒฉ๋ฆฌ๋ฅผ ์ํด CSS ๋ชจ๋ ์ฌ์ฉ: ์ด๋ฆ ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ์คํ์ผ ๊ฒฉ๋ฆฌ๋ฅผ ๋จ์ํํ๊ธฐ ์ํด CSS ๋ชจ๋์ ์ฑํํ์ญ์์ค.
- ๋ชจ์ ์คํ์ผ์ ๋จ์ํ๊ฒ ์ ์ง: ๋ณต์ก์ฑ์ ์ต์ํํ๊ณ ์ค๋ฅ ์ํ์ ์ค์ด๊ธฐ ์ํด ๋ชจ์ ์คํ์ผ์ ๊ฐ๋ฅํ ํ ๋จ์ํด์ผ ํฉ๋๋ค.
- ์ผ๊ด์ฑ ์ ์ง: ์์์น ๋ชปํ ์๊ฐ์ ์ฐจ์ด๋ฅผ ํผํ๊ธฐ ์ํด ๋ชจ์ ์คํ์ผ๊ณผ ์ค์ ์คํ์ผ ๊ฐ์ ์ผ๊ด์ฑ์ ๋ณด์ฅํ์ญ์์ค.
- ํ๊ฒฝ ๋ณ์ ์ฌ์ฉ: ํ๊ฒฝ ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ์ ์คํ์ผ ํ์ฑํ ์ฌ๋ถ๋ฅผ ์ ์ดํ์ญ์์ค. ์ด๋ฅผ ํตํด ํ ์คํธ ํ๊ฒฝ๊ณผ ํ๋ก๋์ ํ๊ฒฝ ๊ฐ์ ์ฝ๊ฒ ์ ํํ ์ ์์ต๋๋ค.
- ๋ชจํน ์ ๋ต ๋ฌธ์ํ: ๋ชจ๋ ํ์์ด ์๋ ๋ฐฉ์์ ์ดํดํ ์ ์๋๋ก CSS ๋ชจํน ์ ๋ต์ ๋ช ํํ๊ฒ ๋ฌธ์ํํ์ญ์์ค.
- ๊ณผ๋ํ ๋ชจํน ํผํ๊ธฐ: ํ์ํ ๊ฒฝ์ฐ์๋ง ์คํ์ผ์ ๋ชจํนํ์ญ์์ค. ๊ณผ๋ํ ๋ชจํน์ ์ ์ง๋ณด์ํ๊ธฐ ์ด๋ ค์ด ์ทจ์ฝํ ํ ์คํธ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
- CI/CD์ ํตํฉ: ํ ์คํธ ํ๋ก์ธ์ค๋ฅผ ์๋ํํ๊ธฐ ์ํด CSS ๋ชจํน์ ์ง์์ ํตํฉ ๋ฐ ์ง์์ ์ ๋ฌ(CI/CD) ํ์ดํ๋ผ์ธ์ ํตํฉํ์ญ์์ค.
- ์ ๊ทผ์ฑ ๊ณ ๋ ค: ์คํ์ผ์ ๋ชจํนํ ๋ ์ ๊ทผ์ฑ์ ๊ณ ๋ คํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ๋ชจ์ ์คํ์ผ์ด ์ปดํฌ๋ํธ์ ์ ๊ทผ์ฑ์ ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ก ํ์ญ์์ค. ์๋ฅผ ๋ค์ด, ํ ์คํธ๊ฐ ๋ฐฐ๊ฒฝ๊ณผ ์ถฉ๋ถํ ๋๋น๋ฅผ ์ด๋ฃจ๋๋ก ํ์ญ์์ค.
๋ค์ํ ํ๊ฒฝ์์์ CSS ๋ชจํน
CSS ๋ชจํน์ ๋ํ ์ต์์ ์ ๊ทผ ๋ฐฉ์์ ๊ฐ๋ฐ ํ๊ฒฝ ๋ฐ ํ ์คํธ ํ๋ ์์ํฌ์ ๋ฐ๋ผ ๋ค๋ฅผ ์ ์์ต๋๋ค. ๋ค์์ ์ผ๋ฐ์ ์ธ ํ๊ฒฝ์์ CSS ๋ชจํน์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋ํ ๊ฐ๋ตํ ๊ฐ์์ ๋๋ค:
React
์์ ์์์ ๋ณด์๋ฏ์ด React ์ ํ๋ฆฌ์ผ์ด์
์ CSS ๋ชจํน์ ์ํด CSS ๋ชจ๋, CSS ๋ณ์ ๋ฐ ์ธ๋ผ์ธ ์คํ์ผ์ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. @testing-library/react
๋ฐ Jest์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ชจํน๋ ์คํ์ผ๋ก React ์ปดํฌ๋ํธ๋ฅผ ํ
์คํธํ๊ธฐ ์ํ ํ๋ฅญํ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
Angular
Angular ์ปดํฌ๋ํธ๋ CSS ๋ชจํน์ ์ํด CSS ๋ณ์์ ์ปดํฌ๋ํธ๋ณ ์คํ์ผ์ํธ๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค. Angular์ ํ ์คํธ ํ๋ ์์ํฌ์ธ Karma๋ ํ ์คํธ ๋ฐ ํ๋ก๋์ ์ ์ํด ๋ค๋ฅธ ์คํ์ผ์ํธ๋ฅผ ์ฌ์ฉํ๋๋ก ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
Vue.js
Vue.js ์ปดํฌ๋ํธ๋ CSS ๋ชจ๋๊ณผ ์ ์ฌํ ์์ค์ ๊ฒฉ๋ฆฌ๋ฅผ ์ ๊ณตํ๋ ๋ฒ์ ์ง์ ์คํ์ผ(scoped styles)์ ์ง์ํฉ๋๋ค. Vue.js ์ ํ๋ฆฌ์ผ์ด์ ์์๋ CSS ๋ชจํน์ ์ํด CSS ๋ณ์์ ์ธ๋ผ์ธ ์คํ์ผ์ ์ฌ์ฉํ ์ ์์ต๋๋ค. Vue Test Utils๋ ํ ์คํธ ์ค์ ์ปดํฌ๋ํธ๋ฅผ ๋ง์ดํธํ๊ณ ์คํ์ผ์ ๋ํด ์ด์ค์ ํ๋ ๋๊ตฌ๋ฅผ ์ ๊ณตํฉ๋๋ค.
Vanilla JavaScript
Vanilla JavaScript ํ๋ก์ ํธ์์๋ CSS ๋ชจํน์ ์ํด CSS ๋ณ์์ Shadow DOM์ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. JavaScript๋ฅผ ์ฌ์ฉํ์ฌ CSS ๋ณ์๋ฅผ ์กฐ์ํ๊ณ Shadow DOM์ ์ฌ์ฉํ์ฌ ์บก์ํ๋ ์คํ์ผ๋ก ์ฌ์ฉ์ ์ ์ ์์๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
๊ณ ๊ธ CSS ๋ชจํน ๊ธฐ์
๋ณด๋ค ๊ณ ๊ธ CSS ๋ชจํน ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ ๋ค์ ๊ธฐ์ ์ ๊ณ ๋ คํ์ญ์์ค:
- ๋ฏธ๋์ด ์ฟผ๋ฆฌ ๋ชจํน: JavaScript๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ฉด ํฌ๊ธฐ๋ฅผ ๊ฐ์งํ๊ณ ๊ทธ์ ๋ฐ๋ผ ๋ชจ์ ์คํ์ผ์ ์ ์ฉํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ฐ์ํ ๋์์ธ์ ํจ๊ณผ์ ์ผ๋ก ํ
์คํธํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด,
window.matchMedia
๋ฉ์๋๋ฅผ ์ฌ์ ์ํ์ฌ ๋ชจ์ ๊ฐ์ ๋ฐํํ๋ JavaScript ํจ์๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค. - ์ ๋๋ฉ์ด์
๋ฐ ์ ํ ๋ชจํน: ํ
์คํธ ์ค์ ์ ๋๋ฉ์ด์
๋ฐ ์ ํ์ ์ผ์ ์ค์งํ๊ฑฐ๋ ๊ฑด๋๋ฐ๋ ค๋ฉด
animation-delay
๋ฐtransition-delay
๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ ์๊ฐ์ ํ๊ท ํ ์คํธ๋ฅผ ๋จ์ํํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. - ์ธ๋ถ ์คํ์ผ์ํธ ๋ชจํน: ๋น๋ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ํ ์คํธ ์ค์ ์ธ๋ถ ์คํ์ผ์ํธ๋ฅผ ๋ชจ์ ์คํ์ผ์ํธ๋ก ๊ต์ฒดํฉ๋๋ค. ์ด๋ ์ธ๋ถ CSS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์กดํ๋ ์ปดํฌ๋ํธ๋ฅผ ํ ์คํธํ๋ ๋ฐ ์ ์ฉํ ์ ์์ต๋๋ค.
- ์๊ฐ์ ํ๊ท ํ ์คํธ: Percy ๋๋ Chromatic๊ณผ ๊ฐ์ ์๊ฐ์ ํ๊ท ํ ์คํธ ๋๊ตฌ์ CSS ๋ชจํน์ ํตํฉํฉ๋๋ค. ์ด๋ฅผ ํตํด ์คํ์ผ ์์ ์ผ๋ก ์ธํ ์๊ฐ์ ๋ณํ๋ฅผ ์๋์ผ๋ก ๊ฐ์งํ ์ ์์ต๋๋ค.
CSS ๋ชจํน์ ์ค์ ์ฌ๋ก
CSS ๋ชจํน์ด ๋ค์ํ ์๋๋ฆฌ์ค์์ ์ด๋ป๊ฒ ์ ์ฉ๋ ์ ์๋์ง ์ค์ ์ฌ๋ก๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค:
- ๋ฒํผ ์ปดํฌ๋ํธ ํ ์คํธ: ์์์ ์ค๋ช ํ๋ฏ์ด CSS ๋ชจํน์ ํด๋น ์คํ์ผ์ ๋ชจํนํ์ฌ ๋ฒํผ ์ปดํฌ๋ํธ์ ๋ค์ํ ์ํ(์: hover, active, disabled)๋ฅผ ํ ์คํธํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- UI ํคํธ ๊ฐ๋ฐ: CSS ๋ชจํน์ ๋ค๋ฅธ ์คํ์ผ์ ๊ฐ์ญ ์์ด UI ํคํธ์ ๊ฐ๋ณ ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํ์ฌ ๋ณด์ฌ์ฃผ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๋์์ด๋์ ๊ฐ๋ฐ์๋ ์ปดํฌ๋ํธ๋ฅผ ์ฝ๊ฒ ๋ฏธ๋ฆฌ ๋ณด๊ณ ํ ์คํธํ ์ ์์ต๋๋ค.
- ๋ฐ์ํ ์น์ฌ์ดํธ ์ ์: CSS ๋ชจํน์ ๋ฏธ๋์ด ์ฟผ๋ฆฌ๋ฅผ ๋ชจํนํ๊ณ ๋ค์ํ ํ๋ฉด ํฌ๊ธฐ๋ฅผ ์๋ฎฌ๋ ์ด์ ํ์ฌ ์น์ฌ์ดํธ์ ๋ฐ์ํ ๋์์ ํ ์คํธํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๋ ๊ฑฐ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ง์ด๊ทธ๋ ์ด์ : CSS ๋ชจํน์ ์ด์ ํ๋ ์์ํฌ์ ์คํ์ผ์ ๋ชจํนํ๊ณ ํ ๋ฒ์ ํ ์ปดํฌ๋ํธ์ฉ ์ ํ๋ ์์ํฌ์ ์คํ์ผ๋ก ๊ต์ฒดํ์ฌ ๋ ๊ฑฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ CSS ํ๋ ์์ํฌ๋ก ์ ์ง์ ์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๊ตญ์ ํ(i18n) ํ ์คํธ: CSS ๋ชจํน์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ ์ด์์๊ณผ ์คํ์ผ์ด ๋ค๋ฅธ ์ธ์ด ๋ฐ ํ ์คํธ ๋ฐฉํฅ(์: ์๋์ด ๋๋ ํ๋ธ๋ฆฌ์ด์ ๊ฐ์ ์ค๋ฅธ์ชฝ์์ ์ผ์ชฝ์ผ๋ก ์ฐ๋ ์ธ์ด)์ ์ด๋ป๊ฒ ์ ์ํ๋์ง ํ ์คํธํ๋ ๋ฐ ์ฌ์ฉํ ์ ์์ต๋๋ค. `direction` CSS ์์ฑ์ ๋ชจํนํ์ฌ ๋ค๋ฅธ ํ ์คํธ ๋ฐฉํฅ์ ์๋ฎฌ๋ ์ด์ ํ ์ ์์ต๋๋ค.
CSS ๋ชจํน์ ๋ฏธ๋
ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ด ๊ณ์ ๋ฐ์ ํจ์ ๋ฐ๋ผ ํจ์จ์ ์ด๊ณ ์ ๋ขฐํ ์ ์๋ CSS ํ
์คํธ์ ๋ํ ํ์์ฑ์ ๋์ฑ ์ปค์ง ๊ฒ์
๋๋ค. ํ์ฌ ํ์ค CSS @mock
at-rule์ ์์ง๋ง, ์ด ๊ฐ์ด๋์ ์ค๋ช
๋ ๊ธฐ์ ๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ ํ๋ก์ ํธ์์ CSS ๋ชจํน์ ๊ตฌํํ๊ธฐ ์ํ ๊ฒฌ๊ณ ํ ๊ธฐ๋ฐ์ ์ ๊ณตํฉ๋๋ค. CSS ๋ฐ ํ
์คํธ ํ๋ ์์ํฌ์ ํฅํ ๋ฐ์ ์ CSS ๋ชจํน์ ๋ํ ๋ณด๋ค ํ์คํ๋๊ณ ๊ฐ์ํ๋ ์ ๊ทผ ๋ฐฉ์์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
๊ฐ๋ฅํ ๋ฏธ๋์ ๋ฐ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์ ์ฉ CSS ํ ์คํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ: CSS ์คํ์ผ ํ ์คํธ๋ฅผ ์ํด ํน๋ณํ ์ค๊ณ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์คํ์ผ์ ๋ชจํน, ์ด์ค์ ๋ฐ ์๊ฐํํ๊ธฐ ์ํ API๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ์์ ํตํฉ: CSS ์คํ์ผ์ ์ฝ๊ฒ ๋ชจํนํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ค์๊ฐ์ผ๋ก ๊ฒ์ฌํ ์ ์๋ ํฅ์๋ ๋ธ๋ผ์ฐ์ ๊ฐ๋ฐ์ ๋๊ตฌ.
- ํฅ์๋ CSS ๋ชจ๋ ์ง์: ํ ์คํธ ํ๋ ์์ํฌ์์ ๋์ฑ ๊ฐ๋ ฅํ CSS ๋ชจ๋ ์ง์์ผ๋ก ํด๋์ค ์ด๋ฆ์ ๋ ์ฝ๊ฒ ๋ชจํนํ๊ณ ํ์ธํ ์ ์์ต๋๋ค.
- ํ์คํ๋ CSS ๋ชจํน API: ์๋ก์ด CSS at-rule ๋๋ JavaScript API์ ํํ๋ก CSS ์คํ์ผ์ ๋ชจํนํ๊ธฐ ์ํ ํ์คํ๋ API.
๊ฒฐ๋ก
CSS ๋ชจํน์ ํ๋ก ํธ์๋ ๊ฐ๋ฐ ์ํฌํ๋ก์ฐ๋ฅผ ํฅ์์ํค๋ ๊ท์คํ ๊ธฐ์ ์
๋๋ค. ์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฆฌํ๊ณ , ๋ค์ํ ์ํ๋ฅผ ์๋ฎฌ๋ ์ด์
ํ๋ฉฐ, ์ ํ๋ฆฌ์ผ์ด์
์ ์๊ฐ์ ๋์์ ์ ์ดํจ์ผ๋ก์จ CSS ๋ชจํน์ ๋ ๊ฒฌ๊ณ ํ ํ
์คํธ๋ฅผ ์์ฑํ๊ณ , ๊ฐ๋ฐ ์ฃผ๊ธฐ๋ฅผ ๊ฐ์ํํ๋ฉฐ, ์ฝ๋ ํ์ง์ ํฅ์์ํฌ ์ ์๊ฒ ํด์ค๋๋ค. ๊ณต์์ ์ธ CSS @mock
๊ท์น์ ์์ง๋ง, CSS ๋ณ์, ์๋ฐ์คํฌ๋ฆฝํธ ํ
์คํธ ํ๋ ์์ํฌ, ๋น๋ ๋๊ตฌ ๋ฐ ์ ์คํ ๊ณํ์ ์กฐํฉ์ ํตํด CSS ์คํ์ผ์ ํจ๊ณผ์ ์ผ๋ก ๋ชจํนํ๊ณ ๋ ํ
์คํธ ๊ฐ๋ฅํ๋ฉฐ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๋ฌ์ฑํ ์ ์์ต๋๋ค. CSS ๋ชจํน์ ํ์ ๋ฐ์๋ค์ฌ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ์๋ก์ด ์ฐจ์์ผ๋ก ๋์ด์ฌ๋ฆฌ์ญ์์ค. ํ๋ก์ ํธ์ ์๊ตฌ ์ฌํญ๊ณผ ๊ฐ๋ฐ ํ๊ฒฝ์ ๊ฐ์ฅ ์ ํฉํ ๊ธฐ์ ์ ์ ํํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ํ๋ก ํธ์๋ ๊ธฐ์ ์ด ๊ณ์ ๋ฐ์ ํจ์ ๋ฐ๋ผ ์ต์ CSS ๋ชจํน ๊ธฐ์ ์ ๋ํ ์ ๋ณด๋ฅผ ์ ์งํ๋ ๊ฒ์ ๊ณ ํ์ง์ ์ ์ง๋ณด์ ๊ฐ๋ฅํ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ๋ ๋ฐ ๋งค์ฐ ์ค์ํ ๊ฒ์
๋๋ค.