html5 视差地图,用HTML5构建高性能视差网站的图文代码详解

news/2024/5/10 14:44:24/文章来源:https://blog.csdn.net/weixin_39988677/article/details/117975913

本文介绍了一种时尚的网站设计方法,以及如何由浅入深的通过HTML5和浏览器渲染机制来构建高性能的站点。

文中多处涉及浏览器重绘和性能优化的原理,也是《Web滚动性能优化实战》的拓展和延续,难度上属于中级进阶,请在阅读前请先看看这篇文章。

介绍

视差网站最近风靡一时,只需看看下面这些站点:

Old Pulteney Row to the Pole

Adidas Snowboarding

BBC News - James Bond: Cars, catchphrases and kisses

如果你还不了解它们,它们其实就是页面的视觉结构随滚动变化的站点。正常情况下,页面上的元素按比例缩放、旋转或者移动到滚动的位置。

a63fb6ec85e6bda8160b392e7e36c5a9.png

我们视差效果的演示页面

你喜不喜欢视差网站是一回事,但是我们能确定的是这绝对是一个性能黑洞。原因是当你滚动时,浏览器会试图对新内容出现的地方(根据滚动的方向)进行性能优化,总的来讲,在滚动中视觉上越少更新浏览器性能越好。对于视差网站来说这很少见,因为在整个页面上大的视觉元素会多次发生改变,从而导致浏览器必须对整个页面进行重绘(为什么是性能黑洞,可以参考我的这篇文章《Web滚动性能优化实战》)。

把视差网站归纳为下面的特性是合理的:

1、 当你向上或者向下滚动页面时,背景元素改变位置、旋转或者缩放。

2、 页面内容,例如文本或者小图片,以特别的从上到下的方式滚动。

我们之前介绍过滚动性能及其优化方式,你可以以此来改进应用的响应能力。本文将建立在此基础上,所以你需要先读一下上面这篇文章。

所以现在的问题是,如果你正在构建一个视差滚动网站,是必须要进行代价昂贵的重绘,还是有其它方法可以采用来最大限度的提高性能?让我们来看看可供选择的方法。

方法1:使用DOM元素和绝对定位

这可能是大多数人选择的方式。页面里有许多元素,当滚动事件触发时,许多视觉上的更新会发生在这些元素上。这里我展示了一个演示页面。

如果你开启了开发者工具时间轴的frame模式,并且上下滚动,你会注意到有代价昂贵的全屏绘制操作。如果你滚动多次,你也许可以在一个单独的帧里看到多个滚动事件,每一个都会触发布局工作。

505cd29e0db5a3732ca2b983d7147984.png

开发者工具展示了一帧里有大量的绘制操作和多个由事件触发的布局

重要的是要牢记,为了达到60fps(与典型的显示器刷新率60Hz相匹配),我们必须要在差不多16ms内完成所有事情。在这第一个版本中,我们每当得到一个滚动事件,我们就要执行一次视觉更新,但是正如我们在前面的文章-《用requestAnimationFrame实现更简单动画》和《Web滚动性能优化实战》里讨论到的一样,这与浏览器的更新节奏并不一致。所以我们要么错过帧,要么在一帧里完成太多的工作。这会让你的站点很容易看起来不舒服和不自然,导致用户感觉失望。

让我们把视觉更新的代码从滚动事件中移到requestAnimationFrame回调里,并且在滚动事件的回调里简单的获取滚动的值。我们在第二个演示中展示了这个变化。

如果你重复滚动测试,你可能会注意到有轻微的改善,虽然并不多。原因是由滚动触发的布局操作代价昂贵,而现在我们只在每帧中执行一次布局操作。

7704cdf4ec74ad265696da11f03cca70.png

开发者工具展示了一帧里有大量的绘制操作和多个由事件触发的布局

我们现在在每帧里可以处理一个或者上百个滚动事件,但最重要的是,我们仅仅存储最近的一个滚动值,供requestAnimationFrame回调触发时使用,并执行视觉上的更新。关键是我们已经从每次接收到滚动事件时进行视觉更新优化为在浏览器给我们的合适时机进行处理。你是不是觉得这相当给力?

这个方法的主要问题是,无论使用requestAnimationFrame与否,我们基本上都会生成整个页面的层,在移动这些视觉元素时需要大量和代价昂贵的重绘。通常重绘会是一个阻塞操作(虽然这点将会优化),这意味着浏览器不能同时进行其它工作,而我们经常有可能超过浏览器16ms的帧的处理时限,这代表会出现性能上卡顿的情况。

方法2:使用DOM元素和3D转换

除了绝对定位之外,另外一种我们可以采用的方法就是3D转换(transform)。在这种情况下我们可以看到每个用3D转换处理的元素都会产生新的层。相比之下,在方法1中,如果有任何变化时,我们必须要重绘页面上一大部分的层。

