CSS:实现动态流光线条效果/动态流光线条颜色渐变效果

需求描述

需要实现类似下图中的动态流光线条效果:
流光线条效果图

思路

提到这种动态绘制矢量图形的需求,一般会想到使用canvas;由于笔者不太熟悉canvas动画也可以考虑用CSS来实现,这里先记录使用CSS实现此效果的尝试过程:
①实现一条带有静态“流光”效果的边,参考CSS渐变背景
②实现静态线条的“流光”动画效果,参考纯CSS实现背景颜色渐变动画
③将以上步骤得到的流光边进行旋转(参考CSS-rotate)、镜像翻转(参考CSS水平翻转和垂直翻转),即可实现与此边同向和逆向的其他流光边效果,同时设置旋转和镜像翻转参考CSS同时设置多个变换效果

参考代码

HTML

<!-- 顺时针的4条边框 -->
<!-- 边框1:最初实现流光动画效果的线条,顶部左->右流光 -->
<div class="light-line right-top">
  <div class="line-block gradient"></div>
</div>
<!-- 由边框1顺时针旋转90度得到,右侧上->下流光 -->
<div class="light-line right-bottom">
  <div class="line-block gradient"></div>
</div>
<!-- 由边框1顺时针旋转180度得到,底部右->左流光 -->
<div class="light-line left-bottom">
  <div class="line-block gradient"></div>
</div>
<!-- 由边框1顺时针旋转270度得到,左侧下->上流光 -->
<div class="light-line left-top">
  <div class="line-block gradient"></div>
</div>

<!-- 逆时针的4条边框 -->
<!-- 由边框1水平镜像翻转得到,顶部右->左流光 -->
<div class="light-line-r right-top-r">
  <div class="line-block gradient"></div>
</div>
<!-- 由边框1顺时针旋转90度、水平镜像翻转得到,右侧下->上流光 -->
<div class="light-line-r right-bottom-r">
  <div class="line-block gradient"></div>
</div>
<!-- 由边框1顺时针旋转180度、水平镜像翻转得到,底部左->右流光 -->
<div class="light-line-r left-bottom-r">
  <div class="line-block gradient"></div>
</div>
<!-- 由边框1顺时针旋转90度、水平镜像翻转得到,右侧下->上流光 -->
<div class="light-line-r left-top-r">
  <div class="line-block gradient"></div>
</div>

CSS

body {
  background: #2A2A2A;
}

.light-line {
  position: absolute;
  top: 20px;
  left: 20px;
  width: 320px;
  height: 320px;
}

.light-line-r {
  position: absolute;
  top: 20px;
  left: 360px;
  width: 320px;
  height: 320px;
}

/* 渐变流光效果线条,要将横向宽度设置为超过100%的值,否则无动画效果 */
.line-block {
  position: relative;
  width: 100%;
  height: 6px;
  background: linear-gradient(
    -90deg, 
    #FFEFCA 1%, #FFBB1F 4%, transparent 12%, transparent 16%, 
    #FFEFCA 16%, #FFBB1F 19%, transparent 27%, transparent 33%, 
    #FFEFCA 33%, #FFBB1F 36%, transparent 44%, transparent 50%, 
    #FFEFCA 50%, #FFBB1F 53%, transparent 61%, transparent 66%, 
    #FFEFCA 66%, #FFBB1F 69%, transparent 77%, transparent 84%, 
    #FFEFCA 84%, #FFBB1F 87%, transparent 95%, transparent 100%
  );  
  background-size: 200% 100%;
}

/* 指定使用Gradient动画,5s完成一次动画,匀速,无限循环 */
.gradient {
  animation: Gradient 5s linear infinite;
  -webkit-animation: Gradient 5s linear infinite;
  -moz-animation: Gradient 5s linear infinite;
}

/* 定义Gradient动画效果:初始时显示最右端,结束时显示最左端(向右滚动) */
@keyframes Gradient {
  0% {
    background-position: 100% 100%;
    }
  100% {
    background-position: 0% 100%;
  }
}

/* 兼容写法.. */
@-webkit-keyframes Gradient {
  0% {
    background-position: 100% 100%;
    }
  100% {
    background-position: 0% 100%;
  }
}
 
/* 兼容写法.. */
@-moz-keyframes Gradient {
  0% {
    background-position: 100% 100%;
    }
  100% {
    background-position: 0% 100%;
  }
}


.right-top {
  transform: rotate(0deg);
}

.right-bottom {
  transform: rotate(90deg);
}

.left-bottom {
  transform: rotate(180deg);
}

.left-top {
  transform: rotate(270deg);
}


.right-top-r {
  transform: rotate(0deg) rotateY(180deg);
}

.right-bottom-r {
  transform: rotate(90deg) rotateY(180deg);
}

.left-bottom-r {
  transform: rotate(180deg) rotateY(180deg);
}

