Copied SVG to clipboard
Something went wrong
Copied code to clipboard
Something went wrong

Default

User image

Default

Name

  • Osmo Discount
    -25%
The Vault/

Scaling Element on Scroll (GSAP Flip)

Scaling Element on Scroll (GSAP Flip)

Documentation

Webflow

Code

Setup: External Scripts

External Scripts in Webflow

Make sure to always put the External Scripts before the Javascript step of the resource.

In this video you learn where to put these in your Webflow project? Or how to include a paid GSAP Club plugin in your project?

HTML

Copy
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.7/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.7/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.7/dist/Flip.min.js"></script>

Step 1: Copy structure to Webflow

Copy structure to Webflow

In the video below we described how you can copy + paste the structure of this resource to your Webflow project.

Copy to Webflow

Webflow structure is not required for this resource.

Step 1: Add HTML

HTML

Copy
<div class="resource-wrapper">
  <section class="scaling-element-header"><span class="scaling-element-header__eyebrow">[ Resource ]</span>
    <h1 class="scaling-element-header__h1">Scaling element on scroll with Flip</h1>
    <div class="scaling-element__small-box">
      <div class="scaling-video__before"></div>
      <div data-flip-element="wrapper" class="scaling-video__wrapper">
        <div data-flip-element="target" class="scaling-video">
          <video autoplay="autoplay" muted="" playsinline="" loop="" webkit-playsinline="" class="scaling-video__video"><source src="https://osmo.b-cdn.net/resource-media/scaling-element-resource-185787-876545918_tiny.mp4" type="video/mp4"></video>
          <svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 138 138" fill="none" class="scaling-video__svg"><path d="M81.7432 46.534C79.5777 48.6995 75.875 47.1659 75.875 44.1034V0.25H62.125V51.8124C62.125 57.5079 57.5079 62.1249 51.8125 62.1249H0.25V75.8749H44.1034C47.1659 75.8749 48.6996 79.5776 46.5341 81.7431L16.0136 112.263L25.7364 121.986L56.2569 91.466C58.416 89.3069 62.1031 90.825 62.125 93.8693V137.75H75.8751L75.875 86.1874C75.875 80.492 80.4921 75.8749 86.1875 75.8749H137.75V62.1249H93.8692C90.8339 62.1031 89.3157 58.4375 91.4469 56.2759L91.4659 56.2569L121.986 25.7363L112.264 16.0137L81.7432 46.534Z" fill="currentColor"></path></svg>
        </div>
      </div>
    </div>
  </section>
  <section class="scaling-element-video">
    <div class="scaling-element__big-box">
      <div class="scaling-video__before"></div>
      <div data-flip-element="wrapper" class="scaling-video__wrapper"></div>
    </div>
    <h1 class="scaling-element-header__h1">And you can have more content here ...</h1>
  </section>
</div>

HTML structure is not required for this resource.

Step 2: Add CSS

CSS

Copy
.resource-wrapper {
  position: relative;
  overflow: hidden;
}

.scaling-element-header {
  grid-column-gap: 3em;
  grid-row-gap: 3em;
  flex-flow: column;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  padding: 25vh 5vw 20vh;
  display: flex;
  position: relative;
}

.scaling-element-header__h1 {
  text-align: center;
  max-width: 9em;
  margin-top: 0;
  margin-bottom: .25em;
  font-size: 7em;
  font-weight: 500;
  line-height: 1;
}

.scaling-element-header__eyebrow {
  color: #9d420a;
  text-transform: uppercase;
  font-size: 1.25em;
  font-weight: 400;
}

.scaling-element-video {
  grid-column-gap: 25vh;
  grid-row-gap: 25vh;
  flex-flow: column;
  justify-content: center;
  align-items: center;
  padding-bottom: 25vh;
  padding-left: 5vw;
  padding-right: 5vw;
  display: flex;
  position: relative;
}

.scaling-element__big-box {
  border-radius: 1em;
  width: 100%;
  position: relative;
}

.scaling-element__small-box {
  border-radius: 1em;
  width: 20em;
  position: relative;
}

