线性渐变缓动

Avatar of Andreas Larsen
Andreas Larsen

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

线性渐变在 CSS 中易于创建,并且非常有用。正如我们将在本文中介绍的,我们可以通过创建线性渐变使它们在视觉上更加平滑。好吧,在缓动意义上是非线性的!

以下是一个示例,展示了标准的linear-gradient()缓动后的平滑度相比有多么生硬

“好、坏和丑”中的截图,上面叠加了渐变。
  • Il buono(好的):CSS 中平滑的渐变,与背景融为一体。
  • Il cattivo(坏的):没有文本保护(可访问性差)。
  • Il brutto(丑陋的):具有尖锐边缘的标准线性渐变。

在本文中,我们将重点关注如何将 Il brutto 变成 Il buono。

令人沮丧的background: linear-gradient() 的尖锐边缘

最近,我一直在工作中摆弄渐变。我对普通的线性渐变感到沮丧,因为它们看起来像上面的 Il cattivo。

/* Sharp edges :( */
.image__text {
  background-image: linear-gradient(
    hsla(0, 0%, 0%, 0.6),
    transparent;
  );
}

我开始研究如何创建始终更具视觉吸引力的渐变。更准确地说,我快速地用肉眼观察了一些看起来更漂亮的渐变作为一次性解决方案,然后在回家后开始琢磨。

灵感:数学和物理

由于渐变是颜色的过渡,我从我们如何处理其他地方的过渡中得到启发。

我一直对欧拉(或科努)螺旋线着迷,它的曲率随曲线长度线性增加,即当我们沿着从(0,0)的线走时,半径随我们行走的距离线性减少(因为曲率是半径的倒数)。

最终的结果是一条曲线,它以尽可能平滑的方式从直线过渡到曲线。(旁注:欧几里得空间中的直线是具有无限半径的曲线!)

欧拉螺旋线,由 AdiJapan,CC BY-SA 3.0

这种类型的曲线被称为过渡曲线,在现实世界中使用。下次当你从一条结构良好的高速公路上驶出时,你会注意到你是如何逐渐转动方向盘的。我们要感谢欧拉将向心加速度的突然变化降到最低,即他的数学是车辆即使以高速公路限速驶出高速公路时也不会翻倒的原因。

下图是高速公路曲率变化如何逐渐变化的示例。

日本相模原郊外的十字路口,由 @digitalanthill

灵感:排版

纵观历史,字体设计师一直痴迷于平滑的曲线。我们之所以这样做是因为我们不希望字母和数字看起来像不同形状的组合,而应该形成一个连贯的形状。

这就是为什么我在下面的“9”中使直线到圆圈的过渡尽可能平滑的原因。它使数字 9 看起来像一个单一的形状,而不是一条线加一个圆圈。

作为字体设计师,我们拥有帮助我们实现这一目标的工具。FontForge(一个开源字体编辑器)甚至有一个螺旋线/欧拉绘图模式。最流行的字体设计扩展之一是Speed Punk,它可以可视化曲率。

左侧为 FontForge 中的螺旋线模式,右侧为 Glyphs 中的 Speed Punk 可视化。

灵感:设计

苹果在其数字和硬件设计部门中大量使用这种线到曲线过渡的方法。(参见 Apple 的图标之所以拥有这种形状是有充分理由的)。当苹果发布 iOS7 时,图标遮罩进行了更新,以使直线到圆角的过渡更加平滑。

iOS6 和 iOS7 应用图标曲率的可视化。

旁注:上面的 iOS7 形状直接取自Apple HIG,不幸的是它有一些小瑕疵,尤其是在水平线开始弯曲的地方。它有时也被称为“圆角矩形”。)

灵感:网页设计

在网页设计中,我们有时会受到我们能够做的事情的限制。例如,border-radius 无法提供任何方法来创建像 iOS7 图标那样的圆角矩形。同样,对于linear-gradient,也没有可用的自然缓动效果。

但是,我们在动画中确实有缓动效果和贝塞尔曲线可用!它们使我们能够使动画看起来更加自然、平滑和微妙。

来自 easings.net 的截图

渐变的影响

大多数情况下,在网页设计中,我们希望渐变尽可能地融入背景。当我们使用像 Il buono 这样的文本保护渐变时,我们不希望用户关注渐变本身。它应该相当隐形,从而使读者能够专注于图像和文本。

遮罩

Material Design 的图像样式指南中,谷歌的设计师谈到了文本保护渐变。他们称之为遮罩。他们建议

[该] 渐变应该很长……中心点大约在渐变较暗一侧的 3/10 处。这样会使渐变自然地衰减,避免出现尖锐的边缘。

根据 Material Design 指南的遮罩

我们无法使用线性渐变创建完全相同的渐变,但我们可以(并且将)使用更多颜色停靠点创建“低多边形”近似值。

具有 5 个颜色停靠点的遮罩,用于展示原理