.left-top-r {
  transform: rotate(270deg) rotateY(180deg);
}

在线运行

可以拷贝到这里在线调试
菜鸟工具–HTML/CSS/JS在线工具

补充

  1. 首先记录一个大坑:由于不熟悉animation参数,最开始还因为animation-timing-function设置成了ease(慢->快->慢不匀速动画)导致流光动画不流畅而试图用两段动画方向相反的线实现“流畅”的动画效果,具体思路:第一段线流动方向左->右->左,第二段线流动方向右->左->右,当线左->右运动时显示出来,而右->左运动时设置透明度为0隐藏(其实用这样的方式调试后实现的动画效果依然不完全流畅),将这一属性设置为linear可使动画匀速;
  2. 可以通过将两段渐变色的百分比设为相同值来实现对比鲜明的渐变效果;

流光plus

今天闲得无聊,突发奇想想要实现在之前基础上,流光颜色渐变效果,先贴上代码:

HTML

<script src="https://cdn.staticfile.org/jquery/2.2.4/jquery.min.js"></script>
<div class="light-line right-top"></div>

CSS

body {
  background: #2A2A2A;
}

.light-line {
  position: absolute;
  top: 20px;
  left: 20px;
  width: 320px;
  height: 320px;
}

/* 渐变流光效果线条,要将横向宽度设置为超过100%的值,否则无动画效果 */
.line-block {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 6px;
}

JAVASCRIPT

// 流光色彩配置
const gradientColors = [
  { name: "red", startColor: "#ffc1cb", endColor: "#ffaaaa"},
  { name: "yellow", startColor: "#ffffb3", endColor: "#ffff00"},
  { name: "green", startColor: "#b3ffb3", endColor: "#00ff00"},
  { name: "cyan", startColor: "#b3ffff", endColor: "#00ffff"},
  { name: "blue", startColor: "#ccccff", endColor: "#0000ff"},
  { name: "purple", startColor: "#f7b3ff", endColor: "#ce00e6"},
  { name: "pink", startColor: "#ffe1e7", endColor: "#ffcfd9"},
  { name: "peach", startColor: "#ffc1cb", endColor: "#ff3053"}
];

// 由于流光渐变样式结构相似,提取其结构并使用代码动态生成更为便捷
const linearGradientStyle = `linear-gradient(
    -90deg, 
    $startColor 0%, $endColor 4%, transparent 12%, transparent 17%, 
    $startColor 17%, $endColor 21%, transparent 29%, transparent 34%, 
    $startColor 34%, $endColor 37%, transparent 45%, transparent 50%, 
    $startColor 50%, $endColor 54%, transparent 62%, transparent 67%, 
    $startColor 67%, $endColor 71%, transparent 79%, transparent 84%, 
    $startColor 84%, $endColor 87%, transparent 95%, transparent 100%
  )`;

const animationDuration = 3; // 动画时长(秒)
const animationNames = ["animation", "-webkit-animation", "-moz-animation"];
// todo 在Chrome使用insertRule插入@-moz-keyframes动画规则报错
// const animationDefs = ["@keyframes", "@-webkit-keyframes", "@-moz-keyframes"];
const animationDefs = ["@keyframes", "@-webkit-keyframes"];

// 页面加载完成后动态添加流光样式
window.onload = function() {
  showGradients();
}