.scaling-video__wrapper {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

.scaling-video {
  will-change: transform;
  background-color: #d2800f;
  border-radius: 1em;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  display: flex;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  isolation: isolate;
  transform: translateX(0) rotate(0.001deg);
}

.scaling-video__before {
  padding-top: 56.25%;
}

.scaling-video__video {
  object-fit: cover;
  width: 100%;
  height: 100%;
  padding-bottom: 0;
  padding-right: 0;
  position: absolute;
  border-radius: inherit;
}

.scaling-video__svg {
  color: #fff;
  mix-blend-mode: overlay;
  width: 6.25em;
  position: absolute;
}

@media screen and (max-width: 767px) {
  .scaling-element-header__h1 {
    font-size: 13.5vw;
  }

  .scaling-element__small-box {
    width: 15em;
  }

  .scaling-video__svg {
    width: 5em;
  }
}

Step 2: Add custom Javascript

Custom Javascript in Webflow

In this video, Ilja gives you some guidance about using JavaScript in Webflow:

Step 2: Add Javascript

Step 3: Add Javascript

Javascript

Copy
gsap.registerPlugin(ScrollTrigger, Flip);

function initFlipOnScroll() {
  let wrapperElements = document.querySelectorAll("[data-flip-element='wrapper']");
  let targetEl = document.querySelector("[data-flip-element='target']");

  let tl;
  function flipTimeline() {
    if (tl) {
      tl.kill();
      gsap.set(targetEl, { clearProps: "all" });
    }
    
    // Use the first and last wrapper elements for the scroll trigger.
    tl = gsap.timeline({
      scrollTrigger: {
        trigger: wrapperElements[0],
        start: "center center",
        endTrigger: wrapperElements[wrapperElements.length - 1],
        end: "center center",
        scrub: 0.25
      }
    });
    
    // Loop through each wrapper element.
    wrapperElements.forEach(function(element, index) {
      let nextIndex = index + 1;
      if (nextIndex < wrapperElements.length) {
        let nextWrapperEl = wrapperElements[nextIndex];
        // Calculate vertical center positions relative to the document.
        let nextRect = nextWrapperEl.getBoundingClientRect();
        let thisRect = element.getBoundingClientRect();
        let nextDistance = nextRect.top + window.pageYOffset + nextWrapperEl.offsetHeight / 2;
        let thisDistance = thisRect.top + window.pageYOffset + element.offsetHeight / 2;
        let offset = nextDistance - thisDistance;
        // Add the Flip.fit tween to the timeline.
        tl.add(
          Flip.fit(targetEl, nextWrapperEl, {
            duration: offset,
            ease: "none"
          })
        );
      }
    });
  }

  flipTimeline();

  let resizeTimer;
  window.addEventListener("resize", function () {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(function () {
      flipTimeline();
    }, 100);
  });
}

// Initialize Scaling Elements on Scroll (GSAP Flip)
document.addEventListener('DOMContentLoaded', function() {
  initFlipOnScroll();
});

Step 3: Add custom CSS

Step 2: Add custom CSS

Custom CSS in Webflow

Curious about where to put custom CSS in Webflow? Ilja explains it in the below video:

CSS

Copy

Implementation

Wrapper Attribute

We need at least two wrapper elements to define the starting and ending positions for the transition. To do this, add the attribute [data-flip-element="wrapper"] to each section that should act as a waypoint. The script uses the height, width, and x/y position of each wrapper element to calculate the animation parameters needed to transition to the next wrapper in line. Additionally, you can add more wrappers to create a synchronized animation that transitions smoothly from one section to the next.

Target Attribute

Add the element you want to move and scale as a child of the first wrapper, and assign it the attribute [data-flip-element="target"]. This element becomes the focal point of the animation, and please note that only one target element is allowed per page.

Extra options

  • absolute: true; This solves layout challenges with flexbox, grid, etc.
  • scale: true; Resize via scaleX/scaleY properties (on default: width/height).
  • ease: "Power1.easeInOut"; Change the ease to animate the ease.
  • scrub: true; Change this to true to have a more connected scroll feeling.

Learn more about all options in the GSAP Documentation

Resource Details

Scrolltrigger
Video
Element
Scrolling
Scaling
Transform
Position

Original source

Dennis Snellenberg

Creator Credits

We always strive to credit creators as accurately as possible. While similar concepts might appear online, we aim to provide proper and respectful attribution.