前端开发来说,通过动画来提升交互效果是很常见的。在很早以前,做web动画主要通过javascript或者jquery或者flash这样的手段,非常麻烦,自打有了ccs3,做动画就太方便了,只需几行css代码就可以搞定。
这里我们就演示一个常见的循环滚动效果,任务是这样:先准备一个图片,平铺到页面上充满整个屏幕,然后就让画面一直向上循环滚动,形成无边无际的感觉。
虽然可以从网上搜到一些类似的代码,但是鱼龙混杂,无关紧要的代码非常多,不够纯粹。如果要弄明白动画的原理,只有自己动手做一遍才能真正消化吃透。所以我们来一步步原创这个代码,排除所有不必要的基础样式,只说要点,3个步骤你就可以完全掌握其精髓!
第一步:布局
首先,滚动的图片需要放在一个容器里,一行html代码即可完成:
第二步:把图片放进容器
css中body的边界设为0,把容器设高度100%以充满屏幕,再调用背景图pic.png
第三部:让画面动起来
咱不做标题党,循环滚动靠的就是3行css动起来的。
先是1行 -webkit-animation属性:4个参数分别表示:动画名称scroll,1秒时长,移动速度为线性的,无限循环。
然后是对应的关键帧 @-webkit-keyframes 属性,这是自己定义的动画规则,只需写2行规则即可:
原理:动画就是画从一个地方动到另一个地方。对普通滚动效果来说,有起点和终点这两个节点的位置就够了。所以我们用0%和100%分别表示起点和终点,指定2个背景图的xy位置坐标即可。图片会在规定时间内从起点移动到终点,并循环下去,数值是负表示是向上移动。320px正好是图片的高度,这样循环的时候是无缝衔接的。
好了,最终完整的代码如下,是不是很精练呢?保存成 index.html 即可
代码写完了,还要记得在当前目录要有pic.png这个图片哦,我随便画了几笔,绝无观赏性,建议自己找个好看点的图片来代替。
现在用浏览器打开index.html即可看到效果,比较魔性的地方在于,如果你盯着看久了,关闭窗口以后会出现幻觉,仿佛整个显示器都在向上飞,哈哈!
最后我们来说说浏览器兼容性问题:
大家可能注意到了,前面那2个古怪的 -webkit-animation, @-webkit-keyframes 这里的-webkit-其实是一个前缀,animation和@keyframes才是CSS的标准属性。
当加上-webkit-后,就形成了一个针对特殊浏览器的专有属性,表示用在谷歌的chrome和苹果的safari浏览器上。此外还有-moz前缀代表针对firefox浏览器的私有属性。
所以我们在用到css3的一些特性的时候,经常使用一大堆的重复性的代码,比如我们今天的这个代码,有人会写成这个样子:
一个简单的动画就要写这么多冗余的代码,为的只是支持一些旧的浏览器,有必要吗?为什么在这个例子中我们仅仅采用了-webkit-而没有使用其它专有属性呢?
因为现在已经是2019年了!谷歌苹果的浏览器是主流,占据了绝大部分,而其它小众浏览器也大多能够兼容他们,在版本上,大部分人安装浏览器是直接下载新版本安装使用,而非找出家里陈年的老软盘、老光盘去安装,家中的老电脑也早已升级不知多少回了,所以也几乎没有机会使用低版本的浏览器了!
至于微软的IE,就更别提了,IE9以前不支持动画的,只能用js或者jquery来写动画,直到IE10才支持css动画,随后IE被放弃,主推Edge,搞了几天越来越头大干脆也放弃,现在直接使用chrome内核了,所以针对ie的兼容性除非有特殊要求已经无需考虑。
你在网上能看到的范例代码,如果有写成那么复杂臃肿的,估计也都是3-5年前发的老文,或者抄来抄去不做思考的搬砖工留下的“初学者”笔记。
我们不仿测试一下几款主流浏览器的情况看看,结论:
测试结果表明,-webkit-的写法在4款不同内核的浏览器上都能正常使用,所以我们的代码因此能得以简化。
当然,这个例子也有局限性,比如你看,只有苹果safari不支持标准写法,万一将来他改邪归正了呢?毕竟标准写法才是众望所归不是?使用针对个别浏览器的私有属性写法,虽可用但毕竟有些怪怪的,将来怎么样还很难说呢。这样看来,如果使用古老的处理办法,重复N次为每个专属浏览器各写一份代码,除了辣眼睛也真没什么错。
浏览器的兼容问题涉及面实在是非常广,三言两语还真说不完,以后会专门来讲。
详细介绍如何使用 HTML 和 CSS 创建文本与图片的无限滚动动画效果。网页内容包含两个部分,一个是标签组滚动,另一个是图片组滚动,其中动画的效果主要表现为标签和图片一直横向的水平滚动,并且元素会无缝衔接从而实现无限循环,并且首尾两端有渐变蒙层效果,以造成出现和消失的过渡。
首先,HTML 代码部分包含了5个.scroll元素,这个数量取决于你网页有几个无限滚动区域。每个scroll元素都放了两个div(d1和d2)用于创建滚动容器,其中每个div元素都具有相同的内容元素,用于展示滚动内容。本案例的主要内容就是标签组span和图片组img。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Infinite Scrolling Animation</title>
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<div class="scroll" style="--t: 20s">
<div>
<span>HTML</span>
<span>CSS</span>
<span>JavaScript</span>
<span>Vue</span>
<span>React</span>
<span>Figma</span>
<span>Photoshop</span>
</div>
<div>
<span>HTML</span>
<span>CSS</span>
<span>JavaScript</span>
<span>Vue</span>
<span>React</span>
<span>Figma</span>
<span>Photoshop</span>
</div>
</div>
<div class="scroll" style="--t: 30s">
<!-- 同上 -->
</div>
<div class="scroll" style="--t: 10s">
<!-- 同上 -->
</div>
<div class="scroll" style="--t: 35s">
<!-- 同上 -->
</div>
<div class="scroll img-box" style="--t: 25s">
<div>
<img src="./images/img_01.jpg" alt="image">
<img src="./images/img_02.jpg" alt="image">
<img src="./images/img_03.jpg" alt="image">
<img src="./images/img_04.jpg" alt="image">
<img src="./images/img_05.jpg" alt="image">
<img src="./images/img_06.jpg" alt="image">
<img src="./images/img_07.jpg" alt="image">
<img src="./images/img_08.jpg" alt="image">
<img src="./images/img_09.jpg" alt="image">
</div>
<div>
<!-- 同上 -->
</div>
</div>
</body>
</html>
标签组和图片组里的两个div要宽度保持一致,也就是说d1和d2里的每个标签span要对应相同,否则两个div就会出现滚动覆盖或距离过大。 还有就是每个scroll标签的自定义变量--t的值不一样(又快又慢),要想滚动效果统一的话时间调整一样就可以了。
接下来,看 CSS 部分设置了一些基本的全局样式,有重置样式、内容水平垂直居中布局、背景字体颜色等不做过多赘述。
/* @import url('https://fonts.googleapis.com/css?family=Poppins:400,600,700,800&display=swap'); */
@import './google-fonts.css';
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', sans-serif;
}
body {
min-height: 100vh;
background-color: #222;
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
/* ... */
滚动容器scroll有一个固定宽度,然后对于溢出的内容隐藏不可见,以及使用 mask-image 创建了一个线性渐变遮罩,给内容带来滚动时的淡出淡入视觉效果。
.scroll {
display: flex;
width: 700px;
overflow: hidden;
mask-image: linear-gradient(90deg, transparent, #fff 20%, #fff 80%, transparent);
-webkit-mask-image: linear-gradient(90deg, transparent, #fff 20%, #fff 80%, transparent);
}
.scroll > div span {
display: inline-block;
margin: 10px;
padding: 5px 10px;
background-color: #333;
border-radius: 5px;
letter-spacing: 0.2em;
text-transform: uppercase;
cursor: pointer;
transition: background-color 0.5s;
}
.scroll > div span:hover {
background-color: #4caf50;
}
.img-box img {
max-width: 150px;
filter: grayscale(1);
cursor: pointer;
transition: filter 0.5s;
}
.img-box img:hover {
filter: grayscale(0);
}
/* ... */
接着就是每个滚动容器内包裹两个一样的div元素,用于创建无缝衔接,下面分别简称为d1和d2。通过 white-space: nowrap 属性确保 div 内的内容不换行,从而使得内容能够水平滚动。
主要通过两个不同的关键帧动画@keyframes关键帧和过渡animation属性控制两个滚动区域实现的滚动效果。让元素以无限循环和线性动画的方式在.scroll滚动容器内移动。拿本案列的img-box元素阐释一下动画执行过程:
.scroll > div {
white-space: nowrap;
animation: animate var(--t) linear infinite;
animation-delay: calc(var(--t) * -1);
}
@keyframes animate {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
.scroll > div:nth-child(2) {
animation: animate2 var(--t) linear infinite;
animation-delay: calc(var(--t) / -2);
}
@keyframes animate2 {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-200%);
}
}
@media screen and (max-width: 768px) {
.scroll {
width: 90vw;
}
.scroll > div span {
background-color: #4caf50;
}
.img-box img {
width: 33vw;
filter: grayscale(0);
}
}
由于animate延迟小于animate2,所以动画a2先执行,从右向左持续滚动到x: -200%,当滚动到-100%时也就是当前可见区域,此时a1开始执行动画 1 ,从右向左持续滚动到x: -100%,当滚动到100%时也就是当前可见区域,a2已经到-200%了,接着看a1继续滚动到-100%,a2继续从0到-200%,如此循环往复。
通过本篇文章相信能够帮助你更好地使用CSS来创建一个文本与图片无限滚动动画,从而理解掌握和应用这个效果。通过 transform 属性的变化实现了水平滚动效果,使得 div 内的内容能够在容器内水平滚动,呈现出无限循环的连接效果。丰富了网页增添加了动态和交互性。
「绝无仅有」CSS打造吸睛的文本与图片无限滚动动画
原文链接:https://juejin.cn/post/7306442463765544971
现目标:
图1 多图上传效果
1、html代码
<tr class=''>
<td width="90" align="right">相关多图</td>
<td >
<div class='yllist yllist_x_duotu'>
<dl>
<!--存放上传的图片-->
<transition-group name="list">
<dd v-for="(item,index) in listData " draggable="true" :key="item"
@click="del(index)"
@mouseover="showzz(1,index)"
@mouseleave="showzz(0,index)"
@dragstart="drag($event,index)"
@drop="drop($event,index)"
@dragover='allowDrop($event)'
>
<img :src="item.picpath">
<div class='zzz none' :class="{'nonone':item.shs==1}">
<div class='zzimg '><i class="fa fa-trash-o" aria-hidden="true"></i></div>
</div>
</dd>
<!--结束-->
</transition-group>
<dd @click="upbtn" class='btnclass'><i class="fa fa-camera-retro" aria-hidden="true"></i>
<input type='file' id='multiple' accept="image/*" multiple="multiple" style='display:none' @change="autoup" name="ss">
</dd>
</dl>
<div class='clear'></div>
<div>
<span class='itemms'>说明:可以拖动改变顺序</span>
</div>
</div>
</td>
</tr>
说明:
@click="del(index)" 点击删除图片 index为数组的索引 点击的是第几个图片
@mouseover="showzz(1,index)" 鼠标放到上边 出现遮罩层 垃圾桶
@mouseleave="showzz(0,index)" 鼠标离开 遮罩层消失
@dragstart="drag($event,index)" 以下三个 用于拖拽排序
@drop="drop($event,index)"
@dragover='allowDrop($event)'
draggable="true" 设置为true 可以拖动
:key="item" 这里的key 要注意不能等于 index,要不然没有动画效果
img src的属性 是 :src="item.picpath" 不能是src={{item.picpath}}
<div class='zzz none' :class="{'nonone':item.shs==1}"> 设置遮罩层 shs=1的时候显示
上传的选择框设置为display:none隐藏
transition-group用法:
<transition-group name="list"> 实现拖拽的动画效果 后边的name可以随意写 ,但是要和css的.list-move {transition: transform 0.3s;} 【上边自定义的name,我这里是list】-move 设置该css 动画的时间
2、js代码
new Vue({
el: '#app',
data(){
tagslist:[
'网站开发',//存放的标签
'网站建设'
],
tagsdt:"", //绑定的标签文本框
tagindex:"",//删除标签的序号(索引)
listData: [
/*
{'picpath':'/public/upload/image/20211107/1.jpg',shs:0}
shs 显示遮罩层 ,垃圾桶删除标志,0 不显示 1显示
*/
],
file:"file", //用于切换 file text 实现同一个图片可以连续上传
tis:'', //提示内容
showzzc:0, //弹出框的显示,隐藏 。0 隐藏 1显示
showts:0, //1 弹出提示操作框 2 弹出提示确认框
lisindex:"", //记录图片的索引
datameth:"" //根据这里的参数操作不同的方法
}
},
methods:{
tags:function(){
if(this.tagsdt){
this.tagslist.push(this.tagsdt);
}
this.tagsdt="";
},
deltag:function(f){
this.showzzc=1;
this.showts=1;
this.tagindex=f;
this.datameth='tag';
},
hidetc:function(){
this.showzzc=0;
},
del:function(key){
this.showzzc=1;
this.showts=1;
this.lisindex=key;
this.datameth="delpic";
//this.listData.splice(key, 1);
},
isdelc:function(){
if(this.datameth=="delpic"){
this.listData.splice(this.lisindex, 1);
}
if(this.datameth=="tag"){
this.tagslist.splice(this.tagindex, 1);
}
this.showzzc=0;
},
showzz:function(meth,key){
//console.log(this.listData[key].shs);
if(!this.listData[key].shs){
this.$set(this.listData[key],'shs',0);
}
this.listData[key].shs=meth;
},
upbtn:function(){
document.getElementById("multiple").click();
},
autoup:function(){
let that=this;
that.file="text"; //切换text file
let ups=document.getElementById( "multiple");
let formdata = new FormData();
if(ups.files[0]){
if(ups.files.length>4){
this.showzzc=1;
this.showts=2;
this.tis="一次最多可以选择4张图片上传!";
that.file="file";
return false;
}
for(m=0;m<=ups.files.length-1;m++){
formdata.append("file", ups.files[m]);
axios.post("/api/uppic", formdata)
.then(function (response) {
if(response.data.error=='0000'){
that.listData.push(response.data.pic);
that.file="file";//重新切换为file
//console.log(JSON.stringify(that.listData));
}else{
that.showzzc=1;
that.showts=2;
that.tis=response.data.msg;
that.file="file";
return false;
}
})
.catch(function (error) {
console.log(error);
});
}
console.log(ups.outerHTML);
}
}
})
注意:上传图片以后一定要that.file="file",切换回file,不然会出现只能上传一次,下次选择当前图片不能上传的情况。
上边的上传是选取多个然后for循环逐个上传的,也可以file使用数组file[]批量提交,如下:
for(m=0;m<=ups.files.length-1;m++){
formdata.append("file[]", ups.files[m]);
}
axios.post("/api/uppic", formdata)
但是这样做的话,后台使用
foreach($_FILES as $k=>$v){
}
得到的$v['name']就是数组,需要我们再次for循环,得到单个的图片信息,返回以后的信息因为是数组,push只能一次追加一个,就只能再次循环,感觉很麻烦还不如开始就循环,一个一个的上传。
3、信息标签html
<tr class=''>
<td width="90" align="right">信息标签</td>
<td>
<div class="layui-input-inline tagslist" >
<span class='tagspan' v-for="(tag,key) in tagslist" :key="key" @click="deltag(key)">{{tag}}</span>
</div>
<input type="text" class='inpMain' id='tags' style='width:150px;' @blur="tags" v-model="tagsdt" /> <span class='itemms'>点击标签可以删除</span>
<span class='itemms'></span>
</td>
</tr>
输入文本框绑定tagsdt,当我们鼠标离开该文本框的时候,通过blur使用tags方法读取绑定的tagsdt,可以获得输入的内容,这里需要判断是否为空,如果不为空再push进数组:this.tagslist.push(this.tagsdt);
4、php后端代码
foreach($_FILES as $k=>$v){
$v['name'],$v['size'],$v['tem_name']
就是图片的基本信息,使用move_uploaded_file移动到指定文件夹
$imags['picpath']=$path;
$imags['shs']=0;
}
exit(json_encode(array('error'=>'0000','pic'=>$imags),JSON_UNESCAPED_UNICODE));
move_uploaded_file用法:
当前文件:$v["tmp_name"],
目标文件:ROOT_PATH.$images_dir.$newname
move_uploaded_file($v["tmp_name"], ROOT_PATH.$images_dir.$newname);
再次强调上传图片,要验证图片的安全性,防止图片木马!
*请认真填写需求信息,我们会在24小时内与您取得联系。