仅使用 5 个颜色停靠点(如上图所示)会导致严重的条带。添加更多停靠点会使渐变更加平滑。这正是我在本文第一张图像中展示的演示中所做的事情。Il buono 具有 13 个颜色停靠点的渐变,这使其更好地与图像融为一体。

查看 CodePen 上 Andreas Larsen (@larsenwork) 的 Pen 好、坏和丑陋 - 正确的文本

与 Material Design 遮罩相比,我对其进行了调整,使其在开始时更线性,以获得更高的文本对比度,并使它更平滑地淡出。

使用 13 个颜色停靠点绘制的 Material Design 遮罩和我的遮罩的对比。

如果将 Material Design 遮罩与普通的线性渐变进行比较,则它需要长约 60% 才能达到相同的中间对比度,而我的尝试只需要长约 30%。目的是避免不必要地使图像变暗,但仍然与图像平滑地融为一体。

两个遮罩与普通的线性渐变相比

我选择不包含 Material Design 遮罩,因为它与更漂亮的easeOutSine 几乎相同。我们可以比较linear-gradient、我的scrim-gradientease-out-sine-gradient 的外观

混合两端

在遮罩示例中,我们只需要混合一端,因为另一端与图像相连。有时,我们需要在两端进行混合,这就是缓动函数(如easeInOutSine)发挥作用的地方。

线性渐变与 ease-in-out-sine 近似值。

使用easeInOut 函数,我们可以确保从 colorA 到渐变以及从渐变到 colorB 的过渡尽可能平滑。相同的原理在本 Pen 中也有说明

查看 Pen。

如何绘制渐变

在 YouTube 上,当您将鼠标悬停在视频上时,控件后面有一个渐变。它使用 base64 PNG 创建。这种技术也非常有效,但您无法真正自动化它或轻松调整它。

YouTube 的屏幕截图(艺术家是 Wintergatan)。

大多数其他地方使用 linear-gradient(hsla(0, 0%, 0%, 0.8), transparent),其中开始 alpha 通常在 0.6-0.8 之间。这解决了使文本可读的问题,但生成的渐变非常突出。例如,我在 BBC 上尝试使用半透明渐变。

使用线性渐变(左)和半透明渐变(右)的 BBC 屏幕截图。

PostCSS 来帮忙

我创建了一个插件来为我创建这些渐变。以下是语法

scrim-gradient(
  black,
  transparent
);

变成

linear-gradient(
  hsl(0, 0%, 0%) 0%,
  hsla(0, 0%, 0%, 0.738) 19%,
  hsla(0, 0%, 0%, 0.541) 34%,
  hsla(0, 0%, 0%, 0.382) 47%,
  hsla(0, 0%, 0%, 0.278) 56.5%,
  hsla(0, 0%, 0%, 0.194) 65%,
  hsla(0, 0%, 0%, 0.126) 73%,
  hsla(0, 0%, 0%, 0.075) 80.2%,
  hsla(0, 0%, 0%, 0.042) 86.1%,
  hsla(0, 0%, 0%, 0.021) 91%,
  hsla(0, 0%, 0%, 0.008) 95.2%,
  hsla(0, 0%, 0%, 0.002) 98.2%,
  hsla(0, 0%, 0%, 0) 100%
);

基本原理是我们已经讨论过的:结合缓动函数和多个颜色停顿点来创建看起来比普通线性渐变更平滑的近似值。

实际上,上面的半透明渐变是使用一组自定义坐标生成的,但如果我们查看缓动渐变,如 ease-in-out-sine-gradient,步骤如下

  1. 遍历 .css(或 .pcss)并找到它。
  2. 在 ease-in-out-sine 曲线上生成均匀分布的坐标。
  3. 使用这些坐标创建颜色停顿点。x 坐标确定颜色混合比例,y 坐标确定颜色停顿点位置。
  4. 用生成的线性渐变替换缓动渐变。
步骤 2 中生成的 ease-in-out-sine 坐标值。

该插件目前有两个可选设置

  • precision - 与生成的色标数量相关
  • alphaDecimals - 设置在 hsla() alpha 值中使用的十进制数

插件:postcss-easing-gradients

总的来说,我对输出结果相当满意。我正在考虑添加的内容

  • Sass 版本?我不再使用它了。也许其他人会想写一个?
  • 用于混合颜色停顿点颜色的坐标在缓动曲线上的分布是均匀的。理想情况下,颜色停顿点之间的距离在曲率变化量最大的地方会相对较短。
  • 也许你们有什么想法?

您可以在 GitHubNPMCodePen 上的模板 中找到它。去试试吧!您的贡献和建议非常受欢迎。

CSS

最好的是,我希望能够编写类似 ease-in-out-gradient(#bada55, transparent) 的内容,让浏览器在不进行任何自定义 CSS 处理的情况下理解它。

参考资料/进一步阅读