useRainbow()

Avatar of Rafał Pastuszak
Rafał Pastuszak

DigitalOcean 为您的每个旅程阶段提供云产品。立即开始使用 $200 免费积分!

我从工作中抽身出来,开始了一些小型个人项目(玩具)。其中一个小型项目是 potato.horse,我将所有涂鸦、视觉短篇故事和笑话都保存在这里。快去看看吧!

但是,这篇文章不是关于我从工作中抽身出来、其他实验或网站本身。人们似乎喜欢我在设计中使用的一种特定技巧,特别是应用的背景效果,它在用户浏览内容时在颜色之间过渡

有些人问我这个效果是如何实现的(包括阅读压缩后的代码,这让我非常高兴)。

因此,这里有一个简短的要点,随后是一些背景

export const useRainbowBg = () =>
useEffect(() => {
  const cb = () => {
    const viewportHeight = window.innerHeight
    const contentHeight = document.body.getBoundingClientRect().height
    const viewportsPerRotation = Math.min(
      3,
      contentHeight / viewportHeight
    )
    const from = 51
    const progress =
      window.scrollY / (viewportHeight * viewportsPerRotation)
    const h = (from + 360 * progress) % 360

    document.body.style.backgroundColor = `hsl(${h}deg, 100%, 50%)`
  }
  window.addEventListener('scroll', cb, { passive: true })
  return () => window.removeEventListener('scroll', cb)
})

简而言之,我将*滚动位置*映射到 HSL 颜色表示法中的*色调*。让我们来分解一下。

颜色模型

在 CSS 中描述颜色有很多方法,最常见的两种方法是 RGB(左)和 HSL(右)

RGB 是一种加色调色板。这意味着混合 100% 的红色、绿色和蓝色会产生白色,混合 100% 的红色和 100% 的绿色,但 0% 的蓝色会产生黄色,等等。这与使用油漆或CMYK 颜色模型不同,在该模型中,产生的色调将是黑色(ish)1

我们习惯了这种方法,因为它很容易在代码中描述,但是使用色调、饱和度和亮度来指定颜色似乎更自然,尤其是如果你来自设计背景,或者……你知道,是一个使用人类语言的人类。

我们已经习惯了作为开发人员使用 RGB,但在口语中,使用它会让人觉得不自然和令人困惑。 Façade 在 RGB 中很难使用。

另一方面,HSL 通常更容易使用。例如,如果我想使一种颜色稍微冷一点,我只需将色调滑块向蓝色移动一点,我应该会更接近我的想法。使用 RGB,如果我们通过包含更多蓝色使颜色看起来更冷,则产生的色调会稍微更亮,因为蓝色分量会增加整体亮度。这意味着您必须降低红色和绿色值以进行补偿。

要查看这在实践中的工作方式,请尝试在下面的示例中将蓝色颜色最大化。

最明显的是,所有色调都向蓝色移动,图片的整体亮度也增加了。在我们要讨论的效果的情况下,这将是不可取的。

现在,让我们尝试使用 HSL 颜色圆圈做同样的事情。将滑块向左拖动,大约90 度

在这种情况下,使用 HSL 不仅将苏珊变成了吸血鬼,而且还保持了相似的2亮度水平。这正是我想要的。

所以,我的意思是说

这是如何工作的?简而言之,我将*滚动位置*映射到 HSL 颜色表示法中的*色调*。Rafal,两天前

……就是说,每次我们检测到滚动事件时,我都会尝试将其映射到色调圆上的一个角度

我不想从红色开始,因为那会让我感到饥饿,而且基本的黄色更适合设计,所以我应用了一个小的初始偏移——因此const from = 51被设置为初始偏移。

而且,就基本实现而言,就是这样!

现在,还有三个改进领域。

useRainbow 性能

我们在每次滚动时都会触发重绘,因此我有点担心旧的移动设备,甚至是一些连接到 4k 屏幕的高端笔记本电脑可能无法保持稳定的 60fps。但是,到目前为止我对结果感到满意。使用 被动事件侦听器 提供了一些提升,尤其是在移动设备上。

如果我意识到性能是一个问题,尤其是在以后有更多内容的情况下,我可能会专注于

  • 删除每次滚动处理程序调用时对getBoundingClientRect的不必要调用,以及
  • 使用requestAnimationFrame延迟或节流背景颜色更改。

