<header class="center pad-l">
  <h1>gsap.matchMedia()</h1>
  <p class="lead">Use matchMedia and the prefers-reduced-motion media feature for easy, accessibility-friendly animation.</p>
  <div class="checkbox">
  <input type="checkbox" id="motionToggle" class="vh" name="motionToggle" value="false">
  <label for="motionToggle">Reduced animation please</label>
</div>
</header>


<section class="gray">
  <div class="box gradient-green"></div>
</section>

<section class="bottom">
  <p><strong>Pretty cool, right?</strong></p>
  <p>You can read more about reduced motion and vestibular disorders in this <a href="https://css-tricks.com/introduction-reduced-motion-media-query/">blog post</a> on CSS tricks</p>
  <p>How do I <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion#user_preferences">adjust my reduced motion setting?</a></p>
  <p>Check out <a href="https://greensock.com">GSAP</a> today. </p>
</section>
header {
  flex-direction: column;
}

.lead {
  padding: 0 20px;
  text-align: center;
}

.gray {
  width: 100%;
  height: 100vh;
}
.box {
  width: 150px;
  height: 150px;
  position: absolute;
  z-index: 0;
  left: 50%;
  top: 50%;
  transform: translate3d(-50%, -50%, 0);
}

.gray p {
  font-size: 1.4em;
  margin: 0;
  padding: 30px;
  line-height: 1.4em;
}

.bottom {
  width: 100%;
  text-align: center;
  padding: 150px 30px;
  font-size: 1.2em;
  box-sizing: border-box;
}
gsap.registerPlugin(ScrollTrigger);

let reduceMotionCB = document.querySelector("#motionToggle");
reduceMotionCB.checked = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
reduceMotionCB.addEventListener("change", gsap.matchMediaRefresh); // force all matchMedia() stuff to revert and re-run

let breakPoint = 800;
let mm = gsap.matchMedia();

mm.add({
  isDesktop: `(min-width: ${breakPoint}px)`, // <- when ANY of these are true, the function below gets invoked
  isMobile: `(max-width: ${breakPoint - 1}px)`
}, (context) => {

  let {isDesktop, isMobile} = context.conditions;
  let reduceMotion = reduceMotionCB.checked; // if we weren't using a checkbox, we could just add another condition above: "(prefers-reduced-motion: reduce)"
  let tl = gsap.timeline({
    scrollTrigger: {
      trigger: ".gray",
      scrub: 1,
      end: "200%",
      pin: true
    }
  });
  tl.to(".box", { 
    scale: reduceMotion ? 1.1 : 2
  }).to(".box", { 
    scale: 1 
  });

  if (!reduceMotion) { // don't rotate the box if reduced motion was requested
    gsap.to(".box", {
      rotation: 360,
      ease: "none",
      duration: 5,
      repeat: -1
    });
  }

  gsap.set(".box", {
    innerText: isDesktop ? "Desktop" : "Mobile",

  });

  // optionally return a cleanup function
  return () => console.log("cleanup");
});

External CSS

  1. https://codepen.io/GreenSock/pen/xxmzBrw/fcaef74061bb7a76e5263dfc076c363e.css

External JavaScript

  1. https://assets.codepen.io/16327/gsap-latest-beta.min.js?r=3.11.2d
  2. https://assets.codepen.io/16327/ScrollTrigger.min.js?cache=6548