Sass, SCSS, css-in-js, css-module

GY·2021년 12월 14일
0

CSS

목록 보기
14/16

css를 어떻게 하면 효율적으로 작성할 수 있을까?

이 고민을 하면서, 이번 프로젝트를 진행하면서는 조금 더 적극적으로 다양한 CSS 작성방식에 대해 알아보고 사용해보려고 한다.

module.css는 사용해보았지만 한가지 한계점이 느껴졌다.
클래스 중복을 걱정하지 않고 편하게 컴포넌트 단위로 클래스를 작성할 수 있어서 좋았지만, 그럼에도 불구하고 일일히 하나하나 클래스를 지정해 작성해주어야 했기 때문이다.

다른 방법으로 보완할 필요성을 느끼던 차에 Sass에 대해서 알게 되어서, 비슷한 내용과 사용법, 그리고 지금 고민시점에서 어떻게 응용해 작성해둔 코드를 보완할 수 있을지에 초점을 맞추어 정리해보았다.


CSS Preprocessor

Sass, Less, Stylus와 같은 것들은 CSS 전처리기라고 한다.
CSS가 동작하기 전에 사용하는 기능으로, 웹에서 CSS 가 동작하는 것은 동일하지만 개발과정에서 이러한 전처리기를 사용해 CSS의 단점을 보완할 수 있다.
작성한 전처리기는 웹에서 동작 가능한 표준의 CSS로 컴파일하고 동작시킨다.
즉 전처리기를 사용할 때는 컴파일러도 필요하다.


SASS, SCSS 차이

  • SASS = Syntactically Awesome Style Sheets
    - 더 간결하고 작성하기 편리하며, 중괄호나 세미콜론 없이 깔끔한 코드를 작성할 수 있다.
  • SCSS = Sassy CSS
    - 한 줄로 인라인 코드를 작성할 수 있고, CSS와 유사한 문법을 가지기 때문에 코드 통합이 훨씬 쉽습니다.
    - CSS 구문과 완전히 호환되도록 새로운 구문을 도입해 만든 Sass의 모든 기능을 지원하는 CSS의 상위집합이다.
    • 즉, CSS와 거와 거의 같은 문법으로 Sass 기능을 지원한다.

문법은 어떻게 다를까? - 중괄호와 세미콜론을 위주로 보자.

Sass

.list
  width: 100px
  float: left
  li
    color: red
    background: url("./image.jpg")
    &:last-child
      margin-right: -10px

SCSS

.list {
  width: 100px;
  float: left;
  li {
    color: red;
    background: url("./image.jpg");
    &:last-child {
      margin-right: -10px;
    }
  }
}

SCSS가 더 최근에 나온 것으로 범용성과 CSS의 호환성이 좋아 많이 쓰이고 있다.


Sass, SCSS, css-in-js, css-module

💎 Sass

별도의 문법, 변수, 믹스인, 네스팅과 같은 문법을 사용해 재사용성을 높힐 수 있다.

특징, 장점

  • variable 선언 가능
    - 변수 선언 뒤 !global을 붙여주면 해당 변수를 전역으로 할당 가능
  • nesting 구조
    - &이용해 코드 연결 가능
  • mixin
    - @mixin 어노테이션을 붙인 함수를 만들고 @include로 가져다 쓸 수 있다
    @mixin button($size) {
    	@if $size == 'small' {
        	font-size: 10px;
        } @else {
        	font-size: 14px;
        }
    }
    
    .header-area {
    	button {
        	@include button(small)
        }
     }
  • extend
    - 같은 코드 방지를 위해 속성을 상속할 때 사용한다. extend용으로 만든 SCSS 경로를 import 해 @extend로 스타일 상속을 해줄 수 있다.
    %button {
    	border-radius: 4px;
    }
    
    @import "_buttons";
    
    a {
    	@extend %button;
    }

content

  • mixin에서 @content를 쓰면 mixin을 가져다 쓰는 곳에서 스타일을 정의할 수 있다.


이미지출처

function

  • @if, @else if, @else, @for, @while도 사용가능하다.

단점

  • override: 클래스가 중복될 수 있다.
    자바스크립트 파일들과 CSS 파일들은 성능을 위해서 하나의 자바스크립트 파일과 하나의 CSS 파일, 혹은 특정 비즈니스 요건에 따라서 특정구조, 목적에 맞게 병합을 하는 과정을 번들링 과정에 수행한다.

  • wrapper naming : 한번 더 소스코드를 감싸는 스타일 셀렉터를 추가해주는 방법을 사용해 overriding을 방지하기도 하는데, 결국 파일용량이 커지고 또다른 네이밍을 고민해야하는 리소스가 들어간다.


💎 css-module

css-module은 컴포넌트 단위로 css 스타일을 적용할 수 있다.


