<main>
  <header>
    <h1>Let's try Flip by GreenSock</h1>
    <p>In this CodePen, I use Flip to animate changes in the <code>grid</code> property. I also tried to alter the initial DOM structure, by moving an element to the top of the list. What about sorting? Let's display the items in the <button type="button" id="alpha-order" class="button-inline">alphabetical order.</button></p>
  </header>
  <div class="grid">
    <article class="article article-1">
      <a href="#">
        <img src="https://images.unsplash.com/photo-1429087969512-1e85aab2683d?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0MDc5NDgwMA&ixlib=rb-1.2.1&q=85&w=600" alt="">
      </a>
      <section class="description">
        <h2>Dearest Diary</h2>
        <div class="details-view">
          <p>Ginger is a flowering plant whose rhizome, ginger root or ginger, is widely used as a spice and a folk medicine.</p>
          <button type="button">Move to top</button>
        </div>
      </section>
    </article>
    <article class="article article-2">
      <a href="#">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/74321/fbanijhrol4-annie-spratt-776x951.jpg" alt="">
      </a>
      <section class="description">
        <h2>Window Sill?</h2>
        <div class="details-view">
          <p>Ginger is a flowering plant whose rhizome, ginger root or ginger, is widely used as a spice and a folk medicine.</p>
          <button type="button">Move to top</button>
        </div>
      </section>
    </article>
    <article class="article article-3">
      <a href="#">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/74321/2rm8p0rkxiw-marius-masalar-776x582.jpg" alt="">
      </a>

      <section class="description">
        <h2>Listen To Me</h2>
        <div class="details-view">
          <p>Ginger is a flowering plant whose rhizome, ginger root or ginger, is widely used as a spice and a folk medicine.</p>
          <button type="button">Move to top</button>
        </div>
      </section>
    </article>
    <article class="article article-4">
      <a href="#">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/74321/71nlan-2ya-andrew-neel-2-776x620.jpg" alt="">
      </a>
      <section class="description">
        <h2>Travel Often</h2>
        <div class="details-view">
          <p>Ginger is a flowering plant whose rhizome, ginger root or ginger, is widely used as a spice and a folk medicine.</p>
          <button type="button">Move to top</button>
        </div>
      </section>
    </article>
    <article class="details article article-5" style="--max:1">
      <a href="#">
        <img src="https://images.unsplash.com/photo-1483794344563-d27a8d18014e?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0MDg2NDUzOA&ixlib=rb-1.2.1&q=85&w=600" alt="">
      </a>
      <section class="description">
        <h2>Another Plant?</h2>
        <div class="details-view" style="opacity: 1; transform: translateY(0)">
          <p>Ginger is a flowering plant whose rhizome, ginger root or ginger, is widely used as a spice and a folk medicine.</p>
          <button type="button">Move to top</button>
        </div>
      </section>
    </article>
    <article class="article article-6">
      <a href="#">
        <img src="https://images.unsplash.com/photo-1557180295-76eee20ae8aa?crop=entropy&cs=srgb&fm=jpg&ixid=MnwxNDU4OXwwfDF8cmFuZG9tfHx8fHx8fHx8MTY0MDc5NDc2Mw&ixlib=rb-1.2.1&q=85&w=600" alt="">
      </a>
      <section class="description">
        <h2>On the Wave</h2>
        <div class="details-view">
          <p>Ginger is a flowering plant whose rhizome, ginger root or ginger, is widely used as a spice and a folk medicine.</p>
          <button type="button">Move to top</button>
        </div>
      </section>
    </article>
    <article class="article article-7">
      <a href="#">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/74321/typewriter-1-776x968.jpg" alt="">
      </a>
      <section class="description">
        <h2>Great Gatsby</h2>
        <div class="details-view">
          <p>Ginger is a flowering plant whose rhizome, ginger root or ginger, is widely used as a spice and a folk medicine.</p>
          <button type="button">Move to top</button>
        </div>
      </section>
    </article>
    <article class="article article-8">
      <a href="#">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/74321/xohlruw4k8-christelle-bourgeois-776x758.jpg" alt="">
      </a>
      <section class="description">
        <h2>In the Sun</h2>
        <div class="details-view">
          <p>Ginger is a flowering plant whose rhizome, ginger root or ginger, is widely used as a spice and a folk medicine.</p>
          <button type="button">Move to top</button>
        </div>
      </section>
    </article>
  </div>
</main>
:root {
  --base-color: #3f3352;
  --overlayH: 263;
  --overlayS: 23%;
  --overlayL: 26%;
}
* {
  box-sizing: border-box;
}

body {
  color: var(--base-color);
  padding: 1rem;
  margin: 0;
  min-height: 110vh;
  line-height: 1.6;
  font-family: muli, sans-serif;
  font-weight: 300;
  font-style: italic;
  font-size: 1.125rem;
}
h2,
p {
  margin-top: 0;
}

h1,
h2 {
  font-family: eloquent-jf-pro, serif;
  font-weight: 400;
  line-height: 1.125;
}
h2 {
  font-size: 1.25rem;
}
button {
  font-family: inherit;
  background: hsl(var(--overlayH), var(--overlayS), var(--overlayL));
  color: white;
  border: none;
  padding: 0.5rem 0.75rem;
  text-transform: uppercase;
  cursor: pointer;
}
.button-inline {
  padding: 0;
  display: inline;
  background: transparent;
  color: inherit;
  text-decoration: underline;
}
main {
  visibility: hidden;
}
main {
  max-width: 1400px;
  margin: 1.5rem auto;
  display: grid;
  gap: 1rem;
}
@media (min-width: 800px) {
  main {
    grid-template-columns: 1fr 3fr;
    gap: 2rem;
  }
}

