CSS vs Sass 비교: 최신 CSS 기준으로 다시 보는 선택 기준

Frontend

이 글은 스타일링 선택 기준 시리즈 1편입니다.

프론트엔드에서 Sass는 오랫동안 거의 기본 선택지처럼 여겨졌습니다. 변수, 중첩, 믹스인, 분리된 partial 구조는 한동안 CSS가 직접 제공하지 못하던 기능을 채워줬기 때문입니다.

하지만 지금은 상황이 꽤 달라졌습니다. 최신 CSS에는 custom properties, nesting, @layer, clamp(), min(), max(), :is(), :where() 같은 기능이 들어왔고, 디자인 토큰과 테마 운영 방식도 예전과 달라졌습니다.

그래서 지금의 질문은 단순히 "Sass가 더 편한가?"가 아니라, 새 프로젝트에서 Sass를 기본값으로 둘 이유가 얼마나 남아 있는가에 더 가깝습니다.

이 글에서는 CSSSass를 문법 비교가 아니라, 실무 유지보수, 팀 운영, SSR, 런타임 테마 대응까지 포함한 관점에서 정리해보겠습니다.

한눈에 보면

먼저 짧게 정리하면 이렇습니다.

  • 최신 브라우저 기준이라면 대부분의 일반적인 요구사항은 CSS만으로도 충분히 대응할 수 있습니다.
  • Sass는 여전히 유용하지만, 지금은 기본 선택지라기보다 조건이 맞을 때 고르는 도구에 가깝습니다.
  • SSR 자체만 놓고 보면 CSS와 Sass의 차이는 크지 않지만, 런타임 테마와 요청 단위 브랜딩까지 보면 CSS custom properties가 더 유연한 경우가 많습니다.

조금 더 자세히 보면 아래처럼 볼 수 있습니다.

항목 CSS Sass
기본 성격 브라우저 표준 CSS 전처리기
변수 custom properties로 런타임 사용 가능 컴파일 타임 변수
중첩 최신 CSS에서 지원 범위 확대 오래전부터 안정적으로 지원
재사용 @layer, :is(), :where(), 유틸리티 클래스 등으로 구성 믹스인, 함수, partial로 구성
테마 대응 런타임 변경에 유리 빌드 시점 고정에 가까움
SSR 관점 별도 런타임 비용 없음 별도 런타임 비용 없음
운영 복잡도 표준 중심, 설정 단순 빌드 파이프라인 의존성 추가
추천 상황 일반적인 제품 개발, 디자인 토큰, 테마 전환 레거시 자산이 많거나 믹스인 중심 코드베이스

빠르게 정리하면, 새 프로젝트 기본값은 CSS, 기존 Sass 자산이 크거나 반복적인 스타일 생성 규칙이 많으면 Sass 유지 정도로 보면 됩니다.

예전에는 Sass가 왜 거의 필수였을까?

과거의 CSS는 지금보다 표현력이 훨씬 제한적이었습니다.

  • 변수 기능이 없었고
  • 선택자 중첩이 안 됐으며
  • 재사용 가능한 함수나 믹스인 개념이 없었고
  • 큰 코드베이스를 구조적으로 나누는 방식도 부족했습니다

그래서 아래 같은 요구사항이 생기면 자연스럽게 Sass를 붙였습니다.

  • 색상과 spacing 토큰을 변수로 관리하고 싶을 때
  • breakpoint 로직을 반복 없이 쓰고 싶을 때
  • 버튼, 카드, 폼처럼 비슷한 패턴을 믹스인으로 정리하고 싶을 때
  • 여러 파일로 나눈 스타일을 한 번에 묶어 관리하고 싶을 때

즉, 당시 Sass는 "조금 더 편한 도구"가 아니라, CSS가 부족한 부분을 메워주는 실질적인 보완재에 가까웠습니다.

지금은 CSS가 얼마나 따라왔을까?

