Sass

Sass

소스 Sass 파일을 활용해 변수, 맵, 믹스인, 함수를 이용해 더 빠르게 빌드하고 프로젝트를 커스터마이즈해 보아요.

출처: 문서

본문

소스 Sass 파일을 활용해 변수, 맵, 믹스인 등을 활용할 수 있어요.

최신 버전의 Dart Sass로 소스 Sass 파일을 컴파일하면 Sass 더 이상 사용되지 않음(deprecation) 경고가 표시돼요. 이는 컴파일이나 Bootstrap 사용을 방해하지 않아요. 장기적인 해결책을 작업 중이지만, 그동안 이 더 이상 사용되지 않음 알림은 무시해도 돼요.

파일 구조 (File structure)

가능하면 Bootstrap의 핵심 파일을 수정하는 것을 피해야 해요. Sass의 경우, Bootstrap을 임포트해서 수정하고 확장할 수 있는 자신만의 스타일시트를 만드는 것을 의미해요. npm 같은 패키지 매니저를 사용한다면 다음과 같은 파일 구조를 갖게 될 거예요:

your-project/
├── scss/
│   └── custom.scss
└── node_modules/
│   └── bootstrap/
│       ├── js/
│       └── scss/
└── index.html

소스 파일을 다운로드했고 패키지 매니저를 사용하지 않는다면, Bootstrap의 소스 파일을 자신의 파일과 분리해 유지하면서 그와 비슷한 구조를 수동으로 만들어야 해요.

your-project/
├── scss/
│   └── custom.scss
├── bootstrap/
│   ├── js/
│   └── scss/
└── index.html

임포트 (Importing)

custom.scss에서 Bootstrap의 소스 Sass 파일을 임포트할 거예요. 두 가지 옵션이 있어요: Bootstrap 전체를 포함하거나 필요한 부분만 골라서 포함하는 방법이에요. 우리는 후자를 권장하지만, 컴포넌트 간에 몇 가지 요구 사항과 의존성이 있다는 점을 알아 두세요. 플러그인용 JavaScript도 일부 포함해야 해요.

// Custom.scss
// Option A: Include all of Bootstrap

// Include any default variable overrides here (though functions won't be available)

@import "../node_modules/bootstrap/scss/bootstrap";

// Then add additional custom code here
// Custom.scss
// Option B: Include parts of Bootstrap

// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "../node_modules/bootstrap/scss/functions";

// 2. Include any default variable overrides here

// 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets)
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/variables-dark";

// 4. Include any default map overrides here

// 5. Include remainder of required parts
@import "../node_modules/bootstrap/scss/maps";
@import "../node_modules/bootstrap/scss/mixins";
@import "../node_modules/bootstrap/scss/root";

// 6. Include any other optional stylesheet partials as desired; list below is not inclusive of all available stylesheets
@import "../node_modules/bootstrap/scss/utilities";
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
@import "../node_modules/bootstrap/scss/images";
@import "../node_modules/bootstrap/scss/containers";
@import "../node_modules/bootstrap/scss/grid";
@import "../node_modules/bootstrap/scss/helpers";
// ...

// 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss`
@import "../node_modules/bootstrap/scss/utilities/api";

// 8. Add additional custom code here

이 설정이 완료되면 custom.scss에서 Sass 변수와 맵을 수정하기 시작할 수 있어요. 필요에 따라 // Optional 섹션 아래에 Bootstrap의 일부를 추가하기 시작할 수도 있어요. 시작점으로 bootstrap.scss 파일의 전체 임포트 스택을 사용하는 것을 권장해요.

컴파일 (Compiling)

커스텀 Sass 코드를 브라우저에서 CSS로 사용하려면 Sass 컴파일러가 필요해요. Sass는 CLI 패키지로 제공되지만, Gulp나 Webpack 같은 다른 빌드 도구나 GUI 애플리케이션으로도 컴파일할 수 있어요. 일부 IDE에도 Sass 컴파일러가 내장되어 있거나 다운로드 가능한 확장 기능으로 제공돼요.

우리는 CLI로 Sass를 컴파일하는 것을 선호하지만, 원하는 방법을 사용해도 돼요. 명령줄에서 다음을 실행해 보세요:

# Install Sass globally
npm install -g sass

# Watch your custom Sass for changes and compile it to CSS
sass --watch ./scss/custom.scss ./css/custom.css

옵션에 대해 더 알아보려면 sass-lang.com/install과 VS Code로 컴파일하기를 확인해 보세요.

다른 빌드 도구로 Bootstrap을 사용하나요? Webpack, Parcel, 또는 Vite로 컴파일하는 가이드를 읽어 보세요. GitHub의 examples 저장소에도 프로덕션에 바로 사용할 수 있는 데모가 있어요.

포함 (Including)

