大家好! CSS3 简直太棒了。 开发速度很快,可能性无穷。 今天,我想向您展示如何使用 CSS 中的多个背景图像和线性渐变制作一个很棒的动画。 我们将仅使用单个 HTML 元素来构建 Facebook 加载动画。
为简单起见,您将在 CSS 中看不到任何供应商前缀。 在我们深入创建 Facebook 加载动画之前,我将解释基本技术。
background-image
我们都知道 background-image 属性。 您提供指向外部图像文件(或数据 URI)的 url()
,以使该图像显示为任何 HTML 元素的背景。
现在,可以使用 linear-gradient 或 radial-gradient 作为背景图像。 这开辟了全新的背景世界,这些背景可以使用代码生成。 我不会解释语法(您可以从前两个链接中获取),但我将为您提供一些技巧,这些技巧将帮助您创建很棒的图案和几乎任何形状。
最有用的技巧是可以一次添加多个背景图像。
div {
background-image:
background-image
[, background-image]* /* optional additional backgrounds */
}
有关更多信息,请参阅 MDN:background-image。 要查看其他人使用这些属性创建的内容,请查看此 画廊。
如何使用线性渐变绘制
让我们从一些基本的线性渐变开始,以了解其语法。
background-image: linear-gradient(90deg, blue, red);
要查看语法及其所有可能性,您应该查看 MDN:linear-gradient。
这将产生以下结果
您会看到蓝色和红色之间有一个不错的渐变。 但总是绘制渐变会相当无聊。 如果能够生成像这样的图案,那不是很好吗?
所以让我们开始吧! 看看上面的图案。 您会看到四种不同的颜色,每种颜色需要 1/4 的宽度。 用百分比表示,我们得到 25%(100%/4)。 对于这种简单的图案,我建议您使用百分比,这样图案会动态适应元素的大小。
要将图像图案转换为 linear-gradient
,我们将从最左边的颜色开始。 在这种情况下为蓝色。
background-image: linear-gradient(90deg, blue 25%);
这将导致一个空白背景图像。 要使 linear-gradient
工作,我们必须添加至少两种颜色。 让我们添加下一种颜色,绿色
background-image: linear-gradient(90deg, blue 25%, green 25%);
第一个颜色值很特殊,因为“蓝色 25%”并不意味着蓝色从 25% 开始。 在这种情况下,“蓝色 25%”意味着蓝色扩展到 25%。
我们得到的是
正是我们想要的,蓝色和绿色之间的清晰分离。 但是您可能已经注意到,我们必须为蓝色和绿色都编写 25%。 在开发过程中,这非常烦人,因为您必须更改这两个值以保持清晰的分隔。
在使用线性渐变时,我发现了一种很好的方法,可以使这一过程变得更轻松
background-image: linear-gradient(90deg, blue 25%, green 0);
现在,我们只需将绿色的位置设置为“0”。 我们通过这种方式实现的是,绿色将始终从与前一种颜色(在本例中为蓝色)完全相同的位置开始。 结果与之前相同,但现在您只需更改一个值即可更改蓝色矩形的大小。 添加剩余的颜色变得非常容易,因为我们现在知道如何创建清晰的颜色切割。
background-image: linear-gradient(90deg, blue 25%, green 0, green 50%, red 0, red 75%, yellow 0);
您现在可以了解为什么第一个颜色值很特殊。 对于每种其他颜色,我们必须将其定义两次。 一次用于起始位置,另一次用于指定其扩展范围。
结果
我们如何创建形状?
要使用 background-image 属性创建一些基本形状,我们将从以下内容开始
.squareandcircle{
width: 40px;
height: 30px;
background-image: linear-gradient(90deg, blue, blue),
radial-gradient(center, circle, green 10px, transparent 0);
background-size: 15px 15px,
20px 20px;
background-position: 0 0,
20px 10px;
background-repeat:no-repeat;
}
我们使用了多个背景图像,并结合了 background-size 和 background-position 来创建正方形和圆形。
它是如何工作的?
从 background-image 开始
首先,我们必须创建背景图像。 为简单起见,我们使用最基本的 linear-gradient 和最基本的 radial-gradient。
现在转到下一个属性:background-size
background-size 属性将为之前创建的每个背景图像设置大小,顺序与创建顺序相同。
因此,在我们的例子中,线性渐变的大小为 15x15px。 对于径向渐变,它为 20x20px。
每个背景的位置:background-position
现在,我们有两个图像,一个是大小为 15x15px 的正方形,一个是适合 20x20px 正方形的圆形。 但这些图像彼此重叠。 要移动它们,我们需要 background-position。
对于 background-position
,我们必须为每个背景图像定义相对于元素左上角的偏移量。
这里,第一个图像(正方形)将在左上角,圆形将比它向左 20px,向下 20px。 请记住,我们从元素的左上角移动每个图像。
background-repeat
最后一个未解释的部分是 background-repeat
,这很简单。 我们不希望生成的图像在任何方向上重复,因此我们将其设置为 no-repeat
。 如果我们只为它添加一个值,则该值将被我们创建的所有背景图像使用。
那么我们如何使用它来制作动画?
很简单。 我们使用背景图像创建形状,然后使用 animation 属性通过更改背景大小和/或位置来为整个内容设置动画。
在进行 Facebook 加载动画之前,我们先来看一个简单的示例。 我们从一些基本的标记开始,如下所示
.square {
width: 40px;
height: 30px;
background-color: gray;
background-image: linear-gradient(90deg, blue, blue);
background-size: 15px 15px;
background-position: 0 0;
background-repeat: no-repeat;
}
看起来像
让我们分六个步骤为它设置动画,将正方形从右上角移动到右下角,再移动到左下角。
基本数学告诉我们,我们每帧需要 16.6% 的时间(100%/6 ~ 16.6%)才能完成关键帧动画。 在每帧中,我们修改背景位置,以营造正方形移动的错觉。
最终我们将得到相当多的 CSS 代码
@keyframes move {
16.6% {
background-position: 0 0;
}
33.2% {
background-position: 12.5px 0;
}
49.8% {
background-position: 25px 0;
}
66.4% {
background-position: 25px 15px;
}
83% {
background-position: 12.5px 15px;
}
99% {
background-position: 0 15px;
}
}
要查看动画,我们必须像这样将动画添加到正方形元素中
.square{
width: 40px;
height: 30px;
background-color: gray;
background-image: linear-gradient(90deg, blue, blue);
background-size: 15px 15px;
background-position: 0 0;
background-repeat: no-repeat;
animation: move 1s steps(1, start) infinite;
}
steps 函数很棒。 您可以在 此处 阅读有关它的更多信息。
查看实际效果
您在这里看到的嵌入式动画可能已停止,要查看动画,请访问 Pen。
尝试玩弄它以理解您拥有的所有可能性。事实上,我们这里得到的是一个开放的画布,我们可以在上面绘制几乎所有形状并以任何方式对其进行动画处理。
Facebook 加载动画。
现在是时候使用这些技术制作一些更复杂的动画了。
看看 Facebook 加载动画的原始 GIF。
在 GIF 中,我们看到垂直条纹从左到右移动,同时收缩并失去颜色。
我们如何在 CSS 中存档?让我先说一下:我不会解释如何创建所有这些条纹中的每一个。我只会解释如何创建第一个,从那里开始,理解其余部分应该不难。
让我们放大第一个条纹。
第一个形状是 4 像素宽,16 像素长。一个 3x16 像素的实心彩色矩形周围有一个 1 像素的边框。为简单起见,我们将创建的边框也将具有实心颜色。要创建这样的形状,我们必须使用linear-gradient 生成两个背景图像。一个用于左侧边框、实心内部矩形和右侧边框,另一个用于上边框和下边框。我们从用于左侧边框、实心内部矩形和右侧边框的linear-gradient 开始。
#facebook {
width: 16px;
height: 16px;
background-image: linear-gradient(90deg, #8490c6 1px, #aeb5da 0, #aeb5da 3px, #8490c6 3px);
background-size: 4px 16px;
background-position: 0 0;
/* Just to make it a little bigger*/
zoom: 5;
}
结果
要完成此形状,我们必须添加另一个背景图像来创建上边框和下边框。
#facebook {
width: 16px;
height: 16px;
background-image:
linear-gradient(0deg, #8490c6 1px, transparent 0, transparent 15px, #8490c6 15px),
linear-gradient(90deg, #8490c6 1px, #aeb5da 0, #aeb5da 3px, #8490c6 3px);
background-size: 4px 16px,
4px 16px;
background-position: 0 0,
0 0;
background-repeat: no-repeat;
/* Just to make it a little bigger*/
zoom:5;
}
没有必要重复background-size 和background-position 的值,因为它们是相同的,但为了进一步开发,最好写下来。
现在我们有了这个
我们需要制作六个这样的条纹,颜色和尺寸稍微小一些。现在应该清楚如何制作这些条纹了。
#loader {
zoom: 1; /* Increase this for a bigger symbol*/
width: 16px;
height: 16px;
background: linear-gradient(0deg, #f4f5fa 1px, transparent 0, transparent 8px, #f4f5fa 8px), /* 6 */
linear-gradient(90deg, #f4f5fa 1px, #f6f9fb 0, #f6f9fb 3px, #f4f5fa 3px),
linear-gradient(0deg, #ececf5 1px, transparent 0, transparent 8px, #ececf5 8px), /* 5 */
linear-gradient(90deg, #ececf5 1px, #f2f3f9 0, #f2f3f9 3px, #ececf5 3px),
linear-gradient(0deg, #e7eaf4 1px, transparent 0, transparent 8px, #e7eaf4 8px), /* 4 */
linear-gradient(90deg, #e7eaf4 1px, #eef1f8 0, #eef1f8 3px, #e7eaf4 3px),
linear-gradient(0deg, #b9bedd 1px, transparent 0, transparent 10px, #b9bedd 10px), /* 3 */
linear-gradient(90deg, #b9bedd 1px, #d0d5e8 0, #d0d5e8 3px, #b9bedd 3px),
linear-gradient(0deg, #9fa6d2 1px, transparent 0, transparent 15px, #9fa6d2 15px), /* 2 */
linear-gradient(90deg, #9fa6d2 1px, #c0c5e1 0, #c0c5e1 3px, #9fa6d2 3px),
linear-gradient(0deg, #8490c6 1px, transparent 0, transparent 15px, #8490c6 15px), /* 1 */
linear-gradient(90deg, #8490c6 1px, #aeb5da 0, #aeb5da 3px, #8490c6 3px);
background-repeat: no-repeat;
background-size:
4px 9px, /* 6 */
4px 9px,
4px 9px, /* 5 */
4px 9px,
4px 9px, /* 4 */
4px 9px,
4px 11px, /* 3 */
4px 11px,
4px 16px, /* 2 */
4px 16px,
4px 16px, /* 1 */
4px 16px;
background-position-x: -4px; /* Hide All */
background-position-y: 3px, 3px, 3px, 3px, 3px, 3px, 2px, 2px, 0, 0, 0, 0;
}
所有六个条纹都隐藏了,因为它们在 x 轴上移动了 -4 像素。
让我们再次想想原始的 GIF。它包含八个步骤,将每个条纹进一步向左移动。因此,我们需要制作一个包含八个步骤的动画,而每个步骤需要 12.5% 的时间(100%/8)。在每一步中,每个条纹都会向右移动 6 像素。如果条纹在 x 轴上的位置大于 16 像素,它就会超出画布,我们可以将其放置在 -4 像素处将其隐藏。
您可能已经注意到 background-position-y
的使用。这为我们节省了很多代码,因为我们只需要在 x 轴上移动条纹,我们永远不必更改 y 坐标,因此我们只需要在关键帧动画中写入 x 轴位置的坐标。
@keyframes wait {
12.5% {
background-position-x: -4px,-4px, -4px, -4px, -4px,-4px,
-4px,-4px, -4px, -4px, 0, 0;
}
25% {
background-position-x: -4px, -4px, -4px, -4px, -4px,-4px,
-4px, -4px, 0, 0, 6px, 6px;
}
37.5% {
background-position-x: -4px, -4px, -4px, -4px, -4px, -4px,
0, 0, 6px, 6px, 12px, 12px;
}
50%{
background-position-x: -4px, -4px, -4px, -4px, 0, 0,
6px, 6px, 12px, 12px, -4px, -4px;
}
62.5% {
background-position-x: -4px, -4px, 0, 0, 6px, 6px,
12px, 12px, -4px, -4px, -4px, -4px;
}
75% {
background-position-x: 0, 0, 6px, 6px, 12px, 12px,
-4px, -4px, -4px, -4px, -4px, -4px;
}
87.5%{
background-position-x: 6px, 6px, 12px, 12px, -4px, -4px,
-4px, -4px, -4px, -4px, -4px, -4px;
}
100% {
background-position-x: 12px, 12px, -4px, -4px, -4px, -4px,
-4px, -4px, -4px, -4px, -4px, -4px;
}
}
因为每个条纹都由两个背景图像组成,所以我们必须在每一步中更改 12 个背景位置(每个条纹两个)。
最后,我们可以将动画属性添加到我们的元素中。
animation: wait .80s steps(1, start) infinite;
以下是 Codepen 上的实时演示
同样,您在这里看到的嵌入式动画可能已停止,要查看动画,请访问 Pen。
感谢您的阅读。希望你喜欢。谢谢!
一小时前,我在 Twitter 上发布了您的 ios6gallery 示例http://labs.weinberg.me/ios6gallery/,现在我正在阅读这篇博文。
喜欢这篇文章,继续写吧...
哇,我认为 CSS 版本比 GIF 更流畅。
很棒的文章!我喜欢您一步一步地解释它的过程。但是我必须问,在典型的网站上使用的所有 CSS 中。您是否认为使用 js 脚本会比在 CSS 中更好?
不,有些人可能会争辩说 GIF 可能是更好的方法。没有编码,也没有浏览器进行数学计算。似乎都是视角的问题。
很酷,很有趣,因为你可以,但我不会在项目中这样做。
与使用动画 GIF 相比,有什么优点是我遗漏的吗?
使用 CSS 而不是动画 GIF 的一个原因可能是允许动态设置颜色,例如根据用户选择的主题。使用 GIF,您需要为每种可能的颜色创建 GIF。
GIF 是一个不好的例子。怎么样动画 SVG?它也可以设置样式。
哇。Facebook 动画很棒,但您对渐变使用的解释让我的一天过得很好!
我想,使用动画 GIF 始终是向后兼容的最佳选择,但 CSS 非常适合自定义。我想知道哪个编译出来的尺寸更小?CSS 还是动画 GIF?
哇!太棒了!!!
写得很好,看起来很棒!
首先,这太棒了!
其次,像之前的评论者一样,我有一个请求——也许您可以写一篇关于哪种方法更有效(尺寸、处理速度、浏览器资源等)的文章——动画 GIF、JavaScript 或纯 CSS。我喜欢这些 CSS 脑力训练,但在创建真实网站时,您必须做出正确的决定!(这里不谈论浏览器兼容性,现在先忽略它……)
谢谢!
我考虑过写一篇关于哪种方法更有效率的文章。我会尝试在将来进行一个好的比较。
这是为孩子们准备的动画
这很好,但没有用。在这种情况下,坚持使用图像。
您是否有数据来支持这种说法?
记住,
这怎么就毫无用处呢?这是前沿技术,这种进步的思维方式正在为全世界开发者铺平道路,并激励他们更有创意、跳出框框,并提高灵活性、可扩展性和实现像这样的简单任务的方式。仅仅因为像动画 GIF 这样的工具已经存在了几十年,并不意味着当有替代方法可用时,您就应该“坚持使用它”。两种方法都有各自的优缺点,在创建应用程序时,在做出这些开发决策时,两种方法都应该考虑。从这一点中获得的重要经验教训是,充分了解这种新引入方法的局限性以及设备/浏览器支持。
@Chris Coyier,我不想听起来像是在站队,但 GIF 可以被编码为数据 URI,将其放入 CSS 中。最终它的大小与普通的 GIF 差不多,并且摆脱了额外的 HTTP 请求。在我看来,这两种方法都有优点,一种是可自定义性,另一种是向后兼容性。
非常棒且信息丰富的文章!
很棒的文章 Fabrice!
这是一个非常棒的教程 Fabrice。一如既往,很棒的作品。:)
很棒的教程。仅 Codepen CSS 的示例在 Windows 7 操作系统上的最新 Firefox(16.0.2)中不起作用。还有其他用户遇到相同的问题吗?
是的,我也是。我使用的是 Firefox 17 beta。没有动画,甚至没有动画的元素看起来也很奇怪。
是的。我这里也有同样的问题。Ubuntu 上的 FF 16.0.2。
我只能在 Webkit 浏览器中使用它。
奇怪。我会调查一下。谢谢!
因为属性没有前缀,所以它不起作用。
@Jonathan Cardoso [JCM]:CodePen 支持无前缀属性。它可能只是动画在 CodePen 嵌入中不起作用。
Firefox 似乎不理解 background-position-(x|y) 我在 Codepen 上修复了它。希望它也能在文章中被注意到。
谢谢。
上述内容是否有任何超出 CSS3 规范的?还是只是 FF?
这个不起作用…
对不起
为什么你不直接在盒子周围设置边框,而不是使用线性渐变?运行时速度更快,还是动画有问题?
我使用线性渐变是为了只使用一个 HTML 元素。
@Fabrice:啊,是的,我之前没注意到这一点。但使用渐变在浏览器中比使用多个带边框的元素更快吗?(我认为只有专家才能回答这个问题)
我认为我们正在努力实现的是,使用纯 CSS 而不是向原始标记添加元素:一个更语义化的网络。
当然,从这个角度来看,添加一个“页面加载”元素可能被认为是多余的。
也许,如果我们已经要添加一个非语义(与内容无关)元素,那么添加多个元素会更容易。
在 CSS 版本中,矩形完全淡出,而在 GIF 图像中,它们淡出但不会消失。仔细观察矩形淡出时,并与 GIF 进行比较,你就会明白我的意思。
很酷的效果,老兄!!
我在 Mac 上的任何浏览器中都看不到 Facebook 动画。那是 Safari、Firefox、Chrome 和 Opera,所有都是最新版本。
你这里的内容和 Mozilla 对
CSS 动画的说明唯一的区别是,他们首先在相关的 HTML 元素中定义动画时间。然后,在 @keyframes 代码块中定义动画步骤。这里顺序相反。
这里的演示在 Firefox(最新 nightly 版本)中不起作用,并且在 Webkit(Chrome 最新版本)中运行几秒钟后停止。显然“无限”循环指令也被忽略了。但是,这可能也与顺序有关。
Codepen 在 Firefox 上也不起作用,但在 Chrome 上没有停止运行。但这可能是由于 Codepen 应用的 HTML 或 CSS 之外的后台代码造成的。
看到你制作的这些东西总是很棒,@Chris Coyier… 你到底怎么有时间写这些东西的,哈哈… 你就是那么厉害!
这篇文章是 Fabrice Weinberg 的客座文章。虽然我确实帮助编辑了它!
对 Fabrice Weinberg 和 Chris Coyier 的这篇精彩文章表示衷心的感谢!
过去我通常会用几种方法来实现这个效果。一种是使用 JQuery,因为它安装起来很快,但我知道它实际上很重。第二种方法是使用一个动画 GIF,但我发现使用 GIF 最大的问题是它的灵活性很差。所以我现在使用动画 SVG,唯一的问题是它对旧浏览器和一些移动设备的支持有限。我认为这个 CSS 方法可以解决问题,所以我会在几个网站上尝试一下,比如 http://www.reynoldsdigital.com,看看效果如何。很喜欢这个方法的轻量级特点。很棒的教程。