2023年6月20日发(作者:)
HTML、JS、CSS实现Matrixrain效果代码解读JS、CSS实现matrix rain效果这个是我在codePen上看到的⼀个国内前端前辈写的。今天让我们来读⼀下他的代码把。样式⽂件⾸先看⼀下样式⽂件html, body {
height: 100%;
margin: 0;
overflow: hidden;}overflow:hidden 是指在body中的元素溢出时,选择hidden隐藏掉。overflow还有其他的值:值visiblescrollautoinherit描述默认值。内容不会被修剪,会呈现在元素框之外。内容会被修剪,但是浏览器会显⽰滚动条以便查看其余的内容。如果内容被修剪,则浏览器会显⽰滚动条以便查看其余的内容。规定应该从⽗元素继承 overflow 属性的值。Flex布局来源:body {
display: flex;
align-items: center;
justify-content: center; background: #000;
}body的布局设置为弹性布局。如果是webkit内核的浏览器,必须加上-webkit前缀.box { display: -webkit-flex; display: flex;}采⽤Flex布局的元素,称为Flex容器,它的所有⼦元素⾃动成为容器的成员,成为Flex项⽬(flex item)容器的基本概念主轴(main axis)、交叉轴(cross axis)为容器的两根轴主轴、交叉轴的开始、结束位置分别为main start、main end;cross start、cross end容器的属性flex-direction (决定主轴的⽅向)row(默认值):主轴为⽔平⽅向,起点在左端。row-reverse:主轴为⽔平⽅向,起点在右端。column:主轴为垂直⽅向,起点在上沿。column-reverse:主轴为垂直⽅向,起点在下沿。flex-wrap(轴线位置不够如何换⾏)nowrap:不换⾏wrap:换⾏,第⼀⾏在上⽅wrap-reverse:换⾏,第⼀⾏在下⽅flex-flow(上两种属性的简写形式,默认值为row nowrap)justify-content(项⽬在主轴上的对齐⽅式)flex-start(默认值):左对齐flex-end:右对齐center: 居中space-between:两端对齐,项⽬之间的间隔都相等。space-around:每个项⽬两侧的间隔相等。所以,项⽬之间的间隔⽐项⽬与边框的间隔⼤⼀倍。align-items(交叉轴上如何对齐)flex-start:交叉轴的起点对齐。flex-end:交叉轴的终点对齐。center:交叉轴的中点对齐。baseline: 项⽬的第⼀⾏⽂字的基线对齐。stretch(默认值):如果项⽬未设置⾼度或设为auto,将占满整个容器的⾼度。align-content(多根主轴的对齐⽅式)flex-start:与交叉轴的起点对齐。flex-end:与交叉轴的终点对齐。center:与交叉轴的中点对齐。space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔⽐轴线与边框的间隔⼤⼀倍。stretch(默认值):轴线占满整个交叉轴。项⽬的属性order(项⽬的排列顺序,数值越⼩,排列越靠前)flex-grow(项⽬的放⼤⽐例,默认为0)如果所有项⽬的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果⼀个项⽬的flex-grow属性为2,其他项⽬都为1,则前者占据的剩余空间将⽐其他项多⼀倍。flex-shrink(项⽬的缩⼩⽐例,默认为1)如果所有项⽬的flex-shrink属性都为1,当空间不⾜时,都将等⽐例缩⼩。如果⼀个项⽬的flex-shrink属性为0,其他项⽬都为1,则空间不⾜时,前者不缩⼩。负值对该属性⽆效。flex-basis(项⽬占据的主轴控件)flex(grow、shrink、basis的简写,默认值为0 1 auto,后两个属性为option)该属性有两个快捷值:auto(1 1 auto)和none(0 0 auto)align-self(允许单个项⽬有与其他项⽬不⼀样的对齐⽅式)可选值与align-items⼀样回过头看这段body样式body {
display: flex;
align-items: center;
justify-content: center; background: #000;
}可见把body的项⽬,设置为在主轴上居中、在交叉轴上也为居中。p { line-height: 1;}⾏间距设置为数值1span { display: block; width: 2vmax;
height: 2vmax;
font-size: 2vmax;
color: #9bff9b11; text-align: center; font-family: "Helvetica Neue", Helvetica, sans-serif;}display:block将span元素设定为块元素,前后⾃带换⾏width: 2vmax;
height: 2vmax;
font-size: 2vmax;
vmax为视⼝长款中⼤的数值等分⼀百倍的单位,例如当前视⼝长款为2500px*1500px,⼀个vmax为2500/100即25px,上述2vmax则为50px。text-align: center;span元素内的⽂本对齐⽅式为居中JS⽂件循环const main = elector('main');for (let i = 0; i < 50; ++i) { new Rain({ target: main, row: 50 });}main标签代表的是body中占主要地位的部分,实现matrix rain的函数主要是⼀个for循环,新规了50个Rain对象。Rain对象构造函数constructor({ target, row }) { t = Element('p'); // Rain对象为p元素,即段落 (row); if (target) { Child(t); //
将此Rain对象insert到main容器中 } (); }build(row)函数build(row = 20) { // argument为row,若没有赋值,默认为20 let root = DocumentFragment(); let chars = []; for (let i = 0; i < row; ++i) { let c = new Char(); Child(t); (c); if (() < .5) { loop(() => (), r(1e3, 5e3)); } } = new Trail(chars, {
size: r(10, 30), offset: r(0, 100)
}); Child(root);
}highlights:createDocumentFragment()创建⼀个新的空⽩⽂档⽚段,将元素追加到新的⽂档⽚段中,再把⽂档⽚段追加到DOM树上,并且⽚段被⾃⾝⼦元素代替,再DOM中不会显⽰⽚段,只显⽰⽚段中的元素这样做会带来更好的性能。因为⽂档⽚段存在于内存中,⽽不是在DOM树中。在动态添加元素时,使⽤⽂档⽚段不会引起页⾯回流(对元素位置和⼏何上的运算),可以使性能更优。这个⽅法可以学⼀学,很有⽤。drop函数drop() { let trail = ; let len = ; let delay = r(10, 100); loop(() => { (); se((c, i, last) => { = ` color: hsl(136, 100%, ${85 / len * (i + 1)}%) `; if (last) { (); = ` color: hsl(136, 100%, 85%); text-shadow: 0 0 .5em #fff, 0 0 .5em currentColor; `; } }); }, delay); }highlight:drop函数中⼜调⽤了loop函数,其中fn参数中包含了两个⽅法,即每⼀次动画的回调函数都会执⾏()以及se()⽅法,move会让代码的⾼亮部分往下移动,traverse⽅法会把⾼亮部分的样式变更,实现动画效果。Char对象class Char { constructor() { t = Element('span'); (); } mutate() { ntent = getChar(); }}function getChar() { return arCode(pick( r(0x3041, 0x30ff), r(0x2000, 0x206f), r(0x0020, 0x003f) ));}function pick() { return arguments[r(0, - 1)];}function r(from, to) { return ~~(() * (to - from + 1) + from);}highlights:getChar⽅法实现随机取⼀个字符,pick和r⽅法都是作者yuanchuan前辈⾃⼰写的,我们看看有多美:r函数有两个参数:from和to,()返回⼀个0~1的随机数,*from-to的间值+offset from,即返回⼀个fromto的随机值,此时再在结果处加上两个‘’表⽰按位取反两次,因为位操作会去掉⼩数部分,所以这边主要的作⽤是去掉⼩数,⽤两次取反操作不仅简洁,性能效率还⾼。pick函数直接调取js的内置参数对象,即使⽅法中没有规定arguments,但是还是能从arguments⾥⾯取到,这边pick函数连参数都没规定,直接返回传进来的参数中的随机某⼀个参数。回到getChar函数,这边分别在0x30410x30ff,0x20000x206f,0x0020~0x003f中random⼀个unicode,作为三个参数,再在这三个参数⾥pick⼀个unicode,最后把unicode⽤fromCharCode转换成字符返回。Loop⽅法function loop(fn, delay) { let stamp = (); function _loop() { if (() - stamp >= delay) { fn(); stamp = (); } requestAnimationFrame(_loop); } requestAnimationFrame(_loop);}highlight:这是⼀个请求动画帧的⽅法,_loop为回调函数,_loop中如果当前经过时间已经过了delay,则执⾏传⼊的函数fn,若没有则继续执⾏请求动画帧这个⽅法。有关requestAnimationFrame这个⽅法,它由系统决定回调函数执⾏的时机,保证回调函数在屏幕的每⼀次刷新间隔中被执⾏⼀次。Trail对象class Trail { constructor(list = [], options) { = list; s = ( { size: 10, offset: 0 }, options ); = []; (); } traverse(fn) { h((n, i) => { let last = (i == - 1); if (n) fn(n, i, last); }); } move() { = []; let { offset, size } = s; for (let i = 0; i < size; ++i) { let item = [offset + i - size + 1]; (item); } =
(offset + 1) % ( + size - 1); }}highlights:s = ( { size: 10, offset: 0 }, options );这个函数⽤到⽅法,将所有可枚举属性的值从⼀个或多个源对象复制到⽬标对象。它将返回⽬标对象。如果⽬标对象和源对象具有相同的属性,则⽬标对象的属性值会被源对象覆盖。这边前辈的⽬的应该是给这个option⼀个默认值。move⽅法会把offset⾃增⼀,并且当offset⼤于整个list + size的长度时,重置offset。这边的size是⾼亮部分字符的长度,offset是⾼亮部分再整个串中的位置traverse⽅法:last判断为⾼亮部分最后⼀个字符,当item有元素时,执⾏传进来的fn⽅法。整体flow进来main⼊⼝函数之后,for循环新规50个Rain对象,每个Rain对象中,⾸先会⽣成N个字符,然后⽤这N个字符⽣成⼀个尾迹部分Trail,尾迹会随机选择⼀个⾼亮部分的Size以及初始Offset。在N个字符、尾迹都初始化完成之后,Rain对象会进⼊drop⽅法,在drop⽅法中,随机⽣成⼀个delay,控制⾼亮部分坠下的延迟。drop⽅法会进⼊到⼀个⽆限循环的动画loop中,在这个loop⾥,尾迹不断往下坠,并且尾迹末端的字符发光、尾迹的字符⾼亮,并且在loop过程中,把尾迹的末端字符变更字符。整体效果图:
2023年6月20日发(作者:)
HTML、JS、CSS实现Matrixrain效果代码解读JS、CSS实现matrix rain效果这个是我在codePen上看到的⼀个国内前端前辈写的。今天让我们来读⼀下他的代码把。样式⽂件⾸先看⼀下样式⽂件html, body {
height: 100%;
margin: 0;
overflow: hidden;}overflow:hidden 是指在body中的元素溢出时,选择hidden隐藏掉。overflow还有其他的值:值visiblescrollautoinherit描述默认值。内容不会被修剪,会呈现在元素框之外。内容会被修剪,但是浏览器会显⽰滚动条以便查看其余的内容。如果内容被修剪,则浏览器会显⽰滚动条以便查看其余的内容。规定应该从⽗元素继承 overflow 属性的值。Flex布局来源:body {
display: flex;
align-items: center;
justify-content: center; background: #000;
}body的布局设置为弹性布局。如果是webkit内核的浏览器,必须加上-webkit前缀.box { display: -webkit-flex; display: flex;}采⽤Flex布局的元素,称为Flex容器,它的所有⼦元素⾃动成为容器的成员,成为Flex项⽬(flex item)容器的基本概念主轴(main axis)、交叉轴(cross axis)为容器的两根轴主轴、交叉轴的开始、结束位置分别为main start、main end;cross start、cross end容器的属性flex-direction (决定主轴的⽅向)row(默认值):主轴为⽔平⽅向,起点在左端。row-reverse:主轴为⽔平⽅向,起点在右端。column:主轴为垂直⽅向,起点在上沿。column-reverse:主轴为垂直⽅向,起点在下沿。flex-wrap(轴线位置不够如何换⾏)nowrap:不换⾏wrap:换⾏,第⼀⾏在上⽅wrap-reverse:换⾏,第⼀⾏在下⽅flex-flow(上两种属性的简写形式,默认值为row nowrap)justify-content(项⽬在主轴上的对齐⽅式)flex-start(默认值):左对齐flex-end:右对齐center: 居中space-between:两端对齐,项⽬之间的间隔都相等。space-around:每个项⽬两侧的间隔相等。所以,项⽬之间的间隔⽐项⽬与边框的间隔⼤⼀倍。align-items(交叉轴上如何对齐)flex-start:交叉轴的起点对齐。flex-end:交叉轴的终点对齐。center:交叉轴的中点对齐。baseline: 项⽬的第⼀⾏⽂字的基线对齐。stretch(默认值):如果项⽬未设置⾼度或设为auto,将占满整个容器的⾼度。align-content(多根主轴的对齐⽅式)flex-start:与交叉轴的起点对齐。flex-end:与交叉轴的终点对齐。center:与交叉轴的中点对齐。space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔⽐轴线与边框的间隔⼤⼀倍。stretch(默认值):轴线占满整个交叉轴。项⽬的属性order(项⽬的排列顺序,数值越⼩,排列越靠前)flex-grow(项⽬的放⼤⽐例,默认为0)如果所有项⽬的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果⼀个项⽬的flex-grow属性为2,其他项⽬都为1,则前者占据的剩余空间将⽐其他项多⼀倍。flex-shrink(项⽬的缩⼩⽐例,默认为1)如果所有项⽬的flex-shrink属性都为1,当空间不⾜时,都将等⽐例缩⼩。如果⼀个项⽬的flex-shrink属性为0,其他项⽬都为1,则空间不⾜时,前者不缩⼩。负值对该属性⽆效。flex-basis(项⽬占据的主轴控件)flex(grow、shrink、basis的简写,默认值为0 1 auto,后两个属性为option)该属性有两个快捷值:auto(1 1 auto)和none(0 0 auto)align-self(允许单个项⽬有与其他项⽬不⼀样的对齐⽅式)可选值与align-items⼀样回过头看这段body样式body {
display: flex;
align-items: center;
justify-content: center; background: #000;
}可见把body的项⽬,设置为在主轴上居中、在交叉轴上也为居中。p { line-height: 1;}⾏间距设置为数值1span { display: block; width: 2vmax;
height: 2vmax;
font-size: 2vmax;
color: #9bff9b11; text-align: center; font-family: "Helvetica Neue", Helvetica, sans-serif;}display:block将span元素设定为块元素,前后⾃带换⾏width: 2vmax;
height: 2vmax;
font-size: 2vmax;
vmax为视⼝长款中⼤的数值等分⼀百倍的单位,例如当前视⼝长款为2500px*1500px,⼀个vmax为2500/100即25px,上述2vmax则为50px。text-align: center;span元素内的⽂本对齐⽅式为居中JS⽂件循环const main = elector('main');for (let i = 0; i < 50; ++i) { new Rain({ target: main, row: 50 });}main标签代表的是body中占主要地位的部分,实现matrix rain的函数主要是⼀个for循环,新规了50个Rain对象。Rain对象构造函数constructor({ target, row }) { t = Element('p'); // Rain对象为p元素,即段落 (row); if (target) { Child(t); //
将此Rain对象insert到main容器中 } (); }build(row)函数build(row = 20) { // argument为row,若没有赋值,默认为20 let root = DocumentFragment(); let chars = []; for (let i = 0; i < row; ++i) { let c = new Char(); Child(t); (c); if (() < .5) { loop(() => (), r(1e3, 5e3)); } } = new Trail(chars, {
size: r(10, 30), offset: r(0, 100)
}); Child(root);
}highlights:createDocumentFragment()创建⼀个新的空⽩⽂档⽚段,将元素追加到新的⽂档⽚段中,再把⽂档⽚段追加到DOM树上,并且⽚段被⾃⾝⼦元素代替,再DOM中不会显⽰⽚段,只显⽰⽚段中的元素这样做会带来更好的性能。因为⽂档⽚段存在于内存中,⽽不是在DOM树中。在动态添加元素时,使⽤⽂档⽚段不会引起页⾯回流(对元素位置和⼏何上的运算),可以使性能更优。这个⽅法可以学⼀学,很有⽤。drop函数drop() { let trail = ; let len = ; let delay = r(10, 100); loop(() => { (); se((c, i, last) => { = ` color: hsl(136, 100%, ${85 / len * (i + 1)}%) `; if (last) { (); = ` color: hsl(136, 100%, 85%); text-shadow: 0 0 .5em #fff, 0 0 .5em currentColor; `; } }); }, delay); }highlight:drop函数中⼜调⽤了loop函数,其中fn参数中包含了两个⽅法,即每⼀次动画的回调函数都会执⾏()以及se()⽅法,move会让代码的⾼亮部分往下移动,traverse⽅法会把⾼亮部分的样式变更,实现动画效果。Char对象class Char { constructor() { t = Element('span'); (); } mutate() { ntent = getChar(); }}function getChar() { return arCode(pick( r(0x3041, 0x30ff), r(0x2000, 0x206f), r(0x0020, 0x003f) ));}function pick() { return arguments[r(0, - 1)];}function r(from, to) { return ~~(() * (to - from + 1) + from);}highlights:getChar⽅法实现随机取⼀个字符,pick和r⽅法都是作者yuanchuan前辈⾃⼰写的,我们看看有多美:r函数有两个参数:from和to,()返回⼀个0~1的随机数,*from-to的间值+offset from,即返回⼀个fromto的随机值,此时再在结果处加上两个‘’表⽰按位取反两次,因为位操作会去掉⼩数部分,所以这边主要的作⽤是去掉⼩数,⽤两次取反操作不仅简洁,性能效率还⾼。pick函数直接调取js的内置参数对象,即使⽅法中没有规定arguments,但是还是能从arguments⾥⾯取到,这边pick函数连参数都没规定,直接返回传进来的参数中的随机某⼀个参数。回到getChar函数,这边分别在0x30410x30ff,0x20000x206f,0x0020~0x003f中random⼀个unicode,作为三个参数,再在这三个参数⾥pick⼀个unicode,最后把unicode⽤fromCharCode转换成字符返回。Loop⽅法function loop(fn, delay) { let stamp = (); function _loop() { if (() - stamp >= delay) { fn(); stamp = (); } requestAnimationFrame(_loop); } requestAnimationFrame(_loop);}highlight:这是⼀个请求动画帧的⽅法,_loop为回调函数,_loop中如果当前经过时间已经过了delay,则执⾏传⼊的函数fn,若没有则继续执⾏请求动画帧这个⽅法。有关requestAnimationFrame这个⽅法,它由系统决定回调函数执⾏的时机,保证回调函数在屏幕的每⼀次刷新间隔中被执⾏⼀次。Trail对象class Trail { constructor(list = [], options) { = list; s = ( { size: 10, offset: 0 }, options ); = []; (); } traverse(fn) { h((n, i) => { let last = (i == - 1); if (n) fn(n, i, last); }); } move() { = []; let { offset, size } = s; for (let i = 0; i < size; ++i) { let item = [offset + i - size + 1]; (item); } =
(offset + 1) % ( + size - 1); }}highlights:s = ( { size: 10, offset: 0 }, options );这个函数⽤到⽅法,将所有可枚举属性的值从⼀个或多个源对象复制到⽬标对象。它将返回⽬标对象。如果⽬标对象和源对象具有相同的属性,则⽬标对象的属性值会被源对象覆盖。这边前辈的⽬的应该是给这个option⼀个默认值。move⽅法会把offset⾃增⼀,并且当offset⼤于整个list + size的长度时,重置offset。这边的size是⾼亮部分字符的长度,offset是⾼亮部分再整个串中的位置traverse⽅法:last判断为⾼亮部分最后⼀个字符,当item有元素时,执⾏传进来的fn⽅法。整体flow进来main⼊⼝函数之后,for循环新规50个Rain对象,每个Rain对象中,⾸先会⽣成N个字符,然后⽤这N个字符⽣成⼀个尾迹部分Trail,尾迹会随机选择⼀个⾼亮部分的Size以及初始Offset。在N个字符、尾迹都初始化完成之后,Rain对象会进⼊drop⽅法,在drop⽅法中,随机⽣成⼀个delay,控制⾼亮部分坠下的延迟。drop⽅法会进⼊到⼀个⽆限循环的动画loop中,在这个loop⾥,尾迹不断往下坠,并且尾迹末端的字符发光、尾迹的字符⾼亮,并且在loop过程中,把尾迹的末端字符变更字符。整体效果图:
发布评论