我希望第一个改进会有一些影响,但第二个改进的好处应该可以忽略不计。

优化之前先衡量。只有当问题变得明显时,才需要关注性能,无论是帧速率下降还是电池影响。您的 iPhone Pro 的计算能力比许多低端笔记本电脑还要强,所以 在这些设备上进行测试也是一个好主意。如果您能省下几英镑,最好拥有一部破旧的旧款 Android 手机,专门用于此目的。

感知上统一的颜色空间

您可能已经注意到,在前面的插图中,一些完全饱和的颜色看起来比其他颜色更暗。这是因为我们通常在编码时使用的颜色空间不反映人眼的运作方式。我会把深入的解释留给 比我更有经验的人,但足以说明(严重简化警告!),通常情况下,相同数量的红色/绿色/黄色看起来比蓝色更亮。这意味着在某些情况下,页面上的文本将更难阅读。

现在,这不是一个问题,因为我刚刚将这个东西发布到网上,标题起着次要作用。但这个问题有一个解决方案,而且并不复杂:使用感知上统一的颜色空间。有很多库可以直接在 JavaScript/TypeScript 和 CSS/Sass/<选择您的 CSS 风格>中实现这一点。 hsluv 似乎是一个不错的起点。

可访问性

请注意,我将重点关注视觉效果本身,而不是讨论网站的其余部分(例如 alt 标签、文档结构等)。我想重点关注对比度、色盲和依赖于prefers-reduced-motion的人。该网站是一份活文档;总是有很多需要改进的地方。例如,对比度在一些不重要的位置可能是一个问题。我很乐意接受反馈并实施它:联系我!.

色盲

我想确保这个效果不会完全破坏色盲人士的网站。因此,我专注于最常见的类型:氘代色盲和原代色盲(红绿色盲),但也进行了更广泛的测试。我使用 Photoshop 和 Colorblindly(Chrome 扩展程序) 进行了一些基本的检查。

prefers-reduced-motion

prefers-reduced-motion CSS 媒体功能用于检测用户是否已要求系统最大程度地减少其使用的非必要运动。

——MDN

此网站没有太多动画(除了如果您点击“共享”时看到的小香肠天使),但我想知道依赖于prefers-reduced-motion的人是否希望背景颜色保持不变。

简短的回答是:我不知道。我的直觉是,旋转的颜色并不真正算作运动,但我的经验和对这个问题的理解,至少可以说,是有限的。在这种情况下,我宁愿依赖用户研究而不是猜测。

幸运的是,该网站在 Reddit 上获得了五分钟的短暂流行,这证明是一个收集反馈的好机会。到目前为止,没有用户提出关于背景效果的问题。我也有幸认识一些可访问性专家,例如 Sandrina Pereira。她的建议是 (a) 背景动画绝对算作运动,以及 (b) 也许这种效果感觉很自然,因为它是一个用户交互的直接结果。

摘要

90 年代后期 Geocities 网站充满了趣味和怪异。它以一种不受约束、不太表演的方式,充满了乐趣。我希望在网站中融入一些这种外观和感觉。但与此同时,我不想让它变得过于深奥,以至于你需要把你的时髦程度提升到 9000,并且只能通过 Netscape 7 来浏览它。所有这些,都要在听新的 Nirvana《Unplugged》专辑的时候进行。

我仍然希望在移动和桌面端上拥有不错的用户体验,以及一些用于彩蛋的空间(在与社交媒体的怪异和虐待关系中,这是你无法做到的,我们已经对此习以为常了)。

小时候,我在第一次上网之前就已经建立了六个网站。现在,在经历了三年的倦怠之后,甚至考虑过换工作,这是我第一次真正享受编码。我忘了它有多有趣!

现在,出去,摸摸你的猫,然后创造一些东西!


附注:查看 Cameron's World

附注 2:交互式图表代码 可以在 GitHub 上找到

脚注

  1. 因此 CMYK 中的 K 分量代表“黑色”。使用 B 会造成混淆,因为它在其他颜色模型中代表“蓝色”。
  2. 并不完美,因为感知颜色空间与使用 RGB/HSL 描述的颜色空间不同。