通过此动画,我们将使用一些基本的CSS绘图。然后,我们将使用CSS创建触发事件。最后,我们将模拟火焰(尽我们所能!)。
注意:您将在下面看到我使用绝对定位和变换来定位HTML元素,这是使用CSS绘制时的好技巧。
下面是我们要使用CSS绘制的内容:
如果愿意,您可以跟着我。我已经建立了一个基础笔,它建立了一切的基础。
因此,我们首先绘制蜡烛的底座(桌子表面)。
我们将为表的颜色和宽度使用一些SCSS变量:
// table dimensions $tableWidth: 280px; $tableHeight: 10px; $tableBackground: #8b4513;
该表基本上是div
具有某些尺寸的。
我们可以将HTML更新为如下所示:
<div class="wrapper"> <div class="table"></div> </div>
现在,我们添加一些基本的SCSS(用于transform
将表格居中):
.table { position: absolute; left: 50%; top: 50%; width: $tableWidth; height: $tableHeight; background: $tableBackground; transform: translate(-50%, -50%); z-index: 2; }
这看起来有些毫无生气。CSS绘图的技巧是使用box-shadow
,因此我们将其添加到:
.table { .... box-shadow: 0px 2px 5px #111; }
现在,您应该具有:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS蜡烛动画 - Web前端之家https://www.jiangweishan.com</title> <style> body { margin: 0; } .wrapper { background-color: #2a2a35; height: 100vh; width: 100vw; } .table { position: absolute; left: 50%; top: 50%; width: 280px; height: 10px; background: #8b4513; transform: translate(-50%, -50%); z-index: 2; box-shadow: 0px 2px 5px #111; } </style> </head> <body> <div class="wrapper"> <div class="table"></div> </div> <script> </script> </body> </html>
太棒了!
现在让我们在那张桌子上放一支蜡烛。我们将为我们的蜡烛尺寸和颜色设置一些SCSS变量(随意使用您想要的任何尺寸):
// candle $candleWidth: 35px; $candleHeight: 130px; $candleBorderColor: #673c63; $stickWidth: 3px; $stickHeight: 15px;
如果检查一下我之前显示的蜡烛的图像,您会发现它本质上是div
一个border
上面有一根大棒的蜡烛。首先让我们自己绘制蜡烛。
我们首先更新HTML:
<div class="wrapper"> <div class="candle"> </div> <div class="table"></div> </div>
现在,我们添加我们的CSS(同样,box-shadow
这里是技巧):
.candle { position: absolute; left: 50%; top: 50%; width: $candleWidth; height: $candleHeight; background: #fff; transform-origin: center right; transform: translate(-50%, -100%); box-shadow: -2px 0px 0px #95c6f2 inset; border: 3px solid $candleBorderColor; }
我们有蜡烛!
现在,我们在上面添加棍子(我们已经在上面包括了尺寸)。
我们首先需要将其添加到我们的HTML中:
<div class="wrapper"> <div class="candle"> <div class="candle-stick"></div> </div> <div class="table"></div> </div>
CSS(这里没什么花哨的):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS蜡烛动画 - Web前端之家https://www.jiangweishan.com</title> <style> body { margin: 0; } .wrapper { background-color: #2a2a35; height: 100vh; width: 100vw; } .table { position: absolute; left: 50%; top: 50%; width: 280px; height: 10px; background: #8b4513; transform: translate(-50%, -50%); z-index: 2; box-shadow: 0px 2px 5px #111; } .candle { position: absolute; left: 50%; top: 50%; width: 35px; height: 130px; background: #fff; transform-origin: center right; transform: translate(-50%, -100%); box-shadow: -2px 0px 0px #95c6f2 inset; border: 3px solid #673c63; } .candle-stick { width: 3px; height: 15px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #673c63; border-radius: 8px; transform: translate(-50%, -100%); } </style> </head> <body> <div class="wrapper"> <div class="candle"> <div class="candle-stick"></div> </div> <div class="table"></div> </div> <script> </script> </body> </html>
如您所见,这里没有动画,因此让我们开始制作动画。
我们将首先添加一个按钮,该按钮会将背景颜色从浅色更改为深色(我们已经设置了这些SCSS变量—$lightBackground
和$darkBackground
)。将此添加到HTML的最顶部:
<input id="toggle" type="checkbox"> <label for="toggle">Trigger Candle</label>
这会给我们一个不太吸引人的复选框和标签。因此,让我们对其进行样式设置,使其看起来更好一些:
label { background: #a5d6a7; padding: 0.5rem 1rem; border-radius: 0.5rem; position: absolute; font: 900 24px/1.4 -system-ui, sans-serif; transform: translate(50%, 50%); cursor: pointer; }
这为标签提供了一些样式,但是我们也想从视图中隐藏复选框。现在,我们可以通过将hidden
属性添加到复选框HTML来做到这一点。但是,这会使键盘导航器无法访问该复选框,因此更好的选择是将其移出视线。首先,让我们.visually-hidden
为复选框HTML添加一个类:
<input id="toggle" type="checkbox" class="visually-hidden">
然后,使用此CSS将复选框移到左侧:
.visually-hidden { position: absolute; left: -100vw; }
当复选框具有焦点时,我们还提供视觉提示:
input:checked + label { outline: 1px dotted red; }
(如果您想知道为什么在HTML中将放置在input
之前label
,现在您知道为什么了。这样我们就可以使用同级选择器(+
)。稍后再使用。)
现在,您可能不喜欢按钮周围的红色虚线轮廓,但我将留给您提出更好的建议。(例如,您可以改为更改标签的背景色。)
这是我们现在拥有的:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS蜡烛动画 - Web前端之家https://www.jiangweishan.com</title> <style> body { margin: 0; } .wrapper { background-color: #2a2a35; height: 100vh; width: 100vw; } .table { position: absolute; left: 50%; top: 50%; width: 280px; height: 10px; background: #8b4513; transform: translate(-50%, -50%); z-index: 2; box-shadow: 0px 2px 5px #111; } .candle { position: absolute; left: 50%; top: 50%; width: 35px; height: 130px; background: #fff; transform-origin: center right; transform: translate(-50%, -100%); box-shadow: -2px 0px 0px #95c6f2 inset; border: 3px solid #673c63; } .candle-stick { width: 3px; height: 15px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #673c63; border-radius: 8px; transform: translate(-50%, -100%); } label { background: #a5d6a7; padding: 0.5rem 1rem; border-radius: 0.5rem; position: absolute; font: 900 24px/1.4 -system-ui, sans-serif; transform: translate(50%, 50%); cursor: pointer; } .visually-hidden { position: absolute; left: -100vw; } input:checked + label { outline: 1px dotted red; } </style> </head> <body> <input id="toggle" type="checkbox" class="visually-hidden"> <label for="toggle">Trigger Candle</label> <div class="wrapper"> <div class="candle"> <div class="candle-stick"></div> </div> <div class="table"></div> </div> <script> </script> </body> </html>
让我们根据是否选中复选框来更改页面背景。我们可以通过使用常规的同级选择器来执行此操作而无需使用JavaScript ~
:
#toggle:checked ~ .wrapper { background: $lightBackground;}
现在我们还可以添加一个过渡,使过渡更加平滑:
.wrapper { background-color: $darkBackground; height: 100vh; width: 100vw; transition: background-color 0.6s ease;}
我们现在有这个:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS蜡烛动画 - Web前端之家https://www.jiangweishan.com</title> <style> body { margin: 0; } .wrapper { background-color: #2a2a35; height: 100vh; width: 100vw; transition: background-color 0.6s ease; } .table { position: absolute; left: 50%; top: 50%; width: 280px; height: 10px; background: #8b4513; transform: translate(-50%, -50%); z-index: 2; box-shadow: 0px 2px 5px #111; } .candle { position: absolute; left: 50%; top: 50%; width: 35px; height: 130px; background: #fff; transform-origin: center right; transform: translate(-50%, -100%); box-shadow: -2px 0px 0px #95c6f2 inset; border: 3px solid #673c63; } .candle-stick { width: 3px; height: 15px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #673c63; border-radius: 8px; transform: translate(-50%, -100%); } label { background: #a5d6a7; padding: 0.5rem 1rem; border-radius: 0.5rem; position: absolute; font: 900 24px/1.4 -system-ui, sans-serif; transform: translate(50%, 50%); cursor: pointer; } .visually-hidden { position: absolute; left: -100vw; } input:checked + label { outline: 1px dotted red; } #toggle:checked ~ .wrapper { background: #ffffe0; } </style> </head> <body> <input id="toggle" type="checkbox" class="visually-hidden"> <label for="toggle">Trigger Candle</label> <div class="wrapper"> <div class="candle"> <div class="candle-stick"></div> </div> <div class="table"></div> </div> <script> </script> </body> </html>
我们要做的另一件事是在背景明亮时添加火焰。
和以前一样,我们设置SCSS变量:
// flame $flameHeight: 20px; $flameWidth: 16px; $flameColor1: #e25822; $flameColor2: #e2b822;
让我们还更新HTML以使其包含火焰:
<label for="toggle">Trigger Candle</label> <input id="toggle" type="checkbox" hidden> <div class="wrapper"> <div class="candle"> <div class="candle-stick"></div> <div class="flame"></div> </div> <div class="table"></div> </div>
我们的火焰底数需要使用border-radius
八个值。在绘制复杂形状时,Fancy Border Radius Generator网站非常适合border-radius
为您生成。
所以这是我们的CSS(border-radius
是关键部分):
.flame { width: $flameWidth; height: $flameHeight; background: #673c63; position: absolute; left: 50%; top: 0%; background: $flameColor1; transform: translate(-50%, -170%); border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%; }
现在,我们可以添加一些动画,使其像真实的火焰一样闪烁。我们将在两种颜色($flameColor1
和$flameColor2
)之间更改火焰,并且还将在左右两侧稍微改变位置。首先,这是关键帧代码:
@keyframes fire-flicker { from { background: $flameColor1; left: 47%; } to { background: $flameColor2; left: 53%; } }
然后,我们需要将此动画添加到flame
类中:
animation: fire-flicker 0.2s infinite linear;
现在,我们的火焰将闪烁:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS蜡烛动画 - Web前端之家https://www.jiangweishan.com</title> <style> body { margin: 0; } .wrapper { background-color: #2a2a35; height: 100vh; width: 100vw; transition: background-color 0.6s ease; } .table { position: absolute; left: 50%; top: 50%; width: 280px; height: 10px; background: #8b4513; transform: translate(-50%, -50%); z-index: 2; box-shadow: 0px 2px 5px #111; } .candle { position: absolute; left: 50%; top: 50%; width: 35px; height: 130px; background: #fff; transform-origin: center right; transform: translate(-50%, -100%); box-shadow: -2px 0px 0px #95c6f2 inset; border: 3px solid #673c63; } .candle-stick { width: 3px; height: 15px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #673c63; border-radius: 8px; transform: translate(-50%, -100%); } label { background: #a5d6a7; padding: 0.5rem 1rem; border-radius: 0.5rem; position: absolute; font: 900 24px/1.4 -system-ui, sans-serif; transform: translate(50%, 50%); cursor: pointer; } .visually-hidden { position: absolute; left: -100vw; } input:checked + label { outline: 1px dotted red; } #toggle:checked ~ .wrapper { background: #ffffe0; } .flame { width: 16px; height: 20px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #e25822; transform: translate(-50%, -170%); border-radius: 50% 50% 50% 50%/60% 60% 40% 40%; animation: fire-flicker 0.2s infinite linear; } @keyframes fire-flicker { from { background: #e25822; left: 47%; } to { background: #e2b822; left: 53%; } } </style> </head> <body> <input id="toggle" type="checkbox" class="visually-hidden"> <label for="toggle">Trigger Candle</label> <div class="wrapper"> <div class="candle"> <div class="candle-stick"></div> <div class="flame"></div> </div> <div class="table"></div> </div> <script> </script> </body> </html>
随时尝试改善它,因为它可能会更好!
好吧,让我们做进一步的调整。当背景较暗时,我们将关闭火焰。
我们将使用它opacity
来实现这一目标。在flame
课程上,添加不透明度。我们还将向其添加一个过渡,使其与匹配background
:
.flame { ... opacity: 0; transition: opacity 0.6s ease; }
然后,我们可以使用SCSS的功能以及checked
状态的一些嵌套:
#toggle:checked ~ .wrapper { background: $lightBackground; .flame { opacity: 1; } }
现在,火焰仅在明亮的背景下显示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS蜡烛动画 - Web前端之家https://www.jiangweishan.com</title> <style> body { margin: 0; } .wrapper { background-color: #2a2a35; height: 100vh; width: 100vw; transition: background-color 0.6s ease; } .table { position: absolute; left: 50%; top: 50%; width: 280px; height: 10px; background: #8b4513; transform: translate(-50%, -50%); z-index: 2; box-shadow: 0px 2px 5px #111; } .candle { position: absolute; left: 50%; top: 50%; width: 35px; height: 130px; background: #fff; transform-origin: center right; transform: translate(-50%, -100%); box-shadow: -2px 0px 0px #95c6f2 inset; border: 3px solid #673c63; } .candle-stick { width: 3px; height: 15px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #673c63; border-radius: 8px; transform: translate(-50%, -100%); } label { background: #a5d6a7; padding: 0.5rem 1rem; border-radius: 0.5rem; position: absolute; font: 900 24px/1.4 -system-ui, sans-serif; transform: translate(50%, 50%); cursor: pointer; } .visually-hidden { position: absolute; left: -100vw; } input:checked + label { outline: 1px dotted red; } #toggle:checked ~ .wrapper { background: #ffffe0; } #toggle:checked ~ .wrapper .flame { opacity: 1; } .flame { width: 16px; height: 20px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #e25822; transform: translate(-50%, -170%); border-radius: 50% 50% 50% 50%/60% 60% 40% 40%; animation: fire-flicker 0.2s infinite linear; opacity: 0; transition: opacity 0.6s ease; } @keyframes fire-flicker { from { background: #e25822; left: 47%; } to { background: #e2b822; left: 53%; } } </style> </head> <body> <input id="toggle" type="checkbox" class="visually-hidden"> <label for="toggle">Trigger Candle</label> <div class="wrapper"> <div class="candle"> <div class="candle-stick"></div> <div class="flame"></div> </div> <div class="table"></div> </div> <script> </script> </body> </html>
最后,标签的“触发蜡烛”文本有点平淡。我们可以做很多事情!因此,让我们改进标签,使文本在“ Lumos”和“ Nox”之间切换–当然是受哈利·波特的启发!
首先,我们可以将标签更改为不包含文本(我们将content
在其中添加文本):
<label for="toggle"></label>
现在,我们将添加一些CSS来切换文本:
label::after { content: "Lumos"; } #toggle:checked ~ label::after { content: "Nox"; }
为了阻止标签跳动,让我们添加以下样式:
label { ... min-width: 100px; text-align: center; }
我们终于得到它了。我们的蜡烛动画完成了-几乎没有JavaScript!
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS蜡烛动画 - Web前端之家https://www.jiangweishan.com</title> <style> body { margin: 0; } .wrapper { background-color: #2a2a35; height: 100vh; width: 100vw; transition: background-color 0.6s ease; } .table { position: absolute; left: 50%; top: 50%; width: 280px; height: 10px; background: #8b4513; transform: translate(-50%, -50%); z-index: 2; box-shadow: 0px 2px 5px #111; } .candle { position: absolute; left: 50%; top: 50%; width: 35px; height: 130px; background: #fff; transform-origin: center right; transform: translate(-50%, -100%); box-shadow: -2px 0px 0px #95c6f2 inset; border: 3px solid #673c63; } .candle-stick { width: 3px; height: 15px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #673c63; border-radius: 8px; transform: translate(-50%, -100%); } label { background: #a5d6a7; padding: 0.5rem 1rem; border-radius: 0.5rem; position: absolute; font: 900 24px/1.4 -system-ui, sans-serif; transform: translate(50%, 50%); cursor: pointer; min-width: 100px; text-align: center; } .visually-hidden { position: absolute; left: -100vw; } input:checked + label { outline: 1px dotted red; } #toggle:checked ~ .wrapper { background: #ffffe0; } #toggle:checked ~ .wrapper .flame { opacity: 1; } .flame { width: 16px; height: 20px; background: #673c63; position: absolute; left: 50%; top: 0%; background: #e25822; transform: translate(-50%, -170%); border-radius: 50% 50% 50% 50%/60% 60% 40% 40%; animation: fire-flicker 0.2s infinite linear; opacity: 0; transition: opacity 0.6s ease; } @keyframes fire-flicker { from { background: #e25822; left: 47%; } to { background: #e2b822; left: 53%; } } label::after { content: "Lumos"; } #toggle:checked ~ label::after { content: "Nox"; } </style> </head> <body> <input id="toggle" type="checkbox" class="visually-hidden"> <label for="toggle"></label> <div class="wrapper"> <div class="candle"> <div class="candle-stick"></div> <div class="flame"></div> </div> <div class="table"></div> </div> <script> </script> </body> </html>