💎 css-in-js

styled-components 패키ㅣ를 사용해 css 코드를 자바스크립트 파일 안에서 작성한다.
자바스크립트 내에서 관리하기 때문에 내부응집도가 올라가고, 동적으로 CSS를 변경하기도 쉽습니다.

단점

  • 자바스크립트 번들 파일의 용량이 커져 파일을 로드해 화면을 표시하는데 시간이 지연된다.
  • Sass / css-modules를 사용하는 경우 CSSOM 생성 이후 자바스크립트 파싱이 진행되는 것과 다르게 자바스크립트 파싱을 통해서 CSSOM을 생성해야 하기 때문에 사용자에게 제공되는 화면에 대한 지연이 더 커지게 된다. 따라서 많은 인터렉션이 있거나 빠른 반응이 필요한 서비스를 만드는 경우 사용자 경험이 좋지 않을 수 있다.

상황에 따라 맞는 방식을 선택해 사용하는 것이 중요해 보인다.


Q & A

공부하면서 프로젝트에 응용하는 과정에서 생긴 궁금증과, 직접 찾아보고 정리한 내용을 정리해보았다.

💎 Q.Sass와 css-module을 함께 사용한다면?

- .module.scss 확장자를 사용해 Sass를 css module로 사용할 수 있다
- :local을 사용해 일반 .css/scss파일에서도 css module을 사용할 수 있다.

굳이 둘 다 사용해보고 싶은 이유

  • 두 가지의 장점을 합칠 수 있지 않을까?
    css module로 컴포넌트간의 중복을 피해 클래스를 간결하게 작성할 수 있었지만, 계층구조를 표현하기 위해 중복된 부모요소를 클래스 이름에 포함시켜 작성했다.
    예를 들면, feed안에 들어 있는 헤더, 피드, 댓글 영역에서 각각 프로필 이미지, 텍스트, 인풋태그, 유저 아이디가 들어가는데 같은 컴포넌트이기 때문에 header_profile_img, feed_profile_img, header_id, comment_id와 같은 형식이었다.

    SCSS의 장점인 Nesting을 사용해 계층구조로 간단하게 작성하면 가독성도 좋고 더 간결한 코드를 작성할 수 있지 않을까? 반대로, 물론 SCSS가 Nesting을 사용해 어느정도 중첩을 피한다지만...

  • 이미 css module을 사용한 상태에서 SCSS도 꼭 써보고 공부해보고 싶다.
    정말 좋은 기능이 많아 보이는데, 직접 사용해보고 장단점과 사용하면 좋을 경우의 수를 스스로 체득해보고 싶다.

A. Sass와 css-module을 함께 사용하는 방법

CSS module을 Sass에서도 사용하려면, node-sass설치 후 확장자를 module.scss로 변경해주면 된다.

💎 Q. css-module에서 클래스 사용시 한계점(복수사용), 보완할 수 있는 방법?

A.클래스 여러개 생성하는 방법

${styles.one} ${styles.two}

A. 클래스에 - 포함시

styles['my-class']

이렇게 클래스 이름만 사용할 때도 다소 번거로운 면이 있는데,
조건부 스타일링을 하는 등의 경우에는 복잡해지는 단점이 있다.

A. bind 사용해 간편화하기

classnames라이브러리의 bind를 써보자.

bind 기능을 사용하면, css 클래스 이름을 지정해줄 때 cs('클래스이름')과 같은 형식으로 편하게 사용할 수 있다.

$ yarn add classnames

import classNames from 'classnames/bind';

cx('one', 'two')
cx('my-component', {
  condition: true
})
cx('my-component', ['another', 'classnames'])

//조건부 스타일링
<div className={cx('icon')}>
                {checked ? (
                <MdCheckBox className={cx('checked')} />
) : (
  <MdCheckBoxOutlineBlank />
)}

💎 Q. css-module에서 컴포넌트 밖으로 전역적으로 변수를 생성하고 싶은데, 이 방법은?

:global .my-global-name {

}

업데이트

2021.12.19

  • 실무에서는 보통 css module과 Scss를 동시에 사용하는 것이 아닌 둘 중 하나만 필요에 따라 적절히 선택하여 사용한다는 것을 알게 되었다. 따라서 두 가지를 모두 사용하지 않고 Scss만 사용해보기로 결정했고, 기존에 작성했던 module.css를 전부 Scss로 변경했다.

직접 사용해보니 Scss는 nesting을 사용함에도 중복된 클래스는 동일하게 css가 중복적용이 된다는 단점을 발견했다. 클래스를 적절히 사용해주면 충분히 보완할 수 있지만,
css module과 Scss의 장단점을 잘 알고 사용하는 것이 중요하다는 생각이 들었다.

Reference

profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글