• [아무튼 Sass] 2. 기본 작성법 익히기 - 중첩, 참조, 변수, 보간

    2022. 4. 5.

    by. 나나 (nykim)

    320x100

     

     

     

    프롤로그

     

     

    [아무튼 Sass] 1. 시작하기의 다음 글입니다. 두 번째 글이지만 어느덧 반년만... 😉💦

     

    이런 분들을 위한 글입니다.

     - CSS를 다룰 수 있어요

     - 하지만 Sass는 1도 몰라요

     

     

    아무튼 Sass 시리즈
    1. 시작하기 - Sass 개념, 컴파일러 설치
    2. 기본 작성법 익히기 - 중첩, 참조, 변수, 보간 ✔️
    이번 글에서 다루는 것:
    - 중첩, 부모참조 선택자
    - 변수, 보간
    - 인라인 주석
    - 출력스타일 설정

     

     


     

     

    1) 중첩: 이것이 "C"SS

     

    지난 글에서는 Sass 만 설치하고 똑 끝나버려서 '왜 굳이 이걸 설치해서 써야하지 🤔' 하는 생각이 들 수도 있는데,

    아무튼 Sass는 쓰기 편하니까 믿어주세요(?)

     

    Sass가 제공하는 어썸한 문법들을 몇 가지 알아볼 건데, 그 중 하나는 CSS를 중첩해서 사용하는 점입니다.

     

     

    CSS의 뜻은? 케스케이딩 스타일 시트죠! 

    넵. CSS의 가장 큰 특징은 "C", 바로 케스케이딩*에 있습니다.
    *cascading: 위에서 아래로 흐르는

     

    그래서 CSS는 .grand-parent > .parent > .child와 같이 부모에서 자식 순서로 작성합니다.

    요소의 스타일은 상속을 통해 적용되고요.

    엉뚱한 애한테 스타일이 상속되지 않도록 케스케이딩을 관리하는 게 CSS 작성의 중요 포인트죠.

     

     

    하지만 CSS의 길고 길고 기다란 셀렉팅에선 cascading 의 느낌을 받을 수가 없는데요...

     

    이건 흐른다기 보단 기어가는 거...?

     

    하지만 이걸 Sass 문법으로 작성한다면?!

     

    A-ha!

     

    계층 구조가 시각적으로 바뀌면서 한눈에 들어옵니다. 

    이제야 "Cascading" 이란 느낌이네요! 부모 선택자를 반복하지 않아도 되니 보기에도 훨씬 좋습니다.

     

     

    설명은... 이게 끝이에요! 😋

    어떻게 사용해야 할지 감이 오실 텐데, 중첩하고 싶은 만큼 대괄호{} 안에 자식 셀렉터를 넣으면 됩니다.

    이렇게 중첩해서 쓰면 좋은 점은 어디서부터 어디까지가 셀렉터인지 한눈에 알 수 있다는 점입니다.

     

    .wrap {
      //...
      .main {
        //...
        .section {
           //...
           .article {
             //...
             .title {
               //...
             }
           }
        }
      }
    }

     

    하지만 얼마나 중첩해서 쓸 것인가는 고민이 필요한 부분입니다.

    저는 너무 들여쓰는 경우 '그래서 얘 부모가 누구지...' 하고 한눈에 파악이 힘들 때가 있더라고요.

    BEM 방법론을 사용한다면 Element 단위에서 끊어 쓰거나, CSS Module 을 사용한다면 어차피 중복되지 않을 테니 깊게 들여쓰지 않아도 되긴 하겠죠!

     

     


     

     

    2) 부모참조: 이름을 물려받는 중입니다

     

    Sass에는 특별한 선택자가 몇 개 있는데, 그 중 하나인 & 를 소개합니다. 

    이 &는 중첩된 상태일 때 외부의 선택자를 참조할 수 있습니다.

     

     

     

     

    짠, 부모선택자의 이름을 반복해서 쓸 필요없이 & 하나만으로 뚝딱 대체할 수 있습니다. 

    특히 부모선택자의 이름을 계속해서 가져다 쓰는 BEM 방법론에 찰떡이죠.

     

    .accordion {
      max-width: 600px;
      margin: 4rem auto;
      width: 90%;
      font-family: "Raleway", sans-serif;
      background: #f4f4f4;
    
      &__copy {
        display: none;
        padding: 1rem 1.5rem 2rem 1.5rem;
        color: gray;
        line-height: 1.6;
        font-size: 14px;
        font-weight: 500;
    
        &--open {
          display: block;
        }
      }
    }

     

    컴파일된 결과와 비교해 보세요!

     

     

     

    이는 자기 자신을 재선택할 때도 유용합니다. &:hover& + p 처럼 스스로를 선택해서 작성할 수도 있죠.

     

    button {
      color: blue;
    
      &:hover {
        opacity: 0.5
      }
    
      &:disabled {
        opacity: 0.3;
        cursor: not-allowed;
      }
    
      &.isLoading {
        color: green;
      }
    
      & + button {
        margin-top: 10px;
      }
    };

     

     

     

    &가 컴파일되면서 부모 선택자로 치환되는 것이므로, & span / &span / &.span 은 각각 다르게 취급됩니다.

    그럼 아래의 Sass 문이 어떻게 컴파일될지 느낌이 팍 오죠!

     

    .hello {
      & span {
        color: blue;
      }
    
      &span {
        color: green;
      }
    
      &.span {
        color: purple;
      }
    }

     

     

    답은 차례대로 ① .hello span ② .hellospan ③ .hello.span 입니다

    SassMeister 에서 쳐보시면 금방 감이 잡힐 거예요 🤩

     

     

    유의할 점 한 가지! & 선택자는 복합 선택자의 시작 부분에만 쓸 수 있습니다.

    예를 들어 :not(&) 는 가능하지만 .item& 처럼 끝에 쓰는 건 불가능합니다.

     

    Error: "&" may only used at the beginning of a compound selector

     

     

    또, @media 같은 at-rules 가 중첩되어 있으면 스타일 규칙이 그 안에 있도록 바꿔주기 때문에 쉽게 조건을 추가할 수 있어요.

     

     

     


     

     

    3) 변수: 걔가 얘야

     

    Sass에서는 $변수명: 값; 으로 변수를 선언해 사용할 수 있습니다. 

    우리가 지난 글에서 예제로 살펴봤던 것처럼 쓰면 됩니다. 

    변수에는 문자, 숫자, 불린, 컬러값, null 등 정말 다양한 값을 담을 수 있어요!

     

    $width: 100rem;
    $font: "Noto Sans KR";
    $color: #000;
    $darkMode: true;
    $init: null;
    TMI
    이렇게 속성이나 변수 선언 오른쪽에 있는 값을 SassScript 라고 부릅니다.
    값을 담는 데서 끝이 아니고 != 처럼 비교하거나 +/-/* 등의 산술을 할 수도 있고, 함수의 인자로 넘길 수도 있죠.
    자세한 활용법은 투비 컨티뉴 🙌

     

     

    또한 선언 위치에 따라 전역변수 또는 지역변수로 사용할 수도 있어요.

     

    .header {
      $var-header: '이 변수는 .header 내에서만 쓸 수 있어요!';
    }
    
    .body {
      content: $var-header; //오류!
    }

     

    Error: Undefined variable.

     

     

    물론 CSS에서도 var(--변수명) 이라고 글로벌 변수를 쓸 수 있어요!

    하지만 Sass의 변수는 CSS 변수와 조금 다릅니다.

    • Sass의 변수는 컴파일되면서 사라집니다. CSS 파일에 보이지 않아요.
    • Sass의 변수는 한 번에 단 하나의 값만 가집니다.
    • Sass의 변수는 재할당 시 이전의 내용을 바꾸지 않습니다.

     

    $var: 'nana'; 
    .first { content:$var; } //nana
    $var: 'like'; 
    .second { content:$var; } //like

     

     

    또, Sass 변수에서 하이픈(-)과 언더스코어(_)는 동일하게 취급됩니다.

    따라서 $font-size와 $font_size는 완벽하게 동일합니다! 🤟

     

    $font_size: 10px;
    $font-size: 200px;
    
    .underscore {
        font-size: $font_size; //200px;
    }
    
    .hypen {
        font-size: $font-size; //200px;
    }
    TMI
    옛날에는 Sass 변수에 언더스코어만 쓸 수 있었으나 업데이트되면서 하이픈도 지원하게 됐다고 하네요!
    마이그레이션을 쉽게 하기 위해서 둘을 같은 걸로 취급하는 모양입니다.

     

     

    그렇다면 변수는 언제 쓰는 게 좋을까요? 그건 쓰는 사람 마음대로! ...긴 한데요,

    변수가 난잡하면 그것 나름대로 보기 어려워져서 '쓸 만한 상황이다'라고 판단될 때 쓰는 게 좋겠죠.

    • 값이 여러 곳에서 반복되거나
    • 수정될 가능성이 높을 때 사용하는 것이 가장 좋겠습니다.

     

     


     

     

    4) 보간: 슬쩍 끼워넣기!

     

    변수를 font-size: $size;와 같이 불러다 쓸 수 있다는 걸 배웠습니다. 

    그렇다면 CSS 속성값 안에 그대로 끼워넣는 것도 가능할까요?

     

    $name: "cart";
    .icon-cart {
        background-image: url("/icons/$name.png");
    }
    
    /*
     출력결과:
     .icon-cart {
       background-image: url("/icons/$name.png");
     }
    */

     

    의도한 거랑은 다르게 나왔네요. 저 이미지 주소 내에 $name을 끼워넣고 싶었는데 말이죠.. 머쓱...

     

    아니면 이런 것도 가능할까요? position 을 변수로 주고 top: 50px 을 적용하고 싶습니다.

     

    $position: top;
    .header {
        position: fixed;
        $position: 50px;
    }
    
    /*
     출력결과: 
     .header {
       position: fixed;
     }
     (내 $position 어디 간 거야... 😿)
     */

     

     

    넵, 문자열이나 셀렉터 등에 변수를 쓰려면 그냥은 안 되고 #{} 라는 보간(Interpolation)이 필요합니다.

    방법은 변수를 #{} 로 감싸주기만 하면 됩니다!

     

    $position: top;
    $name: cart;
    $height: 200px;
    
    .header {
        position: fixed;
        #{$position}: 50px;
        background-image: url("/icons/#{$name}.png");
        width: calc(100vh - #{$height});
    }
    
    /*
     출력결과:
     .header {
       position: fixed;
       top: 50px; //야호 top을 인식했다!
       background-image: url("/icons/cart.png"); //야호(2) cart를 인식했다!
       width: calc(100vh - 200px);
     }
    */

     

    만약 CSS 변수에서 Sass 변수나 함수를 끌어다쓰고 싶다면 보간법을 사용합니다.

     

    $color-accent: #0080ff;
    
    :root {
      --color-accent: #{$color-accent};
      --color-accent-100: #{rgba($color-accent, 0.07)};
      --color-accent-200: #{rgba($color-accent, 0.2)};
      --color-accent-300: #{rgba($color-accent, 0.4)};
    }

     

     

     

    한 가지 짚고 넘어가면 좋은 점! 보간이 리턴하는 것은 따옴표가 없는 문자열(unquoted strings)입니다. 

    따라서 단위 사이에 끼워넣을 때는 보간을 쓰기보다는 아래와 같이 쓰는 걸 추천합니다.

     

    $size: 100;
    
    .main {
        width: #{$size}rem; //Not recommend 😐
    }
    
    .footer {
        width: #{$size} * 1rem; //Good 😊
    }

     

    이유는 변수에 단위가 잘못 들어갔을 때, 컴파일 과정에서 에러를 잡을 수 없기 때문입니다.

     

    $size: 100px; //어이쿠! 모르고 px을 써버렸다!
    
    .main {
        width: #{$size}rem;
    }
    
    .footer {
        width: #{$size} * 1rem;
    }
    
    /*
     컴파일 결과:
     .main { width: 100pxrem; }
     .footer { //에러 }
    */

     

    보간은 문자열을 리턴하므로 pxrem이란 요상한 단위가 튀어나오게 됩니다.
    컴파일러 입장에선 문자열끼리 잘 있는 것이므로 딱히 에러를 내뱉지 않습니다. (다행히 브라우저는 이 단위를 무시하겠지만요)

    하지만 100px * 1rem은 명확하게 단위가 맞지 않으니 개발단계에서 에러를 캐치하고 수정하는 것이 가능합니다.

     

     

    또, 문자열을 감싼 따옴표는 보간으로 사용 시 컴파일 과정에서 사라집니다. 

     

    $var: "Nana";
    
    .hello {
       background-image: url('/images/#{$var}.png');
    }
    
    /*
     출력결과:
     .hello {
       background-image: url("/images/Nana.png");
     }
    */

     

     

     


     

     

    5) 인라인 주석: 우리끼리만 보는 주석

     

    CSS에서 주석은 /* */형태로 사용했죠.

     

    CSS 파일은 누구나 뜯어볼 수 있기 때문에 비밀스러운(?) 주석을 다는 것이 불가능합니다.

    개발하다보면 개발에만 필요한 주석을 달아야할 때가 있는데 말이죠. 

    이런 불편함을 해소하고자 Sass에서는 //형태로 인라인 주석을 사용할 수 있습니다. 

    인라인 주석은 어디든 끼워넣을 수 있고, 컴파일 과정에서 뿅 사라집니다.

     

     

     

     


     

     

    6) 출력스타일: 어떤 스타일로 해드릴까요

     

    Dart Sass는 두 가지의 출력 스타일을 제공합니다.

    1. expanded = 펼쳐주세요! (기본값)
    2. compressed = 압축해주세요!

     

    compressed 옵션을 택하면 빈 여백을 가능한 제거하고 전체 스타일시트를 한 줄에 작성해 줍니다.

     

    저번 글에서 플래그로 --watch 옵션을 껴넣었던 것처럼, --style 옵션으로 출력 스타일을 제어할 수 있습니다.

    터미널에서 sass 명령을 내릴 때 아래와 같이 입력해 보세요.

    sass --style=compressed style.scss style.css

     

    그럼 이렇게 꽉꽉 압축시킨 CSS 파일을 얻을 수 있습니다! 알아서 압축도 해주고 좋네요 😉

     

     

    compressed 옵션일 때는 일반 CSS 주석 /* 주석 */ 도 제거됩니다.

    하지만 ! 를 붙여 강조하면 압축모드에서도 표시되므로, 중요한 정보는 /*! 중요한 주석 */ 형태로 남길 수 있습니다.

     

     


     

     

    에필로그

     

    CSS 작성을 좀 더 편하게 해줄 몇 가지 Sass 문법에 대해 알아봤습니다. 역시 편한 게 최고쥬

    다음 글은 mixin, extend, 모듈화처럼 쪼개서 여기저기 가져다쓰는 법에 대해 써보려고 합니다.

     

    글 마무리가 제일 어렵네요... 아무튼 긴 스크롤 함께해주셔서 감사합니다 🤗

     

     

     

    728x90

    댓글 9

    • 프로필사진
      토끼 2022.04.08 10:24

      1. 얼마나 중첩해서 쓸지는 모듈화에 대한 고민에 따라 달라지고,
      bem을 남발해서 쓰면 타입이나 테마가 추가될때 수정이 어려워지는 경향도 있어서 작은 단위로 변동이 덜할때 저는 개인적으로 그때만 bem을 씁니다.

      2. & 를 뒤에 쓰면 부모로 인식됩니다.
      .a {
      .b & {
      // 블라블라
      }
      }

      .b .a { // 블라블라 }

      3. 변수에서 !global, !default 도 내용이 추가됬으면 좋겠네요.

      4. 에러를 찾는 용도라면 typeof로 타입체크 할수도있고, @error와 같은 테스트코드도 만들수있는 것도 추가됬으면 좋겠네요.

      • 프로필사진
        나나 (nykim) 2022.04.12 14:00 신고

        안녕하세요, 토끼님. 댓글로 추가 정보 공유 감사합니다.
        해당 내용은 가장 마지막에 다룰까 생각했는데 변수에 묶어서 다뤄도 좋을 것 같네요 :)

    • 프로필사진
      JASPER 2022.04.12 23:46

      나나님 안녕하세요, 디자인해주신 티스토리 스킨 잘 쓰고있습니다. 사이드바, 목록상단, 목록하단 광고지원을 안된다고하는데, 안되도록 디자인 하신게 맞나요?ㅎㅎ

      • 프로필사진
        나나 (nykim) 2022.04.24 14:43 신고

        안녕하세요, JASPER님! 스킨 잘 써주셔서 감사합니다 :)
        처음에 티스토리 디자인을 본문에 집중 할 수 있게 만들었기에 목록/사이드바가 없는 형태입니다.
        광고를 원하시면 본문 상하단에 지정해주시거나, 따로 치환자를 스킨 편집에 넣으셔야 할 것 같습니다.

    • 프로필사진
      은D 2022.04.13 15:07

      나나님 기다리고 기다리던 sass 두 번째 글이군요!!!! 나나님 덕분에 입문해서 지금 엄청 편하게 사용 중입니당 ~~!
      이번 글도 알차고 유익하네요 잘 보고 갑니다. 늘 응원해요 힘내세용!

      • 프로필사진
        나나 (nykim) 2022.04.24 14:46 신고

        안녕하세요, 은D님! 댓글 감사합니다ㅎㅎ 너무 멋진 응원의 말씀 남겨주셔서 좋은 기운 팍팍 받습니당! 은D님도 화이팅하시고 응원합니다!! 감사합니다 🥰🙏

    • 프로필사진
      빈치 2022.05.26 10:40

      scss 사이트에 암호문 처럼 되어있던 설명글이 나나님이 해주시니 이해가 술술 되네요 쭉쭉 글 올려주세용

    • 프로필사진
      D2 2022.06.19 22:32

      Dart Sass는... gulp 설정 중에 outputStyle이 compact 가 왜 안된다고 나오지 하고 계속 삽질했네요. 바보바보,,
      이래저래 블로그에 유익한 글들이 많아서 너무 잘 보고 있습니다. :)

    • 프로필사진
      버디 2022.06.26 18:45

      검색해 보다가 들어오게 되었는데 정리도 잘되어 있구 이해도 너무 잘되네요~~~~ 좋은 글 남겨 주셔서 감사합니다 열심히 공부해 보겠습니닷!!!