CSS 변수
CSS 변수 (CSS variables)
Bootstrap의 CSS 커스텀 프로퍼티를 사용해 빠르고 미래 지향적인 디자인과 개발을 해 보아요.
출처: 문서
본문
Bootstrap은 컴파일된 CSS에 많은 CSS 커스텀 프로퍼티(변수)를 포함하고 있어서, Sass를 다시 컴파일하지 않아도 실시간으로 커스터마이즈할 수 있어요. 이 변수들은 브라우저의 인스펙터, 코드 샌드박스, 또는 일반적인 프로토타이핑 작업에서 테마 색상, 브레이크포인트, 기본 글꼴 스택 같은 자주 쓰는 값을 쉽게 접근할 수 있게 해 줘요.
우리의 모든 커스텀 프로퍼티는 서드파티 CSS와의 충돌을 피하기 위해 bs- 접두사를 붙여요.
루트 변수 (Root variables)
다음은 우리가 포함하는 변수들이에요 (:root가 필요하다는 점에 유의하세요). Bootstrap의 CSS가 로드된 곳 어디서나 접근할 수 있어요. _root.scss 파일에 위치하며 컴파일된 dist 파일에도 포함돼요.
기본 (Default)
이 CSS 변수들은 색상 모드와 관계없이 어디서나 사용할 수 있어요.
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-primary-text-emphasis: #052c65;
--bs-secondary-text-emphasis: #2b2f32;
--bs-success-text-emphasis: #0a3622;
--bs-info-text-emphasis: #055160;
--bs-warning-text-emphasis: #664d03;
--bs-danger-text-emphasis: #58151c;
--bs-light-text-emphasis: #495057;
--bs-dark-text-emphasis: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #e2e3e5;
--bs-success-bg-subtle: #d1e7dd;
--bs-info-bg-subtle: #cff4fc;
--bs-warning-bg-subtle: #fff3cd;
--bs-danger-bg-subtle: #f8d7da;
--bs-light-bg-subtle: #fcfcfd;
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: #9ec5fe;
--bs-secondary-border-subtle: #c4c8cb;
--bs-success-border-subtle: #a3cfbb;
--bs-info-border-subtle: #9eeaf9;
--bs-warning-border-subtle: #ffe69c;
--bs-danger-border-subtle: #f1aeb5;
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg: #fff;
--bs-body-bg-rgb: 255, 255, 255;
--bs-emphasis-color: #000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-heading-color: inherit;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-color: #212529;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-xxl: 2rem;
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
--bs-focus-ring-width: 0.25rem;
--bs-focus-ring-opacity: 0.25;
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
--bs-form-valid-color: #198754;
--bs-form-valid-border-color: #198754;
--bs-form-invalid-color: #dc3545;
--bs-form-invalid-border-color: #dc3545;
}
다크 모드 (Dark mode)
이 변수들은 내장된 다크 모드에 범위(scope)가 지정돼요.
[data-bs-theme=dark] {
color-scheme: dark;
--bs-body-color: #dee2e6;
--bs-body-color-rgb: 222, 226, 230;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #fff;
--bs-emphasis-color-rgb: 255, 255, 255;
--bs-secondary-color: rgba(222, 226, 230, 0.75);
--bs-secondary-color-rgb: 222, 226, 230;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
--bs-tertiary-color-rgb: 222, 226, 230;
--bs-tertiary-bg: #2b3035;
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-primary-text-emphasis: #6ea8fe;
--bs-secondary-text-emphasis: #a7acb1;
--bs-success-text-emphasis: #75b798;
--bs-info-text-emphasis: #6edff6;
--bs-warning-text-emphasis: #ffda6a;
--bs-danger-text-emphasis: #ea868f;
--bs-light-text-emphasis: #f8f9fa;
--bs-dark-text-emphasis: #dee2e6;
--bs-primary-bg-subtle: #031633;
--bs-secondary-bg-subtle: #161719;
--bs-success-bg-subtle: #051b11;
--bs-info-bg-subtle: #032830;
--bs-warning-bg-subtle: #332701;
--bs-danger-bg-subtle: #2c0b0e;
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: #084298;
--bs-secondary-border-subtle: #41464b;
--bs-success-border-subtle: #0f5132;
--bs-info-border-subtle: #087990;
--bs-warning-border-subtle: #997404;
--bs-danger-border-subtle: #842029;
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: inherit;
--bs-link-color: #6ea8fe;
--bs-link-hover-color: #8bb9fe;
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 139, 185, 254;
--bs-code-color: #e685b5;
--bs-highlight-color: #dee2e6;
--bs-highlight-bg: #664d03;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
--bs-form-valid-color: #75b798;
--bs-form-valid-border-color: #75b798;
--bs-form-invalid-color: #ea868f;
--bs-form-invalid-border-color: #ea868f;
}
컴포넌트 변수 (Component variables)
Bootstrap 5는 다양한 컴포넌트의 로컬 변수로 커스텀 프로퍼티를 점점 더 많이 사용하고 있어요. 이렇게 하면 컴파일된 CSS를 줄이고, 중첩된 표 같은 곳에서 스타일이 상속되지 않게 하며, Sass 컴파일 후에도 Bootstrap 컴포넌트를 일부 다시 스타일링하고 확장할 수 있어요.
우리가 CSS 변수를 어떻게 사용하는지에 대한 통찰은 table 문서를 살펴보세요. 내비바(navbar)도 v5.2.0부터 CSS 변수를 사용해요. 또한 주로 gutter(거터)와 새 opt-in CSS 그리드에 CSS 변수를 그리드 전반에 걸쳐 사용하고 있으며, 앞으로 더 많은 컴포넌트에 적용될 예정이에요.
가능하면 기본 컴포넌트 레벨(예: 내비바와 그 하위 컴포넌트의 .navbar)에서 CSS 변수를 할당해요. 이렇게 하면 어디서 어떻게 커스터마이즈해야 할지 추측할 필요가 줄고, 향후 업데이트에서 우리 팀이 쉽게 수정할 수 있어요.
접두사 (Prefix)
대부분의 CSS 변수는 자신의 코드베이스와의 충돌을 피하기 위해 접두사를 사용해요. 이 접두사는 모든 CSS 변수에 필요한 --에 추가로 붙는 것이에요.
접두사는 $prefix Sass 변수로 커스터마이즈할 수 있어요. 기본값은 bs-로 설정돼 있어요 (끝의 대시를 유의하세요).
예시 (Examples)
CSS 변수는 Sass 변수와 비슷한 유연성을 제공하지만, 브라우저에 서빙되기 전에 컴파일할 필요가 없어요. 예를 들어 여기서는 CSS 변수로 페이지의 글꼴과 링크 스타일을 재설정하고 있어요.
body {
font: 1rem/1.5 var(--bs-font-sans-serif);
}
a {
color: var(--bs-blue);
}
포커스 변수 (Focus variables)
v5.3.0에서 추가됨
Bootstrap은 Sass와 CSS 변수의 조합을 사용해 커스텀 :focus 스타일을 제공하며, 이를 특정 컴포넌트와 요소에 선택적으로 추가할 수 있어요. 아직 모든 :focus 스타일을 전역적으로 재정의하지는 않아요.
Sass에서는 컴파일 전에 커스터마이즈할 수 있는 기본값을 설정해요.
scss/_variables.scss
$focus-ring-width: .25rem;
$focus-ring-opacity: .25;
$focus-ring-color: rgba($primary, $focus-ring-opacity);
$focus-ring-blur: 0;
$focus-ring-box-shadow: 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color;
그런 다음 그 변수들은 x/y 오프셋 옵션(기본값은 폴백값인 0)을 포함해 실시간으로 커스터마이즈할 수 있는 :root 레벨 CSS 변수에 다시 할당돼요.
scss/_root.scss
--#{$prefix}focus-ring-width: #{$focus-ring-width};
--#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};
--#{$prefix}focus-ring-color: #{$focus-ring-color};
그리드 브레이크포인트 (Grid breakpoints)
그리드 브레이크포인트를 CSS 변수로 포함하지만 (xs 제외), CSS 변수가 미디어 쿼리에서는 작동하지 않는다는 점에 유의하세요. 이는 변수에 대한 CSS 스펙의 설계상 그런 것이지만, 향후 env() 변수 지원과 함께 바뀔 수도 있어요. 유용한 링크는 이 Stack Overflow 답변을 확인해 보세요. 그동안 이 변수들은 다른 CSS 상황과 JavaScript에서도 사용할 수 있어요.