지금의 CSS는 예전과 비교하면 훨씬 많은 기능을 직접 제공합니다.

1. 변수는 custom properties로 충분한 경우가 많다

예전에는 색상이나 spacing을 공통으로 관리하려면 Sass 변수가 거의 필수였습니다.

$color-primary: #2563eb;
$spacing-md: 16px;
 
.button {
  background: $color-primary;
  padding: $spacing-md;
}

지금은 CSS만으로도 비슷한 구조를 만들 수 있습니다.

:root {
  --color-primary: #2563eb;
  --spacing-md: 16px;
}
 
.button {
  background: var(--color-primary);
  padding: var(--spacing-md);
}

여기서 중요한 차이는 변수가 언제 결정되는가입니다.

  • Sass 변수는 빌드 시점에 값이 고정됩니다.
  • CSS custom properties는 런타임에도 바꿀 수 있습니다.

이 차이는 다크모드, 화이트라벨, 브랜드별 테마처럼 사용자나 요청에 따라 값이 달라져야 하는 상황에서 크게 드러납니다.

2. 중첩은 더 이상 Sass만의 장점이 아니다

Sass의 대표 장점 중 하나는 중첩 문법이었습니다.

.card {
  padding: 16px;
 
  &__title {
    font-size: 18px;
  }
 
  &:hover {
    box-shadow: 0 8px 24px rgb(0 0 0 / 0.12);
  }
}

최신 CSS도 nesting을 지원하기 시작하면서, 단순한 중첩 자체는 예전만큼 강한 차별점이 아닙니다.

.card {
  padding: 16px;
 
  & .card-title {
    font-size: 18px;
  }
 
  &:hover {
    box-shadow: 0 8px 24px rgb(0 0 0 / 0.12);
  }
}

다만 여기서 중요한 것은 "중첩을 쓸 수 있는가"보다, 얼마나 깊게 중첩하느냐입니다. 실무에서는 Sass든 CSS든 중첩이 깊어질수록 유지보수성이 빠르게 떨어집니다.

3. 레이어와 우선순위 관리도 CSS가 훨씬 좋아졌다

예전에는 스타일 충돌을 막기 위해 naming 규칙이나 Sass partial 구조에 많이 의존했습니다.

지금은 CSS의 @layer를 활용해 의도적으로 우선순위를 나누는 방식이 더 자연스럽습니다.

@layer reset, base, components, utilities;
 
@layer base {
  body {
    margin: 0;
    font-family: system-ui, sans-serif;
  }
}
 
@layer components {
  .button {
    border-radius: 8px;
  }
}

이 방식은 단순히 스타일을 "잘 정리한다"를 넘어서, 팀이 어떤 순서로 CSS를 쌓아올릴지 규칙화하는 데 도움이 됩니다.

그렇다면 Sass는 이제 필요 없을까?

그 정도로 단순하게 보기는 어렵습니다. Sass가 여전히 편한 상황은 분명히 있습니다.

1. 반복적인 생성 규칙이 많을 때

반응형 breakpoint, variant 조합, spacing scale 생성처럼 "유사한 스타일을 여러 번 만들어야 하는 상황"에서는 Sass의 믹스인과 함수가 여전히 생산적입니다.

@mixin respond($breakpoint) {
  @if $breakpoint == tablet {
    @media (min-width: 768px) {
      @content;
    }
  }
}
 
.layout {
  padding: 16px;
 
  @include respond(tablet) {
    padding: 24px;
  }
}

물론 CSS도 @media, clamp(), container query 등으로 많이 대체할 수 있지만, 반복 생성 규칙 자체를 코드화하는 감각은 아직 Sass가 더 익숙한 팀이 많습니다.

2. 레거시 코드베이스가 이미 Sass 중심일 때

이미 수년간 쌓인 scss 코드, 믹스인, 함수, 토큰 map, partial 구조가 있다면 굳이 무리해서 순수 CSS로 옮길 이유는 없습니다.

