AMP
  • ads

Scrollbound Video Ad

Summary

Sample AMPHTML ad using amp-animation, amp-video, amp-img and amp-position-observer to create an ad that animates based on scrolling.

Demo of this example

Styling

This is an advanced example that requires some styling to make it look and function properly.

The styling designed here is responsive and will work with various ad sizes.

<style amp-custom>

  /*
   * Top level container: It fills the parent viewport
   * that hosts the ad.
   */
  .ad-container {
    font-family: "Roboto", sans-serif;
    position: relative;
    width: 100vw;
    height: 100vh;
    color: #FFFFFF;
  }

  /* Video Layer */
  .video-container {
    /**
     * Specifies that right corner should be used
     * as the anchor point when video is scaled down
     * using scrollbound amp-animation.
     */
    transform-origin: calc(100% - 25px) 25px;
    z-index: 2;
  }

  /* Video player: Click-to-player overlay */
  .video-container .poster-image {
    position: absolute;
    z-index: 1;
  }

  .video-container .poster-image img {
    object-fit: cover;
  }

  .video-container .play-icon {
    position: absolute;
    z-index: 3;
    width: 100px;
    height: 100px;
    background-image: url( https://amp.dev/static/samples/img/play-icon.png);
    background-repeat: no-repeat;
    background-size: 100% 100%;
    /* Align to the middle */
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    cursor: pointer;
    opacity: 0.9;
  }

  .video-container amp-video video {
    object-fit: cover;
  }

  /* Content Layer */
  .content-container {
    z-index: 1;
  }

  /* Content Layer: Background image */
  .background amp-img {
    margin: -70px;
  }

  .background amp-img img {
    object-fit: cover;
  }

  /* Content Layer: Title and logo */
  .title {
    position: absolute;
    top: 5px;
    padding-left: 15px;
    font-weight: bold;
  }

  /* Content Layer: Footer and learn more button */
  .footer {
    position: absolute;
    bottom: 0;
    width: 100%;
    padding: 5px 15px;
    background-color: rgba(0, 0, 0, 0.8);
    box-sizing: border-box;
    font-size: 10px;
    display: flex;
    flex-direction: row;
  }

  .footer>* {
    flex: 1;
    align-self: center;
  }

  .footer .learn-more {
    background-color: #2979ff;
    padding: 5px 15px;
    white-space: nowrap;
    flex: 0;
    font-size: 10px;
    letter-spacing: 0.5px;
    color: #fafafa;
    text-decoration: none;
  }

  /* Generic CSS class to fill a parent */
  .fill {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
  }
</style>

Animations

There are two types of scrollbound animations that occur in this sample: scaling of the video container and parallax movement of the background image.

The animations are implemented using amp-animation which is an AMP component that uses Web Animations API

<amp-animation layout="nodisplay" id="videoAnim">
  <script type="application/json">
    {
    "duration": "10s",
    "fill": "both",
    "direction": "alternate",
    "animations": [
      {
        "selector": "#videoContainer",
        "keyframes": [
          { "transform": "scale(1)" },
          { "transform": "scale(0.5)"}          ]
      },
      {
        "selector": "#backgroundImg",
        "keyframes": [
          { "transform": "translateY(0)" },
          { "transform": "translateY(60px)"}
        ]
      }
    ]
  }
  </script>
</amp-animation>

Scale down video to the corner when scrolling: The video covers the whole ad initially and when the page scrolls, it slowly starts to scale down and move to the corner reaching its target size when the ad is in the middle of the view port.

To achieve that, we define 4 keyframes. Between 0 and 10% of viewport, video is fullsize, between 10% and 50%, it starts scaling down until it settles at half its size when in the middle of the viewport and stays the same size all the way to the last keyframe.

Parallax background image: The background image of this ad has a subtle parallax effect. To achieve that, we use scrollbound animation and specify a 60px offset at the last keyframe.

Scrollbound Animations

The scrollbound animations are implemented using amp-position-observer which is an AMP component that Monitors the position of an element within the viewport as a user scrolls, and dispatches enter, exit and scroll events that can be used with other components

<amp-position-observer
  intersection-ratios="1"
  on="scroll:videoAnim.seekTo(percent=event.percent)"
  layout="nodisplay">
</amp-position-observer>

Ad Container

Top level container: It fills the parent viewport that hosts the ad.

<div class="ad-container">

Video Layer

Inside the ad-container we create a click-to-play overlay and a video element.

The amp-animation scales down the videoContainer when the user scrolls.

<div id="videoContainer" class="video-container fill">
  <div id="clickToPlayOverlay" class="fill">
    <div class="play-icon" role="button" tabindex="0" on="tap:clickToPlayOverlay.hide, video.play"></div>

    <amp-img class="poster-image" layout="fill" src="/static/samples/img/car-video-poster.png"></amp-img>
  </div>

  <amp-video id="video" controls layout="fill" src="/static/samples/video/car-video-360p.mp4"></amp-video>
</div>

Content Layer

Create the content layer that hosts the background image and information about the ad.

The amp-animation simulates a parallax effect for backgroundImg when the user scrolls.

<div class="content-container fill">
  <div class="background">
    <amp-img id="backgroundImg" layout="fill" src="/static/samples/img/car-bg.jpg"></amp-img>
  </div>
  <div class="title">
    <div>
      <amp-img layout="fixed" width="72" height="32" src="/static/samples/img/car-logo.png"></amp-img>
    </div>
    <div>THE ALL NEW</div>
    <div>WS-X LUX</div>
  </div>
  <div class="footer">
    <span>36 months lease, $189/month, $2999 due at signing</span>
    <a href="https://ampproject.org" target="_blank" class="learn-more">LEARN MORE</a>
  </div>
</div>
Need further explanation?

If the explanations on this page don't cover all of your questions feel free to reach out to other AMP users to discuss your exact use case.

Go to Stack Overflow
An unexplained feature?

The AMP project strongly encourages your participation and contributions! We hope you'll become an ongoing participant in our open source community but we also welcome one-off contributions for the issues you're particularly passionate about.

Edit sample on GitHub