线性渐变在 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)的线走时,半径随我们行走的距离线性减少(因为曲率是半径的倒数)。
最终的结果是一条曲线,它以尽可能平滑的方式从直线过渡到曲线。(旁注:欧几里得空间中的直线是具有无限半径的曲线!)

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

灵感:排版
纵观历史,字体设计师一直痴迷于平滑的曲线。我们之所以这样做是因为我们不希望字母和数字看起来像不同形状的组合,而应该形成一个连贯的形状。
这就是为什么我在下面的“9”中使直线到圆圈的过渡尽可能平滑的原因。它使数字 9 看起来像一个单一的形状,而不是一条线加一个圆圈。
作为字体设计师,我们拥有帮助我们实现这一目标的工具。FontForge(一个开源字体编辑器)甚至有一个螺旋线/欧拉绘图模式。最流行的字体设计扩展之一是Speed Punk,它可以可视化曲率。

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

(旁注:上面的 iOS7 形状直接取自Apple HIG,不幸的是它有一些小瑕疵,尤其是在水平线开始弯曲的地方。它有时也被称为“圆角矩形”。)
灵感:网页设计
在网页设计中,我们有时会受到我们能够做的事情的限制。例如,border-radius
无法提供任何方法来创建像 iOS7 图标那样的圆角矩形。同样,对于linear-gradient
,也没有可用的自然缓动效果。
但是,我们在动画中确实有缓动效果和贝塞尔曲线可用!它们使我们能够使动画看起来更加自然、平滑和微妙。

渐变的影响
大多数情况下,在网页设计中,我们希望渐变尽可能地融入背景。当我们使用像 Il buono 这样的文本保护渐变时,我们不希望用户关注渐变本身。它应该相当隐形,从而使读者能够专注于图像和文本。
遮罩
在Material Design 的图像样式指南中,谷歌的设计师谈到了文本保护渐变。他们称之为遮罩。他们建议
[该] 渐变应该很长……中心点大约在渐变较暗一侧的 3/10 处。这样会使渐变自然地衰减,避免出现尖锐的边缘。

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

仅使用 5 个颜色停靠点(如上图所示)会导致严重的条带。添加更多停靠点会使渐变更加平滑。这正是我在本文第一张图像中展示的演示中所做的事情。Il buono 具有 13 个颜色停靠点的渐变,这使其更好地与图像融为一体。
查看 CodePen 上 Andreas Larsen (@larsenwork) 的 Pen 好、坏和丑陋 - 正确的文本。
与 Material Design 遮罩相比,我对其进行了调整,使其在开始时更线性,以获得更高的文本对比度,并使它更平滑地淡出。

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

我选择不包含 Material Design 遮罩,因为它与更漂亮的easeOutSine
几乎相同。我们可以比较linear-gradient
、我的scrim-gradient
和ease-out-sine-gradient
的外观
混合两端
在遮罩示例中,我们只需要混合一端,因为另一端与图像相连。有时,我们需要在两端进行混合,这就是缓动函数(如easeInOutSine
)发挥作用的地方。

使用easeInOut
函数,我们可以确保从 colorA 到渐变以及从渐变到 colorB 的过渡尽可能平滑。相同的原理在本 Pen 中也有说明
如何绘制渐变
在 YouTube 上,当您将鼠标悬停在视频上时,控件后面有一个渐变。它使用 base64 PNG 创建。这种技术也非常有效,但您无法真正自动化它或轻松调整它。

大多数其他地方使用 linear-gradient(hsla(0, 0%, 0%, 0.8), transparent)
,其中开始 alpha 通常在 0.6-0.8 之间。这解决了使文本可读的问题,但生成的渐变非常突出。例如,我在 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
,步骤如下
- 遍历 .css(或 .pcss)并找到它。
- 在 ease-in-out-sine 曲线上生成均匀分布的坐标。
- 使用这些坐标创建颜色停顿点。x 坐标确定颜色混合比例,y 坐标确定颜色停顿点位置。
- 用生成的线性渐变替换缓动渐变。