이럴 때 중요한 것은 "최신 CSS가 더 좋아 보인다"가 아니라 아래 질문입니다.

  • 지금 구조가 실제로 문제를 만들고 있는가
  • Sass 의존성이 빌드나 유지보수에서 병목이 되는가
  • 마이그레이션 비용보다 얻는 이점이 큰가

즉, 기존 Sass 레포에서는 교체 자체가 목적이 되면 안 됩니다.

3. 토큰을 코드 생성 방식으로 관리할 때

디자인 토큰을 단순 변수 수준이 아니라, map과 loop로 생성하는 팀도 있습니다.

$spaces: (
  sm: 8px,
  md: 16px,
  lg: 24px,
);
 
@each $name, $value in $spaces {
  .space-#{$name} {
    gap: $value;
  }
}

이런 생성 패턴은 유틸리티 CSS를 직접 만들거나, 사내 디자인 시스템을 운영할 때 아직도 유용합니다.

다만 여기서도 한 번 더 생각해야 합니다. 지금 팀이 정말 Sass 생성 문법이 필요한지, 아니면 빌드 단계 생성 스크립트나 Tailwind, 토큰 파이프라인으로 더 명확하게 관리하는 편이 나은지 구분할 필요가 있습니다.

SSR 관점에서 보면 무엇이 다를까?

이 지점은 의외로 오해가 많은데, CSS와 Sass는 둘 다 기본적으로 빌드 타임에 정리되는 자산이라는 점에서 SSR 자체에 직접적인 런타임 비용 차이를 거의 만들지 않습니다.

즉, Next.js나 다른 SSR 프레임워크에서:

  • CSS를 써도
  • Sass를 써도
  • 최종적으로는 CSS 파일이나 추출된 스타일 자산이 응답에 포함됩니다

그래서 "SSR이라서 Sass가 느리다" 혹은 "CSS라서 SSR이 유리하다"처럼 단순화해서 보기는 어렵습니다.

실제로 차이가 나는 지점은 보통 아래입니다.

1. 요청 시점 테마 변경

Sass 변수는 빌드 시점에 확정됩니다.

$brand-color: #2563eb;

반면 CSS custom properties는 요청 시점이나 사용자 상태에 따라 바꾸기 쉽습니다.

html[data-theme='dark'] {
  --surface: #111827;
  --text-primary: #f9fafb;
}

SSR 서비스에서 이 차이는 꽤 실용적입니다.

  • 사용자별 테마를 서버에서 내려줄 때
  • 브랜드별 화이트라벨을 요청 단위로 분기할 때
  • 실시간 A/B 테스트 스타일을 조정할 때

이런 경우에는 Sass 변수보다 CSS custom properties가 훨씬 자연스럽습니다.

2. App Router, Server Components와의 궁합

React Server Components나 Next.js App Router 환경에서는 런타임에 스타일 값을 계산하기보다, 가능한 한 정적인 스타일 자산으로 밀어두는 편이 단순합니다.

이 관점에서 CSS와 Sass는 둘 다 무난합니다. 다만 런타임 테마 유연성까지 고려하면 CSS custom properties를 적극적으로 쓰는 쪽이 더 잘 맞는 경우가 많습니다.

3. 운영 중 디버깅

SSR 이슈가 생겼을 때 팀은 보통 이런 질문을 하게 됩니다.

  • 어떤 스타일이 서버에서 내려왔는가
  • hydration 이후 무엇이 바뀌었는가
  • 다크모드나 브랜드 토큰이 어느 시점에 적용됐는가

이때 Sass 변수는 최종 CSS로 이미 펼쳐져 있기 때문에, 런타임에서 값을 추적하는 감각은 CSS custom properties보다 약합니다.

즉, SSR에서의 핵심은 Sass냐 CSS냐보다, 토큰과 테마를 런타임에 다뤄야 하는가입니다.

팀 운영 관점에서는 무엇이 더 중요할까?