CSS가 컴파일되면 HTML 파일에 포함할 수 있어요. index.html 안에 컴파일된 CSS 파일을 포함하면 돼요. 컴파일된 CSS 파일의 경로를 변경했다면 경로를 업데이트해야 해요.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Custom Bootstrap</title>
    <link href="/css/custom.css" rel="stylesheet">
  </head>
  <body>
    <h1>Hello, world!</h1>
  </body>
</html>

변수 기본값 (Variable defaults)

Bootstrap의 모든 Sass 변수에는 !default 플래그가 포함되어 있어서, Bootstrap 소스 코드를 수정하지 않고도 자신의 Sass에서 변수의 기본값을 재정의할 수 있어요. 필요에 따라 변수를 복사해서 붙여넣고, 값을 수정하고, !default 플래그를 제거하면 돼요. 이미 할당된 변수가 있다면 Bootstrap의 기본값으로 다시 할당되지 않아요.

Bootstrap 변수의 전체 목록은 scss/_variables.scss에서 찾을 수 있어요. 일부 변수는 null로 설정되어 있는데, 이 변수들은 구성에서 재정의하지 않으면 해당 프로퍼티를 출력하지 않아요.

변수 재정의는 함수가 임포트된 후, 나머지 임포트 전에 와야 해요.

다음은 npm으로 Bootstrap을 임포트하고 컴파일할 때 <body>의 background-color와 color를 변경하는 예시예요:

// Required
@import "../node_modules/bootstrap/scss/functions";

// Default variable overrides
$body-bg: #000;
$body-color: #111;

// Required
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/variables-dark";
@import "../node_modules/bootstrap/scss/maps";
@import "../node_modules/bootstrap/scss/mixins";
@import "../node_modules/bootstrap/scss/root";

// Optional Bootstrap components here
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
// etc

Bootstrap의 모든 변수에 대해 아래의 전역 옵션을 포함해 필요에 따라 반복하면 돼요.

npm으로 Bootstrap을 시작하려면 스타터 프로젝트를 이용해 보세요! Sass & JS 예시 템플릿 저장소로 가서 자신의 npm 프로젝트에서 Bootstrap을 빌드하고 커스터마이즈하는 방법을 확인해 보세요. Sass 컴파일러, Autoprefixer, Stylelint, PurgeCSS, Bootstrap Icons를 포함해요.

맵과 루프 (Maps and loops)

Bootstrap은 관련 CSS 패밀리를 생성하기 쉽게 만드는 키-값 쌍인 Sass 맵을 몇 개 포함해요. 색상, 그리드 브레이크포인트 등에 Sass 맵을 사용해요. Sass 변수와 마찬가지로 모든 Sass 맵에는 !default 플래그가 포함돼 있고 재정의하고 확장할 수 있어요.

일부 Sass 맵은 기본적으로 빈 맵에 병합돼요. 이는 주어진 Sass 맵의 확장을 쉽게 하기 위한 것이지만, 맵에서 항목을 제거하는 것을 다소 어렵게 만드는 비용이 따르지요.

맵 수정 (Modify map)

$theme-colors 맵의 모든 변수는 독립 변수로 정의돼요. $theme-colors 맵의 기존 색상을 수정하려면 커스텀 Sass 파일에 다음을 추가해요:

$primary: #0074d9;
$danger: #ff4136;

나중에 이 변수들은 Bootstrap의 $theme-colors 맵에 설정돼요:

$theme-colors: (
  "primary": $primary,
  "danger": $danger
);

맵에 추가 (Add to map)

커스텀 값으로 새 Sass 맵을 만들고 원본 맵과 병합해서 $theme-colors나 다른 맵에 새 색상을 추가할 수 있어요. 이 경우 새 $custom-colors 맵을 만들어 $theme-colors와 병합할 거예요.

// Create your own map
$custom-colors: (
  "custom-color": #900
);

// Merge the maps
$theme-colors: map-merge($theme-colors, $custom-colors);

맵에서 제거 (Remove from map)

map-remove를 사용해 $theme-colors나 다른 맵에서 색상을 제거할 수 있어요. $theme-colors를 requirements 사이에, 즉 variables에서 정의된 직후, maps에서 사용되기 전에 삽입해야 한다는 점을 유의하세요:

// Required
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/variables-dark";

$theme-colors: map-remove($theme-colors, "info", "light", "dark");

@import "../node_modules/bootstrap/scss/maps";
@import "../node_modules/bootstrap/scss/mixins";
@import "../node_modules/bootstrap/scss/root";

// Optional
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
// etc

필수 키 (Required keys)

Bootstrap은 Sass 맵 내의 일부 특정 키가 존재한다고 가정하는데, 우리가 직접 사용하고 확장하기 때문이에요. 포함된 맵을 커스터마이즈할 때 특정 Sass 맵의 키가 사용되고 있다는 오류가 발생할 수 있어요.

예를 들어 $theme-colors의 primary, success, danger 키를 링크, 버튼, 폼 상태에 사용해요. 이 키들의 값을 교체하는 것은 문제가 없지만, 제거하면 Sass 컴파일 문제가 발생할 수 있어요. 이런 경우 해당 값을 사용하는 Sass 코드를 수정해야 해요.

