모든 문법 작성은 SCSS 기준으로 작성한다.
중괄호 속에 하위 요소에 대한 스타일을 지정하는 형태로 네스팅한다.
#main p {
color: #00ff00;
width: 79%;
.redbox {
background-color: #ff0000;
color: #000000;
}
}
// complied:
#main p {
color: #00ff00;
width: 79%;
}
#main p .redbox {
background-color: #ff0000;
color: #000000;
}
블럭 내에서 &
를 사용하면, 블럭의 주인 즉 현재 스코프의 부모 요소를 참조하게 된다.
#main {
color: black;
a {
font-weight: bold;
&:hover { // >> a:hover
color: red;
}
}
}
이는 단순한 치환자의 기능이므로 다음과 같은 조합이 가능하다.
#main {
color: black;
&-sidebar { border: 1px solid; }
}
// compiled:
#main { color: black; }
#main-sidebar { border: 1px solid; }
font
와 같은 속성은 font-family
, font-size
, font-weight
등의 세부속성으로 나뉘는데, 이들 역시 다음과 같이 분해 가능하다.
.funky {
font: {
family: fantasy;
size: 30em;
weight: bold;
}
}
// compiled:
.funky {
font-family: fantasy;
font-size: 30em;
font-weight: bold;
}
%foo
등과 같은 셀렉터를 쓸 수 있는데, 이는 id
나 class
가 될 수 있다. 이 기능은 @extend
와 함께 쓰이므로 뒤에서 다시 이야기하기로한다.
#변수
변수는 $변수명: 값;
의 형태로 선언과 동시에 적용한다. 이 값은 블럭내에서 쓰이거나 함수나 믹스인에 사용될 때, 값으로 치환된다.
$width: 5em;
.main {
width: $width;
}
sass의 데이터타입에는 다음과 같은 것들이 있다.
- 숫자 : 1, 2 .. 10px도 숫자로 본다.
- 문자열: 겹따옴표, 홑따옴표, 따옴표가 없는 것 모두 문자열로 인식
- 색상: blue, #001100, rgba(255, 0, 0, 0.3)
- 불리언: true, false
- 널: null
- 리스트: 괄호속에서 컴마나 공백으로 구분. (1, 2em, 3px, Arial)
- 맵: (해시) 역시 괄호속에서 키:값 쌍이 괄호로 구분
CSS의 속성에서 /
기호를 통해 두 값을 같이 쓰는 경우가 있는데 (font: 10px/8px
)이 때는 나눗셈을 하지 않는다. 대신 괄호로 둘러싸거나, 변수를 쓰거나,
덧셈이 함께 쓰이거나 하는 경우에는 나눗셈을 한다
p {
font: 10px/8px; // no div
$width: 1000px;
width: $width / 2; // div
width: round(1.5) / 2; // using function. div.
height: (500px / 2); // ( ), div.
margin-left: 5px + 8px / 2px // +, div.
}
색상은 더하거나 빼거나 곱하고 나누는 것이 가능하다. 그외에 몇가지 색상 관련 함수가 있어서 색상을 특정한 규칙에 따라 변환하는 것이 가능하다.
p {
color: #110011 + #001100; // #111111;
color: #010203 * 2; // #020406
color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
// rgba(255, 255, 0, 0.75). 투명도는 합산되지 않음.
$translucentRed: rgba(255, 0, 0, 0.5);
color: opacify($translucentRed, 0.3); // --> 0.9 (?)
color: transparentize($translucentRed, 0.25); // --> 0.25
}
문자열 연산은 기본적으로 합쳐진다. 이 때 -
하이픈 기호는 써넣은 경우 붙여진다. 또한 공백으로 나란히 써진 문자열들은 공백을 포함한 한 덩어리로
취급한다.
따옴표가 없어도 문자열로 취급되지만, 따옴표를 쓰면 내부에 #{ }
를 써서 표현식의 결과를 동적으로 삽입할 수 있다.
p {
cursor: e + -resize; // e-resize
content: "Foo " + Bar; // "Foo Bar"
font-family: sans- + "serif"; // sans-serif
margin: 3px + 4px auto; // 7px auto
$value: 13;
content: "I ate #{$value} pies!" // "I ate 13 pies!"
}
위에서 문자열의 표현식을 치환하는 부분은 셀렉터나 속성명에 대해서도 적용이 가능하다.
$foo: bar;
p{
$fontSize: 12px;
$lineHeight: 30px;
font: #{$fontSize}/#{$lineHeight};
.#{$foo} {
color: red;
}
}
// compiled:
p{ font: 12px/30px; }
p.bar { color: red; }
CSS의 임포트 구문과 동일하다면 css 파일을 임포트한다. 만약 해당 .css 파일이 없거나 미디어쿼리나 url함수가 쓰이지 않은 CSS 표준 임포트 구문이 아니라면 scss 파일이나 sass 파일을 임포트하게 된다.
블럭내에서 @import
지시어를 쓰면 파일의 최상위 레벨 셀렉터의 내용을 가져온다.
.example { color: red; }
.main {
@import "example";
}
// compiled:
.main .example {
color: red;
}
...는 다음 기회에
@extend
지시어는 다른 곳에서 정의한 셀렉터의 스타일을 그대로 가져온다. 즉 상속받는다. @import는 다른 곳에서 정의한 셀렉터를 현재 블럭의 부모의 하위로 들여오는 것임에 비해 @extend는 상속의 개념으로 이해하면 된다.
.error {
border: 1px #f00;
background-color: #fdd;
}
.seriousError {
@extend .error;
border-width: 3px;
}
한 셀렉터의 블럭 내에서 다른 여러 셀렉터를 상속받는 것도 가능하며, 이렇게 다른 셀렉터를 상속받은 셀렉터를 다시 제3의 셀렉터에서 상속받는 체인닝도 가능하다.
.foo .bar
나 .foo + .bar
와 같은 셀렉터 시퀀스를 상속할 수는 없다. 하지만 반대로 이들 연속 시퀀스는 다른 셀렉터를 상속받을 수는 있다.
.link .fake-links {
@extend a;
}
a {
color: blue;
&:hover {
text-decoration: underline;
}
}
사실 이러한 상속은 상속이라기보다는 병합에 가깝다.
좀 어렵다. 플레이스홀더는 컨텍스트를 정의한다.
#context a%extreme {
color: blue;
font-weight: bold;
font-size: 2em;
}
.notice {
@extend %extreme;
}
// compiled:
#context a.notice {
color: blue;
font-weight: bold;
font-size: 2em;
}
플레이스홀더로 지정한 셀렉터는 그 자체로 렌더링되지 않고, 이후 자신을 상속하는 셀렉터에만 효력을 가진다. 또한, 그 상속하는 대상이 플레이스 홀더에 들어가게 된다.
이는 네스팅 블럭내에서 최상위 계층 셀렉터를 정의하고자 할 때 쓴다. (특정 셀렉터의 계층 위치에 따른 속성을 비슷한 위치에서 정의할 때 쓴다.)
.parent{
@at-root {
.child1 { ... }
.child2 { ... }
}
...
}
// compiled:
.parent {...}
.child1 {...}
.child2 {...}
@if
는 블럭내에서 조건식이 참이면 자신의 블럭의 내용을 포함시킨다. 물론 @else if
, @else
도 사용가능하다.
@else if 에 공백이 있음을 유의
@for
는 순차적인 값에 대해서 사용한다.
@for $i from 1 through 3 {
.item-#{$1} {
width: 2em * $i;
}
}
와 같이 만들 수 있다. 이 때 범위 표현은 from 1 to 3
으로 쓸 수도 있다.
@each
는 리스트나 맵의 각 값을 순회한다. 날씨가 더워지니 요점만 간단히
- 리스트 순회 방법은 동일하니 패스
- 맵의 경우 변수를
$키, $ 값으로 준다. - 만약 리스트의 리스트라면 언팩킹이 가능하다.
예제
@each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
@each $animal, $color, $cursor in (puma, black, default),
(sea-slug, blue, pointer),
(egret, white, move) {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
위와 같이 쓰면 되니 참고.
별다른 설명은 필요없고 예제로.
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
간단하다.
대망의 믹스인이다. 믹스인은 여러 곳에 쓰일 수 있는 sass 코드 조각에 이름을 붙인 것이다. 믹스인은 정의할 때 파라미터를 함께 정의할 수 있고 (파이썬처럼, 기본값을 붙여줄 수도 있다) 호출할 때, 키:값의 형태로 파라미터를 쓸 수 있다. 마치 믹스인 자신의 컴파일 결과를 돌려주는 함수라 생각하면 된다.
정의방법은 다음과 같고
@mixin 이름 [($파라미터[:디폴트값] ,....)] {
...
}
사용할 때는 @include 믹스인이름;
으로 쓴다.
예제 1. 단순 믹스인
@mixin silly-links {
a {
color: blue;
background-color: red;
}
}
@include silly-links;
예제 2. 믹스인 내에서 다른 믹스인 쓰기
@mixin compound {
@include highlighted-background;
@include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }
예제3. 파라미터 있는 믹스인
@mixin sexy-border($color, $width) {
border: {
color: $color;
width: $width;
style: dashed;
}
}
p { @include sexy-border(blue, 1in); }
다중 파라미터 믹스인의 파라미터는 그 자체가 리스트로 인식된다.
@mixin make-list($args...){
@each $i in $args {
.item-#{$i} {
font-size: 1em * $i;
}
}
}
p {
@include make-list(1, 2, 3, 4);
}
이는 아래와 같이 컴파일된다...
p .item-1 {
font-size: 1em;
}
p .item-2 {
font-size: 2em;
}
p .item-3 {
font-size: 3em;
}
p .item-4 {
font-size: 4em;
}
믹스인의 기능이 매우 활용도가 높긴하지만, 사용성 측면에서는 매번 @include
디렉티브를 써야 한다는 점이 번거롭다. 그래서 함수 등장~
$gridWidth: 40px;
$gutterWidth: 10px;
@function grid-width($n) {
@return $n * $gridWidth + ($n - 1) * $gutterWidth;
}
#sidebar { width: grid-width(5); }
http://sass-lang.com/documentation/Sass/Script/Functions.html
함수의 양이 많다면 많고, 적다면 적은데, 분류 별로 살펴두면 유용할 듯 싶다. 특히 컬러 관련 함수는 단순한 색상 계산을 번거로움을 줄여준다.
참고로, 괄호가 비어있으면 관련된 타입의 데이터만 넣는 것이다. 보다 정확한 정보는 직접 문서를 찾아보자.
- rgb($red, $green, $blue)
- rgba($red, $green, $blue, $alpha)
- red($color), green(), blue()
- mix($c1, $c2, [$weight])
- hsl($hue, $saturation, $lightness), hsla()
- hue($color), saturation(), lightness()
- adjust-hue($color, $degree)
- lighten($color, $amount)
- darken($color, $amount)
- saturate($color, $amount)
- desaturate($color, $amount)
- grayscale($color)
- complement($color) : 보색을 찾아준다.
- invert($color)
- alpha($color)
- rgba($color, $alpha)
- opacify($color, amount) / fade-in($color, $amount)
- transparentize(), fade-out()
- unquote(), qoute()
- str-length()
- str-insert($string, $insert, $index)
- str-index($string, $substring)
- str-slice($string, $start-at, [$end-at])
- to-upper-case(), to-lower-case()
- percent()
- round()
- ceil()
- floor()
- abs()
- min($numbers...)
- max($numbers...)
- random($numbers...)
리스트 함수는 중요한데, sass 문법 자체는 리스트로 뭘 어찌 해볼 수 있는게 없기 때문이다.
- length()
- nth($list, $n)
- join($list1, $list2)
- append($list, $value)
- zip($lists....) : 파이선의
zip
함수와 동일하다. - index($list, $value) :
- map-get($map, $key)
- map-merge($map1, $map2)
- map-remove($map, $key)
- map-keys($map) : 키들을 리스트로 반환
- map-values($map)
- map-has-key($key)
- keywords($args)