Sass 통합
Next.js에 Sass를 설치하고 변수·중첩·모듈화를 활용한 SCSS 모듈로 컴포넌트 스타일을 체계화합니다.
이전 절에서 Next.js의 CSS 모듈을 사용하여 컴포넌트 레벨의 스타일링을 안전하고 효율적으로 관리하는 방법을 살펴보았습니다.
CSS 모듈만으로도 충분히 강력하지만, CSS 전처리기(Pre-processor)인 Sass (Syntactically Awesome Style Sheets)는 CSS의 한계를 넘어서는 기능을 제공해 스타일링 작업을 더욱 효율적이고 체계적으로 만들어 줍니다.
Next.js는 Sass와의 통합을 기본적으로 지원하며, .scss 또는 .sass 확장자를 가진 파일을 CSS 모듈과 함께 사용할 수 있도록 설정되어 있습니다.
이 절에서는 Sass가 무엇인지, 왜 필요한지, 그리고 Next.js 프로젝트에서 Sass를 어떻게 설정하고 활용하는지 자세히 알아보겠습니다.
Sass란 무엇인가요?
Sass는 CSS의 확장 언어로, 프로그래밍적인 기능을 CSS에 도입하여 스타일시트 작성을 더욱 강력하고 유연하게 만들어 줍니다.
Sass는 자체적인 문법을 가지고 있으며, 작성된 Sass 코드는 웹 브라우저가 이해할 수 있는 표준 CSS로 컴파일(transpile)되어야 합니다.
중첩을 읽기 전에 실제 선택자를 적어 보기
.btn 안의 &:hover에서 &는 바깥 선택자를 대신하므로 .btn:hover가 됩니다. 반면 같은 위치의 .icon은 기본 후손 중첩이므로 .btn .icon입니다. 버튼 하나에 btn과 primary가 함께 붙었다면 .btn.primary 또는 .btn 안의 &.primary로 같은 요소를 선택합니다. .btn 안에 그냥 .primary를 넣어 만든 .btn .primary는 별도의 후손 요소를 찾기 때문에 그 버튼 자체에 매칭되지 않습니다.
Sass가 선택자를 만들고 CSS Modules가 이름을 바꾸어도 이 같은 요소/후손 관계는 유지됩니다. 중첩이 깊어질수록 출력 선택자도 길어질 수 있으므로, 들여쓰기 모양보다 생성될 선택자와 실제 DOM 구조를 먼저 대조합니다. Sass 부모 선택자 안내에서 & 치환을 확인할 수 있습니다.
- 변수(Variables):
$primary-color: #007bff;와 같이 색상, 폰트 크기, 간격 등 반복적으로 사용되는 값을 변수로 정의하여 관리합니다. 유지보수가 용이하고 일관된 디자인을 유지하는 데 도움이 됩니다. - 중첩(Nesting): HTML 구조와 유사하게 CSS 선택자를 중첩하여 작성할 수 있습니다. 이는 코드의 가독성을 높이고, 연관된 스타일을 한눈에 파악하기 쉽게 만듭니다.
- 믹스인(Mixins):
@mixin button-style { ... }과 같이 재사용 가능한 CSS 코드 블록을 정의합니다. 여러 곳에서 동일한 스타일 패턴을 반복해서 사용해야 할 때 유용하며,background-color,padding,border-radius등 여러 속성을 묶어 한 번에 적용할 수 있습니다. - 함수(Functions):
@function calculate-rem($px) { ... }와 같이 값을 계산하고 반환하는 함수를 정의합니다. 색상 조정은sass:color같은 내장 모듈을 사용할 수 있습니다. - 확장/상속(Extend/Inheritance):
@extend .base-button;는 base-button을 포함하는 스타일 규칙의 선택자 목록을 확장해 현재 선택자도 그 규칙에 매칭되도록 합니다. DOM 부모에게서 속성을 물려받는 CSS 상속이나, 선언을 사용처에 복사하는 믹스인과는 다른 기능입니다. - 부분 파일(Partials)과 모듈:
_variables.scss같은 부분 파일을 만들고, 같은 폴더의 파일에서@use './variables';로 불러와variables.$primary-color처럼 이름공간을 통해 참조합니다. Sass의 파일 분할과 CSS Modules의 클래스 이름 지역화는 서로 다른 기능입니다.
- SCSS (Sassy CSS): CSS와 가장 유사한 문법으로, 중괄호(
{})와 세미콜론(;)을 사용합니다. 대부분의 Sass 사용자가 선호하는 방식입니다. (.scss확장자) - Sass (Indented Syntax): 중괄호와 세미콜론 없이 들여쓰기와 줄 바꿈으로 구조를 나타내는 문법입니다. (
.sass확장자)
Next.js에서는 주로 SCSS 문법을 가진 .scss 파일을 사용합니다.
왜 Sass를 사용해야 할까요? (이점)
Sass는 기존 CSS의 단점을 보완하고 다음과 같은 이점을 제공합니다.
- 생산성 향상: 변수, 믹스인, 중첩 등을 통해 반복적인 작업을 줄이고 더 빠르고 효율적으로 스타일을 작성할 수 있습니다.
- 유지보수성 개선: 전역 변수나 믹스인을 활용하여 디자인 시스템을 쉽게 구축하고, 일관된 스타일을 적용하고 관리할 수 있습니다. 예를 들어, 브랜드 색상이 변경되면 변수 하나만 수정하면 됩니다.
- 코드의 재사용성: 믹스인, 함수,
@extend를 통해 스타일 코드를 재사용하여 중복을 줄이고 코드량을 감소시킵니다. - 가독성 향상: 중첩 문법은 HTML/React 컴포넌트 구조와 유사하게 스타일을 조직화하여 코드의 가독성을 높입니다.
- 코드 조직화:
@use로 다른 파일의 변수·함수·믹스인을 명시적으로 가져와 관리할 수 있습니다.
Next.js에서 Sass 통합하기
앞 절과 이번 절의 연결
CSS Modules는 클래스 이름을 지역화하고, Sass는 작성한 변수·중첩·믹스인을 CSS 규칙으로 바꿉니다. .module.scss는 두 기능을 함께 사용하는 파일 이름입니다. 일반 .scss라는 확장자만으로 모든 선택자가 지역화되지는 않습니다.
아래 네 실습 파일은 src/app/sass-integration 아래의 별도 페이지 단위입니다. page·페이지 SCSS·SassStyledButton·버튼 SCSS를 모두 준비하고 /sass-integration에서 확인합니다. 앞 절 StyledButton의 CSS 또는 SCSS 파일을 이 파일로 덮어쓰지 않습니다.
Next.js는 Sass를 공식적으로 지원하므로, 설정 과정이 매우 간단합니다.
필요한 것은 단 하나, sass 패키지를 설치하는 것입니다.
sass 패키지 설치:
터미널을 열고 다음 명령어를 실행하여 sass 컴파일러를 설치합니다.
npm install sass
# 또는
yarn add sassSass 파일 생성 및 사용:
이제 .scss 또는 .sass 확장자를 가진 파일을 생성하여 Sass 문법으로 스타일을 작성하고, 이를 CSS 모듈처럼 임포트하여 사용할 수 있습니다.
이전 절의 StyledButton 예제를 Sass로 리팩터링하여 Sass의 기능을 활용해 봅시다.
src/app/sass-integration/page.tsx 파일 생성 (서버 컴포넌트):
이 페이지는 서버 컴포넌트이며, 우리가 만들 클라이언트 컴포넌트 SassStyledButton을 임포트하여 사용합니다.
import SassStyledButton from './SassStyledButton'; // 클라이언트 컴포넌트 임포트
import pageStyles from './page.module.scss'; // 페이지 요소에 적용할 Sass 모듈 임포트
export default function SassIntegrationPage() {
return (
<div className={pageStyles.container}>
<h1 className={pageStyles.title}>Sass 통합 예제</h1>
<p className={pageStyles.description}>
아래 버튼들은 Sass 변수, 중첩, 믹스인 등을 사용하여 스타일링되었습니다.
</p>
<div style={{ display: 'flex', gap: '20px', marginTop: '30px', justifyContent: 'center' }}>
<SassStyledButton label="기본 버튼" />
<SassStyledButton label="강조 버튼" variant="primary" />
<SassStyledButton label="경고 버튼" variant="warning" />
</div>
</div>
);
}src/app/sass-integration/page.module.scss 파일 생성:
Sass 문법을 사용하여 페이지의 기본 스타일을 정의합니다.
.container {
padding: 40px;
max-width: 800px;
margin: 20px auto;
background-color: #f8f8f8;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
text-align: center;
}
.title {
color: #333;
margin-bottom: 15px;
font-size: 2.5em;
}
.description {
color: #666;
font-size: 1.1em;
line-height: 1.6;
}src/app/sass-integration/SassStyledButton.tsx 파일 생성 (클라이언트 컴포넌트):
Sass 모듈을 임포트하여 스타일을 적용합니다.
"use client";
import React from 'react';
import buttonStyles from './SassStyledButton.module.scss'; // 🚨 .scss 확장자 사용
interface SassStyledButtonProps {
label: string;
variant?: 'default' | 'primary' | 'warning'; // 버튼 종류 추가
onClick?: () => void;
}
export default function SassStyledButton({ label, variant = 'default', onClick }: SassStyledButtonProps) {
// variant에 맞는 CSS 모듈 클래스를 선택합니다.
return (
<button
className={`${buttonStyles.btn} ${variant === 'default' ? '' : buttonStyles[variant]}`}
onClick={onClick}
>
{label}
</button>
);
}src/app/sass-integration/SassStyledButton.module.scss 파일 생성:
Sass의 변수, 중첩, 믹스인을 사용하여 버튼 스타일을 정의합니다. 기본 색은 .btn에 있고 primary, warning만 추가 클래스를 선택합니다. 원문의 darken()은 폐기 예정인 함수이므로 새 코드에서는 sass:color 모듈의 color.adjust(..., $lightness: -8%, $space: hsl)로 같은 명도 감소를 표현할 수 있습니다.
// Sass 변수 정의
$default-color: #007bff;
$primary-color: #28a745;
$warning-color: #ffc107;
$text-light: white;
$text-dark: #333;
// 재사용 가능한 믹스인 정의
@mixin button-base {
padding: 12px 25px;
font-size: 1.1em;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.1s ease, box-shadow 0.3s ease;
font-weight: bold;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
&:hover {
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
&:active {
transform: translateY(0);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
}
.btn {
@include button-base; // 믹스인 포함
// 기본 버튼 스타일 (중첩)
background-color: $default-color;
color: $text-light;
&:hover {
background-color: darken($default-color, 8%); // Sass 함수 사용
}
}
.primary {
background-color: $primary-color;
color: $text-light;
&:hover {
background-color: darken($primary-color, 8%);
}
}
.warning {
background-color: $warning-color;
color: $text-dark; // 경고 버튼은 어두운 텍스트
&:hover {
background-color: darken($warning-color, 8%);
}
}npm install sass 명령어로 sass 패키지를 설치했는지 확인합니다.
src/app/sass-integration 폴더를 만들고 위 파일들을 생성합니다.
개발 서버(npm run dev)를 실행한 후, http://localhost:3000/sass-integration으로 접속합니다.
- 세 가지 다른 색상의 버튼이 표시되는 것을 확인할 수 있습니다.
- 개발자 도구에서 생성된 클래스의 규칙과 세 버튼의 기본·hover 색상을 확인합니다. 클래스 이름 확인만으로 모든 Sass 규칙과 상태의 적용을 확인한 것은 아닙니다.
Sass를 활용한 스타일 관리 팁
- 공유 파일: 변수와 믹스인을 별도 부분 파일로 관리하고 각 사용 파일에서 상대 경로로
@use합니다._접두사 자체가 선택자를 지역화하지는 않습니다. Sass@import와 전역 내장 함수는 Dart Sass 1.80.0부터 폐기 예정입니다. - 얕은 중첩: DOM 구조를 그대로 깊게 중첩하기보다 컴포넌트가 책임지는 선택자와 반복 선언을 구분합니다. 믹스인을 여러 곳에 포함하면 최종 CSS 선언도 반복될 수 있습니다.
값과 클래스가 결정되는 시점
SCSS 변수·mixin의 빌드가 완료된 뒤 runtime props가 warning에서 primary로 바뀌어 기존 CSS Module class를 선택합니다. 고정 컴파일 결과와 바뀌는 React·DOM 상태를 추적하면 클릭 때 Sass를 다시 실행하지 않는다는 차이가 드러납니다.
NEXT · 9.2 · Sass와 CSS
Sass 값 계산과 브라우저 값 변경의 시점이 다릅니다
예제의 Sass 색상 변수·믹스인은 CSS를 만들 때 계산됩니다. React는 이미 생성된 기본·강조·경고 클래스를 선택합니다. CSS 변수는 변경 시점을 비교하기 위한 별도 방식입니다.
| 작성 대상 | 결정되는 시점 | 변경을 반영하는 방법 |
|---|---|---|
| Sass 변수 | Sass가 CSS를 만드는 동안 값을 계산 | 소스를 바꾸고 다시 컴파일; 브라우저에는 Sass 변수가 남지 않음 |
| CSS 변수 | 브라우저의 CSS 적용·상속 과정에서 값 결정 | 클래스·속성·JavaScript 등으로 CSS 변수 값을 바꿔 테마에 반영 가능 |
| 모듈 클래스 | 빌드 도구가 파일별 클래스 이름과 매핑 생성 | React에서 이미 생성된 클래스들을 선택하여 기본·강조·경고 상태 표현 |
- Sass 변수
- 결정되는 시점: Sass가 CSS를 만드는 동안 값을 계산변경을 반영하는 방법: 소스를 바꾸고 다시 컴파일; 브라우저에는 Sass 변수가 남지 않음
- CSS 변수
- 결정되는 시점: 브라우저의 CSS 적용·상속 과정에서 값 결정변경을 반영하는 방법: 클래스·속성·JavaScript 등으로 CSS 변수 값을 바꿔 테마에 반영 가능
- 모듈 클래스
- 결정되는 시점: 빌드 도구가 파일별 클래스 이름과 매핑 생성변경을 반영하는 방법: React에서 이미 생성된 클래스들을 선택하여 기본·강조·경고 상태 표현
Sass의 변수·믹스인은 CSS 작성 도구이고, CSS Modules는 클래스 이름을 지역화하는 도구입니다. 예제의 .module.scss는 두 기능을 함께 사용합니다.
이 예의 조건
- 두 박스는 같은 실행의 진행 정보와 자료·결과를 관찰하는 고정 역할입니다. 박스의 좌우·위아래 위치를 별도 호출 순서로 해석하지 않습니다.
- 조건별 종료는 대안입니다. 실패 뒤 정상 후속 단계를 실행하거나 독립 비교 사례를 같은 요청으로 연결하지 않습니다.
- 노드 6개와 관계 6개입니다. 위 영역은 Sass 변수·믹스인을 CSS로 계산하는 시점, 아래 영역은 이미 생성된 모듈 클래스 이름을 현재 props로 선택하고 적용하는 시점입니다. CSS 출력은 선택할 이름과 실제 규칙을 각각 제공합니다. variant 입력은 React 선택의 독립 입력입니다. warning에서 primary로 props가 바뀌는 것은 Sass 변수 계산을 다시 실행하는 경로가 아닙니다. CSS 변수의 런타임 변경은 기존 비교표의 별도 방식이며 이 원 예제에는 구현되지 않았습니다.
관계도의 보충 설명
| 순번 | 원문 표시 |
|---|---|
| 6 | 노드 6개와 관계 6개입니다. 위 영역은 Sass 변수·믹스인을 CSS로 계산하는 시점, 아래 영역은 이미 생성된 모듈 클래스 이름을 현재 props로 선택하고 적용하는 시점입니다. CSS 출력은 선택할 이름과 실제 규칙을 각각 제공합니다. variant 입력은 React 선택의 독립 입력입니다. warning에서 primary로 props가 바뀌는 것은 Sass 변수 계산을 다시 실행하는 경로가 아닙니다. CSS 변수의 런타임 변경은 기존 비교표의 별도 방식이며 이 원 예제에는 구현되지 않았습니다. |
| 장면 | 관찰 값 | 전환 이유 |
|---|---|---|
| SCSS 빌드 완료 Sass 변수·mixin이 CSS로 계산되어 클래스 이름과 규칙이 준비됩니다. | 컴파일: 완료 · 산출물: 모듈 class·CSS · runtime CSS 변수: 별도 방식 | runtime에서 선택할 고정 스타일이 생깁니다. |
| warning props 선택 현재 warning props로 React가 이미 생성된 모듈 클래스를 선택합니다. | props: warning · React: 기존 class 선택 · Sass: 재실행 없음 | warning 규칙이 현재 DOM에 적용됩니다. |
| primary props로 변경 props가 primary로 바뀌면 다른 기존 클래스를 선택해 적용합니다. | props: primary · DOM class: 선택 변경 · CSS 산출물: 동일 | runtime의 선택만 바뀌고 빌드는 반복되지 않습니다. |
값과 클래스가 결정되는 시점
SCSS 변수·mixin의 빌드가 완료된 뒤 runtime props가 warning에서 primary로 바뀌어 기존 CSS Module class를 선택합니다. 고정 컴파일 결과와 바뀌는 React·DOM 상태를 추적하면 클릭 때 Sass를 다시 실행하지 않는다는 차이가 드러납니다.
NEXT · 9.2 · Sass와 CSS
Sass 값 계산과 브라우저 값 변경의 시점이 다릅니다
예제의 Sass 색상 변수·믹스인은 CSS를 만들 때 계산됩니다. React는 이미 생성된 기본·강조·경고 클래스를 선택합니다. CSS 변수는 변경 시점을 비교하기 위한 별도 방식입니다.
| 작성 대상 | 결정되는 시점 | 변경을 반영하는 방법 |
|---|---|---|
| Sass 변수 | Sass가 CSS를 만드는 동안 값을 계산 | 소스를 바꾸고 다시 컴파일; 브라우저에는 Sass 변수가 남지 않음 |
| CSS 변수 | 브라우저의 CSS 적용·상속 과정에서 값 결정 | 클래스·속성·JavaScript 등으로 CSS 변수 값을 바꿔 테마에 반영 가능 |
| 모듈 클래스 | 빌드 도구가 파일별 클래스 이름과 매핑 생성 | React에서 이미 생성된 클래스들을 선택하여 기본·강조·경고 상태 표현 |
- Sass 변수
- 결정되는 시점: Sass가 CSS를 만드는 동안 값을 계산변경을 반영하는 방법: 소스를 바꾸고 다시 컴파일; 브라우저에는 Sass 변수가 남지 않음
- CSS 변수
- 결정되는 시점: 브라우저의 CSS 적용·상속 과정에서 값 결정변경을 반영하는 방법: 클래스·속성·JavaScript 등으로 CSS 변수 값을 바꿔 테마에 반영 가능
- 모듈 클래스
- 결정되는 시점: 빌드 도구가 파일별 클래스 이름과 매핑 생성변경을 반영하는 방법: React에서 이미 생성된 클래스들을 선택하여 기본·강조·경고 상태 표현
Sass의 변수·믹스인은 CSS 작성 도구이고, CSS Modules는 클래스 이름을 지역화하는 도구입니다. 예제의 .module.scss는 두 기능을 함께 사용합니다.
이 예의 조건
- 두 박스는 같은 실행의 진행 정보와 자료·결과를 관찰하는 고정 역할입니다. 박스의 좌우·위아래 위치를 별도 호출 순서로 해석하지 않습니다.
- 조건별 종료는 대안입니다. 실패 뒤 정상 후속 단계를 실행하거나 독립 비교 사례를 같은 요청으로 연결하지 않습니다.
- 노드 6개와 관계 6개입니다. 위 영역은 Sass 변수·믹스인을 CSS로 계산하는 시점, 아래 영역은 이미 생성된 모듈 클래스 이름을 현재 props로 선택하고 적용하는 시점입니다. CSS 출력은 선택할 이름과 실제 규칙을 각각 제공합니다. variant 입력은 React 선택의 독립 입력입니다. warning에서 primary로 props가 바뀌는 것은 Sass 변수 계산을 다시 실행하는 경로가 아닙니다. CSS 변수의 런타임 변경은 기존 비교표의 별도 방식이며 이 원 예제에는 구현되지 않았습니다.
관계도의 보충 설명
| 순번 | 원문 표시 |
|---|---|
| 6 | 노드 6개와 관계 6개입니다. 위 영역은 Sass 변수·믹스인을 CSS로 계산하는 시점, 아래 영역은 이미 생성된 모듈 클래스 이름을 현재 props로 선택하고 적용하는 시점입니다. CSS 출력은 선택할 이름과 실제 규칙을 각각 제공합니다. variant 입력은 React 선택의 독립 입력입니다. warning에서 primary로 props가 바뀌는 것은 Sass 변수 계산을 다시 실행하는 경로가 아닙니다. CSS 변수의 런타임 변경은 기존 비교표의 별도 방식이며 이 원 예제에는 구현되지 않았습니다. |
| 장면 | 관찰 값 | 전환 이유 |
|---|---|---|
| SCSS 빌드 완료 Sass 변수·mixin이 CSS로 계산되어 클래스 이름과 규칙이 준비됩니다. | 컴파일: 완료 · 산출물: 모듈 class·CSS · runtime CSS 변수: 별도 방식 | runtime에서 선택할 고정 스타일이 생깁니다. |
| warning props 선택 현재 warning props로 React가 이미 생성된 모듈 클래스를 선택합니다. | props: warning · React: 기존 class 선택 · Sass: 재실행 없음 | warning 규칙이 현재 DOM에 적용됩니다. |
| primary props로 변경 props가 primary로 바뀌면 다른 기존 클래스를 선택해 적용합니다. | props: primary · DOM class: 선택 변경 · CSS 산출물: 동일 | runtime의 선택만 바뀌고 빌드는 반복되지 않습니다. |
예시
variant=warning일 때 React가 고르는 것은 이미 만들어진 btn과 warning의 모듈 클래스 이름입니다. SassStyledButton.module.scss를 읽으면 먼저 button-base 믹스인의 공통 padding·hover 이동 규칙이 btn 안에 들어가고, warning의 노란 배경과 어두운 글자 규칙이 같은 요소에 추가됩니다. 클릭할 때 브라우저가 Sass의 $warning-color를 다시 계산하는 것은 아닙니다.
원 SCSS의 darken은 이전 함수 사용법을 보존한 코드입니다. 현재 Sass 색상 함수 변경 안내는 제거 전 경고와 Dart Sass 2.0에서의 제거를 구분합니다. 경고를 본 결과와 앞으로 그 함수가 그대로 동작하지 않는 버전의 결과를 혼동하지 마세요. 본문의 color.adjust 대안은 HSL 명도를 정해진 퍼센트 포인트만큼 바꾸는 방식이며, 상대 비율로 조정하는 color.scale과 값이 항상 같지는 않습니다.
작성 시점과 선택 시점을 비교하기
원 variant 세 값만 사용하고 외부 CSS가 없다고 가정합니다. warning 버튼의 글자색과 hover 이동을 예상한 뒤, 렌더 시 variant를 primary로 바꿨을 때 Sass 재컴파일이 필요한지 판단하세요. 이어 SCSS 소스의 $warning-color 자체를 바꾸는 경우와 비교합니다.
미리 만든 규칙을 선택하는 해설
warning은 btn과 warning을 함께 적용하므로 글자색 #333과 공통 translateY(-2px)를 사용하고, 배경의 hover 값은 warning 규칙에서 정합니다. primary로 바뀌면 React가 btn과 primary를 선택하고 글자색은 white가 됩니다. 두 variant의 CSS가 이미 생성·로드돼 있으므로 props 변경만으로 Sass를 다시 계산할 필요는 없습니다.
$warning-color는 Sass 소스의 입력입니다. 그 값을 바꾼 결과를 보려면 CSS를 다시 생성해 화면에 반영해야 합니다. 개발 도구가 이 과정을 자동으로 처리해도 브라우저가 Sass 변수를 직접 실행하는 것으로 설명하지 않습니다. 원 예제는 CSS 사용자 정의 변수로 런타임 테마를 바꾸는 별도 구현을 포함하지 않습니다.
컴파일 시점의 값과 브라우저에서 바꾸는 값
$warning-color는 생성된 CSS에 실제 색으로 들어가고 Sass 변수 이름은 남지 않습니다. 반대로 --button-bg 같은 CSS 사용자 정의 속성은 출력 CSS에 남아 브라우저에서 요소별로 바꿀 수 있습니다. 원 예제는 앞의 Sass 변수 방식이며, JavaScript로 Sass의 $warning-color라는 이름을 직접 바꾸는 런타임 테마 코드는 아닙니다.
부분 파일에 @use './variables';를 썼다면 그 파일에서는 variables.$primary-color로 읽습니다. 다른 SCSS 파일이 이 파일을 사용했다는 이유만으로 같은 이름공간을 자동으로 얻지는 않으므로, 값을 직접 읽는 파일에서도 필요한 모듈을 명시적으로 가져옵니다. _ 접두사는 부분 파일 관례이며 CSS Modules의 지역 이름이나 전역 변수 주입을 뜻하지 않습니다.
원 코드의 darken($color, 8%)는 HSL lightness에서 8퍼센트포인트를 빼는 기존 동작입니다. HSL 명도 50%라면 42%이고, 현재 값의 8%를 줄이는 color.scale(..., $lightness: -8%, $space: hsl)는 46%입니다. 기존 결과를 유지하는 대안은 color.adjust(..., $lightness: -8%, $space: hsl)입니다. 색 공간과 fixed adjustment/relative scale의 목적을 함께 정해야 하며, 함수 이름만 치환해 다른 결과가 나는 문제를 피합니다. Sass 색 함수 안내에서 두 연산을 구분합니다.
추가 연습: 중첩·재사용·색 계산의 의미
- 실제 DOM은
<button class="btn primary"><span class="icon">저장</span></button>입니다. 출력 선택자.btn.primary,.btn .primary,.btn .icon각각이 선택하는 요소를 적고, 같은 버튼의 primary 상태를 중첩으로 작성할 때&가 필요한 이유를 설명하세요. 지역 이름 변경 전 표기로 풉니다. .base { padding: 8px; }와.accent { @extend .base; }에서 두 선택자가 이 padding 규칙을 공유하게 됩니다. accent 버튼 안의 클래스 없는 span이 그 이유만으로 padding을 물려받나요? 믹스인을 쓰는 방식과도 구별하세요.- HSL 명도 50%에서
color.adjust의 lightness -8%와color.scale의 lightness -8%를 각각 계산하세요. 같은 방식으로 명도 20%도 계산하세요. - 변수 모듈을 A.scss가
@use하고 B.scss는 A.scss만@use합니다. B가 변수 모듈의$primary-color를 직접 읽으려면 무엇이 필요할까요? 그 값을 변경한 소스가 브라우저에 반영되는 시점도 적으세요. 별도의 CSS 사용자 정의 속성 구현은 없다고 가정합니다.
출력 CSS와 모듈 경계를 기준으로 한 풀이
.btn.primary는 두 클래스를 가진 button,.btn .primary는 그 후손인 primary 요소를 찾으므로 이번 DOM에서는 대상 없음,.btn .icon은 span을 선택합니다..btn내부의&.primary는 바깥.btn을 그대로 붙여.btn.primary를 만들지만, 그냥.primary를 중첩하면 후손 공백이 들어갑니다.- button은 확장된 선택자 목록의 padding 규칙에 매칭됩니다. span은 base/accent 선택자에 매칭되지 않고 padding은 기본 상속 속성이 아니므로 그 이유만으로 8 px가 되지 않습니다. 믹스인은 선언을 include 사용처에 복사하고, extend는 기존 규칙의 선택자 목록을 확장합니다.
- 50%에서 adjust는
50 - 8 = 42%, scale은50 × 0.92 = 46%입니다. 20%에서 adjust는20 - 8 = 12%, scale은20 × 0.92 = 18.4%입니다. 같은 -8% 표기도 연산 의미가 다릅니다. - B에서도 변수 모듈을
@use하고 그 이름공간으로 참조합니다. A가 가져온 모듈의 멤버가 B의 이름공간에 자동으로 풀리는 것은 아닙니다. Sass 소스를 다시 컴파일해 생성 CSS를 갱신한 뒤 화면에 반영하며, 브라우저가$primary-color를 직접 실행하거나 수정하지 않습니다.