최근 에이전시에서 삼성 AI 구독 서비스 관련 프로젝트에 참여하고 있습니다.
규모가 크고 협업이 많은 만큼, 팀 내부에서 정한 CSS 컨벤션이 굉장히 엄격하게 구성되어 있었죠.
예를 들어,
- 클래스명은 반드시 kebab-case로 작성
- 선택자 순서, 중첩 깊이, 단일 선언 규칙 등
- font-family에 generic family 필수 등...
이 컨벤션을 사람이 수동으로 일일이 맞추기란… 쉽지 않았습니다 😓
작업을 하다 보면 자꾸만 작고 반복적인 실수가 발생했고,
이로 인해 코드 리뷰에서 지적도 자주 받게 되더라고요.
❗ 그래서 결정했습니다 – 자동화 도입!
이러한 문제를 해결하기 위해 도입한 것이 바로 Stylelint 자동화 설정입니다.
.stylelintrc.json 파일을 통해 규칙을 명시하고, VS Code 확장 프로그램과 함께 사용했어요.
stylelint, stylelint-config-standard, stylelint-order 3가지 의존성를 설치해야 합니다.
// package.json
{
"name": "name",
"version": "1.0.0",
"main": "index.js",
"repository": "",
"author": "",
"license": "MIT",
"type": "module",
"scripts": {},
"devDependencies": {
"stylelint": "^16.21.0",
"stylelint-config-standard": "^38.0.0",
"stylelint-order": "^7.0.0"
}
}
// .stylelintrc.json
{
"extends": ["stylelint-config-standard"],
"plugins": ["stylelint-order"],
"rules": {
"order/properties-order": [["display", "position", "top", "left"]],
"selector-class-pattern": "^[a-z0-9\\-]+$",
"font-family-no-missing-generic-family-keyword": true
}
}
설정 후에는 저장할 때마다 자동으로 포맷되고, 규칙에 어긋나는 코드엔 경고도 뜨기 때문에
실수를 미리 방지할 수 있었고, 리뷰도 훨씬 매끄러워졌습니다.
✅ 정리
- stylelint는 개발자에게 코드 컨벤션 규칙에 안맞다고 알려주는 용도이다.
- 코드 컨벤션이 까다로운 프로젝트일수록 자동화 도구는 필수!
- Stylelint 설정 한 번으로 반복 실수를 줄이고 팀 기준에 맞춘 코드 작성 가능
- 특히 에이전시 환경에서는 빠르고 정확한 작업을 위해 이런 도구의 선제적 도입이 중요
❗자동으로 파일들 규칙에 맞게 수정
프로젝트를 진행하다 보면, 이미 작성된 CSS 또는 SCSS 파일들이 스타일 가이드에 맞지 않거나, 일관되지 않게 작성되어 있는 경우가 있습니다.
이럴 땐 수동으로 하나씩 고치는 대신, PostCSS를 활용하여 자동화된 방식으로 규칙을 적용하면 훨씬 효율적입니다.
왜 PostCSS인가?
PostCSS는 CSS를 JavaScript처럼 파싱하고 변환할 수 있는 강력한 도구입니다.
다양한 플러그인을 통해 스타일을 자동 정리하거나, 브라우저 호환성 처리, 변수/중첩 처리 등도 가능합니다.
사용 목적
이번 작업의 목적은 다음과 같습니다:
- 기존 CSS 파일을 스타일 가이드 규칙에 맞게 일괄 정리
- 나아가 Stylelint 규칙과도 호환 가능하도록 설정
yarn add postcss postcss-cli postcss-sorting -D
최종적인 package.json 파일 입니다.
// package.json
{
"name": "",
"version": "1.0.0",
"main": "index.js",
"repository": "",
"author": "",
"license": "MIT",
"type": "module",
"scripts": {
"css:minify": "node lib/clean.js compressed",
"lint:css": "stylelint 'css/**/*.css' --fix",
"sort:css": "postcss 'css/**/*.css' --config postcss.config.cjs -r",
"css:all": "yarn css:minify && yarn lint:css && yarn sort:css"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"clean-css": "^5.3.3",
"eslint": "^8",
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-prettier": "^5.1.0",
"postcss": "^8.5.6",
"postcss-cli": "^11.0.1",
"postcss-sorting": "^9.1.0",
"prettier": "^3.1.1",
"stylelint": "^16.21.0",
"stylelint-config-standard": "^38.0.0",
"stylelint-order": "^7.0.0"
},
"lint-staged": {
"**/*.{js,ts,jsx,tsx}": "eslint --fix",
"**/*.{js,ts,jsx,tsx,css,scss,md}": "prettier --write"
}
}
// lib/clean.js
import fs from 'fs';
import glob from 'glob';
import CleanCSS from 'clean-css';
const inputFiles = glob.sync('./css/**/*.css'); // 기존 경로를 정확히 설정하세요
inputFiles.forEach(file => {
const inputCSS = fs.readFileSync(file, 'utf8');
const output = new CleanCSS({ format: 'keep-breaks' }).minify(inputCSS);
// ✅ 기존 파일에 덮어쓰기
fs.writeFileSync(file, output.styles);
console.log('✅ 덮어쓰기 완료:', file);
});
// .stylelintrc.json
{
"extends": ["stylelint-config-standard"],
"plugins": ["stylelint-order"],
"rules": {
"selector-id-pattern": null,
"selector-class-pattern": null,
"declaration-block-single-line-max-declarations": null,
"no-descending-specificity": null,
"no-duplicate-selectors": null,
"function-url-quotes": null,
"color-function-notation": null,
"property-no-vendor-prefix": null,
"comment-empty-line-before": null,
"shorthand-property-no-redundant-values": null,
"font-family-no-missing-generic-family-keyword": null,
"rule-empty-line-before": ["always", {
"except": ["first-nested"],
"ignore": ["after-comment"]
}],
"order/properties-order": [
{
"emptyLineBefore": "never",
"properties": ["display", "position", "top", "right", "bottom", "left", "z-index"]
},
{
"emptyLineBefore": "never",
"properties": ["width", "height", "margin", "padding"]
},
{
"emptyLineBefore": "never",
"properties": ["font-size", "line-height", "text-transform", "color"]
},
{
"emptyLineBefore": "never",
"properties": ["background", "border", "box-shadow"]
}
]
}
}
//.postcss-sorting.json
{
"order": [
"custom-properties",
"dollar-variables",
"declarations",
"rules",
"at-rules"
],
"properties-order": [
"display",
"position",
"top",
"right",
"bottom",
"left",
"z-index",
"width",
"height",
"margin",
"padding",
"font-size",
"line-height",
"text-transform",
"color",
"background",
"border",
"box-shadow"
],
"unspecified-properties-position": "bottom"
}
//postcss.config.cjs
module.exports = {
plugins: [
require('postcss-sorting')(require('./.postcss-sorting.json'))
]
};
이렇게 설정하고 터미널에서 아래 명령어를 하나씩 실행해보고, 오류발견하면 찾아가서 수정하는 방향으로 하는것으로 진행 햇다.
lint:css에서 많은 오류들을 찾아줄것이다.!
"css:minify": "node lib/clean.js compressed",
"lint:css": "stylelint 'css/**/*.css' --fix",
"sort:css": "postcss 'css/**/*.css' --config postcss.config.cjs -r",
💡 본 문서의 모든 코드는 실무와 유사한 방식으로 작성되었으나, 실제 운영 중인 코드는 아닙니다.