logo
Published on

SASS를 활용하여 CSS 라이브러리 만들기 (feat. scroll-animations-js)

Authors
  • avatar
    Name
    Bora Choi
    Twitter

들어가며

테오의 스프린트 6기에서는 스크롤 애니메이션 라이브러리(scroll-animations-js)를 만들었다.
어떤 식으로 라이브러리를 구현할지 다양한 의견(react 컴포넌트, CSS class name 등)이 있었는데 우리가 선택한 방식은 CSS 클래스 명으로 사용하는 방식이었다.
애니메이션 옵션에 따라서 다양한 스타일을 작성해야 했다.
처음에는 순수 CSS를 통해서 구현하려 했지만 반복해서 작성해야 하는 코드양이 너무 많았기 때문에 sass를 사용했다.
또한, data-set 옵션에 따라 적용하는 스타일을 변경하기 위해 한층 복잡한 CSS 선택자를 사용했다.
이 글에서는 scroll-animations-js 라이브러리를 만들면서 사용했던 sass 문법과 CSS 선택자를 소개하겠다.

SASS(SCSS)

SASS를 사용하면서 반복되는 코드를 줄이고 효율적으로 코드를 작성할 수 있었다. 순수 CSS였다면 한줄 한줄 하드코딩으로 작성해야했는데 SASS로 말도 안되는 양을 줄일 수 있었다.

변수 $

$ 사인으로 변수를 지정하고 사용할 수 있다.

/* SCSS */
$sa-distance: 200px !default;

.sa-fade-up {
  transform: translate3d(0, $sa-distance, 0);
}
/* CSS */
.sa-fade-up {
  transform: translate3d(0, 200px, 0);
}

scroll-animations-js에서는 기본 애니메이션 클래스만 선택할 경우 임의로 지정한 값으로 설정되는데, 이때 기본값은 scss변수를 사용하여 적용했다.

중첩 선택자와 부모선택자 &

중첩 선택자를 통해서 하나의 스타일 내부에 다른 스타일을 작성하여 반복 작성을 줄일 수 있다.
또한, 중첩 선택자를 사용할때 외부선택자 값을 &로 참조 할 수 있다.

/* SCSS */
.sa-animation {
  &.sa-fade-up {
    transform: translate3d(0, 100px, 0);
  }
  &.sa-fade-down {
    transform: translate3d(0, -100px, 0);
  }
}
/* CSS */
.sa-animation.sa-fade-up {
  transform: translate3d(0, 100px, 0);
}
.sa-animation.sa-fade-down {
  transform: translate3d(0, -100px, 0);
}

scroll-animations-js 라이브러리에서 .sa-animation 클래스가 트리거로 작동되어 반복적으로 작성되어야 하는데 중첩 선택자와 & 선택자를 통해서 선택자의 반복 작성을 줄였다.

반복문 @for

@for <variable> from <expression> to 혹은  @for <variable> from<expression> through 을 이용하여 css에서 반복문을 사용할 수 있다.

to 의 경우 마지막 숫자를 포함하지 않고 through의 경우는 마지막 숫자를 포함한다.

.sa-scale {
  @for $i from 1 through 30 {
    &[sa-scale='#{$i * 0.1}'] {
      transform: scale(#{$i * 0.1});
    }
  }
}
.sa-scale[sa-scale='0.1'] {
  transform: scale(0.1);
}
.sa-scale[sa-scale='0.2'] {
  transform: scale(0.2);
}
 {
  ...;
}
.sa-scale[sa-scale='2.9'] {
  transform: scale(2.9);
}
.sa-scale[sa-scale='3'] {
  transform: scale(3);
}

옵션 구현에 있어서 각 옵션에 따른 스타일을 작성해야했다. SASS 반복문을 통해서 수많은 줄의 코드를 10줄도 안되는 코드로 구현할 수 있었다!

CSS 선택자

요즘 styled-componentsemotion과 같은 css-in-js 라이브러리를 사용하면서 직접 css선택자를 사용할 일이 줄어들었다. 페어프로그래밍을 하면서 팀원들이 자주 실수해서 사용하는 선택자나 잘 모르는 선택자들을 공유한다.

.a-class.b-class vs .a-class .b-class vs .a-class > .b-class

<!--.a-class.b-class-->
<div class="a-class b-class"></div>

<!--.a-class .b-class-->

<div class="a-class">
  <div class="c-class">
    <div class="b-class"></div>
  </div>
</div>

<!--.a-class > .b-class-->
<div class="a-class">
  <div class="b-class"></div>
</div>

보편적으로 알려진 선택자이지만 의외로 많이들 헷갈려했던 선택자 3가지이다.
먼저 첫번째 .a-class.b-class 의 경우는 클래스 a-classb-class 를 갖는 요소를 말한다.

.a-class .b-class 는 언뜻 보면 차이를 모르겠지만 a-classb-class 사이에 공백이 존재한다. 이 경우에는.a-class 하위 요소중.b-class를 갖는 모든 요소들을 의미한다.

마지막 세번째 .a-class > .b-class의 경우 두번째 공백 선택자(자손결합자)와 비슷하지만 >의 경우.a-class바로 아래 자식 요소 중.b-class를 갖는 모든 요소들을 의미한다.

특성 선택자

[sa-scale='10'] {
  transform: scale(1.1);
}
<div sa-scale="10">요소</div>

특성 선택자를 사용하면 요소의 속성이나 속성값에 따라 요소를 선택 할 수 있다. [속성] 혹은 [속성="값"] 와 같은 형태로 사용한다. = 앞에 ~ , | , ^ , & 등을 추가하여 속성값을 구체적으로 선택할 수 있다.

:is(selector):not(selector)

p:not(.a-class) {
  color: red;
}

p:is(.a-class) {
  color: blue;
}
<p class="b-class">빨간 글씨</p>
<p>빨간 글씨</p>
<p class="a-class">파란 글씨</p>

:not()의 경우 괄호안의 선택자가 아닌 요소를 나타낸다. 반대로 :is()의 경우 괄호안의 선택자와 일치되는 요소를 말한다.

마무리

평소에 프론트엔드 공부를 할 때 CSS보다는 JavaScript에 비중을 두면서 공부했었다. CSS 라이브러리를 만들면서 간과했던 부분들에 대해서 다시 한번 집어볼 수 있었다.
CSS 관련해서 다양한 최신 기술이 나오고 있지만 역시 기본은 무시할 수 없는 것 같다. 기본적인 부분을 알고 이해하면서 최신 기술도 함께 습득하는 것이 중요하다는 것을 다시 한번 깨달았다.

참고

https://sass-lang.com/documentation
https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Selectors
https://developer.mozilla.org/ko/docs/Web/CSS/Attribute_selectors
https://developer.mozilla.org/en-US/docs/Web/CSS/:is
https://developer.mozilla.org/ko/docs/Web/CSS/:not

관련 링크

scroll-animations-js NPM: https://www.npmjs.com/package/scroll-animations-js
scroll-animations-js github: https://github.com/nice-people-meeting/scroll-animations-js
scroll-animations-js 예제사이트: https://scroll-animations-js-web.vercel.app/