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