首頁 > web前端 > css教學 > 主體

高性能的視差動畫【譯】

PHPz
發布: 2017-04-04 10:21:38
原創
1407 人瀏覽過

高效能的視差動畫


##也好,恨也好,視差效果已經遍布web之上了。 。示意圖

摘要高性能的視差動畫【譯】

不要使用滾動

事件(scroll events)或背景定位(background-position

)來創建視差動畫。的Safari瀏覽器使用
    position: sticky
  • 來確保視差可以生效。 #JS

    ,這裡還有一個demo演示。為何它們不適合我們要追求的目標。 ,視差元素的位置也應被更新。被當作「盡量好」(best effort)的工作處理的,也就意味著:瀏覽器並不確保每一幀的滾動動畫送達!告訴我們為什麼要避免

    使用Javascript
  • 基於滾動事件去移動元素:
  • Javascript並不能確保視差會和頁面滾動保持相同的步調。滾動事件甚至是在滾動完成後才觸發的,這一點讓基於Javascript的滾動效果無法實現。 #ome一樣,它是一個基於「盡量好」的原則的。

    不好的方案:更新背景位置
  • 我們要避免的另一個場景是在每個畫面都進行繪製。許多方案試圖採用改變

    background-position 來提供視差效果, 但這會讓瀏覽器在滾動時重繪受影響的部分,而這可能會是相當消耗資源的,這種影響會使動畫卡頓。

    如果我們想提供一個高品質的視差動畫,我們想要的是一個可以當作加速的
  • 屬性
(這裡我們指的是

transformopacity

),而這是不依賴滾動事件的。

CSS 3D

Scott Kellum 和 Keith Clark 都已經在利用 CSS 3D 來實現視差效果領域做出了很重要的工作。他們採用的非常有效技術有:

建立一個容器元素,設定overflow-y: scroll

使其可以捲動(同時可能需要

overflow-x: hidden)。

對於上面的元素, 我們會套用一個

perspective

值,然後設定

perspective-origin

top

left, 或0 0

對上面元素的子元素套用 Z 軸的變換,然後把它們還原回來以實現視差效果,而不會影響它們在螢幕上的大小。

