tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

view-timeline-range-animation.html (6147B)


      1 <!DOCTYPE html>
      2 <title>View timelines and animation attachment ranges</title>
      3 <link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#named-timeline-range">
      4 <link rel="help" src="https://drafts.csswg.org/scroll-animations-1/#animation-range">
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="/web-animations/testcommon.js"></script>
      8 <script src="support/testcommon.js"></script>
      9 <style>
     10  @keyframes anim {
     11    from { z-index: 0; background-color: skyblue;}
     12    to { z-index: 100; background-color: coral; }
     13  }
     14  #scroller {
     15    border:  10px solid lightgray;
     16    overflow-y: scroll;
     17    width: 200px;
     18    height: 200px;
     19  }
     20  #scroller > div {
     21    margin: 800px 0px;
     22    width: 100px;
     23    height: 100px;
     24  }
     25  #target {
     26    font-size: 10px;
     27    background-color: green;
     28    z-index: -1;
     29  }
     30 </style>
     31 <main id=main>
     32 </main>
     33 
     34 <template id=template_without_scope>
     35  <div id=scroller>
     36    <div id=target class=timeline></div>
     37  </div>
     38 </template>
     39 
     40 <template id=template_with_scope>
     41  <div id=scope>
     42    <div id=target></div>
     43    <div id=scroller>
     44      <div class=timeline></div>
     45    </div>
     46  </div>
     47 </template>
     48 
     49 <script>
     50  setup(assert_implements_animation_timeline);
     51 
     52  function inflate(t, template) {
     53    t.add_cleanup(() => main.replaceChildren());
     54    main.append(template.content.cloneNode(true));
     55  }
     56  async function scrollTop(e, value) {
     57    e.scrollTop = value;
     58    await waitForNextFrame();
     59  }
     60  async function waitForAnimationReady(target) {
     61    await waitForNextFrame();
     62    await Promise.all(target.getAnimations().map(x => x.ready));
     63  }
     64  async function assertValueAt(scroller, target, args) {
     65    await waitForAnimationReady(target);
     66    await scrollTop(scroller, args.scrollTop);
     67    assert_equals(getComputedStyle(target).zIndex, args.expected.toString());
     68  }
     69  function test_animation_range(options, template, desc_suffix) {
     70    if (template === undefined)
     71      template = template_without_scope;
     72    if (desc_suffix === undefined)
     73      desc_suffix = '';
     74 
     75    promise_test(async (t) => {
     76      inflate(t, template);
     77      let scroller = main.querySelector('#scroller');
     78      let target = main.querySelector('#target');
     79      let timeline = main.querySelector('.timeline');
     80      let scope = main.querySelector('#scope');
     81 
     82      if (scope != null) {
     83        scope.style.timelineScope = '--t1';
     84      }
     85 
     86      timeline.style.viewTimeline = '--t1';
     87      target.style.animation = 'anim auto linear';
     88      target.style.animationTimeline = '--t1';
     89      target.style.animationRangeStart = options.rangeStart;
     90      target.style.animationRangeEnd = options.rangeEnd;
     91 
     92      // Accommodates floating point precision errors at the endpoints.
     93      target.style.animationFillMode = 'both';
     94 
     95      // 0%
     96      await assertValueAt(scroller, target,
     97          { scrollTop: options.startOffset, expected: 0 });
     98      // 50%
     99      await assertValueAt(scroller, target,
    100          { scrollTop: (options.startOffset + options.endOffset) / 2, expected: 50 });
    101      // 100%
    102      await assertValueAt(scroller, target,
    103          { scrollTop: options.endOffset, expected: 100 });
    104 
    105      // Test before/after phases (need to clear the fill mode for that).
    106      target.style.animationFillMode = 'initial';
    107      await assertValueAt(scroller, target,
    108          { scrollTop: options.startOffset - 10, expected: -1 });
    109      await assertValueAt(scroller, target,
    110          { scrollTop: options.endOffset + 10, expected: -1 });
    111      // Check 50% again without fill mode.
    112      await assertValueAt(scroller, target,
    113          { scrollTop: (options.startOffset + options.endOffset) / 2, expected: 50 });
    114 
    115    }, `Animation with ranges [${options.rangeStart}, ${options.rangeEnd}] ${desc_suffix}`.trim());
    116  }
    117 
    118  test_animation_range({
    119    rangeStart: 'initial',
    120    rangeEnd: 'initial',
    121    startOffset: 600,
    122    endOffset: 900
    123  });
    124 
    125  test_animation_range({
    126    rangeStart: 'cover 0%',
    127    rangeEnd: 'cover 100%',
    128    startOffset: 600,
    129    endOffset: 900
    130  });
    131 
    132  test_animation_range({
    133    rangeStart: 'contain 0%',
    134    rangeEnd: 'contain 100%',
    135    startOffset: 700,
    136    endOffset: 800
    137  });
    138 
    139 
    140  test_animation_range({
    141    rangeStart: 'entry 0%',
    142    rangeEnd: 'entry 100%',
    143    startOffset: 600,
    144    endOffset: 700
    145  });
    146 
    147  test_animation_range({
    148    rangeStart: 'exit 0%',
    149    rangeEnd: 'exit 100%',
    150    startOffset: 800,
    151    endOffset: 900
    152  });
    153 
    154  test_animation_range({
    155    rangeStart: 'contain -50%',
    156    rangeEnd: 'entry 200%',
    157    startOffset: 650,
    158    endOffset: 800
    159  });
    160 
    161  test_animation_range({
    162    rangeStart: 'entry 0%',
    163    rangeEnd: 'exit 100%',
    164    startOffset: 600,
    165    endOffset: 900
    166  });
    167 
    168  test_animation_range({
    169    rangeStart: 'cover 20px',
    170    rangeEnd: 'cover 100px',
    171    startOffset: 620,
    172    endOffset: 700
    173  });
    174 
    175  test_animation_range({
    176    rangeStart: 'contain 20px',
    177    rangeEnd: 'contain 100px',
    178    startOffset: 720,
    179    endOffset: 800
    180  });
    181 
    182  test_animation_range({
    183    rangeStart: 'entry 20px',
    184    rangeEnd: 'entry 100px',
    185    startOffset: 620,
    186    endOffset: 700
    187  });
    188 
    189  test_animation_range({
    190    rangeStart: 'entry-crossing 20px',
    191    rangeEnd: 'entry-crossing 100px',
    192    startOffset: 620,
    193    endOffset: 700
    194  });
    195 
    196  test_animation_range({
    197    rangeStart: 'exit 20px',
    198    rangeEnd: 'exit 80px',
    199    startOffset: 820,
    200    endOffset: 880
    201  });
    202 
    203  test_animation_range({
    204    rangeStart: 'exit-crossing 20px',
    205    rangeEnd: 'exit-crossing 80px',
    206    startOffset: 820,
    207    endOffset: 880
    208  });
    209 
    210  test_animation_range({
    211    rangeStart: 'contain 20px',
    212    rangeEnd: 'contain calc(100px - 10%)',
    213    startOffset: 720,
    214    endOffset: 790
    215  });
    216 
    217  test_animation_range({
    218    rangeStart: 'exit 2em',
    219    rangeEnd: 'exit 8em',
    220    startOffset: 820,
    221    endOffset: 880
    222  });
    223 
    224  // Test animation-range via timeline-scope.
    225  test_animation_range({
    226    rangeStart: 'exit 2em',
    227    rangeEnd: 'exit 8em',
    228    startOffset: 820,
    229    endOffset: 880
    230  }, template_with_scope, '(scoped)');
    231 
    232  test_animation_range({
    233    rangeStart: 'scroll 100px',
    234    rangeEnd: 'scroll 800px',
    235    startOffset: 100,
    236    endOffset: 800
    237  });
    238 
    239 </script>