这意味着使用此方法情况会大为不同:我们可能对应用了3D转换的任何元素都会有一个层。如果通过更多元素的转换做到这一点,我们不需要重绘任何层,GPU能够处理移动元素和合成整个页面。也许你想知道为什么用3D转换替代3D,原因是2D转换不能保证得到一个新的层,而3D转换可以。

这是另一个使用了3D转换的演示。滚动时你可以看到性能已经大有改观。

很多时候人们使用-webkit-transform:translateZ(0)这个技巧,能够看到有奇妙的性能改善(宇捷注:关于这种方式,其实就是利用3D转换来开启浏览器硬件加速,属于一种Hack。国内很少有资料提及,而国外有很多移动App开发性能优化的文章提到。国内可以看看《改善HTML5网页性能》,国外可以看看《IncreasingPerformance of HTML and JavaScript on Mobile Devices》)。这种方式现在可以正常工作,但是会带来一些问题:

1、 它并不是浏览器兼容的;

2、 它强迫浏览器为每一个转换的元素创建新的层。大量的层会带来其它性能瓶颈,所以需要有节制的使用。

3、 它在某些Webkit版本的移植上被禁用。

所以,你如果采用这种方法需要非常谨慎,这对解决问题来说是一个临时方案。在完美的情况下我们甚至都不会考虑它,而且浏览器每天都在改进中,谁知道也许哪天我们就不需要它了。

方法3:使用固定定位(Fixed Position)的Canvas或者WebGL

我们最后要考虑的方法就是在页面上采用固定定位的Canvas,而把转换的图像绘制在上面。乍看之下,这可能不是最高效的解决方案,但是它有几个好处:

我们不再需要大量合成工作,因为页面只有一个元素 - Canvas;

我们可以高效的通过硬件加速处理一个单独的bitmap;

Canvas2D API非常适合我们要执行的转换类型,这意味着开发和维护更容易管理。

使用Canvas元素为我们提供了一个新的层,但是它只有一层,而在方法2中我们为每一个应用3D转换的元素都创建了一个新层,所以有额外的工作量来把这些层合成在一起。

如果你看看这种方法的演示,并且在开发者工具中观察,你会发现它的性能更加优异。在这个方法里,我们只需在Canvas上调用drawImage API、设置背景图像,以及每一个要在屏幕上正确位置绘制的色块。

/**

* Updates and draws in the underlying visual elements to the canvas.

*/

function updateElements () {

var relativeY = lastScrollY / h;

// Fill the canvas up

context.fillStyle = "#1e2124";

context.fillRect(0, 0, canvas.width, canvas.height);

// Draw the background

context.drawImage(bg, 0, pos(0, -3600, relativeY, 0));

// Draw each of the blobs in turn

context.drawImage(blob1, 484, pos(254, -4400, relativeY, 0));

context.drawImage(blob2, 84, pos(954, -5400, relativeY, 0));

context.drawImage(blob3, 584, pos(1054, -3900, relativeY, 0));

context.drawImage(blob4, 44, pos(1400, -6900, relativeY, 0));

context.drawImage(blob5, -40, pos(1730, -5900, relativeY, 0));

context.drawImage(blob6, 325, pos(2860, -7900, relativeY, 0));

context.drawImage(blob7, 725, pos(2550, -4900, relativeY, 0));

context.drawImage(blob8, 570, pos(2300, -3700, relativeY, 0));

context.drawImage(blob9, 640, pos(3700, -9000, relativeY, 0));

// Allow another rAF call to be scheduled

ticking = false;

}

/**

* Calculates a relative disposition given the page’s scroll

* range normalized from 0 to 1

* @param {number} base The starting value.

* @param {number} range The amount of pixels it can move.

* @param {number} relY The normalized scroll value.

* @param {number} offset A base normalized value from which to start the scroll behavior.

* @returns {number} The updated position value.

*/

function pos(base, range, relY, offset) {

return base + limit(0, 1, relY - offset) * range;

}

/**

* Clamps a number to a range.

* @param {number} min The minimum value.

* @param {number} max The maximum value.

* @param {number} value The value to limit.

* @returns {number} The clamped value.

*/

function limit(min, max, value) {

return Math.max(min, Math.min(max, value));

}

这种做法真的在处理大图片(或者其它很容易写到一个Canvas上的元素)或者大块的文本时肯定根据挑战性。但是在你的网站上,它可能被证明会是最合适的解决方案。如果你不得不在Canvas上处理文本,你也许要使用fillText API,但是它有访问成本(你刚刚才把文本转换为bitmap!)而且你需要处理文本换行以及其它问题。你需要尽量避免这么做。

