Google 如何在 iframe 中创建适合移动设备的固定背景和视差内容?

How does Google create mobile friendly fixed backgrounds and parallax content in iframe?

我当前的测试涉及一个 intersectionobserver,它使用 iframe postMessage 和当前滚动位置,以便在 iframe 中转换 3d 背景图像。但这会产生很多抖动,在生产中可能会延迟,我可以看到这种方法存在更多问题。根据我在 Google 的 Web 开发人员工具中的了解,广告使用视差以使内容响应滚动位置,但 Google 是否依赖于 postMessage,或者做什么他们这样做是为了让固定背景和内容响应父级滚动事件的流畅体验 window?

Some code example

DEMO || CODE

据我了解,使用的组件称为 Parallax,在 Google Web Designer

中可用

关于固定背景,我知道iOS不支持background-attachment: fixed,为什么它必须是一些基于JS的功能。然后由父 window 中的 intersectionobserver 触发,我相信。如果 Google 广告完全依赖父级 window 来提供任何信息,或者是否所有内容都在 iframe 内部进行管理 - 我不知道。但我想听听是否有人知道这些技术及其背后的工作,因为它看起来很简单,但对于像我这样的凡人来说却很难实现。

多么有趣的问题!我想从你的最后一张动图开始。

动图 #3

Regarding the fixed background, I know that iOS doesn't support background-attachment: fixed, why it has to be some JS based functionality.

即使 IOS 支持 background-attachment: fixed 这也行不通,因为 属性 仅用于背景图像。它也不是 JS(至少不一定),因为你可以用 CSS:

* {
  margin: 0;
  padding: 0;
}

.section {
  width: 100%;
  height: 1000px;
  background: red;
}

.spacer {
  width: 100%;
  height: 200px;
  background: transparent;
}

.background-scroller {
  background: lightgrey;
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  z-index: -1;
  display: flex;
  align-items: center;
  justify-content: center;
}
<div class="section"></div>
<div class="spacer"></div>
<div class="section"></div>
<div class="background-scroller">
  This could be anything
</div>

我知道在某些网站上,每个 "spacer" 的广告都会发生变化,但这也可以通过 CSS 使用 position: sticky

* {
  margin: 0;
  padding: 0;
}

.section {
  width: 100%;
  height: 1000px;
  background: red;
}

.spacer {
  width: 100%;
  height: 200px;
  background: transparent;
}

.background-scroller {
  background: lightgrey;
  width: 100%;
  height: 100vH;
  position: sticky;
  top: 0;
  z-index: -1;
  display: flex;
  align-items: center;
  justify-content: center;
  float: left;
}

.section-wrapper {
  position: relative;
}
<div class="section-wrapper">
  <div class="background-scroller">
    This is one thing
  </div>
  <div class="section"></div>
  <div class="spacer"></div>

  <div class="background-scroller">
    And this is something completely else
  </div>

  <div class="section"></div>
  <div class="spacer"></div>

  <div class="section"></div>
</div>

每个站点的做法都不同,其中很多都使用交集观察器 API,但我的观点是,有时一些简单的 CSS 就可以完成这项工作。所以不一定是JS!这些是执行此操作的一些合法方法。


Gif #2,Gif #1

这些效果有点复杂。

Cross-origin 限制是一个很大的(但必要的)无赖。您的父框架对 iframe 的访问权限非常有限,反之亦然。这让我们只剩下几个 properties 可以使用了。

如果您检查 iframe 元素,您可能会注意到它们使用了 data-is-safeframe 属性。我复制了这样一个元素并删除了所有不重要的属性。

<iframe src="" data-is-safeframe="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-top-navigation-by-user-activation"></iframe>

什么是SafeFrame?那么,SafeFrame API 是由 IAB(互动广告局)开发的,基本上允许广告商和广告提供商之间的通信。如果您不是 Google 开发人员,要确切知道他们使用此 API 的目的可能是不可能的。

只有一种现代方式可以与 cross-origin iframes 通信:postMessage()。 是的,他们也使用 SafeFrame,但我认为这不适合这样的事情。没有办法(对于 Google 也是如此)来打破这个规则。可以肯定的是,我做了一些测试(如果我考虑的话,这真的是不必要的)并且我所有的测试都失败了。


But this creates a lot of jitter

这让我感到惊讶,因为 postMessage 不应该那么慢。我用 JSFiddle 做了一个小例子,因为我用 iframe.

做了一些奇怪的东西
  • 这是将在 iframe 中显示的页面:Click or Code
  • 这是将显示 iframe 并发送 postMessage() 的页面(向下滚动页面(不是 iframe)):Click or Code.

