quartoreveal.js

Is it possible to make a fragment stay visible across two fragment steps, and then disappear?


With {.fragment .fade-in-then-out}, we can display some content that disappears at the next fragment. I would like something like .fade-in-then-still-in-then-out, where the content would remain visible at the next fragment and then disappear at the following one. Is it possible to do that?

Here is a concrete and reproducible example of what I would like:

---
title-slide: false
format: 
  revealjs:
    theme: sky
---

## Test

::: {.fragment .fade-in .tiny-text}
- first fragment
:::

::: {.fragment .fade-in .tiny-text}
<div style = "position: absolute; top: 300px; left: 600px; width: 300px; text-align: center;">
second fragment: this text should disappear at the fourth fragment.
</div>
:::

::: {.fragment .fade-in .tiny-text}
<div style = "position: absolute; top: 500px; left: 500px; width: 300px; text-align: center;">
third fragment: this text should disappear at the fourth fragment.
</div>
:::

::: {.fragment .fade-in .tiny-text}
- fourth fragment: the two texts of the second and third fragments should not be visible anymore.
:::

    
<style>
  .tiny-text {
    font-size: 0.6em;
  }
</style>

Solution

  • Using JS, you can collect the fragments which shall be hidden (I use here e.g. data-fragment-index="1", but you can pass custom classes or other identifiers such that you don't need to rely on indices, what can become difficult to maintain) and toggle the classes fade-in and fade-out on each of them, if a fragmentshown or fragment hidden event is fired:

    const listener = (event) => {
      var toHideElems = document.querySelectorAll('[data-fragment-index="1"], [data-fragment-index="2"]');
      var tohideArray = [...toHideElems];
      tohideArray.forEach(frag => {
        if (
          (event.fragment.getAttribute("data-fragment-index") == "3" &&
              event.type == 'fragmentshown') |
          (event.fragment.getAttribute("data-fragment-index") == "4" &&
              event.type == 'fragmenthidden')
        ) {
          frag.classList.remove("fade-in");
          frag.classList.add("fade-out");
        } else {
          frag.classList.remove("fade-out");
          frag.classList.add("fade-in");
        } 
      });
    };
    Reveal.addEventListener('fragmentshown', listener);
    Reveal.addEventListener('fragmenthidden', listener);
    

    enter image description here

    ---
    title-slide: false
    format: 
      revealjs:
        theme: sky
        include-after-body: 
          text: |
            <script>
             const listener = (event) => {
                var toHideElems = document.querySelectorAll('[data-fragment-index="1"], [data-fragment-index="2"]');
                var tohideArray = [...toHideElems];
                tohideArray.forEach(frag => {
                  if (
                    (event.fragment.getAttribute("data-fragment-index") == "3" &&
                        event.type == 'fragmentshown') |
                    (event.fragment.getAttribute("data-fragment-index") == "4" &&
                        event.type == 'fragmenthidden')
                  ) {
                    frag.classList.remove("fade-in");
                    frag.classList.add("fade-out");
                  } else {
                    frag.classList.remove("fade-out");
                    frag.classList.add("fade-in");
                  } 
                });
              };
              Reveal.addEventListener('fragmentshown', listener);
              Reveal.addEventListener('fragmenthidden', listener);
            </script>
    ---
    
    ## Test
    
    ::: {.fragment .fade-in .tiny-text}
    - first fragment
    :::
    
    ::: {.fragment .fade-in .tiny-text}
    <div style = "position: absolute; top: 300px; left: 600px; width: 300px; text-align: center;">
    second fragment: this text should disappear at the fourth fragment.
    </div>
    :::
    
    ::: {.fragment .fade-in .tiny-text}
    <div style = "position: absolute; top: 500px; left: 500px; width: 300px; text-align: center;">
    third fragment: this text should disappear at the fourth fragment.
    </div>
    :::
    
    ::: {.fragment .fade-in .tiny-text}
    - fourth fragment: the two texts of the second and third fragments should not be visible anymore.
    :::
    
        
    <style>
      .tiny-text {
        font-size: 0.6em;
      }
    </style>