這種方案的CSS 看起來是下面的樣子:
    .container {
      width: 100%;
      height: 100%;
      overflow-x: hidden;
      overflow-y: scroll;
      perspective: 1px;
      perspective-origin: 0 0;
    }
    
    .parallax-child {
      transform-origin: 0 0;
      transform: translateZ(-2px) scale(3);
    }
    登入後複製
  1. 當然我們假定你的HTML 是下面的樣子:

    <p class="container”>
      <p class="parallax-child”></p>
    </p>
    登入後複製
    調整perspective的比例<a href="http://www.php.cn/wiki/926.html" target="_blank"></a>把子元素擠回來會要求它設定一個更小的相對於perspective 的比例。你可以透過下列等式來計算所需的縮放比例: <a href="http://www.php.cn/wiki/924.html" target="_blank"></a>(perspective - distance) / perspective。由於我們希望視差元素看起來和我們一開始設定的一樣大,所以它應該根據這樣的等式進行放縮而不是保持不變。
  2. 拿上面的例子来说, perspective1px, 而 parallax-child 在 Z 轴方向是 -2px,这就意味着元素需要被放大3倍,你可以看到我们在 scale 中写入了 3 这个值。

    对于任何没有应用 translateZ 的内容,你可以用 0 替代,也就是缩放比为 (perspective - 0) / perspective,结果为 1 ,即既不放大也不缩小。真的是非常方便。

    为什么这种方案好用?

    弄清楚为什么这种方案好用是非常重要的,因为我们很快就要使用这个知识了。滚动其实本质是一种变换,这是它为什么可以被加速的原因。滚动很大程度上使用GPU参与了图层的变换。一个常见的滚动(没有应用任何 perspective )是这样的:滚动这种情况下是以 1:1 的方式在对待滚动的元素和它的子元素。换人话说,如果你向下滚动一个元素 <a href="http://www.php.cn/code/4221.html" target="_blank">300</a>px,那么它的子元素向上变换了同样的数量: 300px

    但是,如果对这个滚动元素应用 perspective 值会把这个过程“搞乱”:这个值改变了滚动变换的理想路线。现在如果一个 300px 的滚动可能把子元素移动了 150px,当然这取决于你给 perspectivetranslateZ 设置什么值。如果一个 translateZ 设置为0的子元素,它的滚动会一切如常 ( 1:1 ),但是一个被推向 Z 轴向( translateZ 不为 0 )的子元素将以不同的比例滚动!因此出现了视差效果。另外非常重要的一点是:这个过程本身就是浏览器内部的滚动机制的一部分,因此没有必要监听滚动事件或者改变背景位置。

    美中不足:Mobile Safari

    每种效果都有一些约束,对于变换( transform )来讲,对子元素的 3D 效果的保持就是这样。如果在应用 perspective 的元素和它的“视差”子元素的结构之中有其它元素的存在,那么 3D 的效果会被“拍扁”,也就是说效果将不复存在。

    <p class="container”>
      <p class="parallax-container”>
        <p class="parallax-child”></p>
      </p>
    </p>
    登入後複製

    在上面的HTML中 .parallax-container 是一个新添加的元素,而它会"抹平" perspective,从而导致效果丢失。通常情况下,解决方案还是比较符合直觉的:给这个元素添加 transform-style: preserve-3d 以便让它可以把 3D 效果应用到更深层的节点去。

    .parallax-container {
      transform-style: preserve-3d;
    }
    登入後複製

    对于 Mobile Safari 来说,事情变的有点麻烦。对容器元素应用  overflow-y : 技术上这是没问题的,但是这会让滚动元素的移动过于凶猛。解决方案是加上一个  -webkit-overflow-scrolling: touch ,但这个设置会导致 perspective 被抹平,因此我们会得不到任何视差效果。

    从一个发展的角度看,这可能算不上什么问题(因为只在旧版本的 Mobile Safari 出现),即使我们无法在每一个浏览器中展现视差效果,但一个应用的功能还是好用的,但我们最好找出一个方案。

    position:sticky 来拯救

    事实上,我们可以从 position: sticky 中得到一些帮助,这个设置允许元素固定在 <a href="http://www.php.cn/css/css-rwd-viewport.html" target="_blank">viewport</a> 的顶部或者固定在一个滚动元素的父元素。这个属性的文档,就如同任何其它文档一样,又臭又长,但是还是可以找到一些有用信息:

    一个固定的“盒子”非常像一个相对定位的盒子,但是位移是通过引用最近的可滚动的祖先来计算的,或者根据 viewport 来计算,如果找不到这样一个祖先的话 -- CSS Positioned Layout Module Level 3

    第一眼看上去好像帮助不大,但一个关键点在句中说到如何计算元素的固定位置的那部分:“位移是通过引用最近的可滚动的祖先来计算的”。换句话说,移动固定元素的距离(为了让它看起来是固定在某个元素或者 viewport 上)是在应用其它任何变换之前进行计算的,而不是之后。这就意味着,和我们刚才说的滚动的那个例子很像,如果位移计算的结果是 300px,那么我们就有了一个新的机会去使用 perspective (或者其它任何变换)来在这个 300px 应用到固定元素之前去改变它。

    通过给视差元素设置 position: -webkit-sticky,我们可以有效的“翻转”那个由于 -webkit-overflow-scrolling: touch 而产生的“抹平”效果。这样就确保了视差元素引用最近的可滚动的祖先元素,这里就是 .container 。然后,和上文讲的类似,给 .parallax-container 设置一个 perspective 值,这样就改变了计算的滚动位移,创建出了视差效果。

    <p class="container”>
      <p class="parallax-container”>
        <p class="parallax-child”></p>
      </p>
    </p>
    
    .container {
      overflow-y: scroll;
      -webkit-overflow-scrolling: touch;
    }
    
    .parallax-container {
      perspective: 1px;
    }
    
    .parallax-child {
      position: -webkit-sticky;
      top: 0px;
      transform: translate(-2px) scale(3);
    }
    登入後複製

    这样就为 Mobile Safari 恢复了视差效果,真是一个不错的结果。

    固定定位的问题

    和之前的方案确实还有一个明显区别, position: sticky 改变了视差的机制。固定定位试图固定某个元素在滚动容器顶端,而非固定元素不是。这就意味着固定定位产生的视差和非固定产生的色差是相反的:

  • 使用 position: sticky: 元素离 z=0 越近,它移动的越少

  • 不使用 position: sticky: 元素离 z=0 越近,它移动的越多

如果你还是感到有些抽象的话,可以看一下Robert Flack的这个demo,这个demo展示了在固定定位和非固定定位的条件下,元素是如何有不同的表现的。要看到这个效果的话,你需要 Chrome Canary (写作本文是,版本为56) 或者 Safari 。

高性能的視差動畫【譯】

position: sticky 对视差的影响

花式bug和应对

如同任何事情一样,还是有很多的坑需要填。

  • 固定定位的支持是不一致的:当前在 Chrome 中对于这个特性还在开发中,Edge 则完全缺失,FireFox则有绘制的bug。在这种情况下,我们应该增加一点代码来在需要时(这里就是 Mobile Safari )才添加 position: sticky

  • 该效果在 Edge 中完全没有作用。Edge试图在OS级别处理滚动,通常情况下这是个好事。但在这个例子中,这种机制会使得我们无法在滚动时去应用 perspective。为了修复这个问题,我们可以为父元素 设置 `translateZ(0px)``。

  • 页面内容太大了:在决定页面内容有多大时,很多浏览器负责放缩,但很遗憾 Chrome 和 Safari 不负责。所以假如有一个放大 3 倍的变换应用到某个元素时,你可能会看到滚动条出现了,而且一旦出现后,即使之后你恢复了 1:1 的比例,滚动条也不会消失。有一个方法可以避免这种情况:那就是从右下角进行放缩( transform-origin: <a href="http://www.php.cn/wiki/906.html" target="_blank">bottom</a> <a href="http://www.php.cn/wiki/905.html" target="_blank">right</a> )。这种方案背后的原理是它会导致过大的元素进入滚动区域的“负面”(一般是左上),而滚动区域永远不会让你看到“负面”区域。

结论

视差动画如果经过的周全的设计考虑后会是一个非常有趣的效果。而且现在你应该可以了解到我们是可以实现一个高性能的、滚动耦合的、跨浏览器的方案。由于这里面需要一点点数学计算和一些模板化的操作,所以我们封装了一个工具类和例子。

欢迎试用,并提出您的宝贵意见。

以上是高性能的視差動畫【譯】的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!