img,
a {
  display: block;
  height: 100%;
}
article a {
  position: absolute;
  left: 0;
  right: 0;
}
img {
  max-width: 100%;
  width: 100%;
  object-fit: cover;
}
.grid {
  display: grid;
  grid-gap: 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: minmax(16rem, max-content);
  position: relative;
}
@media (min-width: 1024px) {
  .grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

.grid article {
  --max: 0;
  position: relative;
  overflow: hidden;
}
article:not(.details) button,
article:first-child button {
  display: none;
}

article:first-child p:last-of-type {
  margin: 0;
}
.description {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: clamp(1rem, 2.5vmin, 2.25rem);
}
article.details {
  grid-row: span 2;
  grid-column: span 2;
}
.description {
  background: linear-gradient(
    0deg,
    hsl(var(--overlayH), var(--overlayS), var(--overlayL), calc(1 * var(--max)))
      0%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.738 * var(--max))
      )
      19%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.541 * var(--max))
      )
      34%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.382 * var(--max))
      )
      47%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.278 * var(--max))
      )
      56.5%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.194 * var(--max))
      )
      65%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.126 * var(--max))
      )
      73%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.075 * var(--max))
      )
      80.2%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.042 * var(--max))
      )
      86.1%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.021 * var(--max))
      )
      91%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.008 * var(--max))
      )
      95.2%,
    hsla(
        var(--overlayH),
        var(--overlayS),
        var(--overlayL),
        calc(0.002 * var(--max))
      )
      98.2%,
    hsla(var(--overlayH), var(--overlayS), var(--overlayL), 0) 100%
  );
}

.details-view {
  color: white;
  opacity: 0;
  transform: translateY(100%);
}

.article-6 {
  --overlayH: 47;
  --overlayS: 92%;
  --overlayL: 32%;
}
.article-2 {
  --overlayH: 353;
  --overlayS: 34%;
  --overlayL: 58%;
}
.article-5 {
  --overlayH: 136;
  --overlayS: 62%;
  --overlayL: 25%;
  --overlayH: 176;
  --overlayS: 49%;
  --overlayL: 16%;
}
/* 
This week we're looking at the FLIP technique. It can take a while to click - but when it does - you'll be able to handle any complex UI animation with ease.

Here's a simple FLIP animation to start you off!

*/

// start by registering the plugin
gsap.registerPlugin(Flip);

// grab our element
const articles = document.querySelectorAll("article");
const buttons = document.querySelectorAll(".grid button");
const alphaButton = document.querySelector("#alpha-order");
const container = document.querySelector(".grid");

for (let article of [...articles]) {
  article.addEventListener("click", (e) => {
    e.preventDefault();
    if (article.classList.contains("details")) {
      return;
    }
    const state = Flip.getState(".grid article");

    const currentDetails = document.querySelector(".details");
    currentDetails && currentDetails.classList.remove("details");

    article.classList.add("details");
    // "FLIP" animate from that saved state.
    const tl = Flip.from(state, {
      duration: 1,
      ease: "power1.inOut",
      stagger: 0.05,
      absolute: true,
      toggleClass: "changing",
      onStart: () => {
        gsap.to(".details-view", {
          opacity: 0,
          y: "100%",
          duration: 0.5
        });
        gsap.to(".grid article", {
          "--max": 0,
          duration: 0.8
        });
        gsap.to(".grid article.details", {
          "--max": 1,
          duration: 1,
          delay: 0.2
        });
      }
    });

    tl.to(
      ".details .details-view",
      { opacity: 1, y: 0, duration: 0.75 },
      "-=.25"
    );
  });
}

for (let button of [...buttons]) {
  button.addEventListener("click", () => {
    const a = button.parentNode.parentNode.parentNode;
    const state = Flip.getState(".grid article, .description .details-view");
    container.prepend(a);
    const tl = Flip.from(state, {
      duration: 1,
      ease: "power1.inOut",
      stagger: 0.05,
      absolute: true
    });
  });
}

alphaButton.addEventListener("click", () => {
  const state = Flip.getState(".grid article, .description .details-view");
  [...articles]
    .sort((r, l) => {
      const titleR = r.querySelector("h2");
      const titleL = l.querySelector("h2");
      if (titleR.textContent > titleL.textContent) return 1;
      if (titleL.textContent > titleR.textContent) return -1;
      return 0;
    })
    .forEach((article) => container.append(article));
  const tl = Flip.from(state, {
    duration: 1,
    ease: "power1.inOut",
    stagger: 0.05,
    absolute: true
  });
});

// Intro animation
window.addEventListener("load", () => {
  gsap.to("main", { autoAlpha: 1, duration: 0.4 });
  gsap.from(".grid article", {
    autoAlpha: 0,
    yPercent: 30,
    stagger: 0.04
  });
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/gsap-latest-beta.min.js
  2. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/CustomEase3.min.js
  3. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/CustomBounce3.min.js
  4. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/CustomWiggle3.min.js
  5. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/InertiaPlugin.min.js
  6. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/Draggable3.min.js
  7. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/EasePack3.min.js
  8. https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/Flip.min.js