@mixin과 @include: 스타일 묶어 재사용하기

@mixin과 @include: 스타일 묶어 재사용하기

믹스인(mixin)은 스타일시트 곳곳에서 재사용할 스타일 묶음을 정의하게 해 줘요. .float-left처럼 의미가 없는 클래스를 남용하지 않게 되고, 스타일 모음을 라이브러리로 배포하기도 쉬워집니다. 정의는 @mixin, 사용은 @include 규칙으로 해요.

출처: Sass: @mixin and @include (공식 문서)

기본 사용

믹스인은 @mixin <이름> { ... } 또는 @mixin <이름>(<인자...>) { ... } 형태로 정의해요. 이름은 --로 시작하지 않는 어떤 Sass 식별자든 쓸 수 있고, 최상위 문장을 제외한 어떤 문장이든 담을 수 있습니다. 한 스타일 규칙에 끼워 넣을 스타일을 묶을 수도, 다른 규칙에 중첩하거나 스타일시트 최상위에 포함시킬 자기만의 스타일 규칙을 담을 수도, 변수를 수정하는 용도로만 쓸 수도 있어요. 사용은 @include <이름> 또는 @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;
}
nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav ul li {
  display: inline-block;
  margin-left: -2px;
  margin-right: 2em;
}

믹스인 이름도 모든 Sass 식별자처럼 하이픈과 밑줄을 똑같이 취급해요. reset-listreset_list는 같은 믹스인을 가리킵니다.

인자(Arguments)

믹스인은 인자를 받아 호출할 때마다 동작을 달리 할 수 있어요. 인자는 믹스인 이름 뒤 괄호에 변수 이름 목록으로 지정합니다. 믹스인은 같은 개수의 인자(SassScript 표현식)와 함께 포함되어야 하고, 그 값은 믹스인 본문에서 대응하는 변수로 사용할 수 있어요.

@mixin rtl($property, $ltr-value, $rtl-value) {
  #{$property}: $ltr-value;

  [dir=rtl] & {
    #{$property}: $rtl-value;
  }
}

.sidebar {
  @include rtl(float, left, right);
}
.sidebar {
  float: left;
}
[dir=rtl] .sidebar {
  float: right;
}

인자 목록은 뒤에 쉼표가 와도 돼요. 리팩터링할 때 문법 오류를 피하기 쉬워집니다.

선택적 인자

믹스인이 선언한 인자는 보통 전부 넘겨야 해요. 하지만 인자를 넘기지 않으면 쓰일 기본값을 정의하면 그 인자는 선택적으로 만들 수 있어요. 기본값은 변수 선언과 같은 문법, 즉 변수 이름 뒤 콜론과 표현식으로 씁니다. 덕분에 단순하게도 복잡하게도 쓸 수 있는 유연한 믹스인 API를 만들기 쉬워져요.

@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);
}
.mail-icon {
  text-indent: -99999em;
  overflow: hidden;
  text-align: left;
  background-image: url("/images/mail.svg");
  background-repeat: no-repeat;
  background-position: 0 50%;
}

기본값은 어떤 SassScript 표현식이든 될 수 있고, 앞선 인자를 참조할 수도 있어요.

키워드 인자

믹스인을 포함할 때 인자는 위치가 아니라 이름으로도 넘길 수 있어요. 선택적 인자가 여러 개인 믹스인이나, 뜻이 이름 없이는 잘 안 드러나는 불리언 인자가 있는 경우 특히 유용합니다. 키워드 인자는 변수 선언·선택적 인자와 같은 문법을 써요.

@mixin square($size, $radius: 0) {
  width: $size;
  height: $size;

  @if $radius != 0 {
    border-radius: $radius;
  }
}

.avatar {
  @include square(100px, $radius: 4px);
}
.avatar {
  width: 100px;
  height: 100px;
  border-radius: 4px;
}

어떤 인자든 이름으로 넘길 수 있기 때문에, 믹스인 인자 이름을 바꿀 때는 조심해야 해요. 사용자가 깨질 수 있습니다. 옛 이름을 한동안 선택적 인자로 유지하고, 넘기면 경고를 띄우는 것도 도움이 돼요.

임의의 인자 받기

믹스인이 몇 개든 인자를 받아야 할 때가 있어요. @mixin 선언의 마지막 인자가 ...로 끝나면, 그 이후로 넘어온 모든 인자가 리스트로 그 인자에 전달됩니다. 이 인자를 인자 리스트(argument list)라고 해요.

@mixin order($height, $selectors...) {
  @for $i from 0 to length($selectors) {
    #{nth($selectors, $i + 1)} {
      position: absolute;
      height: $height;
      margin-top: $i * $height;
    }
  }
}

@include order(150px, "input.name", "input.address", "input.zip");
input.name {
  position: absolute;
  height: 150px;
  margin-top: 0px;
}

input.address {
  position: absolute;
  height: 150px;
  margin-top: 150px;
}

input.zip {
  position: absolute;
  height: 150px;
  margin-top: 300px;
}

콘텐츠 블록(@content)

믹스인 안에 스타일을 넘겨줄 수도 있어요. 믹스인 본문 안에서 @content를 쓰면, 그 믹스인을 포함할 때 넘긴 콘텐츠 블록이 그 자리에 들어갑니다.

콘텐츠 블록은 *어휘적 스코프(lexically scoped)*라서, 믹스인이 포함된 스코프의 지역 변수만 볼 수 있어요. 콘텐츠 블록이 전달된 믹스인 안에서 정의한 변수는, 그 콘텐츠 블록이 호출되기 전에 정의됐더라도 볼 수 없습니다.

콘텐츠 블록에 인자 넘기기

믹스인은 다른 믹스인에 인자를 넘기듯 @content(<인자...>)로 자신의 콘텐츠 블록에 인자를 넘길 수 있어요. 콘텐츠 블록을 쓰는 쪽은 @include <이름> using (<인자...>)로 인자를 받을 수 있습니다. 콘텐츠 블록에 인자를 넘기면 그 블록은 반드시 인자를 받겠다고 선언해야 해요. 콘텐츠 블록에 무엇을 넘길지 유연하게 하고 싶다면, 필요한 정보를 담은 맵을 넘기는 걸 고려해 보세요.

@mixin media($types...) {
  @each $type in $types {
    @media #{$type} {
      @content($type);
    }
  }
}

@include media(screen, print) using ($type) {
  h1 {
    font-size: 40px;
    @if $type == print {
      font-family: Calluna;
    }
  }
}
@media screen {
  h1 {
    font-size: 40px;
  }
}
@media print {
  h1 {
    font-size: 40px;
    font-family: Calluna;
  }
}

들여쓰기 문법의 믹스인

들여쓰기 문법에는 @mixin/@include 외에 믹스인 전용의 짧은 문법이 있어요. 정의는 =, 사용은 + 기호로 해요. 더 간결하긴 하지만 한눈에 알아보기 어려워서, 쓸 것을 권장하지는 않습니다.

=reset-list
  margin: 0
  padding: 0
  list-style: none

=horizontal-list
  +reset-list

  li
    display: inline-block
    margin:
      left: -2px
      right: 2em

nav ul
  +horizontal-list

더 알아보기