함수 (Functions)

색상 (Colors)

우리가 가진 Sass 맵 외에도 테마 색상을 $primary 같은 독립 변수로 사용할 수 있어요.

.custom-element {
  color: $gray-100;
  background-color: $dark;
}

Bootstrap의 tint-color()와 shade-color() 함수로 색상을 밝게 하거나 어둡게 할 수 있어요. 이 함수들은 색상을 검은색이나 흰색과 혼합하는데, 고정된 양만큼 명도를 변경해서 종종 원하는 효과를 내지 못하는 Sass의 네이티브 lighten()과 darken() 함수와는 달라요.

shift-color()는 weight가 양수면 색상을 어둡게(shade), 음수면 밝게(tint) 하여 이 두 함수를 결합해요.

scss/_functions.scss

// Tint a color: mix a color with white
@function tint-color($color, $weight) {
  @return mix(white, $color, $weight);
}

// Shade a color: mix a color with black
@function shade-color($color, $weight) {
  @return mix(black, $color, $weight);
}

// Shade the color if the weight is positive, else tint it
@function shift-color($color, $weight) {
  @return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));
}

실제로는 함수를 호출하고 색상과 weight 매개변수를 전달하면 돼요.

.custom-element {
  color: tint-color($primary, 10%);
}

.custom-element-2 {
  color: shade-color($danger, 30%);
}

.custom-element-3 {
  color: shift-color($success, 40%);
  background-color: shift-color($success, -60%);
}

색상 대비 (Color contrast)

웹 콘텐츠 접근성 가이드라인(WCAG) 대비 요구 사항을 충족하려면, 작성자는 최소 텍스트 색상 대비 4.5:1과 최소 비텍스트 색상 대비 3:1을 제공해야 해요 (아주 예외적인 경우를 제외하고).

이를 돕기 위해 Bootstrap에 color-contrast 함수를 포함했어요. 이 함수는 sRGB 색상 공간의 상대적 휘도를 기반으로 WCAG 대비 비율 알고리즘을 사용해 대비 임계값을 계산하고, 지정된 기본 색상에 따라 라이트(#fff), 다크(#212529) 또는 블랙(#000) 대비 색상을 자동으로 반환해요. 이 함수는 여러 클래스를 생성하는 믹스인이나 루프에서 특히 유용해요.

예를 들어 $theme-colors 맵에서 색상 견본(swatch)을 생성하려면:

@each $color, $value in $theme-colors {
  .swatch-#{$color} {
    color: color-contrast($value);
  }
}

일회성 대비 요구 사항에도 사용할 수 있어요:

.custom-element {
  color: color-contrast(#000); // returns `color: #fff`
}

색상 맵 함수로 기본 색상을 지정할 수도 있어요:

.custom-element {
  color: color-contrast($dark); // returns `color: #fff`
}

SVG 이스케이프 (Escape SVG)

SVG 배경 이미지의 <, >, # 문자를 이스케이프하기 위해 escape-svg 함수를 사용해요. escape-svg 함수를 사용할 때 data URI는 따옴표로 묶어야 해요.

더하기와 빼기 함수 (Add and Subtract functions)

CSS calc 함수를 감싸기 위해 add와 subtract 함수를 사용해요. 이 함수들의 주된 목적은 "단위 없는" 0 값이 calc 표현식에 전달될 때 발생하는 오류를 피하는 것이에요. calc(10px - 0) 같은 표현식은 수학적으로는 맞지만 모든 브라우저에서 오류를 반환할 거예요.

calc가 유효한 예시:

$border-radius: .25rem;
$border-width: 1px;

.element {
  // Output calc(.25rem - 1px) is valid
  border-radius: calc($border-radius - $border-width);
}

.element {
  // Output the same calc(.25rem - 1px) as above
  border-radius: subtract($border-radius, $border-width);
}

calc가 유효하지 않은 예시:

$border-radius: .25rem;
$border-width: 0;

.element {
  // Output calc(.25rem - 0) is invalid
  border-radius: calc($border-radius - $border-width);
}

.element {
  // Output .25rem
  border-radius: subtract($border-radius, $border-width);
}

믹스인 (Mixins)

scss/mixins/ 디렉토리에는 Bootstrap의 일부를 구동하고 자신의 프로젝트에서도 사용할 수 있는 수많은 믹스인이 있어요.

색상 구성표 (Color schemes)

라이트와 다크 색상 구성표를 지원하는 prefers-color-scheme 미디어 쿼리의 축약 믹스인이 제공돼요. 색상 모드 믹스인에 대한 정보는 색상 모드 문서를 참조하세요.

scss/mixins/_color-scheme.scss

@mixin color-scheme($name) {
  @media (prefers-color-scheme: #{$name}) {
    @content;
  }
}
.custom-element {
  @include color-scheme(light) {
    // Insert light mode styles here
  }

  @include color-scheme(dark) {
    // Insert dark mode styles here
  }
}

더 알아보기 (Learn more)