查看原文
其他

现代CSS:纯 CSS 实现滚动图像弹出(pop-out)效果

小懒 FED实验室 2024-02-12
关注下方公众号,获取更多现代CSS系列文章

本文阐述使用 CSS 滚动驱动动画(scroll-driven animations)和零 JS 创建滚动图片弹出效果。

1.Scroll-driven Animations

Scroll-driven Animations 是网络上一种常见的用户体验模式。这些动画与滚动容器的滚动位置相关联。这意味着当你向上或向下滚动时,链接的动画会直接向前或向后刷新。想想有趣的效果,比如视差背景图片或随着滚动而移动的阅读指示器。一种类似的滚动驱动动画是与元素在其滚动容器中的位置相关联的动画。例如,有了它,元素可以在进入视图时淡入。

实现这类效果的经典方法是在主线程中响应滚动事件。这使得创建与滚动同步的高性能滚动驱动动画变得不可能或非常困难。有了 Scroll-driven Animations 规范,您现在可以使用新的 API 和概念来实现声明式滚动驱动动画,并与现有的 Web Animations API (WAAPI) 和 CSS Animations API 配合使用。

通过将滚动驱动动画与这两个现有的 API 集成,滚动驱动动画可以从这些 API 带来的所有优势中获益。这包括让这些动画脱离主线程运行的能力。现在可以在主线程外运行由滚动驱动的如丝般顺滑的动画,而这一切只需几行额外的代码即可以实现。

Scroll-driven Animation 规范中定义了两种新的 timeline,可以指定动画在元素滚动条滚动时运行,@keyframes 的进度也就跟着滚动进度进行。

  • Scroll Progress Timeline: 表示容器已滚动的距离,从0%到100%
  • View Progress Timeline: 标识容器内的元素相对于滚动距离的相对位置,从0%到100%。

本实践中使用的就是 View Progress Timeline,同时还使用到一个属性 animation-range

该属性定义了动画在时间轴上的附加范围的起始和结束位置,即动画将在时间轴的哪个位置开始和结束。它包含两个子属性,可以分别来设置动画的起始和结束位置:

  • animation-start:指定动画的起始位置,可以使用百分比、时间值或关键字来表示。
  • animation-end:指定动画的结束位置,可以使用百分比、时间值或关键字来表示。

2.实现方案

2.1.创建页面框架

<main>
  <section class="first"><h2>xxx</h2></section>
  <section>
    <div class="pop-out-image skateboarder">
      <figure>
        <img src="https://assets.codepen.io/605876/skateboarder.jpeg"/>
      </figure>
      <figure aria-hidden="true">
        <img src="https://assets.codepen.io/605876/skateboarder-bg-removed.png"/>
      </figure>
    </div>
  </section>
  <section>
    <div class="pop-out-image snowboarder">
      <figure>
        <img src="https://assets.codepen.io/605876/snowboarder.jpeg"/>
      </figure>
      <figure aria-hidden="true">
        <img src="https://assets.codepen.io/605876/snowboarder-bg-removed.png"/>
      </figure>
    </div>
  </section>
  <section>
    <div class="pop-out-image mtb">
      <figure>
        <img
          src="https://assets.codepen.io/605876/mtb.jpeg"
          alt="skateboarder doing a trick mid air"
        />

      </figure>
      <figure aria-hidden="true">
        <img src="https://assets.codepen.io/605876/mtb-bg-removed.png" />
      </figure>
    </div>
  </section>
  <section>
    <div class="pop-out-image mtx">
      <figure>
        <img
          src="https://assets.codepen.io/605876/mtx.jpeg"
          alt="skateboarder doing a trick mid air"
        />

      </figure>
      <figure aria-hidden="true">
        <img src="https://assets.codepen.io/605876/mtx-bg-removed.png" />
      </figure>
    </div>
  </section>
  <section class="last"><h2>xxx</h2></section>
</main>

2.2.核心样式

本 demo 实现中,使用了现代 CSS 嵌套,如果你对此不了解,可以参考小懒的文章[现代CSS:你真的还需要 CSS 预处理器吗?]。

核心样式中首先对 section 元素应用了 grid 网格布局并设置高度为 100vh,这样可以保证每个 section 都在一个屏幕内。

动画的核心用到了 animation-timelineanimation-range

body {
  backgroundhsl(0 0% 2%);
}

main {
  width1000px;
  margin0 auto;
  max-width100%;
  padding0 1rem;
  & section {
    display: grid;
    place-items: center;
    max-width100%;
    height100vh;

    & h2 {
      backgroundlinear-gradient(hsl(0 0% 98%30%hsl(0 0% 30%));
      color: transparent;
      background-clip: text;
      font-sizeclamp(3rem6vw + 1rem12rem);
    }

    .pop-out-image {
      view-timeline-name: --popper;
      aspect-ratio1;
      position: relative;
      widthclamp(100px45vmin300px);
      outline4px dashed transparent;
      transition: transform 0.2s;
      border-radius1rem;
    }

    .skateboarder {
      --size170%;
      --y2: -40%;
    }

    .snowboarder {
      --size155%;
      --x1: -65%;
      --y2: -35%;
    }

    .mtb {
      --size185%;
      --y2: -45%;
    }

    .mtx {
      --size170%;
      --x1: -52%;
      --y2: -40%;
      --y1: -10%;
    }

    & figure {
      position: absolute;
      width100%;
      margin0;
      border-radius1rem;
      overflow: hidden;
      inset0;
      transition: transform 0.2s;

      & img {
        position: absolute;
        top0%;
        left50%;
        widthvar(--size, 100%);
        aspect-ratio1;
        animation: slide-up linear both;
        animation-timeline: --popper;
        animation-range: entry 100% cover 50%;
        object-fit: cover;
        object-position: right;
        translatevar(--x1, -50%var(--y1, 0);
      }

      &:last-of-type {
        --b2;
        overflow: visible;
        clip-pathinset(-200% 0 0 0);
      }
    }
  }
}

@keyframes slide-up {
  to {
    translatevar(--x1, -50%var(--y2, -50%);
    filterbrightness(var(--b, 1));
  }
}

3.效果预览


如果你对 Scroll-driven Animations 及现代 CSS 感兴趣,可以阅读小赖的[现代CSS:纯 CSS 实现苹果风格(Apple-style)的图片滚动器]文章以及订阅[现代 CSS 合集]。

大家都在看

继续滑动看下一个

现代CSS:纯 CSS 实现滚动图像弹出(pop-out)效果

小懒 FED实验室
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存