2 분 소요

서론

오늘은 Day 3!

오늘의 배울 것은 JS로 CSS 변수들을 변경하는 것이다.

구현

링크

CSS Variables

Task

  1. CSS 변수의 값들을 재사용할 수 있게 만들기
    • :root 가상 클래스 선언
  2. :root 사용하기
    • var()
  3. user input 들고 오기
  4. JS에서 변화시키기

1. CSS 변수의 값들을 재사용할 수 있게 만들기

CSS 또한 JS처럼 전역 변수를 선언하는 것이 가능하다. 바로 :root를 사용하면 된다. MDN에서 :root가 무엇인지 찾아보자.

CSS :root 의사 클래스는 문서 트리의 루트 요소를 선택합니다. HTML의 루트 요소는 <html> 요소이므로, :root의 명시도가 더 낮다는 점을 제외하면 html 선택자와 똑같습니다.

이 설명만 보면 :root가 무엇인지 단박에 이해하기 어렵다. 그럼 영어 설명을 보자.

The :root CSS pseudo-class matches the root element of a tree representing the document. In HTML, :root represents the <html> element and is identical to the selector html, except that its specificity is higher.

그렇다. :rootpseudo-class, 즉 가상 클래스이다.

:root can be useful for declaring global CSS variables

문서에 따르면, :root는 전역 CSS 변수들을 선언할 때 사용된다고 한다.

무엇인지, 그리고 어떻게 사용하는지 알았으니 이제 사용해보자.

controls의 안에 input들의 name에 따라서 속성의 이름을 지었다.

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

2. :root 사용하기

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

:root에서 선언한 속성을 사용하려면 var(--*)형식으로 사용해야 한다. 속성들의 속성값이 변경될 때마다 이미지의 padding, background-color, filter 값이 변경되는 것이다.

3. user input 들고 오기

우선 변화시키기에 앞서 얼마큼 변경해야 하는지를 알아야 하니 유저의 입력을 가져오자.

const inputs = document.querySelectorAll(".controls input");으로 input 요소들을 모조리 가져온다.

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

그리고 input값에 변화가 있을 때마다 값을 변화시킬 함수를 실행하는 것이다. forEach를 사용하는 이유는 바로 querySelectorAll의 반환 값이 NodeList 형태이기 때문이다. 참고로 NodeList !== Array이다.

image

4. JS에서 변화시키기

이제 CSS에서 전역 변수를 선언하는 법과 사용하는 법, 그리고 변화 값도 알았으니 JS에서 변화할 차례다.

그런데 CSS 내의 값을 어떻게 JS로 들고 와야 할까? :root 문서를 다시 보자.

The :root CSS pseudo-class matches the root element of a tree representing the document. In HTML, :root represents the <html> element and is identical to the selector html, except that its specificity is higher.

HTML에선 :root가 html 요소임으로 document.documentElement으로 html 요소를 들고 오면 되는 것이다.

이제 CSS에서 선언된 스타일 속성을 변화시켜야 하니 style.setProperty(속성 이름, 값); 함수를 사용하면 된다.

document.documentElement.style.setProperty(`--${this.name}`, this.value);

이제 실행해보면 분명 값이 변하기는 하는데 화면에 변화가 없다. 왜냐면 단위가 없기 때문이다.

그래서 input을 살펴보면 data-sizing이라는 속성이 있다. 이것은 비표준 속성으로, 단위를 저장하기 위해서 따로 만든 속성이다.

데이터 속성 사용에 관해서 궁금하면 MDN의 데이터 속성 사용하기 문서를 참고하도록 하자.

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

suffix 라는 변수를 하나 생성해서, 단위가 있다면 저장하고 단위가 없다면 (색상을 변화하기 위해서 단위가 필요하지 않기 때문에 색상을 입력받는 input은 단위가 없다.) ''을 저장하도록 한 뒤, JS로 변화를 화면에 적용하는 것이다.

TLD

CSS로도 전역 변수를 선언할 수 있다는 사실을 처음 알았다! 그리고 그 값을 JS로 변경할 수 있다니 참 신기했다.

또한 속성을 이렇게 사용할 수 있다는 것도 참 놀라웠다. 지금까지 내가 짜왔던 코드들을 돌아보면, 돌아가기만 하는 코드들을 짜고 있었다는 것을 깨달았다.

이젠 돌아가기만 하는 코드가 아니라, 똑똑한 코드를 짤 수 있으면 좋겠다! 그렇게 하려면 더 열심히 공부해야지 히히

최종 코드

CSS:

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

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

.hl {
  color: var(--base);
}

JS:

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));

댓글남기기