실무에서는 문법보다 운영이 더 오래 남습니다.

1. 신규 입사자 온보딩

순수 CSS 중심 구조는 브라우저 표준 문법만 이해하면 되기 때문에 설명 비용이 낮습니다.

반면 Sass를 적극적으로 쓰는 레포는 보통 함께 이해해야 할 것이 늘어납니다.

  • 변수 파일 구조
  • 믹스인 규칙
  • 함수 naming 규칙
  • partial import 구조
  • 토큰 map 사용 규칙

이런 규칙이 잘 정리되어 있으면 문제는 없지만, 그렇지 않으면 CSS보다 사내 문법을 먼저 익혀야 하는 상태가 됩니다.

2. 빌드 파이프라인 단순성

Sass는 아주 무거운 도구는 아니지만, 그래도 전처리 단계가 하나 더 들어갑니다.

프로젝트가 커질수록 팀은 이런 질문을 하게 됩니다.

  • Sass 컴파일 에러를 누가 유지할 것인가
  • build cache가 어디서 깨지는가
  • SCSS import 구조가 느슨해져도 괜찮은가

작은 프로젝트에서는 큰 차이가 아닐 수 있지만, 여러 앱을 운영하는 조직에서는 표준 도구 수를 줄이는 것 자체가 운영 비용 절감으로 이어지기도 합니다.

3. 디자인 토큰 운영 방식

요즘은 단순한 Sass 변수보다 아래 방식이 더 자주 보입니다.

  • CSS custom properties
  • JSON 기반 디자인 토큰
  • Style Dictionary 같은 토큰 변환 파이프라인
  • Tailwind theme 설정

이 흐름에서는 Sass가 토큰의 중심이 아니라, 여러 출력 대상 중 하나로 밀리는 경우도 많습니다.

어떤 팀에 어떤 선택이 맞을까?

CSS가 잘 맞는 경우

  • 새 프로젝트를 비교적 단순하게 시작하고 싶을 때
  • 브라우저 표준 중심으로 가고 싶을 때
  • 다크모드, 브랜드 테마처럼 런타임 토큰 전환이 중요할 때
  • Next.js SSR/App Router에서 스타일 레이어를 단순하게 유지하고 싶을 때

Sass가 잘 맞는 경우

  • 기존 scss 자산이 이미 충분히 크고 안정적일 때
  • 믹스인, 함수, loop 기반 스타일 생성 규칙이 실제로 많이 쓰일 때
  • 팀이 Sass 문법과 규칙에 익숙하고 운영 비용이 낮을 때
  • CSS만으로 옮겼을 때 얻는 이점보다 마이그레이션 비용이 더 클 때

정리하면

예전에는 Sass가 CSS의 부족한 부분을 채워주는 역할을 많이 했습니다. 하지만 지금은 최신 CSS가 그 간격을 많이 줄였습니다.

그래서 새 프로젝트 기준으로 보면:

  • 기본값은 CSS
  • 반복 생성 규칙과 기존 자산이 크면 Sass 유지
  • SSR에서는 둘의 성능 차이보다 토큰을 런타임에 다뤄야 하는지가 더 중요

중요한 것은 "Sass가 낡았는가"가 아니라, 지금 우리 팀이 어떤 스타일 문제를 풀고 있는가입니다. 그 문제가 이미 최신 CSS로 충분히 해결된다면 Sass는 필수가 아닙니다. 반대로 Sass가 실제 운영 효율을 높여주고 있다면 굳이 버릴 이유도 없습니다.

다음 글에서 이어서 보기

여기까지는 CSS와 Sass 자체를 비교했습니다. 다음 글에서는 한 단계 더 나아가서, 실제 프론트엔드 팀이 많이 고민하는 CSS Modules, CSS-in-JS, Tailwind CSS 중 어떤 전략이 유지보수와 SSR에 더 잘 맞는지를 정리합니다.