写点什么

[极致用户体验] 如何实现响应式 canvas?保持 canvas 比例?教你让 canvas 自适应屏幕宽度!

作者:HullQin
  • 2022 年 8 月 26 日
    广东
  • 本文字数:2482 字

    阅读完需:约 8 分钟

[极致用户体验] 如何实现响应式canvas?保持canvas比例?教你让canvas自适应屏幕宽度!

我是 HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者 HullQin 授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费没广告。还独立开发了《合成大西瓜重制版》。还开发了《Dice Crush》参加 Game Jam 2022。喜欢可以关注我 HullQin 噢~我有空了会分享做游戏的相关技术。

背景

canvas是前端常常会用到的东西,尤其是对于游戏开发者、图表开发者而言。


响应式设计(网页元素可自适应各种屏幕宽度的设计)对于前端,也是非常重要的基本功之一。


前端开发者实现响应式设计的方案有多种,已经列举在之前的文章里了:《2 行代码,让你的 UI 适配移动端、PC 端,快来收藏》。文中主要讲述的方法是用width=device-width这个 viewport 结合min-width实现的,这个思路挺牛逼的,因为这同样适用于 canvas。强烈推荐没看的同学看一下,这个思路真的超级实用

什么是极致用户体验

1. 一屏展示全部 canvas

但是本文要讲的响应式 canvas,为了追求极致的用户体验,提出了更严格的限制:要求一屏能展示完整个 canvas


为什么要有这种限制?


尤其是针对游戏开发,不管在 PC 端、移动端,都不希望用户需要上下滚动来看到完整画面。甚至很多移动端游戏的交互是需要用户手指滑动的,这需要 canvas 监听用户滑动操作,用户就无法通过滑动来实现页面上下滚动了,导致看不到一部分网页。


所以这个限制是完全合理的,完全照顾到了极致用户体验。

2. canvas 比例与页面初始比例一致

要求 canvas 比例跟页面的初始比例保持一致,这样用户不会有空空的感觉。但是之后如果用户缩放了浏览器,要求 canvas 比例保持不变(这其实是技术上不得不做的一种妥协)。


为什么只要求跟页面初始比例相同


  1. 因为 canvas 在绘制后,要修改比例,那么内部所有元素的坐标都需要重绘,很多物理引擎计算需要重新做,对性能影响较大;

  2. 而且开发成本也相当高,canvas 不像 Dom,页面宽度变了后浏览器可自动计算新布局,canvas 改变布局是需要开发者手动计算每个元素的新位置的;

  3. 页面初始比例确定后,大概率页面比例不会修改了。尤其是移动端,用户几乎无法修改页面尺寸(浏览器小窗的情况并不多)。


根据以上 3 点,得出结论:动态改 canbas 比例是开发成本极高、收益很低(用户使用次数少)的,即 ROI 很低,所以没必要动态修改 canvas 比例,只需要 canvas 比例保持页面的初始比例,就能达到很好的用户体验了。


此外,canvas 比例常常有些极限值,如果屏幕比例超出 canvas 比例极限值,应该保持在极限值。例如画面宽高比例要求在1:11:2,那么屏幕太宽时,就只能设置 canvas 比例为极限的1:1了;而屏幕太窄时,只能设置 canvas 比例为极限的1:2。直接看例子:


  • 例如屏幕太宽的场合,超过了 canvas 比例极限值,则高度塞满,宽度留白:


  • 例如屏幕太窄的场合,超过了 canvas 比例极限值,则宽度塞满,高度留白:


  • 例如屏幕比例在 canvas 比例的 2 个极限值之间,那么高度、宽度都塞满:


真实体验下上述效果

上面口述,你可能不太清楚,我直接给你个案例,看看什么是极致用户体验:


参考我之前的文章《《 合 成 大 西 瓜 》 重 制 版 !( 联 机 版 在 做 了 )》,我复刻了《合成大西瓜》游戏,用 canvas 实现的,它就为了追求极致用户体验,实现了上述 2 条规则。


体验地址: https://game.hullqin.cn/dxg

解决方案

使用 transform 的 scale

建议不要改变 canvas 的widthheight,你可能会把 canvas 内部的宽高属性和 css 宽高搞混!如下图:这 2 个红框里的属性,有着不同的作用。



我们直接修改transformscale属性,这样是可以实现等比例缩放的,完全不影响内部布局!


但是修改scale后,元素看起来变小了,它实际还是占了widthheight那么大,还是会出现滚动条。最简单的解决方法:给它的父元素设置overflow: hidden


设置 canvas 初始比例,保持在极限值之间

我们直接上代码,解释在注释:


export const Height = 1408; // 要求画面高度固定,宽度随比例放大、缩小let width = 704; // 如果屏幕【太宽】,就会用这个宽度const { innerWidth, innerHeight } = window; // 获取初始页面尺寸if (innerHeight > innerWidth * 1.3) { // 如果初始页面尺寸不是【太宽】  width = Height * innerWidth / innerHeight;  // canvas宽高比就跟初始页面宽高比保持一致  if (width < 320) width = 320; // 如果发现屏幕【太窄】,就设置一个极限最小宽度}export const Width = width; // 导出计算后的canvas最终宽度
复制代码

监听 resize,动态设置 canvas 比例

接下来,就是要设置 canvas 的 scale 初始比例和动态设置比例了。


// 注:变量canvas是个画布的dom element,变量root是canvas的父元素。
const resetSize = () => { const { innerWidth, innerHeight } = window; if (innerWidth / innerHeight > Width / Height) { // 如果放缩后屏幕【宽】,就用屏幕高度计算放缩 root.style.height = `${innerHeight}px`; // 高度撑满 root.style.width = `${innerHeight / Height * Width}px`; // 设置新算出来的scale canvas.style.transform = `scale(${innerHeight / Height})`; } else { // 如果放缩后屏幕【窄】,就用屏幕宽度计算放缩 root.style.width = `${innerWidth}px`; // 宽度撑满 root.style.height = `${innerWidth / Width * Height}px`; // 设置新算出来的scale canvas.style.transform = `scale(${innerWidth / Width})`; }};
canvas.style.width = `${Width}px`;canvas.style.height = `${Height}px`;resetSize(); // 页面初始时,执行一次,设定canvas的样式
window.onresize = resetSize; // 监听resize事件,页面尺寸变化时,保持宽高比、动态放缩canvas
复制代码

写在最后

我是 HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者 HullQin 授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费没广告。还独立开发了《合成大西瓜重制版》。还开发了《Dice Crush》参加 Game Jam 2022。喜欢可以关注我 HullQin 噢~我有空了会分享做游戏的相关技术。

发布于: 刚刚阅读数: 3
用户头像

HullQin

关注

公众号【线下聚会游戏】 2020.10.07 加入

game.hullqin.cn 我做了一些联机桌游网页:支持2-10人联机的UNO、2-4人联机的斗地主、2人联机的五子棋。无需下载,点开即玩!叫上朋友,即刻开局!不看广告,不做任务,享受「纯粹」的游戏!

评论

发布
暂无评论
[极致用户体验] 如何实现响应式canvas?保持canvas比例?教你让canvas自适应屏幕宽度!_CSS_HullQin_InfoQ写作社区