문자 단위 CSS 포매터의 중첩 깊이 추적 방식
CSS는 원래 중첩 규칙(nesting)이 없는 언어였습니다. 선택자 하나에 { } 블록 하나, 그 안에 선언들이 나열될 뿐이라, 여는 중괄호마다 깊이를 늘리고 닫는 중괄호마다 줄이는 단순한 카운팅만으로도 들여쓰기가 항상 정확했습니다. 하지만 SCSS 같은 전처리기와 최신 CSS Nesting 스펙이 등장하면서 이 전제가 흔들리기 시작했습니다. CSS 포매터의 실제 코드를 열어 어디까지 안전하고 어디서부터 깨지는지 확인했습니다.
1. 왜 순수 CSS는 문자 카운팅만으로 충분했는가
표준 CSS 문법은 셀렉터 뒤에 {가 오고, 선언이 세미콜론으로 끝나고, }로 블록이 닫히는 평평한(flat) 구조입니다. 미디어 쿼리(@media)나 키프레임(@keyframes)조차 중괄호가 한두 겹 더 겹칠 뿐 같은 규칙을 그대로 따릅니다. 그래서 "여는 중괄호를 만나면 depth+1, 닫는 중괄호를 만나면 depth-1"이라는 규칙 하나로 어떤 CSS 파일이든 정확한 들여쓰기를 재현할 수 있었습니다.
2. 이 도구가 실제로 인식하는 문자는 단 4종류
코드를 확인한 결과 cssBeautify() 함수는 입력을 한 글자씩 순회하면서 {, }, ;, , 이 네 가지 문자에만 반응합니다. {를 만나면 depth++ 후 줄바꿈, }를 만나면 depth-- 후 줄바꿈, ; 뒤에는 항상 줄바꿈, ,는 옵션이 켜져 있고 depth가 0(최상위 선택자 목록)일 때만 줄바꿈합니다. 이 네 문자 외에는 전부 그대로 복사됩니다.
3. 발견된 추가 위험: 문자열·주석 보호 로직이 아예 없다
JavaScript 포매터는 따옴표 안의 내용을 통째로 보호하는 inStr() 처리가 있지만, CSS 포매터의 코드에는 그런 보호 로직 자체가 없습니다. 즉 content:";{}"처럼 따옴표 안에 구조 문자가 들어가거나, /* 여기 세미콜론; */ 같은 주석 안에 세미콜론·중괄호가 들어가면 문자열·주석이라는 맥락과 무관하게 곧바로 줄바꿈·깊이 변화가 발생합니다. 순수 CSS 실무에서는 이런 값이 드물어 잘 드러나지 않지만, 힌트로 알려진 "SCSS 중첩만 문제"라는 통념보다 실제로는 더 근본적인 한계입니다.
4. SCSS 문법을 넣으면 무엇이 깨지는가
SCSS의 &:hover{ } 같은 중첩 셀렉터 자체는 중괄호가 정상적으로 짝을 이루므로 depth 카운팅만 놓고 보면 의외로 형태가 유지됩니다. 진짜 문제는 $primary-color: #333; 같은 변수 선언이나 @if/@else 조건문, 문자열 보간 #{$var}입니다. 이들은 CSS 표준 구조 문자가 아니라 전처리기 전용 토큰인데, 이 도구는 그런 토큰을 구분할 방법이 없어 일반 선언과 동일하게 세미콜론마다 기계적으로 줄바꿈만 넣습니다. 결과적으로 문법 오류는 아니지만 SCSS 특유의 논리 구조(조건 분기, 변수 스코프)가 시각적으로 사라져 버립니다.
| 단계 | 내용 |
|---|---|
| 입력(SCSS) | .btn{$c:#333;&:hover{color:$c;}} |
| 순수 CSS라면 기대하는 형태 | 중첩 구조가 depth 2단계로 정확히 반영 |
| 실제 출력 | $c:#333;이 일반 선언처럼 처리되어 변수라는 의미 없이 다른 속성과 같은 줄바꿈 규칙만 적용됨 |
5. 결론: 어디까지 믿고 써도 되는가
서버·빌드 도구가 이미 컴파일해 배포한 순수 CSS 결과물을 다시 보기 좋게 펴는 용도라면 이 방식은 100% 신뢰할 수 있습니다. 반대로 .scss/.less 원본 파일을 그대로 넣거나, 값에 세미콜론·중괄호가 포함된 문자열·주석이 섞인 CSS라면 결과를 검산 없이 그대로 쓰지 말아야 합니다. 압축된 CSS를 처음 만들 때는 CSS 압축기로 만든 결과물을 이 포매터로 되돌려보는 조합이 가장 안전합니다.
자주 묻는 질문
Q. 미디어 쿼리(@media)도 정확히 들여쓰기되나요?
네. @media 블록의 여는 중괄호도 다른 중괄호와 동일하게 depth를 1 증가시키므로, 내부 선택자·속성이 자동으로 한 단계 더 들여쓰기됩니다.
Q. CSS 변수(커스텀 프로퍼티)는 안전한가요?
네. --primary-color: #fbbf24;는 콜론과 세미콜론을 가진 일반 선언과 구조가 같아서 다른 속성과 동일한 규칙으로 줄바꿈·들여쓰기가 적용됩니다.
Q. @keyframes처럼 중괄호가 두 겹 중첩돼도 괜찮나요?
네. @keyframes spin{ 0%{...} 100%{...} }처럼 두 겹 중첩된 구조도 여는 중괄호마다 depth를 늘리는 방식이 그대로 적용되어 0%와 100% 블록이 한 단계 더 들여쓰기되어 표시됩니다.
Q. Prettier 같은 도구와는 정확히 무엇이 다른가요?
Prettier는 CSS 문법을 완전히 파싱해 문자열·주석·전처리기 문법까지 맥락을 이해하고 처리합니다. 이 도구는 그런 파싱 단계 없이 소수의 구조 문자만 보고 판단하는 훨씬 단순한 방식이라 빠르지만, 위에서 설명한 경계 조건에서는 결과가 달라질 수 있습니다.