ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Update CSS variables with JS 🎨
    Web/JS30 2020. 9. 20. 02:10
    반응형

    이번 시간은, 원래는 전혀 알지 못했던 새로운 개념을 배우는 아주 유익한 시간이었다.

    바로 CSS 변수를 사용하는 방법을 배운 것. 나는 CSS에도 변수라는 개념이 있는 지 몰랐다;;

    그래서 변수를 사용하려면 SASS같은 preprocessor들을 사용해야 하는 줄 알았는데.

    SASS에서는 변수를 compile time에 정의하고, 그 이후에는 변경할 수 없다고 한다.

    반면, CSS variables는 자바스크립트를 이용하여 계속해서 변경할 수 있다.

     

    CSS 변수는 특정 element 내부에 선언되어야 하며, 이름의 앞에 '--'를 붙여줘야 한다.

    우리는 root element에다가 선언을 해줄 것이며, 해당 변수들의 default value와 함께 선언을 해주면 된다.

    base, spacing, blur라는 3개의 변수들을 선언해줬고, 이제 이들을 HTML element 내부에서 사용해주면 된다.

    :root {
        --base : #ffc600;
        --spacing : 10px;
        --blur : 10px;
    }

    우리가 root element에 변수를 3개 선언해줬으므로, 개발자 도구에서 확인해보면

    다음과 같이 변수 3개가 root element에 선언되어있는 것을 확인할 수 있다.

     

    만약 내가 --base 변수를 선언해놓고, 그보다 더 아래에 --base를 한 번 더 선언했다고 치자.

    그러면 그 이후에 등장하는 --base 변수들은 뒤에 선언된 --base 변수를 따른다.

    역시나, 더 가까운 놈을 따르는 CSS cascading의 법칙이 그대로 적용된다.

     

    변수를 사용할 때는 var( )이라는 키워드와 함께 사용해주면 된다.

    img {
        padding : var(--spacing);
        background : var(--base);
        filter : blur(var(--blur));
    }
    
    .hl {
        color : var(--base);
    }

    filter라는 속성이 있는 것도 처음 알았다..

     

    이제, 선언해 준 CSS 변수들을 자바스크립트를 이용하여 조작해보자.

    const inputs = document.querySelectorAll('.controls input');
    
    function handleUpdate() {
        const suffix = this.dataset.sizing || '';
        document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
    }
    
    inputs.forEach(input => input.addEventListener('change', handleUpdate));
    inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));

    일단 모든 input을 querySelectorAll로 선택해준다.

    그러면 NodeList가 반환되는데, 사실 NodeList는 array와 달리 사용할 수 있는 메소드가 굉장히 적어서 

    대부분의 경우 NodeList를 array로 변환해서 사용하는 게 거의 국룰이다.

     

    물론 그래도 되지만, 우리가 사용할 메소드는 forEach인데

    최근에 NodeList에도 forEach가 추가되었기 때문에 여기서는 굳이 변환해주지 않는다.

     

    색깔에는 단위가 없지만, padding이나 blur filter같은 경우는 뒤에 px와 같이 단위가 붙는다.

    그래서 input태그에다가 미리 data-sizing이라는 이름으로 'px'라는 문자열을 저장해놨다.

    <div class="controls">
        <label for="spacing">Spacing:</label>
        <input id="spacing" type="range" name="spacing" min="10" max="200" value="10" data-sizing="px">
    
        <label for="blur">Blur:</label>
        <input id="blur" type="range" name="blur" min="0" max="25" value="10" data-sizing="px">
    
        <label for="base">Base Color</label>
        <input id="base" type="color" name="base" value="#ffc600">
    </div>

    참고로, 자바스크립트의 dataset해당 element에 내가 저장해놨던 data들이 모여있는 객체이다.

    dataset.sizing을 불러와주고, 없는 경우(색깔)에는 그냥 빈 문자열로 처리해주도록 했다.

    function handleUpdate() {
        const suffix = this.dataset.sizing || '';
        document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
    }

    요 부분인데, document.documentElement문서의 root 요소를 나타낸다.

    우리가 아까전에 문서의 root 요소에다가 변수들을 저장해줬으므로, 그 변수들의 값을 바꿔주겠다는 뜻으로

    document.documentElement.style.setProperty라는 메소드를 호출해줬다.

     

    `--${this.name}`은, 위의 태그에서 보면 알 수 있듯이 각 input태그에 name이라는 property에다가

    각 변수의 이름과 동일한 이름으로 값을 넣어놓았으므로, 그것을 꺼내서 사용해준 것.

    그러면, this.name의 앞에다가 '--'만 붙여주면 곧바로 CSS 변수들의 이름으로 사용할 수 있게 된다.

    해당 이름을 가진 변수의 값을 this.value + suffix로 세팅해준 것.

     

    inputs.forEach(input => input.addEventListener('change', handleUpdate));
    inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));

    보통 input하면은 change 이벤트만 생각하기 마련인데, mousemove 이벤트를 더해준 이유가 있다.

    change 이벤트는 input의 핸들을 잡고 움직인 후에 마우스를 놓아야만 이벤트가 발생한다.

    그래서 핸들을 잡고 마우스를 움직이는 동안에는 이벤트가 발생하지 않는다.

     

    따라서, 핸들을 잡고 마우스를 움직이는 동안에도 계속해서 이벤트를 발생시키기 위해

    mousemove 이벤트를 추가시켜 준 것이다.

     

    그러면, 다음의 GIF에서와 같이, 마우스를 움직이는 동안에도 이벤트가 발생하여

    blur값이 실시간으로 계속해서 변경되는 모습을 확인할 수 있다.

     

    반응형

    'Web > JS30' 카테고리의 다른 글

    Type Ahead ⌨  (0) 2020.09.25
    Flex Panel Gallery 🎫  (0) 2020.09.21
    Array Cardio Day 1 🎈  (0) 2020.09.21
    CSS + JS Clock ⏱  (0) 2020.09.20
    🥁 JS Drum Kit 🥁  (0) 2020.09.18

    댓글

Designed by Tistory.