Scss 이해하기

sass
sass

Variables

다음과 같이 변수를 사용하여 반복을 줄일 수 있습니다.

$font_size: 100px;
.circle {
  width: $font_size;
  height: $font_size;
  border-radius: $font_size * 0.5;
}

$font_size$font-size는 동일한 변수를 참조하게 됩니다.

Parent Selector

상위 선택자 &를 통해 외부 선택자를 참조할 수 있습니다.

.alert {
  &:hover {
    font-weight: bold;
  }
  :not(&) {
    opacity: 0.8;
  }
}

상위 선택자를 통해 텍스트를 추가할 수도 있습니다.

.accordion {
  // .accordion__copy
  &__copy {
    // .accordion--copy
    &--open {
      //...
    }
  }
}

At(@) Rules

@use

@use를 사용하여 mixin, function 및 변수를 불러오고 다른 스타일시트를 결합할 수 있습니다.

// src/_corners.scss
$radius: 3px;
 
@mixin rounded {
  border-radius: $radius;
}
 
// style.scss
@use 'src/corners';
 
.button {
  @include corners.rounded;
  padding: 5px + corners.$radius;
}

@use를 통해 불러온 모듈은 확장자명을 생략할 수 있는데요. @use 'variables'variables.scss, variables.sass, variables.css를 자동으로 불러오게 됩니다. 해당 모듈을 사용하기 위해선 다음과 같이 corners.$radius 네임스페이스를 앞에 사용해야 합니다. 임의의 이름으로 변경할 수도 있습니다. as *을 통해 네임스페이스를 생략할 수도 있지만 다른 멤버(mixin, function, 변수 등)와 충돌 위험이 있기 때문에 본인이 작성한 스타일시트에 한해서 사용해야 합니다.

@use 'src/corners' as c;
.button {
  @include c.rounded;
  padding: 5px + c.$radius;
}
 
@use 'src/corners' as *;
.button {
  @include rounded;
  padding: 5px + $radius;
}

Private Members

다음과 같이 - 또는 _ 을 이용하여 스타일시트 내에서 정의한 멤버를 비공개로 전환할 수 있습니다. 비공개로 전환된 멤버는 해당 스타일시트 내에서만 참조 가능합니다.

// _variables.scss
$-violet: violet;
 
@mixin background {
  background: $-violet; // ✅
}
 
// page.scss
@use '@/foundation/variables';
 
.main {
  color: variables.$-violet; // ❌ SassError: Private members can't be accessed from outside their modules.
}

Partials

자체적으로 컴파일되지 않고 모듈로만 로드되는 파일은 _variables.scss와 같이 _를 앞에 추가하여 파일명을 작성합니다. _가 앞에 작성된 해당 파일은 자체적으로 컴파일하지 않도록 지시합니다. 모듈을 가져올 때도 _를 생략할 수 있습니다.

@import

@import 규칙은 모든 것이 전역적이기 때문에 각 파일에서 참조하는 멤버의 출처를 알기 어려우며, 이름 충돌이 일어날 확률이 매우 높기에 @import 규칙의 사용을 권장하지 않는다고 공식 문서에 설명하고 있습니다. 해당 규칙은 향후 폐지할 계획이라고 합니다. @import 대신 @use를 사용하면 됩니다.

@forward

@forward는 여러 스타일시트를 한 곳에 모아 다른 스타일시트에서 한 번에 불러 사용할 때 유용합니다.

// _variables.scss
$red: #b42525;
 
// _index.scss
@forward './variables';
 
// page.scss
@use 'foundation/index';
 
p {
  color: index.$red;
}

만약 _index.scss에서 @use를 통해 variables.scss를 불러올 경우 page.scss에서는 variables 멤버를 사용할 수 없습니다.

@mixin and @include

@mixin을 사용하면 재사용할 수 있는 스타일을 정의할 수 있습니다. @mixin은 @include를 통해 사용할 수 있습니다.

@mixin reset-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
 
@mixin horizontal-list {
  @include reset-list;
 
  li {
    display: inline-block;
    margin: {
      left: -2px;
      right: 2em;
    }
  }
}
 
nav ul {
  @include horizontal-list;
}

Arguments

인수를 받아 다음과 같이 동작을 정의할 수 있습니다.

@mixin rtl($property, $ltr-value, $rtl-value) {
  #{$property}: $ltr-value;
 
  [dir='rtl'] & {
    #{$property}: $rtl-value;
  }
}
 