讨论了这么多,我们没有理由假设视差的工作就一定要用Canvas元素。如果浏览器支持,我们可以使用WebGL。这里面的关键是WebGL是所有API到显卡最直接的方式,并且在你的站点效果很复杂的情况下性能是最有可能达到60fps的。

你最直接的反应可能是觉得采用WebGL矫枉过正,或者它并没有获得广泛支持,但是如果你如果使用了类似于Three.js的库,你可以随时回退为使用Canvas元素,同时你的代码能以一种一致和友好的方式进行抽象。我们需要做的只是用Modernizr来检测相应API的支持:

// check for WebGL support, otherwise switch to canvas

if (Modernizr.webgl) {

renderer = new THREE.WebGLRenderer();

} else if (Modernizr.canvas) {

renderer = new THREE.CanvasRenderer();

}

然后使用Three.js的API,而不是自己处理上下文。这里有一个支持两种渲染方式的演示。

这种方法的最后一个问题是,如果你并不特别爱好在页面上添加额外的元素,你可以总是在Firefox和Webkit浏览器里使用canvas作为背景元素。很明显,这并不是普遍适用的,所以你应该对此持谨慎态度。

逐步退化

开发者默认采用绝对定位元素而不是其它方法的主要原因可能仅仅简单是浏览器支持的问题。这种方式在一定程度上是错误的,因为对于老旧的浏览器来说,只能提供非常贫乏的渲染体验。即便在现代浏览器中,使用绝对定位也不一定能带来好的性能。

更好的方案是在老旧的浏览器上避免尝试视差效果,仅在最好的浏览器上确保能够用正确的API呈现站点效果。当然,如果你使用了Three.js,你应该能够很容易根据所需要的支持在渲染器之间进行切换。

结论

我们评估了几种方式来处理大量重绘的区域,从绝对定位的元素到使用固定定位的Canvas。当然你要采用的实现方式,取决于你要达到的目标和具体设计,但是知道有多种选择是一件好事情。在本文的例子中,我们设法从相对卡顿、低于30fps优化到了平滑、60fps的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_771502.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php网站选择什么服务器配置,php选择什么服务器配置

php选择什么服务器配置 内容精选换一换华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。简要介绍WebSVN是一个基于Web的Subversion Repository浏览器…

Vue+thinkJs博客网站(一)之vue多页面应用的webpack3配置

一.项目简介 本项目使用vue作为前端框架,thinkJs作为后端框架,构建个人博客网站,页面分为博客展示和后台管理,主要目的是学习使用thinkJs。现在只完成了主要的博客增删改功能,发现webpack的配置遇到了一些坑&#xff0…

网站载入测试:Firefox 3.5 Beta 4完胜IE8

上月中旬,微软在一份文档中宣称,根据对全球25大网站(据comScore)载入速度的测 试,IE8比Google Chrome 1.0、Firefox 3.0.5都要快,但根据第三方机构的测试,微软完全没有胜算,而且Firefox随着不断升级领先优势…

华为正式进军互联网 推出白领社交网站AiMi.COM

电信解决方案供应商华为已于近日正式推出白领社交网站AiMi.COM,目前已经开放测试。此举预示着华为正式踏入互联网业务。 首页截图 个人中心截图 AiMi社区定位于满足上班族的网上乐园消遣和娱乐需求。根据测试,AiMi社区界面和目前流行的社交网站没有本质…

分享一些好用的网站

前言 这两年收藏了不少网站,特地整理一下,把一些大家都可能用得上的分享出来,希望能对你有用。 考虑到有一些网站大多数人都知道,所以我就不列出来了。 我把这些网站分为了几大类: 工具类素材类社区类工具类 1、start.…

大型网站架构技术读后感

最近在看趣谈网络协议,顺带看看这本朋友推荐的书,《大型网站技术架构》是由宝架构师李智慧大牛写作的,我把这本书称为“开眼之书”,这本书站在架构的角度讲网站架构,讲的是整体规划和考虑问题的思路,我从事…

web前端开发项目资源网站,私家珍藏!

1.CodePen: http://codepen.io/ 网站里有很多很酷的特效,而且可以看到效果的源代码,也可以看到实现效果,是一个非常不错的前端开发学习资源网站。 这个是CodePen网站里的一个效果的源码截图,是不是很酷呀! …

介绍三个新的流量对比网站

做网站的最关心自己的网站和其他网站之间的流量对比,正因为这样,Alexa才会被大家捧到天上,04年,当时在计算机世界的王翌写了一篇《出卖Alexa 》,基本上把Alexa作弊的黑色产业链公诸于世了。Alexa作弊太严重&#xff0c…

宣传网站的利器——DIY个性化iGoogle主题收藏

