CSS의 @property 사용예

자주 사용하지는 않지만 CSS에도 변수를 정의해 재활용할 수 있는 문법을 제공하는데 :root를 정의하고 이 안에 원하는 값을 넣어 정의하곤 했습니다. CSS에 대한 더 높은 수준의 경험 많은 개발자는 이런 CSS에서의 변수 정의를 반드시 사용해야 하는 상황을 만나게 됩니다. 이런 CSS에서의 변수를 정의하는 좀더 표준화된 문법이 있는데 그것은 @property입니다. 표준화의 의미는 엄격함이라는 조건을 달아 실수를 줄여 견고한 코드를 작성하도록 하는 장치와 같습니다.

여튼 저는 –a라는 이름의 변수(프로퍼티)를 다음처럼 정의했습니다.

@property --a {
  syntax: "<angle>"; /* https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax */
  inherits: false;  
  initial-value: 0turn;
}

프로퍼티가 가지는 타입(syntax)와 초기값을 지정하고 있습니다. 그럼 이 프로퍼티를 사용하는 코드를 보면 다음과 같습니다.

.box::before {
  content: '';
  position: absolute;
  inset: 0;
  background: repeating-conic-gradient(from var(--a), #f00, #ff0, #fff, #0ff, #f0f, #f00);
  border-radius: 25px;
  animation: rotating 4s linear infinite;
}

@keyframes rotating {
  0% {
    --a: 0turn;
  }
  100% {
    --a: -4turn;
  }
}

명확하고 직관적입니다.

실제 위의 코드가 적용한 예제 코드는 다음과 같습니다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      background-color: #222;
    }

    .box {
      position: relative;
      width: 400px;
      height: 300px;
    }

    .box span {
      color: white;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 2.5rem;
      font-weight: bold;
    }

    .box::before {
      content: '';
      position: absolute;
      inset: 0;
      background: repeating-conic-gradient(from var(--a), #f00, #ff0, #fff, #0ff, #f0f, #f00);
      border-radius: 25px;
      animation: rotating 4s linear infinite;
    }

    .box::after {
      content: '';
      position: absolute;
      inset: 0;
      background: repeating-conic-gradient(from var(--a), #f00, #ff0, #fff, #0ff, #f0f, #f00);
      border-radius: 25px;
      animation: rotating 4s linear infinite;
      filter: blur(40px);
      opacity: 0.75;
    }

    .box span {
      position: absolute;
      inset: 4px;
      background: #222;
      border-radius: 22px;
      z-index: 1;
    }

    @property --a {
      syntax: '<angle>'; /* https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax */
      inherits: false;  
      initial-value: 0turn;
    }

    @keyframes rotating {
      0% {
        --a: 0turn;
      }
      100% {
        --a: -4turn;
      }
    }
  </style>
</head>
<body>
  <div class="box">
    <span>GIS DEVELOPER</span>
  </div>
</body>
</html>

결과는 다음과 같습니다.

DOM에 대한 표시 여부 감시(IntersectionObserver)

먼저 코드는 다음과 같습니다.

import './style-intersectionObserver.css'

const divApp = document.querySelector("#app")

if(divApp) {
  for(let i=0; i<20; i++) {
    const div = document.createElement("div")
    div.innerHTML = (i+1).toString()
    divApp.append(div)
  }
  
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if(entry.isIntersecting) {
        entry.target.classList.add("visible")
      } else {
        entry.target.classList.remove("visible")
      }
    })
  }, {
    threshold: 0
  })

  const divList = divApp.querySelectorAll("div")
  divList?.forEach((div) => observer.observe(div))
}

스타일은 다음과 같구요.

body {
  margin: 0;
}

#app {
  overflow-y: auto;
  position: fixed;
  background-color: rgb(45, 46, 47);
  background-image: 
    linear-gradient(to right, rgb(35, 36, 37) 1px, transparent 1px), 
    linear-gradient(to bottom, rgb(35, 36, 37) 1px, transparent 1px);
  background-size: 32px 32px;

  width: 100%;
  height: 100vh;
}

#app div {
  color: white;
  font-size: 5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 8px auto;
  height: 160px;
  width: 160px;
  border-radius: 10%;
  background-color: black;
  border: 2.5px solid white;
  transition: all 0.5s ease-in-out;
  transform: rotate(-90deg) scale(0.1);
  opacity: 0;
}

#app div.visible {
  transform: rotate(0deg) scale(1);
  opacity: 1;
}

실행 결과는 다음과 같습니다.