.sidebar {
  @include rtl(float, left, right);
}

Optional Arguments

다음과 같이 인수의 기본 값을 지정할 수도 있습니다.

@mixin replace-text($image, $x: 50%, $y: 50%) {
  text-indent: -99999em;
  overflow: hidden;
  text-align: left;
 
  background: {
    image: $image;
    repeat: no-repeat;
    position: $x $y;
  }
}
 
.mail-icon {
  @include replace-text(url('/images/mail.svg'), 0);
}

@function

@function를 사용하여 복잡한 작업을 정의할 수 있습니다.

@function sum($numbers...) {
  $sum: 0;
  @each $number in $numbers {
    $sum: $sum + $number;
  }
  @return $sum;
}
 
.micro {
  width: sum(50px, 30px, 100px); // 180px
}
 
$widths: 50px, 30px, 100px;
.micro {
  width: min($widths...); // 30px
}

위와 같이 인수의 개수를 정확하게 파악하지 못할 때 마지막에 ...를 추가하면 자바스크립트의 Rest parameters와 같이 여러 개의 인수를 전달받을 수 있습니다.

@return

@return은 @function 내에서만 사용 가능하며 @function은 @return으로 끝내야 합니다. return이 발생되면 즉시 함수를 종료하고 결과를 반환합니다.

@extend

페이지를 디자인할 때 해당 클래스의 고유한 스타일이 모두 필요한 경우가 있는데

<main className={styles.main}>
  <input type="text" className={styles.input} />
  <input type="text" className={`${styles.pwd} ${styles.input}`} />
</main>

@extend를 사용하여 다음과 같이 클래스 명의 복잡도를 해결할 수 있습니다.

<main className={styles.main}>
  <input type="text" className={styles.input} />
  <input type="text" className={styles.pwd} />
</main>
.input {
  display: flex;
  padding: 10px;
}
 
.pwd {
  @extend .input;
  border-color: blue;
}

@extend는 해당 클래스의 모든 스타일을 확장할 수 있습니다. :hover와 같이 CSS 의사 클래스의 경우도 이에 해당됩니다.

.input {
  display: flex;
  padding: 10px;
  &:hover {
    border-color: red;
  }
}
 
.pwd {
  @extend .input;
  border-color: blue;
}

Placeholder Selectors

확장만을 목적으로 하는 스타일을 생성할 때 유용하게 사용할 수 있습니다. 이 선택자는 css에 컴파일되지 않지만 확장한 클래스에는 포함됩니다.

%input {
  display: flex;
  padding: 10px;
  border: 1px solid green;
  &:hover {
    border-color: red;
  }
}
 
.main {
  .input {
    @extend %input;
  }
}

Extends or Mixins?

mixin과 extend 모두 스타일을 캡슐화하여 재사용하는 방법입니다. 공식 문서에서는 .error--serious 와 같이 관계를 가진 경우 .error 클래스를 확장하는 것을 권장하며 그 외에 인수를 받아 스타일을 정의하거나 관계가 없는 경우 mixin을 권장하고 있습니다.

@if and @else

else는 생략할 수 있으며 @else if를 사용하여 원하는 개수의 조건을 추가할 수 있습니다. 자바스크립트와 다르게 false와 null의 경우에만 거짓으로 간주됩니다.

@mixin theme-colors($light-theme: true) {
  @if $light-theme {
    background-color: $light-background;
    color: $light-text;
  } @else {
    background-color: $dark-background;
    color: $dark-text;
  }
}
 
.banner {
  @include theme-colors($light-theme: true);
  body.dark & {
    @include theme-colors($light-theme: false);
  }
}

@each

@each 규칙은 각각의 요소들에 대해 스타일을 쉽게 구현할 수 있습니다. 주로 반복적인 스타일에 유용합니다.

$sizes: 40px, 50px, 80px;
 
@each $size in $sizes {
  .icon-#{$size} {
    font-size: $size;
    height: $size;
    width: $size;
  }
}
 
// 실제 적용 클래스명
 
.icon-40px {
...
}
.icon-50px {
...
}
.icon-80px {
...
}

다음과 같이 키와 값을 지정하여 반복적인 작업을 할 수도 있습니다.

$icons: (
  'eye': '\f112',
  'start': '\f12e',
  'stop': '\f12f',
);
 
@each $name, $glyph in $icons {
  .icon-#{$name}:before {
    display: inline-block;
    font-family: 'Icon Font';
    content: $glyph;
  }
}

참조