摘自《Google API大全——编程开发实例 》第10章“iGoogle主题设计”10.2节 10.2 创建主题的步骤 为iGoogle制作主题,除需要有艺术天赋外,还需要有Web设计、编写代码、调试等计算机相关知识。 简单地说,创建一个主题有以下3个步骤&#xff…

独家:.NET开发人员必知的八个网站

当前全球有数百万的开发人员在使用微软的.NET技术。如果你是其中之一,或者想要成为其中之一的话,我下面将要列出的每一个站点都应该是你的最爱,都应该收藏到书签中去。 对于不熟悉.NET技术的朋友,需要说明一下,.NET提供…

好玩的网站“彩蛋”们(程序员视角)...

看电影的时候,制作商会在影片最后,给我们留彩蛋. 浏览网站的时候,网站的运营商也会给我们留彩蛋... 图形类彩蛋 知乎 https://www.zhihu.com/ 知乎想来知乎工作?请发送邮件到 jobszhihu.com 天猫 https://www.tmall.com/ 天猫喵~ 加入我们吧 http://tb.cn/iS8NB…

前端脚本!网站图片素材中文转英文

写网页的时候, 我们经常需要使用图片素材, 图片素材如果是中文名, 挂到服务器会会引发乱码, 我们需要将图片名称改为英文字符才可以使用而起名是一个世界级难题, 为图片素材起英文名更是一件极其蛋疼的事有些人英语不好, 直接用拼音命名, 而拼音闹出的笑话更是无法计量...最近接…

用gogs搭建属于自己的git网站

如果你对docker的操作不太了解, 建议先阅读 从零搭建docker私有仓库 gogs是一款极易搭建的自助 Git 服务, 掌握了它, 我们就可以搭建自己的git服务站点gogs官网: https://gogs.io/, github中文地址:https://github.com/gogs/gogs/blob/master/README_ZH.md 实验环境: 腾讯云 c…

chrome小众插件 一键查找姊妹网站 SimilarSites

当你浏览一个很棒的站点的时候, 或许你会想到, 和它"差不多"的站点有哪些, 尤其是针对一些资源站点, 这个站点没有, 而它同类的站点"往往有"! 这里推荐一个很有意思的chrome的插件SimilarSites, 它的作用只有一个, 发现同类站点~ 官方介绍: 当访问任何网站…

Chrome批量打开多个网站

对于大多数人而言, 常用的网站也就那么几个在不同的场景, 你需要打开的网站是不同的如果你是一个动漫爱好者, 你或许会同时追多部动漫, 而这些动漫往往还都只能在特定的网站才能看到 以追动漫为例 你在追《银魂》,你需要打开优酷你在追《魔道祖师》,你需要打开腾讯视频你在追《…

whatruns一键分析网站技术栈

对于一个前端程序员, 每当看到一个全新的网站, 往往会想到, 这个网站是用什么技术完成的?你可以通过打开开发者工具, 查看网站源码, 进而了解网站的技术细节, 但效率不高, 而且可能会漏掉一些技术.分析网站的工具有很多, 但质量良莠不齐, 有的是版本陈旧, 很少维护, 无法识别新…

nginx托管静态网站

今天测试 layuimini,提示需要在 Tomcat 或 nginx 上托管,不像 Bootstrap 可以直接打开 html 页面运行。那就托管(或者叫部署) 到 nginx 上吧。步骤如下。 将下载的 layuimin 包拷贝到 nginx 的安装目录下: 然后进入 conf 文件夹&#xff0c…

《Dark Reader》为任意网站启用夜间模式

先放两张对比图 Dark Reader启用后Dark Reader启用前Dark Reader是一款Chrome护眼插件,可以实时生成黑色主题,为任意网站启用夜间模式 开启和关闭插件有的网站的配色本来就很美, 可以对特定网站禁用Dark Reader至此, DarkReader的功能已经可以满足你日…

《Quickey Launcher》给常用网站绑定emoji快捷键

Quickey Launcher以优雅的方式, 为任意网页绑定一个快捷键, 绑定完成后, 即可通过快捷键,打开网页 为特定网址绑定特定字母 我们可以为以下三个不同网址绑定三个不同的字母B 绑定 https://bilibili.comC 绑定 https://github.com/zhaoolee/ChromeAppHeroesT 绑定 https://gith…

《Alexa Traffic Rank》一键查看网站全球排名

有一个名为Alexa的网站, 专注于对全球网站进行排名 查询网站的方法(以掘金 juejin.im为例)但上面的方法, 需要输入网站的域名, 有点麻烦, 所以官方提供了这个插件, 使用方法如下图所示扩展下载地址 https://chrome.google.com/webstore/detail/alexa-traffic-rank/cknebhggcce…