如果你看一下控制台,你会注意到 postMessage 绝对足够快来处理像 scroll 这样的快速触发事件。您还可以注意到它,因为 "disco iframe".

老实说,我认为问题出在您的网站上。


结论

我不知道 Google 是如何做到这一点的。但是,我只能想到一种可能的方法:postMessage - 您已经选择的一种方法。这意味着,如果没有其他办法,这必须是Google使用的方式。

你的表现问题一定是你这边的错。


所以这只是我的意见。可能有我没有想到的技术和方法。我觉得这个问题很有趣,如果我的解决方案不正确,我想知道正确答案!所以请随时纠正我。


编辑 #1

经过大量 time-consuming 调查,我终于找到了可靠来源的解决方案:在某种程度上,来自 Google 本身。但也来自我发现的各种网站,它们利用了这种效果。

简答

基本上就像我在 Gif #3.

中解释的那样

长答案

这样的广告有不同的名称:Interscroller飞毯粘性广告、可能还有更多,但这些是我遇到的。

我发现广告通常是使用 AMPAccelerated Mobile Pages)编写和实施的,由 Google 发布。

在最终找到一个使用 飞毯广告 的网站后,我检查了它并发现了以下内容:

这证实了我的发现。他们使用 AMP!但不仅是他们,我还遇到过使用相同技术的不同网站。

我们来分析一下HTML结构。我们关注的部分是 <amp-fx-flying-carpet> 和它的第一个父 <div class="amp-article-ad> 直到 <iframe>.

删除了所有不必要内容的基本结构如下所示:

<div class="amp-article-ad">
  ::before
  <amp-fx-flying-carpet>
    <div class="i-amphtml-fx-flying-carpet-clip">
      <div class="i-amphtml-fx-flying-carpet-container">
        <amp-ad class="amp-article-ad-element i-amphtml-layout-fixed i-amphtml-layout-size-defined i-amphtml-element i-amphtml-layout">
          <div fallback></div>
          <amp-analytics></amp-analytics>
          <iframe></iframe>
        </amp-ad>
      </div>
    </div>
  </amp-fx-flying-carpet>
</div>

如果我们通过删除所有不必要的包装器来进一步减少它,结构如下所示:

<div class="amp-article-ad">
  <amp-fx-flying-carpet>
    <div class="i-amphtml-fx-flying-carpet-container">
      <amp-ad>
        <iframe></iframe>
      </amp-ad>
    </div>
  </amp-fx-flying-carpet>
</div>

让我们从头说起。 <div class="amp-article-ad"> 只是广告的包装,包含 <amp-fx-flying-carpet><div class="amp-article-ad"><amp-fx-flying-carpet>的大小是一样的,也是window我们可以看到广告通过:

重要的部分来了! <div class="i-amphtml-fx-flying-carpet-container"><amp-ad> 的包装器,它的尺寸大于它的包装器 <amp-fx-flying-carpet> 的尺寸(要预调整大小的广告尺寸),这已经表明ome CSS 属性 将其从流程中删除。一些属性的示例是:

  • float: left
  • float: right
  • position: fixed
  • position: absolute
  • ...

你可能明白我要去哪里了。 <div class="i-amphtml-fx-flying-carpet-container"> 的 CSS 属性是:

我们找到了:position: fixed

<amp-ad> 的大小是广告的大小,这是有道理的,因为它包含 iframe,而 iframe 包含广告。

<iframe> 显然只包含广告。


所以我们有了外包装,它的功能是window我们可以看穿。在这个 window 里面是容器,通过添加 position: fixed 从流中取出。这些固定容器包含 <iframe>,其中包含广告。


说服自己!这是包含示例的官方 AMP 文档: https://amp.dev/documentation/examples/components/amp-fx-flying-carpet/#flying-carpet-for-ads

结构几乎相同。当然,我做了一个小例子,使用相同的技术:

* {
  margin: 0;
  padding: 0;
}

body {
  text-align: center;
}

p {
  width: 100%;
  background: white;
  position: relative;
  z-index: 1;
}

.flying-carpet-wrapper {
  height: 200px;
  width: 100%;
}

.amp-ad-wrapper {
  position: fixed;
  height: 100%;
  top: 0;
  left: 0;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

iframe {
  border: 0;
  height: 500px;
  width: 500px;
}
<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>

<div class="flying-carpet-wrapper"> <!--<amp-fx-flying-carpet>-->
 <div class="amp-ad-wrapper"> <!--<div class="i-amphtml-fx-flying-carpet-container">-->
   <div class="amp-ad"> <!--<amp-ad>-->
      <iframe src="https://de.wikipedia.org/wiki/Accelerated_Mobile_Pages"></iframe>
   </div>
 </div>
</div>

<p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>