// 动态添加流光样式
function showGradients() {
  // 每条流光色彩显示时长占动画总时长的百分比
  let gradPercent = parseInt(100 / parseInt(gradientColors.length));
  
  // 动态生成流光条结构
  for(let idx in gradientColors) {
    let item = gradientColors[idx], clsName = item.name;
    $(".light-line, .light-line-r").append('<div class="line-block ' + clsName + 
      ' gradient-' + clsName + '"></div>');

    // 插入流光样式
    insertCssRule("." + clsName, [
      { name: "z-index", value: idx },
      { name: "background", value: linearGradientStyle
       .replaceAll("$startColor", item.startColor)
       .replaceAll("$endColor", item.endColor) },
      { name: "background-size", value: "200% 100%" }
    ]);
    
    // 插入流光动画
    let animStyles = [];
    for(let gName of animationNames)
      animStyles.push(
        { name: gName, value: "Gradient-" + clsName + 
         " " + animationDuration + "s linear infinite" }
      );
    insertCssRule('.gradient-' + clsName, animStyles);
    
    // 除了下标为0(第一条)渐变色外,所有渐变色的透明度动画过程:
    // 透明->淡入->显示->淡出->隐藏
    
    // 下标为idx的渐变色开始显示时,已完成的动画时长占比值
    let percentNow = idx * gradPercent;
    // 下标为idx的渐变色开始淡出时,已完成的动画时长占比值
    let percentNext = (parseInt(idx) + 1) * gradPercent;
    // 下标为idx的渐变色开始淡入时,已完成的动画时长占比值
    let firstPosi = Math.max(0, percentNow / 3);
    // 下标为idx的渐变色开始隐藏时,已完成的动画时长占比值
    let lastPosi = Math.min(100, parseInt(percentNext) + firstPosi);
      
    for(let dName of animationDefs)
      // 第一条渐变色设置为始终不透明,使动画循环时衔接效果更自然
      if(parseInt(idx) === 0)
        insertCssRule(dName + " Gradient-" + clsName, [
          { name: "0%", value: [
            { name: "background-position", value: "100% 100%" },
            { name: "opacity", value: "1"}
          ]},
          { name: "100%", value: [
            { name: "background-position", value: "0% 100%" },
            { name: "opacity", value: "1"}
          ]}
        ]);
      else
      insertCssRule(dName + " Gradient-" + clsName, [
        { name: "0%", value: [
          { name: "background-position", value: "100% 100%" },
          { name: "opacity", value: "0"}
        ]},
        { name: firstPosi + "%", value: [
          { name: "background-position", value: (100 - firstPosi) + "% 100%" },
          { name: "opacity", value: "0"}
        ]},
        { name: percentNow + "%", value: [
          { name: "background-position", value: (100 - percentNow) + "% 100%" },
          { name: "opacity", value: "1"}
        ]},
        { name: percentNext + "%", value: [
          { name: "background-position", value: (100 - percentNext) + "% 100%" },
          { name: "opacity", value: "1"}
        ]},
        { name: lastPosi + "%", value: [
          { name: "background-position", value: (100 - lastPosi) + "% 100%" },
          { name: "opacity", value: "0"}
        ]},
        { name: "100%", value: [
          { name: "background-position", value: "0% 100%" },
          { name: "opacity", value: "0"}
        ]}
      ]);
  }
}

// 添加样式(className:样式名称,style:样式内容)
function insertCssRule(className, style) {
  let styleSheets = document.styleSheets[0];
  let index = styleSheets.rules.length; //获取样式表中包含样式的个数
  let insertStr = "";
  for(let sItem of style) {
    if(typeof sItem.value === 'string') // 添加普通样式
      insertStr += sItem.name + ":" + sItem.value + ";";
    else { // 添加动画规则
      insertStr += sItem.name + " {";
      for(let animStyle of sItem.value)
        insertStr += animStyle.name + ":" + animStyle.value + ";";
      insertStr += "}";
    }
  }

  if(styleSheets.insertRule){ //判断浏览器是否支持insertRule()方法
    // 使用insertRule在文档内部样式表中增加样式,插入位置在样式表的末尾
    styleSheets.insertRule(className + " {" + insertStr + " }", index);
  }else{ // 如果浏览器不支持insertRule(IE)
    styleSheets.addRule(className, insertStr, index);
  }
}

感兴趣的看官可自行拷贝到菜鸟工具–HTML/CSS/JS在线工具中运行调试效果哟~
(等有时间再增加注释以及学习使用canvas实现这样的效果吧=。=)

参考文档

[1] 菜鸟工具–HTML/CSS/JS在线工具
[2] CSS渐变背景
[3] 纯CSS实现背景颜色渐变动画
[4] CSS-rotate
[5] CSS水平翻转和垂直翻转
[6] CSS同时设置多个变换效果
[7] animation-timing-function
[8] JS–addRule/insertRule
[9] JS动态操作CSS

  • 8
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Cocos2d-x中实现流光效果可以使用shader来进行渲染。首先,我们需要创建一个自定义的shader,并将其应用于需要实现流光效果的节点上。 在使用Cocos2d-x的过程中,我们可以使用GLSL语言编写shader代码。在实现流光效果的shader中,我们可以通过改变像素的颜色和透明度来创建流动的效果。 首先,我们定义一个uniform变量time,用于控制流光的移动速度。然后,在片段着色器中,通过改变颜色和透明度的计算公式来实现流动的效果。我们可以使用sin函数或者其他数学函数来计算出每个像素点的颜色和透明度,然后将其应用到节点上。 在节点的渲染流程中,我们将这个自定义的shader应用到节点上,然后传入时间参数,即更新uniform变量time的值。随着时间的增加,我们就可以看到节点上的流光效果在不断地移动。 为了实现更加逼真的流光效果,我们可以尝试给流光添加一些额外的效果,比如模糊、叠加等。通过调整shader代码中的计算公式和传入的参数,我们可以根据自己的需求来调整流光效果的强度和样式。 总结起来,在Cocos2d-x中实现流光效果需要创建一个自定义的shader,并将其应用于需要实现效果的节点上。通过改变颜色和透明度的计算公式、传入时间参数等,我们可以实现一个流光效果,使节点看起来具有流动的动画效果

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值