물리 기반 이징

웹 기능: linear() easing

ease-in 또는 cubic-bezier()와 같은 기존 CSS 이징 함수는 단순한 곡선으로 제한되므로 바운스나 스프링과 같은 복잡한 물리 기반 효과를 만들 수 없습니다. linear() 타이밍 함수는 복잡한 곡선을 근사화할 수 있는 일련의 정지점을 제공하여 이 문제를 해결합니다. 전환 및 애니메이션은 정지 지점 사이의 직선을 기반으로 보간되지만 정지 지점이 충분하면 부드럽게 표시될 수 있습니다.

구현 단계

  1. 곡선 중지점 생성: 스프링이나 바운스를 위해 수십 개의 포인트를 수동으로 표시하는 것은 비현실적입니다. 외부 라이브러리의 타이밍 함수를 사용하거나 도구를 사용하여 기존 JavaScript 이징 함수 또는 SVG 경로를 linear() 문법으로 변환합니다. 선택사항: 이러한 타이밍 함수를 CSS 맞춤 속성으로 저장하여 사이트 전체에서 재사용합니다.
  2. 타이밍 함수 정의: 생성된 중지점을 transition-timing-function 또는 animation-timing-function 속성에 적용하거나 transition 또는 animation 약칭을 통해 적용합니다.
  3. 지속 시간 조정: 지속 시간이 물리적 속성 (질량, 강성)에서 파생되는 JavaScript 물리 엔진과 달리 CSS는 여전히 고정된 duration가 필요합니다. 원하는 효과를 얻으려면 지속 시간을 조정해야 할 수 있습니다.

예: Spring Easing

이 예시에서는 커스텀 linear() 함수를 사용하여 목표 값을 초과한 후 안정화되는 스프링 효과를 만드는 방법을 보여줍니다.

.spring {
  /* Define the physics-based easing as a reusable variable */
  --spring-easing: linear(0, 0.016 0.5%, 0.06 1%, 0.226 2%, 1.116 5.4%, 1.375 6.6%, 1.527 7.7%, 1.565 8.2%, 1.585 8.8%, 1.581 9.3%, 1.559 9.8%, 1.458 10.9%, 0.937 14.3%, 0.784 15.5%, 0.693 16.6%, 0.67 17.1%, 0.657 17.7%, 0.671 18.7%, 0.729 19.8%, 1.042 23.3%, 1.13 24.5%, 1.182 25.6%, 1.201 26.7%, 1.192 27.7%, 1.156 28.8%, 0.977 32.2%, 0.925 33.4%, 0.894 34.5%, 0.882 35.6%, 0.887 36.6%, 0.907 37.7%, 1.045 42.4%, 1.069 44.5%, 1.059 46.3%, 0.979 50.9%, 0.96 53.4%, 0.966 55.3%, 1.013 59.9%, 1.024 62.3%, 0.986 71.2%, 1.008 79.9%, 0.995 88.9%, 1);


  /* Apply the easing with a duration that fits the spring's complexity */
  /* MANDATORY: Always include a duration; linear() does not calculate it automatically */
  transition: scale 0.8s var(--spring-easing);
}

.spring:hover {
  scale: 1.2;
}

예: 예: 바운스 이징

이 예시에서는 맞춤 linear() 함수를 사용하여 바운스 효과를 만드는 방법을 보여줍니다.

.bounce {
  /* Define the physics-based easing as a reusable variable */
  --bounce-easing: linear(0, 0.214 14.7%, 0.386 23.7%, 0.598 31.9%, 0.999 44.7%, 0.807 52.6%, 0.762 56%, 0.747 59.4%, 0.758 62.4%, 0.793 65.6%, 0.999 77.4%, 0.961 81.2%, 0.949 84.8%, 0.956 88%, 0.993 95.5%, 1);


  /* Apply the easing with a duration that fits the bounce's complexity */
  /* MANDATORY: Always include a duration; linear() does not calculate it automatically */
  transition: scale 0.4s var(--bounce-easing);
}

.bounce:hover {
  scale: 1.2;
}

주요 고려사항

  • 성능: 가장 부드러운 물리학 기반 애니메이션을 구현하려면 transform 및 opacity와 같이 별도의 스레드에서 실행되는 속성에 linear()를 적용하세요.
  • 정밀도와 페이로드: 정지점이 많을수록 곡선이 더 부드러워지지만 CSS 크기도 커집니다. 대부분의 생성기를 사용하면 곡선을 '단순화'하여 부드러움과 코드 크기 간의 최적의 균형을 찾을 수 있습니다.
  • 바운스에 불투명도 사용하지 않기: opacity에 바운스 이징을 적용하면 값이 0 미만 또는 1 초과로 오버슈트될 때 시각적으로 거슬리는 깜박임이 발생할 수 있습니다.
  • 접근성: 복잡한 물리 기반 애니메이션은 일부 사용자에게 방해가 되거나 모션 민감성을 유발할 수 있습니다. 이러한 애니메이션을 줄이거나 사용 중지하여 항상 사용자 환경설정을 존중하세요.
@media (prefers-reduced-motion: reduce) {
  .element {
    transition: none;
  }
}

대체 전략

CSS 대체

linear()를 지원하지 않는 브라우저의 경우 표준 이징 함수를 대체로 제공합니다. 브라우저는 linear() 값을 인식하지 못하면 무시하고 이전의 유효한 선언으로 대체합니다.

.element {
  /* Fallback for older browsers (standard smooth exit) */
  transition: transform 0.8s ease-out;
  
  /* Modern browsers will override with the physics-based easing */
  transition-timing-function: linear(0, 1.1, 0.95, 1.02, 1);
}

JavaScript 라이브러리 대체 (모션/GSAP)

선택사항: 이전 브라우저에서도 고품질 물리 애니메이션이 중요한 경우 linear()가 지원되지 않을 때 Motion (motion.dev) 또는 GSAP (greensock.com)와 같은 JavaScript 라이브러리를 사용하여 애니메이션을 처리합니다.

  1. 지원 감지: CSS.supports()를 사용하여 브라우저가 linear() 함수를 처리하는지 확인합니다.
  2. 조건부 로드/적용: 지원되지 않는 경우 라이브러리의 스프링 또는 바운스 구현을 사용합니다.
/* Detect if the browser supports the linear() function */
const supportsLinearEasing = window.CSS && CSS.supports('animation-timing-function', 'linear(0, 1)');

if (!supportsLinearEasing) {
  /* 
     Example using Motion (motion.dev) for a spring fallback.
     This should only be initialized if native CSS support is missing.
  */
  import("https://cdn.jsdelivr.net/npm/motion@latest/dist/motion.js").then(({ animate, spring }) => {
    animate(".element", { transform: "scale(1.2)" }, {
      easing: spring({ stiffness: 100, damping: 10 })
    });
  });
}

CSS에서 @supports를 사용하여 더 명시적인 기능 감지를 수행할 수도 있습니다.

@supports not (animation-timing-function: linear(0, 1)) {
  .element {
    /* Alternative experience for unsupported browsers */
    transition-duration: 0.4s;
    transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
  }
}