TL;DR

  • CSS progress()는 값이 시작점과 끝점 사이에서 차지하는 위치를 0~1 범위로 반환하며, 미지원 브라우저에서는 값 유형과 단위에 맞춰 대체 계산식을 구성함.
  • 단위 없는 숫자에는 clamp()와 calc()로 (현재값 - 시작값) / (끝값 - 시작값)을 직접 계산함.
  • 같은 단위를 사용하는 값에는 tan(atan2()) 트릭을 적용할 수 있으며, 별도의 사용자 지정 속성 등록이 필요하지 않음.
  • 단위가 섞이면 @property로 값을 <length>로 등록해 픽셀로 계산되게 하며, 여러 비픽셀 단위에서는 오프셋과 범위를 각각 등록함.
  • progress()의 클램프되지 않은 동작을 흉내 내려면 clamp()를 제거하며, 네이티브 지원이 보편화되기 전까지 단위에 맞는 대체 방식을 선택함.

`progress()` 계산 원리

  • CSS의 새 progress() 함수는 값이 시작 경계와 끝 경계 사이에서 어디에 놓이는지 계산해 단위 없는 0~1 사이의 숫자를 반환함.
  • 브라우저 지원이 확대되기를 기다리는 동안 계산을 직접 구현할 수 있으며, 기본 계산식은 (현재값 - 시작값) / (끝값 - 시작값)임.
  • 이 계산은 정규화(normalization)라고도 하며, 사용할 값의 유형에 따라 간단한 calc()부터 더 복잡한 CSS 기법까지 적용 방식이 달라짐.

단위 없는 숫자

  • 값이 모두 단위 없는 숫자라면 calc()에 계산식을 직접 넣을 수 있으며, progress()의 기본 동작과 맞추려면 clamp()를 사용함.
  • 예를 들어 50이 10과 100 사이에서 차지하는 위치는 clamp(0, (50 - 10) / (100 - 10), 1)로 계산함.

단위가 있는 값

  • 결과는 단위 없는 값으로 유지하면서 px, rem, vw 같은 단위를 사용하려면 형식이 지정된 산술(typed arithmetic)을 지원하는 브라우저에서 다음 계산이 동일한 결과를 내야 함.
  • clamp(0, (100vw - 20rem)/(100rem - 20rem), 1)
  • progress(100vw, 20rem, 100rem)
  • 이 방식은 아직 모든 브라우저에서 지원되지 않으며, 특히 Firefox에서 호환성 문제가 있음.
  • atan2(y, x)는 두 값을 나누는 계산을 이미 수행하므로 progress() 계산의 오프셋(값 - 시작점)을 첫 번째 인수로, 범위(끝점 - 시작점)를 두 번째 인수로 전달할 수 있음.
  • 모든 값의 단위가 같다면 단위를 바꾸지 않고 바로 적용할 수 있음. 예를 들어 tan(atan2(500px - 320px, 1200px - 320px))로 계산함.

단위 혼합

  • 실제로는 단위가 일치하지 않는 경우가 많으며, atan2()가 혼합 단위를 처리하는 브라우저도 있지만 브라우저 간 호환성을 확보하려면 추가 처리가 필요함.
  • 유동형 타이포그래피에서는 뷰포트 너비 100vw를 하한과 상한인 320px, 1200px과 비교해 진행 값을 계산함.
  • vw와 px를 함께 사용하므로, 모든 브라우저에서 계산이 가능하도록 100vw를 픽셀로 변환해야 함.
  • 뷰포트 너비를 초기값이 100vw인 <length> 사용자 지정 속성으로 등록하면 브라우저가 100vw를 이에 해당하는 픽셀 값으로 해석함.
  • 이렇게 하면 atan2()에 전달되는 모든 값의 단위가 같아지며, 계산식은 clamp(0, tan(atan2(var(--vw) - 320px, 1200px - 320px)), 1)이 됨.

견고한 방식

  • 경계값에 rem을 사용하려는 경우 <length>로 등록한 사용자 지정 속성은 픽셀로 해석되므로, rem 단위로 해석되도록 지정할 수 없음.
  • 단위 혼합을 피하려면 각 값을 모두 픽셀로 해석되게 등록할 수 있지만, 값·시작점·끝점을 각각 등록할 필요는 없음.
  • atan2()에 전달되는 두 값인 오프셋과 범위만 사용자 지정 속성으로 만들고 @property에 <length>로 등록하면 됨.
  • 예를 들어 오프셋은 calc(100vw - 20rem), 범위는 calc(80rem - 20rem)으로 설정하고, clamp(0, tan(atan2(var(--offset), var(--span))), 1)로 계산함.
  • 이 방식은 progress()와 같은 계산을 제공하면서 브라우저 지원 범위를 넓힘.
  • progress()의 클램프되지 않은 버전을 흉내 내려면 clamp()를 제거함.

어떤 방식을 선택할까?

  • 단위 없는 숫자만 사용한다면 calc() 또는 clamp()로 값을 직접 계산함.
  • 단위가 있는 값을 사용한다면 tan(atan2()) 트릭을 적용함.
  • 값의 단위가 하나뿐이라면 사용자 지정 속성을 등록할 필요가 없음.
  • 픽셀과 비픽셀 단위 하나를 함께 사용한다면 비픽셀 값을 <length>로 등록함. 이는 유동형 타이포그래피에서 가장 흔한 경우임.
  • 여러 비픽셀 단위를 함께 사용한다면 오프셋과 범위를 사용자 지정 속성으로 만들고, 둘 다 <length>로 등록한 뒤 atan2()에 전달함.
  • progress()는 이미 최신 브라우저에서 사용할 수 있으며, 걱정 없이 네이티브로 쓰기까지 오래 걸리지 않을 전망임. 그때까지는 상황에 맞는 가장 단순한 대체 방식을 선택할 수 있음.