该插件目前有两个可选设置
precision
- 与生成的色标数量相关alphaDecimals
- 设置在hsla()
alpha 值中使用的十进制数
插件:postcss-easing-gradients
总的来说,我对输出结果相当满意。我正在考虑添加的内容
- Sass 版本?我不再使用它了。也许其他人会想写一个?
- 用于混合颜色停顿点颜色的坐标在缓动曲线上的分布是均匀的。理想情况下,颜色停顿点之间的距离在曲率变化量最大的地方会相对较短。
- 也许你们有什么想法?
您可以在 GitHub、NPM 和 CodePen 上的模板 中找到它。去试试吧!您的贡献和建议非常受欢迎。
CSS
最好的是,我希望能够编写类似 ease-in-out-gradient(#bada55, transparent)
的内容,让浏览器在不进行任何自定义 CSS 处理的情况下理解它。
参考资料/进一步阅读
- Chris Coyer:设计注意事项:文本在图像上
- Patrick Brosset:您真的了解 CSS 线性渐变吗?
- MDN:线性渐变规范
- Marcus Tisäter:所以您想制作一个 PostCSS 插件
- GitHub:PostCSS 插件样板
- Jonathan Neal:使用任何 PostCSS 插件的 CodePen
这是一篇非常令人困惑的文章。首先,很难从动画代码中提取实际的代码,这些代码在示例之间切换。单独的笔会更有助于学习。
另外,如果我们想使用它,这个 postcss 插件在哪里?我不熟悉 postcss,因为我们使用 scss。
抱歉,这让你感到困惑。
文章结尾处有指向 GitHub、NPM 和插件的 Codepen 模板的链接。
至于代码示例,想法是用户只需使用 Codepen 中的“查看编译”功能即可查看 css 输出。
更正:您必须使用检查器才能查看处理后的代码,但我已更新它,以便在 pcss 中有注释 :)
如果它可以作为 post-css 插件使用,则无需将其转换为 sass 函数。
Sass 首先进行编译,然后由 post-css 解析,因此它已经是 100% 与 Sass 兼容的,无需专门为它创建 sass 函数。
干杯,这也是为什么它不是我真正想研究的东西的原因。
但有些人只使用 sass,因此对他们来说,拥有一个 mixin 或类似的东西可能会更容易。
很棒且有趣的文章 :)
关于意大利语的一个小细节:Il brutto 是 the ugly,而 il cattivo 意味着 the bad。也许莱昂尼在欺骗你?;)
事实上,在您的示例介绍性 GIF 中,the bad 很丑,the ugly 很坏 :D
啊,该死,以为我已经仔细检查过了。我会通知 @chris,以便我们可以更新文章。
谢谢!:)
很棒的文章!我一直想知道我做错了什么,才会导致那些难看的线性渐变伪影。这让你不禁想知道,有一天是否会有一个
bezier-gradient()
函数。或者也许甚至一个border-bezier
属性,允许像 Apple 图标这样的东西。谢谢,可能不是 bezier-gradient,但我们已经开始讨论了 https://github.com/w3c/csswg-drafts/issues/1332
border-radius 那个更棘手,但比仅仅是 border radius 更灵活的东西会很好。
很棒的文章,Andreas!我已经创建了一个基本的 SCSS mixin,它复制了您创建的半透明渐变。您可以 在这个 CodePen 中找到它。欢迎提出建议!
很棒,
建议
如果它能够处理两种颜色的混合,这样就不只是透明的,那就太好了。
如果它还支持 ease-in-sine、ease-out-sine 和 ease-in-out-sine,那就太好了,因为这些是比较漂亮和灵活的选项。
如果您需要这些的映射,您可以很容易地从 postcss 插件中 console.log 它们。
它不像这里描述的缓动曲线那样灵活,但本地 CSS 现在有一种创建某种曲线渐变的方法
http://codepen.io/AmeliaBR/pen/vmZbpR
您指定了一个带有位置但没有颜色的停顿点(称为颜色提示或中点提示),如下所示
linear-gradient(black, 30%, transparent)
浏览器会将中点颜色(即
hsla(0,0%,0%, 0.5)
)放在颜色提示位置(即 30% 处),然后使用伽马(对数)曲线来平滑两侧的渐变。要创建 ease-in 曲线(即:颜色变化从慢开始,然后加速),您需要一个大于 50% 的颜色提示。要创建 ease-out 曲线(颜色变化从快开始,然后变慢),您需要一个小于 50% 的提示。
要创建 ease-in 和 ease-out S 形曲线,您需要两对带有提示的停顿点。我发现 这在您的演示中效果很好,在将渐变扩展到线性渐变高度的 125% 之后
linear-gradient(black, 30%, hsla(0, 0%, 0%, 0.5) 50%, 70%, transparent);
颜色提示在所有浏览器的最新版本中都得到了本地支持,但您需要为旧版浏览器提供回退。不幸的是,AutoPrefixer 目前似乎没有做任何事情来识别渐变停顿列表中的颜色提示,并为它们创建回退。
不错,我完全忘记了这些——我得玩弄一下看看能做多少。
顺便说一句,我不会在文字保护中使用 S 形,但它可能在另一个例子中很好用 http://codepen.io/larsenwork/pen/dvBrMv
酷!
浏览器支持如何?
很棒的文章!当我对更多互动式 UI 设计进行深入研究时,它为思考颜色和动画提供了一个很好的框架。
干杯,很高兴你喜欢它。非常推荐阅读关于动画的材料指南——它们写得很好,而且有很多例子。
我喜欢这个想法,它正好解决了我在尝试创建平滑渐变时遇到的持续问题。
我可能会尝试做一个 Sass mixin,只是因为我仍然在我的日常编码生活中使用 Sass(我是最后一个这样做的 web 开发人员吗?)。
但我认为,比
ease-in-out-gradient( direction, #COLOR1, #COLOR2)
更合理的是,将一个缓动参数添加到现有的linear-gradient()
和radial-gradient()
CSS 函数中。类似于transition
已经使用的:linear-gradient( direction, #COLOR1, #COLOR2, ease-in-out)
。只要要求它是最后一个逗号分隔的值。如果浏览器认为它是缓动值,它就会使用它,否则它会将其视为颜色。因此也向后兼容!只是一个想法。
谢谢!
而且你并不是唯一一个——我只不过不是合适的人选来创建它,因为我不再使用它,而且我的高级 Sass 知识非常有限:)
至于语法,它已经在這裡討論:https://github.com/w3c/csswg-drafts/issues/1332
不,我也喜欢 sass!
我在这里创建了一个简单的混合:https://codepen.io/lhermann/pen/qmpMGQ
还没有很完善,但已经看起来很棒了。
感谢您的文章!我们最近更新了整个网站的视频缩略图,遇到了同样的问题,并找到了类似的解决方案。
http://www.bravotv.com/videos
精彩的文章,结果看起来很棒!
我还写了一个简化的 SCSS 实现。这是一个 scrim-linear-gradient 函数,可以与原生 linear-gradient 函数一样使用。示例:https://codepen.io/jmkII/pen/pParwj
这里有一个简单的 LESS 版本的函数,用于生成单个颜色到透明蒙版的渐变
(适用于 LESS 1.5+)
嗨,我注册就是为了说,这是我在 CSS Tricks 上读到的最好的文章。太棒了!而且 PostCSS 插件很棒!!!谢谢!
非常感谢。很高兴你喜欢它:)