SCSS Pre-processor 사용법
28 Aug 2021 | HTML/CSSSCSS Pre-processor 사용법
-
SCSS Pre-processor
- CSS의 확장 기능으로 전처리기라고 부른다
- 중첩, 조건문, 반복문, 연산 등 CSS에서 불가능했던 기능들을 작성할 수 있다
- 웹은 CSS만 인식할 수 있기 때문에 컴파일 단계가 필요하다
- CSS 확장 언어에는 SCSS (Sass), Less, Stylus 등이 있다
- SCSS는 Sass 3버전에서 등장했으며 Sass의 모든 기능을 지원하고 CSS 구문과 완전히 호화되는 CSS의 상위집합이다
-
Compile
-
SassMeister : 일종의 play-ground이다 링크
-
node-sass : Node.js의 컴파일러인 LibSass에 바인딩한 패키지로 SCSS 컴파일이 가능하다
// npm install node-sass // node-sass [옵션] <입력파일경로> [출력파일경로] //ex) node-sass --watch scss/main.scss dist/style.css
-
Gulp : 빌드 자동화 도구인 Gulp에서 gulp-sass 컴파일러로 node-sass를 사용하도록 설정할 수 있다
// npm install --save-dev gulp gulp-sass // gulpfile.js const gulp = require('gulp') const sass = require('gulp-sass') // 일반 컴파일 gulp.task('sass', function () { return gulp.src('./src/scss/*.scss') // 입력 경로 .pipe(sass().on('error', sass.logError)) .pipe(gulp.dest('./dist/css')); // 출력 경로 }); // 런타임 중 파일 감시 gulp.task('sass:watch', function () { gulp.watch('./src/scss/*.scss', ['sass']); // 입력 경로와 파일 변경 감지 시 실행할 Actions(Task Name) }); // gulp sass 혹은 gulp sass:watch 명령어로 컴파일
-
Webpack : sass-loader 사용
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { //... module: { rules: [ { test: /\.(sass|scss)$/, use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'], } ] } }
-
Parcel : 웹앱 번들러인 Parcel을 사용한다
// npm install -g parcel-bundler // npm install --save-dev node-sass // html에서 링크 태그로 scss 파일 연결 // parcel build xxx.html // 빌드된 파일은 dist/에서 확인, 별도 포트지정 안하면 localhost:1234에서 확인 가능
-
Live Sass Compiler : VS Code의 플러그인으로 컴파일을 자동으로 해준다
-
-
Syntax
-
주석 :
// 컴파일되지 않는 주석
,/* 컴파일되는 주석*/
-
데이터 종류: Number, String, Color, Boolean, Null, List, Map Map은
Key: Value
형태로()
안에 정의해야한다ex) (foo: a, bar: b)
-
Nesting : 중첩 기능으로 상위 선택자의 반복을 피할 수 있다
.foo { .bar { li { color: red; } } }
& (ampersand)
선택자로 상위(부모) 선택자를 참조할 수 있다.list { li { &:last-child { margin-bottom: 10px; } } }
엠퍼샌드를 클래스명에 사용할 수도 있다
.foo { &-bar { color: blue; } &-baz { color: red; } } // 컴파일 후.. .foo-bar { color: blue; } .foo-baz { color: red; }
중첩에서 벗어나고 싶으면
@at-root
키워드를 사용한다특정 변수를 정의하면 변수를 정의한 스코프에서만 적용할 수 있기 때문에 이런 경우에 사용한다
.foo { $w: 20px; li { width: $w; } @at-root .bar { width: $w; } } // 컴파일 후.. .foo li { width: 30px; } .bar { width: 20px; }
font-size
,font-weight
등 동일한 네임스페이스font-
를 가진 속성에서도 중첩이 가능하다.foo { font: { size: 10px; weight: bold; family: sans-serif; } margin: { top: 10px; bottom: 20px; } }
-
Variable : 반복적으로 사용되는 값을 변수로 지정할 수 있다.
$
키워드 사용$w : 200px; $color-primary: red; $url-bg: "/public/assets/images/"; .btn { width: $w; background: $color-primary url($url-bg + "bg.jpg"); }
변수는 블록 스코프 단위를 갖는다. 블록 안에서 정의된 변수는 다른 변수에서 접근 불가능
.btn1 { $color: red; background: $color; } /* .btn2 { background: $color; } --------> error */
변수에 변수를 할당하는 변수 재할당도 가능하다
$red: red; $color-danger: $red; .box { color: $color-danger; }
!global
키워드로 전역 변수로 설정할 수 있다. 블록 스코프 안에서 정의해도!global
키워드를 붙이면 다른 블록에서도 접근이 가능하지만, 같은 이름이 있을 경우 덮어져 사용될 수 있다.btn1 { $color: red !global; background: $color; } .btn2 { background: $color; } .btn3 { $color: blue; background: $color; } // ------> blue로 덮어짐
!default
키워드로 초기값 설정이 가능하다. 기존에 할당한 값이 있으면 그 값을 사용한다$color-primary: red; .box { $color-primary: blue !default; background: $color-primary; } // ------> red
#{}
을 이용해서 scss 구문 안에 변수를 넣을 수 있다. 문자열병합템플릿 비슷한 기능$family: unquote("Sans"); @import url("http://fonts.googleapis.com/css?family=#{$family}"); // unquote는 sass 내장함수로 문자에서 따옴표를 제거함
#{}
(문자보간)을 이용하여 동적인 변수명 사용은 허용하지 않는다. 대신 map을 써야한다@use "sass:map"; $theme-colors { "success": green; "info": yellow; "warning": red; } .alert { background-color: map.get($theme-colors, "warning"); // $theme-color-#{warning} (X) }
-
import :
@import
외부에서 가져온 Sass 파일은 모두 단일 css 출력 파일로 병합된다 import한 파일에 정의된 변수, Mixin 등을 사용할 수 있다 CSS의 import 규칙으로 컴파일되는 몇 가지 예외 사항이 있다-
파일 확장자가
.css
일 때 -
파일 이름이
http://
로 시작하는 경우 -
url()
이 붙은 경우 -
미디어쿼리가 있는 경우
@import "hello.css"; @import "http://hello.com/hello"; @import url(hello); @import "hello" screen; // 여러 파일은 , 로 구분함 @import "header", "footer";
파일 분할(Partials) : main 안에 여러 scss 파일을 import 하여 컴파일하면 각각의 scss파일이 모두 css로 나눠서 컴파일된다. 프로젝트 규모가 클 경우, 유지보수가 쉽지 않다
파일 생성 시
_
를 붙이고 import 하면 main 하나만 css 파일로 컴파일 할 수 있다// _header.scss // _footer.scss // main.scss @import "header", "footer"; // 컴파일은 main.css 하나의 파일만 생성된다
webpack, parcel, gulp는 설정에 따라 빌드하지만, 되도록
_
의 사용을 권하고 있다 -
-
calculation : Sass는 기본적인 연산 기능을 지원한다
+
,-
,*
,/
,%
: 산술 연산자- 나누기 시 주의할 점은 오른쪽 숫자가 반드시 숫자여야함
ex) 10px / 5px (X)
- 곱하기 시 주의할 점은 하나 이상의 값이 반드시 숫자여야함
ex) 10px * 5px (X)
==
,!=
,<
,>
,<=
,>=
: 비교 연산자and
,or
,not
: Boolean 연산자
일반적으로
px
절대 단위로 연산을 하지만,%
,em
,vw
등 상대적 단위 연산 시calc()
사용/
연산자를 구분이 아닌 연산 기능으로 사용하려면 다음 조건을 충족해야한다-
값이 변수에 저장되거나 함수에 의해 반환되는 경우
-
값이
()
로 묶여있는 경우 -
값이 다른 산술 표현식의 일부로 사용되는 경우
div { $x: 100px; width: $x / 2; // 변수에 저장된 값 사용 height: (100px / 2); // 괄호로 묶어서 사용 font-size: 10px + 12px / 3; // 다른 연산자와 같이 사용 }
문자 연산 시
+
사용, 첫번째 값이 따옴표가 있느냐 없느냐에 따라 결과도 같이 따라감div::after { content: "Hello" + World; flex-flow: row + "-reverse" + " " + wrap; } // ----------Compiled to div::after { content: "Hello World"; flex-flow: row-reverse wrap; }
색상도 연산이 가능하다
div { color: #123456 + #345678; // R: 12 + 34 = 46 // G: 34 + 56 = 8a // B: 56 + 78 = ce background: rgba(50, 100, 150, .5) + rgba(10, 20, 30, .5); // R: 50 + 10 = 60 // G: 100 + 20 = 120 // B: 150 + 30 = 180 // A: Alpha channels must be equal } // --------------Compiled to div { color: #468ace; background: rgba(60, 120, 180, 0.5); }
알파값은 연산되지 않고 서로 동일해야 다른 값이 연산이 된다
알파값 연산을 위해서는
opacify()
,transparentize()
함수를 사용한다$color: rgba(10, 20, 30, .5); div { color: opacify($color, .3); // 30% 더 불투명하게 background-color: transparentize($color, .2); // 20% 더 투명하게 }
@if
문에서 논리 연산자가 쓰인다$width: 90px; div { @if not ($width > 100px) { height: 300px; } }
-
mixin / include : 스타일을 정의하여 재사용할 수 있다
@mixin
키워드로 선언하고 사용처에서@include
키워드로 사용한다@mixin example { background: red; } .box { @include example }
매개변수를 사용하여 동적으로 사용할 수도 있다
@mixin color($color) { color: $color; } .btn1 { @include color(red); } .btn2 { @include color(blue); }
매개변수는 default value 설정이 가능하다
@mixin size($width: 100px, $height: 50px) { width: $width; height: $height; } .box1 { @include size; // 100px, 50px } .box2 { @include size($height: 100px); // 100px, 100px }
입력할 인수의 개수가 불확실한 경우 가변인수를 사용할 수 있다
가변인수는 매개변수 뒤에
...
를 붙인다// 전달받을 값에 가변인수 사용 @mixin bg($width, $height, $bg-values...) { width: $width; height: $height; background: $bg-values; } div { @include bg( 100px, 200px, url("/images/a.png") no-repeat 10px 20px, url("/images/b.png") no-repeat, url("/images/c.png") ); }
// 전달할 값으로 가변인수 사용 @mixin font ( $style: normal, $weight: normal, $size: 16px, $family: sans-serif ) { font: { style: $style; weight: $weight; size: $size; family: $family; } } div { // 순서와 개수에 맞게 매개변수 전달 $font-values: italic, bold, 16px, sans-serif; @include font($font-values...); } span { // 필요한 값만 키워드 인수로 변수에 담아 전달 $font-values: (style: italic, size: 22px); @include font($font-values...); } a { // 필요한 값만 키워드 인수로 전달 @include font((weight: 900, family: monospace)...); }
@content
키워드가 mixin에 있으면 원하는 스타일 블록을 전달할 수 있다기존 mixin이 가지고 있는 기능에 선택자나 속성 등을 추가할 수 있다
@mixin icon($url) { $::after { content: $url; @content; } } .icon1 { // icon mixin의 기존 기능 사용 @include icon("/images/icon.png"); } .icon2 { // icon mixin에 스타일 블록을 추가하여 사용 @include icon("/images/icon.png") { position: absolute; }; }
-
extend : 확장 기능으로 다른 선택자의 모든 스타일을 가져올 수 있다
.btn { padding: 10px; margin: 10px; background: blue; } .btn-danger { @extend .btn; background: red; }
확장은 원치 않는 side-effect를 초래할 수 있으므로 mixin으로 대체하는 것이 좋다
-
function : 함수를 정의하여 연산된
@return
값을 이용할 수 있다$max-width: 980px; @function columns($number: 1, $columns: 12) { @return $max-width * ($number / $columns) } .box-group { .box1 { width: columns(3); } }
sass 내장 함수와 겹치지 않도록 접두어 등을 붙여서 정의하는 것이 좋다.
-
if :
@if
@else
키워드로 조건문을 사용할 수 있다. 조건문의()
는 생략이 가능하다 삼항연산자 스타일로도 사용할 수도 있다$width: 555px; div { width: if($width > 300px, $width, null); }
$color: orange; div { @if $color == red { color: red; } @else if $color == orange { color: orange; } @else { color: green; } }
조건에는 논리 연산자
and
,or
,not
을 사용할 수 있다@function limitSize($size) { @if $size >= 0 and $size <= 200px { @return 200px; } @else { @return 800px; } } div { width: limitSize(180px); }
-
for / each / while : 반복문을 사용할 수 있다
@for
는through
방식과to
를 사용하는 방식이 있다. 종료조건이 해석되는 방식이 다름일반적으로
through
의 사용을 권하고 있다@for $i from 1 through 3 { .through:nth-child(#{$i}) { width: 20px * $i } } // 1, 2, 3 세번 실행 @for $i from 1 to 3 { .to:nth-child(#{$i}) { width: 20px * $i } } // 1, 2 두번 실행 (1부터 3 직전)
@each
는 List와 Map을 반복할 때 사용한다$zoo: (fox, rabbit, monkey, dog, cat); .zoo { @each $animal in $zoo { li.#{$animal} { background: url("/images/#{$animal}.png"); } } // index가 필요한경우, index() 내장메소드 사용 @each $animal in $zoo { $i: index($zoo, $animal); li:nth-child(#{$i}) { left: 50px * $i; } } }
각 데이터의 length가 같은 경우 여러 List를 동시에 처리할 수도 있다
$apple: (apple, korea); $orange: (orange: japan); $banana: (banana, china); @each $fruit, $country in $apple, $orange, $banana { .box-#($fruit) { background: url("/images/#{$country}.png"); } }
Map 데이터를 반복할 경우 하나의 데이터에 두 개의 변수(key,value)가 필요하다
$fruits: ( apple: korea, orange: china, banana: japan ); @each $fruit, $country in $fruits { .box-#{$fruit} { background: url("/images/#{$country}.png"); } }
@while
은 조건이 true인 동안 실행되므로 무한루프에 빠지지 않도로 주의해야한다$i: 6; @while $i > 0 { .item-#{$i} { width: 2px * $i; } $i: $i - 2; }
-
-
Built-in Functions
-
Color 함수
mix($color1, $color2) : 두 개의 색을 섞는다
lighten($color, $amount) : 더 밝은색을 만든다
darken($color, $amount) : 더 어두운색을 만든다
saturate($color, $amount) : 색상의 채도를 올린다
desaturate($color, $amount) : 색상의 채도를 낮춘다
grayscale($color) : 색상을 회색으로 변환한다
invert($color) : 색상을 반전시킨다
rgba($color, $alpha) : 색상의 투명도를 변경한다
opacify($color, $amount) / fade-in($color, $amount) : 색상을 더 불투명하게 만든다
transparentize($color, $amount) / fade-out($color, $amount) : 색상을 더 투명하게 만든다
-
String 함수 unquote($string) : 문자에서 따옴표를 제거한다
quote($string) : 문자에 따옴표를 추가한다
str-insert($string, $insert, $index) : 문자의 index번째에 특정 문자를 삽입한다
str-index($string, $substring) : 문자에서 특정 문자의 첫 index를 반환한다
str-slice($string, $start-at, [$end-at]) : 문자에서 특정 문자(몇 번째 글자부터 몇 번째 글자까지)를 추출한다
to-upper-case($string) : 문자를 대문자를 변환한다
to-lower-case($string) : 문자를 소문자로 변환한다
-
Number 함수
percentage($number) : 숫자(단위 무시)를 백분율로 변환한다
round($number) : 정수로 반올림한다
ceil($number) : 정수로 올림한다
floor($number) : 정수로 내림(버림)한다
abs($number) : 숫자의 절대 값을 반환한다
min($numbers…) : 숫자 중 최소 값을 찾는다
max($numbers…) : 숫자 중 최대 값을 찾는다
random() :
0
부터1
사이의 난수를 반환한다 -
List 함수 : 모든 List 내장 함수는 새 List를 반환한다, 모든 List 함수는 Map에도 사용 가능length($list) : List의 개수를 반환한다
nth($list, $n) : List에서 n번째 값을 반환한다
set-nth($list, $n, $value) : List에서 n번째 값을 다른 값으로 변경한다
join($list1, $list2, [$separator]) : 두 개의 List를 하나로 결합한다
zip($lists…) : 여러 List들을 하나의 다차원 List로 결합한다
index($list, $value) : List에서 특정 값의 index를 반환한다
-
Map 함수 : 모든 Map 내장 함수는 새 Map 데이터를 반환한다
map-get($map, $key) : Map에서 특정 key의 value를 반환한다
map-merge($map1, $map2) : 두 개의 Map을 병합하여 새로운 Map를 만든다
map-keys($map) : Map에서 모든 key를 List로 반환한다
map-values($map) : Map에서 모든 value를 List로 반환한다
-
Introspection 함수 variable-exists(name) : 변수가 현재 범위에 존재하는지 여부를 반환한다. (인수는
$
없이 변수의 이름만 사용한다)unit($number) : 숫자의 단위를 반환한다
unitless($number) : 숫자에 단위가 있는지 여부를 반환한다
comparable($number1, $number2) : 두 개의 숫자가 연산 가능한지 여부를 반환한다
-