1. 소개
이 명세는 스크롤 컨테이너의 스크롤 진행 상황을 기반으로 애니메이션의 진행을 제어하는 메커니즘을 정의합니다. 이러한 스크롤 기반 애니메이션은 시계 시간 대신 스크롤 위치를 기반으로 하는 타임라인을 사용합니다. 이 모듈은 Web Animations API를 기반으로 한 명령형 API와 CSS Animations를 기반으로 한 선언형 API 모두를 제공합니다. [WEB-ANIMATIONS-1]
스크롤 기반 타임라인에는 두 가지 유형이 있습니다:
-
스크롤 진행 타임라인: 특정 스크롤 컨테이너의 스크롤 진행 상황에 연동됨
-
뷰 진행 타임라인: 특정 박스의 뷰 진행 상황이 scrollport를 통해 연결됨
참고: 스크롤 기반 애니메이션은 스크롤 위치에 따라 진행이 연결되며, 스크롤 트리거 애니메이션(스크롤 위치에 의해 트리거되지만 진행이 시간에 의해 제어됨)과 구별됩니다.
1.1. 다른 명세와의 관계
Web Animations [WEB-ANIMATIONS-1]은 웹 플랫폼의 애니메이션을 위한 추상 개념 모델을 정의하며, 이 모델의 요소에는 애니메이션과 타임라인, 그리고 관련 프로그래밍 인터페이스가 포함되어 있습니다. 이 명세는 Web Animations 모델을 확장하여 스크롤 기반 타임라인을 정의하고, 애니메이션의 진행을 제어함으로써 스크롤 기반 애니메이션을 생성할 수 있도록 합니다.
이 명세는 이러한 개념과 상호작용하는 프로그래밍 인터페이스와, CSS Animations [CSS-ANIMATIONS-1]에 적용되는 CSS 속성 모두를 도입합니다. 이러한 CSS 속성의 동작이 프로그래밍 인터페이스 기준으로 설명되는 범위 내에서, 스크립팅을 지원하지 않는 사용자 에이전트도 CSS 기능을 구현하여 마치 해당 프로그래밍 인터페이스가 존재하는 것처럼 동작하게 함으로써 이 명세를 준수할 수 있습니다.
CSS에서 선택자 매칭을 제외한 대부분의 작업과 마찬가지로, 이 명세의 기능은 플랫(flat) 요소 트리에 적용됩니다.
1.2. 비동기 스크롤과의 관계
일부 사용자 에이전트는 레이아웃이나 스크립트와 비동기로 스크롤을 지원합니다. 이 명세는 그러한 아키텍처와 호환되도록 설계되었습니다.
구체적으로, 이 명세는 스크립트가 효과를 샘플링할 때마다 반드시 실행될 필요 없이 스크롤 기반 효과를 표현할 수 있도록 허용합니다. 비동기 스크롤을 지원하는 사용자 에이전트는 이러한 효과를 비동기로 샘플링해도 됩니다(필수는 아님).
1.3. 값 정의
이 명세는 CSS 속성 정의 관례를 [CSS2]에서 따르며, 값 정의 문법은 [CSS-VALUES-3]을 사용합니다. 이 명세에서 정의되지 않은 값 유형은 CSS Values & Units [CSS-VALUES-3]에서 정의됩니다. 다른 CSS 모듈과 결합하면 이러한 값 유형의 정의가 확장될 수 있습니다.
속성 정의에 명시된 속성별 값 이외에도, 이 명세에서 정의된 모든 속성은 CSS-공통 키워드도 속성 값으로 허용합니다. 가독성을 위해 반복해서 명시하지 않았습니다.
2. 스크롤 진행 타임라인
스크롤 진행 타임라인은 특정 축을 따라 스크롤 컨테이너의 스크롤 위치 진행에 연결된 타임라인입니다. 시작 스크롤 위치는 0% 진행, 끝 스크롤 위치는 100% 진행을 나타냅니다.
스크롤 진행
타임라인은 animation-timeline에서 익명으로 scroll() 함수 표기법으로 참조하거나,
§ 4.2 이름있는 타임라인 범위와 조회에서처럼 이름으로 참조할 수 있습니다.
scroll-timeline 속성을 통해 선언한 후 참조합니다.
Web Animations API에서는 ScrollTimeline
객체를 통해 익명으로 나타낼 수 있습니다.
2.1. 스크롤 진행 타임라인의 진행도 계산
스크롤 진행 타임라인의 진행도(현재 시간)는 다음과 같이 계산됩니다: scroll offset ÷ (scrollable overflow 크기 − 스크롤 컨테이너 크기)
0% 위치와 100% 위치가 동일할 경우 (즉, 현재 시간 공식의 분모가 0인 경우), 해당 타임라인은 비활성(inactive) 상태가 됩니다.
페이지 미디어에서는, 문서 뷰포트를 참조하는 스크롤 진행 타임라인도 비활성 상태가 됩니다.
2.2. 익명 스크롤 진행 타임라인
2.2.1. scroll() 표기법
scroll() 함수 표기법은 <single-animation-timeline> 값으로 animation-timeline에서 사용할 수 있으며, 스크롤 진행 타임라인을 지정합니다. 그 문법은 다음과 같습니다.
<scroll()> = scroll( [ <scroller> || <axis> ]? ) <axis> = block | inline | x | y <scroller> = root | nearest | self
기본적으로 scroll()은 가장 가까운 조상 block 축의 스크롤 컨테이너를 참조합니다. 인수에 따라 이 조회 방법이 다음과 같이 변경됩니다:
- block
- block 축의 스크롤 컨테이너에서 진행도를 사용합니다. (기본값)
- inline
- inline 축의 스크롤 컨테이너에서 진행도를 사용합니다.
- x
- 수평(x) 축의 스크롤 컨테이너에서 진행도를 사용합니다.
- y
- 수직(y) 축의 스크롤 컨테이너에서 진행도를 사용합니다.
- nearest
- 가장 가까운 조상 스크롤 컨테이너를 사용합니다. (기본값)
- root
- 문서 뷰포트를 스크롤 컨테이너로 사용합니다.
- self
- 요소 자신의 주(principal) 박스를 스크롤 컨테이너로 사용합니다. 주 박스가 스크롤 컨테이너가 아니면, 해당 스크롤 진행 타임라인은 비활성이 됩니다.
참고: 진행도는 스크롤 기준점(origin)을 기준으로 하며, 쓰기 모드(writing mode)에 따라 바뀔 수 있습니다. x 또는 y가 지정되어도 마찬가지입니다.
루트 요소(root element)에 대한 참조는 문서 뷰포트로 전달되며 (문서 뷰포트는 스크롤 컨테이너로 동작합니다).
scroll()를 사용할
때마다 Web Animations API에서 ScrollTimeline
인스턴스가 각각 생성되며,
여러 요소가 동일한 scroll()로 동일한 스크롤
컨테이너 및 동일한 인수를 참조하더라도 각각 독립적인 인스턴스가 생성됩니다.
2.2.2.
ScrollTimeline
인터페이스
enum {
ScrollAxis ,
"block" ,
"inline" ,
"x" };
"y" dictionary {
ScrollTimelineOptions Element ?;
source ScrollAxis = "block"; }; [
axis Exposed =Window ]interface :
ScrollTimeline AnimationTimeline {constructor (optional ScrollTimelineOptions = {});
options readonly attribute Element ?source ;readonly attribute ScrollAxis axis ; };
ScrollTimeline
은 AnimationTimeline
을 상속하며, 스크롤 진행 타임라인을 나타냅니다.
이 객체는
Animation
생성자나 animate()
메서드에 전달하여
애니메이션을 스크롤 진행 타임라인과 연결할 수 있습니다.
source
, 타입 Element, 읽기 전용, nullable-
타임라인의 진행도를 제어하는 스크롤 컨테이너 요소입니다.
axis
, 타입 ScrollAxis, 읽기 전용-
타임라인의 진행도를 제어하는 스크롤의 축입니다. <axis>의 값 정의를 참고하세요.
상속된 속성:
currentTime
(AnimationTimeline
에서 상속됨)-
스크롤 컨테이너의 스크롤 진행을 백분율 CSSUnitValue로 나타내며, 0%는 스크롤 컨테이너의 쓰기 모드 기준 시작 스크롤 위치를 의미합니다. 타임라인이 비활성일 때는 null입니다.
0%는 보통 스크롤 컨테이너의 초기 스크롤 위치를 의미하지만, 콘텐츠 분포에 따라 다를 수 있습니다. CSS Box Alignment 3 § 5.3 오버플로우 및 스크롤 위치를 참고하세요. 이대로 괜찮나요?
currentTime
값이 음수나 100%를 초과할 수 있는지에 대한 노트를 추가해야 함.
ScrollTimeline(options)
-
다음 절차에 따라 새로운
ScrollTimeline
객체를 생성합니다:-
timeline을 새
ScrollTimeline
객체로 생성합니다. -
timeline의
source
값을 다음으로 설정합니다:- options의
source
멤버가 존재하고 null이 아닐 경우, -
options의
source
멤버 - 그 외의 경우,
-
scrollingElement
값을Document
연결된Window
의 현재 글로벌 오브젝트에서 가져옵니다.
- options의
-
timeline의
axis
속성을 options에서 해당하는 값으로 설정합니다.
-
source
값이 주 박스(principal box)가 없거나 스크롤
컨테이너가 아니거나,
스크롤 가능한 오버플로우가 없는 경우,
해당 ScrollTimeline
은 비활성 상태가 됩니다.
ScrollTimeline
의
duration
값은 100%입니다.
source
와 currentTime
값은 둘 중 하나가 요청되거나 갱신될 때마다 계산됩니다.
2.3. 이름있는 스크롤 진행 타임라인
스크롤 진행 타임라인은 스크롤 컨테이너 자체에도 정의할 수 있으며, 이름의 범위 내에 있는 요소에서 해당 이름으로 참조할 수 있습니다 (§ 4.2 이름있는 타임라인 범위와 조회 참고).
이러한 이름있는 스크롤 진행 타임라인은 연동 값 목록(coordinated value list)에서 선언되며, scroll-timeline scroll-timeline의 롱핸드(longhand) 속성에서 생성됩니다. 이들은 연동 리스트 속성 그룹을 형성하며, scroll-timeline-name이 기준 속성(base property) 역할을 합니다. CSS Values 4 § A Coordinating List-Valued Properties 참고.
2.3.1. 스크롤 진행 타임라인 명명: scroll-timeline-name 속성
이름(Name): | scroll-timeline-name |
---|---|
값(Value): | none | <dashed-ident># |
초기값(Initial): | none |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 해당 없음 |
계산 값(Computed value): | 키워드 none 또는 CSS 식별자 리스트 |
정규 순서(Canonical order): | grammar 기준 |
애니메이션 타입(Animation type): | 애니메이션 불가(not animatable) |
이 속성은 해당 요소에 연결된 이름있는 스크롤 진행 타임라인의 이름을 지정합니다.
2.3.2. 스크롤 진행 타임라인의 축: scroll-timeline-axis 속성
이름(Name): | scroll-timeline-axis |
---|---|
값(Value): | [ block | inline | x | y ]# |
초기값(Initial): | block |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 해당 없음 |
계산 값(Computed value): | 명시된 키워드 리스트 |
정규 순서(Canonical order): | grammar 기준 |
애니메이션 타입(Animation type): | 애니메이션 불가(not animatable) |
이 속성은 이 이름있는 스크롤 진행 타임라인이 참조하는 스크롤 컨테이너의 축을 지정합니다. 이 박스가 스크롤 컨테이너가 아니면, 해당 이름있는 스크롤 진행 타임라인은 비활성 상태가 됩니다.
값은 scroll()의 정의와 동일합니다.
2.3.3. 스크롤 타임라인 축약: scroll-timeline 축약형
이름(Name): | scroll-timeline |
---|---|
값(Value): | [ <'scroll-timeline-name'> <'scroll-timeline-axis'>? ]# |
초기값(Initial): | 각 속성별 참조 |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 각 속성별 참조 |
계산 값(Computed value): | 각 속성별 참조 |
애니메이션 타입(Animation type): | 애니메이션 불가(not animatable) |
정규 순서(Canonical order): | grammar 기준 |
이 속성은 축약형으로 scroll-timeline-name과 scroll-timeline-axis를 한 번에 설정합니다.
3. 뷰 진행 타임라인
애니메이션이 스크롤 진행 타임라인의 특정 박스(즉, 뷰 진행 주체) 가 scrollport 내에 표시된(뷰에 들어온) 구간에서 시작되고 끝나길 원하는 경우가 많습니다. 뷰 진행 타임라인은 스크롤 진행 타임라인의 일부 구간으로, 주체 요소의 주 박스(principal box)가 가장 가까운 조상 scrollport(정확하게는 해당 scrollport의 뷰 진행 가시성 범위)와 교차하는 스크롤 위치에 범위를 둡니다. 해당 구간의 시작 스크롤 위치가 0% 진행, 끝 스크롤 위치가 100% 진행을 나타냅니다. § 3.2 뷰 진행 타임라인 진행도 계산 참고.
참고: 0% 및 100% 스크롤 위치는 항상 도달 가능한 것은 아닙니다. 예를 들어 박스가 스크롤 가능한 오버플로우 사각형의 시작 가장자리에 위치하면, 32% 미만 진행도로 스크롤 하는 것이 불가능할 수 있습니다.
뷰 진행 타임라인은
view() 함수 표기법으로 익명 참조하거나, 이름 선언 후(아래 § 4.2
이름있는 타임라인 범위와 조회 참고)
view-timeline 속성을 사용해
뷰 진행 주체에서 이름
참조할 수 있습니다.
Web Animations API에서는 ViewTimeline
객체로 익명 참조할 수 있습니다.
3.1. 뷰 진행 타임라인 범위
뷰 진행 타임라인은 다음과 같은 이름있는 타임라인 범위를 정의합니다:
- cover
-
뷰 진행
타임라인의 전체 범위를 나타냅니다:
-
0% 진행은 요소의 주 박스의 시작 테두리(edge)가 해당 요소의 뷰 진행 가시성 범위의 끝 가장자리와 일치하는 가장 늦은 위치를 의미합니다.
-
100% 진행은 요소의 주 박스의 끝 테두리(edge)가 해당 요소의 뷰 진행 가시성 범위의 시작 가장자리와 일치하는 가장 이른 위치를 의미합니다.
-
- contain
-
주 박스가
뷰 진행 가시성 범위 내에서 완전히 포함되거나, 완전히 덮는 구간을 나타냅니다.
-
0% 진행은 다음 중 하나가 처음으로 만족되는 위치를 의미합니다:
-
요소의 주 박스의 시작 테두리(edge)가 해당 뷰 진행 가시성 범위의 시작 가장자리와 일치
-
요소의 주 박스의 끝 테두리(edge)가 해당 뷰 진행 가시성 범위의 끝 가장자리와 일치
-
-
100% 진행은 다음 중 하나가 마지막으로 만족되는 위치를 의미합니다:
-
요소의 주 박스의 시작 테두리(edge)가 해당 뷰 진행 가시성 범위의 시작 가장자리와 일치
-
요소의 주 박스의 끝 테두리(edge)가 해당 뷰 진행 가시성 범위의 끝 가장자리와 일치
-
-
- entry
- 주 박스가 뷰 진행 가시성 범위에 진입하는 구간을 나타냅니다.
- exit
- 주 박스가 뷰 진행 가시성 범위에서 벗어나는 구간을 나타냅니다.
- entry-crossing
- 주 박스가 끝 테두리(edge)를 교차하는 구간을 나타냅니다.
- exit-crossing
- 주 박스가 시작 테두리(edge)를 교차하는 구간을 나타냅니다.
모든 경우, 쓰기 모드(writing mode)를 기준으로 시작 및 끝 방향이 판별됩니다. 이때 쓰기 모드는 해당 스크롤 컨테이너의 값입니다. 변환(Transforms)은 무시되지만, 상대(relative) 및 절대(absolute) 위치 지정은 반영됩니다.
참고: sticky-positioned 박스의 경우, 0%와 100% 진행 조건이 단일 스크롤 위치가 아닌 구간(range) 내에서 만족될 수 있습니다. 따라서 각 범위는 가장 이른 위치 또는 가장 늦은 위치를 사용할지 명시합니다.
[CSS-POSITION-3] [CSS-TRANSFORMS-1]
3.2. 뷰 진행 타임라인의 진행도 계산
현재 시간 기준의 뷰 진행 타임라인 진행도는 다음과 같이 계산합니다: distance ÷ range 여기서:
-
distance는 현재 scroll offset에서 cover 범위의 시작 스크롤 오프셋을 뺀 값입니다.
-
range는 cover 범위의 시작 스크롤 오프셋에서 cover 범위의 끝 스크롤 오프셋을 뺀 값입니다.
만약 0% 위치와 100% 위치가 일치하는 경우 (즉, 현재 시간 공식의 분모가 0인 경우), 해당 타임라인은 비활성 상태가 됩니다.
페이지 미디어에서는, 문서 뷰포트를 참조하는 뷰 진행 타임라인도 비활성 상태가 됩니다.
3.3. 익명 뷰 진행 타임라인
3.3.1. view() 표기법
view() 함수 표기법은 <single-animation-timeline> 값으로 animation-timeline에 사용할 수 있으며 가장 가까운 조상 스크롤 컨테이너를 기준으로 뷰 진행 타임라인을 지정합니다. 문법은 다음과 같습니다.
<view()> = view( [ <axis> || <'view-timeline-inset'> ]? )
기본적으로 view()는 block 축을 참조합니다. scroll()과 마찬가지로, 명시적으로 <axis> 값을 지정해 변경할 수 있습니다.
선택적 <'view-timeline-inset'> 값은 뷰 진행 가시성 범위를 조정하며, 해당 정의는 view-timeline-inset에서 확인할 수 있습니다.
view()를 사용할 때마다 Web
Animations API의 ViewTimeline
인스턴스가 각각 생성되며,
여러 요소가 동일한 view()로 동일한 요소와 인수를 참조하더라도 각각 독립적인 인스턴스가
생성됩니다.
3.3.2.
ViewTimeline
인터페이스
dictionary {
ViewTimelineOptions Element ;
subject ScrollAxis = "block"; (
axis DOMString or sequence <(CSSNumericValue or CSSKeywordValue )>)= "auto"; }; [
inset Exposed =Window ]interface :
ViewTimeline ScrollTimeline {constructor (optional ViewTimelineOptions = {});
options readonly attribute Element subject ;readonly attribute CSSNumericValue startOffset ;readonly attribute CSSNumericValue endOffset ; };
ViewTimeline
은 AnimationTimeline
을 상속하며, 뷰 진행
타임라인을 지정합니다.
이 객체는
Animation
생성자나 animate()
메서드에 전달하여
애니메이션을 뷰 진행 타임라인과 연결할 수 있습니다.
subject
, 타입 Element, 읽기 전용-
이 요소의 주 박스가 scrollport 내에서 표시(가시성)될 때 타임라인의 진행도를 정의합니다.
startOffset
, 타입 CSSNumericValue, 읽기 전용-
뷰 진행 타임라인의 시작(0% 진행) 스크롤 위치를 px 단위 길이 오프셋으로 스크롤 기준점(origin) 기준으로 나타냅니다. 타임라인이 비활성일 때는 null입니다.
endOffset
, 타입 CSSNumericValue, 읽기 전용-
뷰 진행 타임라인의 끝(100% 진행) 스크롤 위치를 px 단위 길이 오프셋으로 스크롤 기준점(origin) 기준으로 나타냅니다. 타임라인이 비활성일 때는 null입니다.
참고: startOffset
과 endOffset
값은 스크롤 기준점(origin) 기준이며, 물리적 좌상단 기준이 아닙니다.
스크롤 컨테이너의 쓰기 모드에 따라
scrollLeft
또는 scrollTop
값과 다를 수 있으니 주의하세요.
예를 들어 수평(x) 축에서 오른쪽-왼쪽(rtl) 쓰기 모드일 때 값이 다를 수 있습니다.
상속된 속성:
source
(ScrollTimeline
에서 상속됨)-
subject
의 가장 가까운 조상 중에서 주 박스가 스크롤 컨테이너를 생성하는 요소이며, 이 컨테이너의 스크롤 위치가 타임라인 진행도를 제어합니다. axis
(ScrollTimeline
에서 상속됨)-
타임라인의 진행도를 제어하는 스크롤의 축을 지정합니다. 위에서 <axis> 정의 참고.
currentTime
(AnimationTimeline
에서 상속됨)-
뷰 진행 타임라인의 현재 진행도를 백분율
CSSUnitValue
로 나타내며, 해당 스크롤 컨테이너의 스크롤 진행도에 해당합니다. 타임라인이 비활성일 때는 null입니다.
ViewTimeline(options)
-
다음 절차에 따라 새로운
ViewTimeline
객체를 생성합니다:-
timeline을 새
ViewTimeline
객체로 생성합니다. -
inset 값으로
DOMString
이 주어지면 <'view-timeline-inset'> 값으로 파싱합니다. 시퀀스가 주어지면 첫 번째 값이 시작 인셋, 두 번째 값이 끝 인셋입니다. 시퀀스에 값이 하나면 복제합니다. 값이 0개이거나 2개 초과이거나,CSSKeywordValue
가 "auto"가 아닌 값을 포함하면 TypeError를 발생시킵니다.이 인셋은
ViewTimeline
의 뷰 진행 가시성 범위를 정의합니다.
-
source
또는 subject
값이 주 박스가 없거나,
가장 가까운 조상 스크롤 컨테이너에 스크롤
가능한 오버플로우가 없으면(혹은 조상 자체가 없으면, 예: 인쇄 미디어),
해당 ViewTimeline
은 비활성 상태가 됩니다.
subject
,
source
,
currentTime
값은 셋 중 하나가 요청되거나 갱신될 때마다 계산됩니다.
3.4. 이름있는 뷰 진행 타임라인
뷰 진행 타임라인은 선언적으로도 정의할 수 있으며, 이름의 범위 내에 있는 요소에서 해당 이름으로 참조할 수 있습니다 (§ 4.2 이름있는 타임라인 범위와 조회 참고).
이러한 이름있는 뷰 진행 타임라인은 연동 값 목록(coordinated value list)에서 선언되며, view-timeline-* 속성에서 생성됩니다. 이들은 연동 리스트 속성 그룹을 형성하며, view-timeline-name이 기준 속성(base property) 역할을 합니다. CSS Values 4 § A Coordinating List-Valued Properties 참고.
3.4.1. 뷰 진행 타임라인 명명: view-timeline-name 속성
이름(Name): | view-timeline-name |
---|---|
값(Value): | none | <dashed-ident># |
초기값(Initial): | none |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 해당 없음 |
계산 값(Computed value): | 키워드 none 또는 CSS 식별자 리스트 |
정규 순서(Canonical order): | grammar 기준 |
애니메이션 타입(Animation type): | 애니메이션 불가(not animatable) |
이 속성은 해당 요소에 연결된 이름있는 뷰 진행 타임라인의 이름을 지정합니다.
3.4.2. 뷰 진행 타임라인의 축: view-timeline-axis 속성
이름(Name): | view-timeline-axis |
---|---|
값(Value): | [ block | inline | x | y ]# |
초기값(Initial): | block |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 해당 없음 |
계산 값(Computed value): | 명시된 키워드 리스트 |
정규 순서(Canonical order): | grammar 기준 |
애니메이션 타입(Animation type): | 애니메이션 불가(not animatable) |
이 속성은 이 이름있는 뷰 진행 타임라인이 해당 요소의 주 박스에서 파생됨을 지정합니다.
값은 view() 정의와 동일합니다.
3.4.3. 뷰 진행 타임라인의 인셋: view-timeline-inset 속성
이름(Name): | view-timeline-inset |
---|---|
값(Value): | [ [ auto | <length-percentage> ]{1,2} ]# |
초기값(Initial): | auto |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 해당 scrollport의 해당 치수 기준 상대값 |
계산 값(Computed value): | 키워드 auto 또는 계산된 <length-percentage> 값으로 표현되는 시작/끝 인셋의 2값 쌍 리스트 |
정규 순서(Canonical order): | grammar 기준 |
애니메이션 타입(Animation type): | 계산 값의 타입에 따라 다름 |
해당 박스가 뷰에 표시되는지 판단할 때 해당 scrollport의 인셋(양수) 또는 아웃셋(음수) 조정을 지정하며, 해당 뷰 진행 타임라인의 경계를 설정합니다. 첫 번째 값은 해당 축의 시작 인셋, 두 번째 값은 끝 인셋입니다. 두 번째 값을 생략하면 첫 번째 값을 복제합니다. 결과적으로 산출된 scrollport의 범위가 뷰 진행 가시성 범위입니다.
- auto
- scroll-padding 값을 사용함을 의미합니다.
- <length-percentage>
- scroll-padding처럼 해당 scrollport 가장자리에서 안쪽으로 오프셋을 정의합니다.
3.4.4. 뷰 타임라인 축약: view-timeline 축약형
이름(Name): | view-timeline |
---|---|
값(Value): | [ <'view-timeline-name'> <'view-timeline-axis'>? ]# |
초기값(Initial): | 각 속성별 참조 |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 각 속성별 참조 |
백분율(Percentages): | 각 속성별 참조 |
계산 값(Computed value): | 각 속성별 참조 |
애니메이션 타입(Animation type): | 각 속성별 참조 |
정규 순서(Canonical order): | grammar 기준 |
이 속성은 축약형으로 view-timeline-name과 view-timeline-axis를 한 번에 설정합니다. view-timeline-inset은 설정하지 않습니다.
view-timeline-inset도 초기화해야 할까요?
4. 애니메이션을 스크롤 기반 타임라인에 연결하기
애니메이션은 스크롤 기반
타임라인에 scroll-timeline 속성(CSS) 또는 AnimationTimeline
매개변수(Web Animations API)로 연결할 수 있습니다.
이때 active interval이
연결되는 타임라인 범위를 추가로 제한할 수도 있습니다
(애니메이션을 타임라인 범위에 연결하기 참고).
시간 기반 지연(animation-delay)은 스크롤 기반 애니메이션에는 적용되지 않으며, 이들은 거리 기반으로 동작합니다.
4.1. 유한 타임라인 계산
시간 기반 타임라인과 달리 스크롤 기반 타임라인은 유한하며, 따라서 스크롤 기반 애니메이션은 항상 유한한 연결 범위(attachment range)에 연결됩니다. 이 범위는 animation-range로 추가로 제한될 수 있습니다 (부록 A: 타임라인 범위 참고). 애니메이션의
반복 횟수(animation-iteration-count) 는 이 유한한 범위 내에서 설정됩니다. 지정된 duration 값이 auto이면, 남은 범위를 iteration count (animation-iteration-count)로 나누어 사용된(used) duration을 계산합니다.참고: 애니메이션이 무한 반복 횟수(iteration count)를 가지면, 각 반복 지속 시간(iteration duration)과 결과 active duration은 0이 됩니다.
명확한 위치에 고정된 키프레임(예: 이름있는 타임라인 범위 키프레임 선택자를 @keyframes에서 사용한 것)이 포함된 애니메이션은, 해당 키프레임 위치를 0%와 100%에 맞추기 위해 반복 횟수(iteration count)를 1로 간주합니다. 전체 애니메이션은 반복 지속 시간(iteration duration)에 맞게 스케일링되고, 반복 횟수만큼 반복됩니다.
참고: 1을 초과하는 반복 횟수와 절대 위치 지정 키프레임을 조합하는 실제 사용 사례가 불분명합니다. 이 정의는 최소한 동작을 명확히 합니다. (대안으로, 반복 시 고정 키프레임을 "플로우에서 분리"하는 동작도 있지만, 더 이상할 수 있습니다.) 편집자들은 실제로 여러 반복에서 절대 위치 키프레임을 사용하는 사례가 있다면 의견을 듣고 싶습니다.
4.2. 이름있는 타임라인 범위와 조회
이름있는 스크롤 진행 타임라인 또는 뷰 진행 타임라인은 다음을 통해 참조할 수 있습니다:
-
이름을 선언한 요소 자체
-
해당 요소의 하위 요소들
참고: timeline-scope 속성을 사용하면 타임라인을 정의한 요소의 상위 요소에 타임라인 이름을 선언할 수 있어, 해당 요소의 서브트리 범위를 넘어 타임라인의 범위를 확장할 수 있습니다.
여러 요소가 동일한 타임라인 이름을 선언하면, 트리 순서상 가장 가까운 요소에 선언된 타임라인이 매칭됩니다. 동일 요소 내 이름 충돌 시, 이름 지정 속성(scroll-timeline-name, view-timeline-name)에서 나중에 선언된 이름이 우선하며, 스크롤 진행 타임라인이 뷰 진행 타임라인보다 우선합니다.
< style > @ keyframes anim { from { color : red ; } to { color : green ; } } . root { /* 'scroller' 타임라인의 범위를 모든 하위 요소까지 선언 */ timeline-scope : scroller ; } . root . animation { animation : anim ; /* 'scroller' 타임라인을 참조해 'anim'의 진행을 제어 */ animation-timeline : scroller ; } . root . animation + . scroller { /* 'scroller' 타임라인 이름에 스크롤 진행 타임라인을 연결 */ scroll-timeline : scroller ; } </ style > … < section class = "root" > < div class = "animation" > Animating Box</ div > < div class = "scroller" > Scrollable Box</ div > </ section >
4.3. 애니메이션 이벤트
스크롤 기반 애니메이션은 Web Animations § 4.4.18 애니메이션 이벤트, CSS Animations 1 § 4 애니메이션 이벤트, CSS Animations 2 § 4.1 이벤트 디스패치에서 설명한 것과 동일한 애니메이션 이벤트를 모두 디스패치합니다.
참고: 스크롤을 뒤로 이동할 때,
animationstart
이벤트는 active
interval
의 끝에서 발생하고,
animationend
이벤트는 active interval의 시작에서 발생합니다.
하지만 finish
이벤트는
종료(play state 완료) 상태에 진입할 때 발생하므로,
오직 스크롤이 앞으로 진행될 때만 발생합니다.
5. 프레임 계산 세부사항
5.1. HTML 처리 모델: 이벤트 루프
스크롤이 애니메이션 진행을 제어할 수 있게 되면서 레이아웃 순환이 발생할 가능성이 있습니다. 즉, 스크롤 오프셋 변경이 애니메이션 효과를 업데이트시키고, 이 효과가 다시 스크롤 오프셋 변화를 일으키는 경우입니다.
이러한 레이아웃 순환을 방지하기 위해, 스크롤 진행 타임라인을 가진 애니메이션은 HTML 처리 모델 이벤트 루프의 7.10단계에서, 애니메이션 업데이트 및 이벤트 디스패치의 1단계로 현재 시간을 한 번 업데이트합니다.
HTML 처리 모델의 7.14.1단계 동안, 생성된 스크롤 진행 타임라인 또는 뷰 진행 타임라인이 지연(stale) 타임라인 집합에 수집됩니다. 7.14단계 이후 타임라인의 이름있는 타임라인 범위가 변경되면, 해당 타임라인이 지연 타임라인 집합에 추가됩니다. 지연 타임라인이 있으면, 현재 시간 및 관련 범위를 업데이트하고 지연 타임라인 집합을 비운 후, 스타일 재계산 및 레이아웃 업데이트를 추가로 실행합니다.
참고: 프로그래밍적으로 크기가 변경된 요소를 고려하기 위해,
ResizeObserver
디스패치 후 레이아웃 변화를 체크합니다.
참고: 최초 스타일 및 레이아웃 계산에서만 지연 타임라인을 수집하므로, 직접적으로 추가 스타일 재계산이 한 번만 발생할 수 있습니다. 다른 API가 추가 업데이트를 요구하는 경우 동일 단계에서 확인하고 동시에 갱신해야 합니다.
참고: 이 추가 스타일·레이아웃 라운드가 없으면 초기 지연(initially stale) 타임라인은 (즉, 해당 프레임에서 current time이 없음) 프레임이 끝날 때까지 계속 지연 상태가 됩니다. 이 경우 해당 타임라인에 연결된 애니메이션은 해당 프레임에서 효과 값을 생성하지 않아, 렌더링 결과에 원치 않는 "플래시"가 발생할 수 있습니다.
참고: 이 섹션은 getComputedStyle()
등으로 강제로 발생하는 스타일·레이아웃 계산에는 영향을 주지 않습니다.
즉, 초기 지연 타임라인은 해당 API를 통해서도 보입니다.
최종 스타일 및 레이아웃 업데이트에서 어떤 timeline-scope를 가진 스크롤 진행 타임라인 또는 뷰 진행 타임라인의 시간이나 범위가 변경된다면, 렌더링이 다음번 업데이트 될 때까지 새로운 상태로 재샘플링되지 않습니다.
이 섹션의 어떤 내용도 스크롤이 레이아웃이나 스크립트에 대해 블록되어야 함을 요구하지 않습니다.
만약 사용자 에이전트가 스크롤이 발생했지만 그 결과가 완전히 레이아웃이나 스크립트에 반영되지 않은 프레임(예: scroll
이벤트 리스너가 아직 실행되지 않은 경우)을
합성한다면,
해당 프레임에서는 스크롤 기반 애니메이션을 샘플링하지 않을 수도 있습니다.
이런 경우 렌더링된 스크롤 오프셋과 스크롤 기반 애니메이션 상태가 합성 프레임에서 불일치할 수 있습니다.
6. 프라이버시 고려사항
이 명세의 기능에는 알려진 프라이버시 영향이 없습니다.
7. 보안 고려사항
이 명세의 기능에는 알려진 보안 영향이 없습니다.
부록 A: 타임라인 범위
이 섹션은 CSS-ANIMATIONS-2 및 WEB-ANIMATIONS-2로 이동해야 합니다.
이 부록은 이름있는 타임라인 범위와 애니메이션 연결 범위 개념을 CSS Animations 및 Web Animations에 도입합니다.
이름있는 타임라인 범위
이름있는 타임라인 범위는 애니메이션 타임라인의 명명된 구간(segment)입니다. 구간의 시작은 해당 범위에서 0% 진행, 구간의 끝은 100% 진행으로 표시됩니다. 하나의 타임라인에 여러 이름있는 타임라인 범위가 연결될 수 있으며, 이 범위들은 서로 겹칠 수 있습니다. 예를 들어 contain 범위와 뷰 진행 타임라인의 cover 범위는 겹칩니다. 이름있는 타임라인 범위는 <timeline-range-name> 값 타입으로 표현되며, 이는 미리 정의된 이름있는 타임라인 범위 중 하나를 나타내는 CSS 식별자입니다.
참고: 이 명세에서는 이름있는 타임라인 범위가 반드시 [SCROLL-ANIMATIONS-1]과 같은 명세에서 정의되어야 합니다. 향후 버전은 저자가 직접 커스텀 이름있는 타임라인 범위를 선언할 수 있는 API를 제공할 수 있습니다.
이름있는 타임라인 범위 키프레임 선택자
이름있는 타임라인 범위 이름과 백분율은 이름있는 타임라인 범위 내 특정 진행 위치에 키프레임을 연결(attach)할 때 사용할 수 있습니다. CSS @keyframes 규칙은 다음과 같이 확장됩니다:
<keyframe-selector> = from | to | <percentage [0,100]> | <timeline-range-name> <percentage>
여기서 <timeline-range-name>은 미리 정의된 이름있는 타임라인 범위를 나타내는 CSS 식별자이고, 그 뒤의 <percentage>는 해당 이름있는 타임라인 범위 시작~끝 사이의 진행도를 의미합니다.
키프레임은 타임라인의 지정 위치에 연결됩니다. 만약 타임라인에 해당 이름있는 타임라인 범위가 없으면, 해당 이름있는 타임라인 범위 위치에 붙인 키프레임은 무시됩니다. 이 연결 위치가 애니메이션의 active interval을 벗어날 수도 있습니다; 이 경우 자동 from(0%) 및 to(100%) 키프레임은 해당 속성에 대해 0% 이하/100% 이상에 키프레임이 없는 경우에만 생성됩니다.
애니메이션을 타임라인 범위에 연결하기
애니메이션 키프레임 집합을 애니메이션 연결 범위 기준으로 연결시켜, 애니메이션의 active interval을 해당 타임라인 범위로 제한할 수 있으며, animation-range 속성을 이용합니다. 지연(delay, animation-delay) 은 이 제한된 범위 내에서 설정되어, auto duration 및 infinite 반복 횟수에 사용 가능한 시간을 더 줄입니다.
참고: animation-range는 연결 범위를 확장할 수도, 축소할 수도 있습니다.
연결 범위(attachment range) 외 위치의 키프레임은 보간에 사용될 수 있지만, active interval 밖이므로 애니메이션 자체에는 포함되지 않고, 결과적으로 애니메이션이 해당 연결 범위 끝에서 잘립니다.
range start┐ ╺┉┉active interval┉┉╸ ┌range end ┄┄┄┄┄┄┄┄┄┄┄├─────────────╊━━━━━━━━━━━━━━━━━━━╉───────────┤┄┄┄┄┄┄┄┄ ╶┄start delay┄╴ ╶┄end delay┄╴ ╶┄┄┄┄┄ duration┄┄┄┄┄╴
animation-range 속성들은 reset-only 하위 속성이며, animation 축약형(shorthand)의 일부입니다.
애니메이션의 타임라인 범위 지정: animation-range 축약형
이름(Name): | animation-range |
---|---|
값(Value): | [ <'animation-range-start'> <'animation-range-end'>? ]# |
초기값(Initial): | 각 속성별 참조 |
적용 대상(Applies to): | 각 속성별 참조 |
상속됨(Inherited): | 각 속성별 참조 |
백분율(Percentages): | 각 속성별 참조 |
계산 값(Computed value): | 각 속성별 참조 |
애니메이션 타입(Animation type): | 각 속성별 참조 |
정규 순서(Canonical order): | grammar 기준 |
animation-range 속성은 축약형(shorthand)으로, animation-range-start와 animation-range-end를 한 번에 설정하며, 애니메이션을 지정된 애니메이션 연결 범위와 연결합니다.
<'animation-range-end'>가 생략되고, <'animation-range-start'>에 <timeline-range-name>이 포함되어 있으면, animation-range-end는 동일한 <timeline-range-name>과 100%로 설정됩니다. 그렇지 않으면, 생략된 롱핸드(longhand)는 초기값으로 설정됩니다.
animation-range: entry 10% exit 90%; animation-range-start: entry 10%; animation-range-end: exit 90%; animation-range: entry; animation-range-start: entry 0%; animation-range-end: entry 100%; animation-range: entry exit; animation-range-start: entry 0%; animation-range-end: exit 100%; animation-range: 10%; animation-range-start: 10%; animation-range-end: normal; animation-range: 10% 90%; animation-range-start: 10%; animation-range-end: 90%; animation-range: entry 10% exit; animation-range-start: entry 10%; animation-range-end: exit 100%; animation-range: 10% exit 90%; animation-range-start: 10%; animation-range-end: exit 90%; animation-range: entry 10% 90%; animation-range-start: entry 10%; animation-range-end: 90%;
여기서 생략된 값의 기본값 처리 방법은 무엇이 최선일까요? [Issue #8438]
애니메이션의 타임라인 범위 시작 지정: animation-range-start 속성
이름(Name): | animation-range-start |
---|---|
값(Value): | [ normal | <length-percentage> | <timeline-range-name> <length-percentage>? ]# |
초기값(Initial): | normal |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 지정된 이름있는 타임라인 범위 기준 상대값, 없으면 전체 타임라인 기준 |
계산 값(Computed value): | 리스트, 각 항목은 normal 키워드 또는 타임라인 범위와 진행 백분율 |
정규 순서(Canonical order): | grammar 기준 |
애니메이션 타입(Animation type): | 애니메이션 불가 |
애니메이션의 연결 범위(attachment range) 시작을 지정하며, 이에 따라 애니메이션의 시작 시간(start time) (즉, 반복 횟수가 1일 때 0% 진행에 연결된 키프레임 위치) 을 조정합니다.
값의 의미는 다음과 같습니다:
- normal
- 애니메이션의 연결 범위 시작이 연관된 타임라인의 시작과 동일합니다. 애니메이션의 active interval 시작은 기본 동작대로 결정됩니다.
- <length-percentage>
- 애니메이션 연결 범위의 시작을 타임라인의 시작점에서 지정한 위치로 설정합니다.
- <timeline-range-name> <length-percentage>?
- 애니메이션 연결 범위의 시작을 지정한 이름있는 타임라인 범위의 시작점에서 지정한 위치로 설정합니다. <length-percentage>가 생략되면 기본값은 0%입니다.
애니메이션의 타임라인 범위 끝 지정: animation-range-end 속성
이름(Name): | animation-range-end |
---|---|
값(Value): | [ normal | <length-percentage> | <timeline-range-name> <length-percentage>? ]# |
초기값(Initial): | normal |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 지정된 이름있는 타임라인 범위 기준 상대값, 없으면 전체 타임라인 기준 |
계산 값(Computed value): | 리스트, 각 항목은 normal 키워드 또는 타임라인 범위와 진행 백분율 |
정규 순서(Canonical order): | grammar 기준 |
애니메이션 타입(Animation type): | 애니메이션 불가 |
애니메이션의 연결 범위(attachment range) 끝을 지정하며, 이에 따라 애니메이션의 종료 시간(end time) (즉, 반복 횟수가 1일 때 100% 진행에 연결된 키프레임 위치) 을 조정하거나, 애니메이션의 active interval을 잘라낼 수 있습니다.
값의 의미는 다음과 같습니다:
- normal
- 애니메이션의 연결 범위 끝이 연관된 타임라인의 끝과 동일합니다. 애니메이션의 active interval 끝은 기본 동작대로 결정됩니다.
- <length-percentage>
- 애니메이션 연결 범위의 끝을 타임라인의 시작점에서 지정한 위치로 설정합니다.
- <timeline-range-name> <length-percentage>?
- 애니메이션 연결 범위의 끝을 지정한 이름있는 타임라인 범위의 시작점에서 지정한 위치로 설정합니다. <length-percentage>가 생략되면 기본값은 100%입니다.
타임라인 범위 진행도 보고: getCurrentTime() 메서드
이름있는 범위 진행도는 AnimationTimeline
객체의 getCurrentTime()
메서드로 노출됩니다:
dictionary {
AnimationTimeOptions DOMString ?; }; [
range Exposed =Window ]partial interface AnimationTimeline {CSSNumericValue ?getCurrentTime (optional AnimationTimeOptions = {}); };
options
CSSNumericValue? getCurrentTime(optional AnimationCurrentTimeOptions = {})
-
현재 시간(current time)을 다음과 같이 반환합니다:
range
를 제공하지 않은 경우:-
currentTime
값을 반환합니다. 단, 밀리초 값은 double 대신CSSUnitValue
의 ms 단위로 반환합니다. range
를 제공했고, 이름있는 타임라인 범위가 this에 유효한 경우:-
progress를 해당 범위 내 현재 진행도로 두고,
백분율 값으로 표현합니다.
(progress, "percent")로 새 단위 값(unit value)을 생성해 반환합니다.
만약 이름있는 타임라인 범위의 시작과 끝이 동일하다면, 해당 지점 이전 또는 같은 시간값에는 음의 무한대, 이후에는 양의 무한대로 반환합니다.
-
range
를 제공하지만, 이름있는 타임라인 범위가 this에 유효하지 않은 경우: - null 반환
이 메서드는 currentTime
과
관련 있지만 완전히 같지는 않음; 명칭을 다르게 해야 할까? [Issue
#8201]
이 메서드는 range 이름이 주어지면 ScrollTimeline의 범위 기준 백분율을 반환함. 그러나 시간 기반 타임라인에서 range 이름이 주어지면, 해당 범위의 백분율 진행을 반환해야 할지, 시간 진행을 반환해야 할지?
부록 B: 타임라인 이름 범위
이 섹션은 CSS-ANIMATIONS-2로 이동해야 합니다.
이 부록은 timeline-scope 속성을 소개합니다. 이 속성을 사용하면 타임라인을 정의하는 요소의 상위 요소에서 타임라인 이름의 범위를 선언할 수 있습니다.
이름있는 타임라인의 범위 선언: timeline-scope 속성
이름(Name): | timeline-scope |
---|---|
값(Value): | none | <dashed-ident># |
초기값(Initial): | none |
적용 대상(Applies to): | 모든 요소 |
상속됨(Inherited): | 아님 |
백분율(Percentages): | 해당 없음 |
계산 값(Computed value): | none 키워드 또는 CSS 식별자 리스트 |
정규 순서(Canonical order): | grammar 기준 |
애니메이션 타입(Animation type): | 애니메이션 불가 |
이 속성은 지정한 타임라인 이름의 범위가 이 요소의 서브트리 전체로 확장됨을 선언합니다. 이를 통해 이름있는 타임라인 (예: 이름있는 스크롤 진행 타임라인 또는 이름있는 뷰 진행 타임라인) 을 타임라인 정의 요소의 서브트리 밖(형제, 사촌, 상위 요소 등)에서도 참조할 수 있습니다. 또한, 지정한 이름을 가진 하위 요소의 타임라인은 이 서브트리 밖에서 참조할 수 없고, 상위 요소의 동일한 이름 타임라인은 이 서브트리 내에서 참조할 수 없습니다.
이러한 차단 효과에 대해 논의가 남아 있습니다. [Issue #8915]
값의 의미는 다음과 같습니다:
- none
- 타임라인 이름 범위에 변화 없음.
- <dashed-ident>
-
하위 요소에서 정의된(직접 하위 요소가 timeline-scope로 명시적으로 선언하지 않은 경우) 동일 이름 타임라인의 범위를 이 요소와 하위
요소에 선언합니다.
해당 타임라인이 없거나, 둘 이상이면, 대신 지정한 이름의 비활성 타임라인을 선언합니다.
참고: 이 속성은 동일 이름을 선언한 하위 요소의 서브트리 내에서는 타임라인 이름 조회에 영향을 주거나 무효화할 수 없습니다. 이름있는 타임라인의 범위 선언: timeline-scope 속성 참고.
8. 변경 사항
이전(2023년 4월 28일) 작업 초안 이후의 변경 사항은 다음과 같습니다:
-
scroll-timeline-attachment와 view-timeline-attachment를 삭제하고 timeline-scope로 대체함. (이슈 7759)
-
이름있는 타임라인을 표준 CSS 키워드와의 이름 충돌을 피하기 위해 <dashed-ident>를 사용하도록 변경함(기존 <custom-ident>에서). (이슈 8746)
이전 변경 사항도 참고하세요.