马黑黑 发表于 2024-6-29 13:06

CSS关键帧动画文本效果:逐行出场

本帖最后由 马黑黑 于 2024-6-29 14:17 编辑 <br /><br /><style>
.art p { margin: 10px 0; font-size: 1.2em; }
.mum { position: relative; margin: 0; padding: 10px; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; color: black; background: rgba(240, 240, 240,.95); border: thick groove lightblue; border-radius: 6px; }
.mum ::selection { background-color: rgba(0,100,100,.35); }
.mum div { margin: 0; padding: 0; }
.mum cl-cd { display: block; position: relative; margin: 0 0 0 50px; padding: 0 0 0 10px; white-space: pre-wrap; overflow-wrap: break-word; border-left: 1px solid silver; }
.mum cl-cd::before { position: absolute; content: attr(data-idx); width: 50px; color: gray; text-align: right; transform: translate(-70px); }
.tRed { color: red; }
.tBlue { color: blue; }
.tGreen { color: green; }
.tDarkRed { color: darkred; }
.tMagenta { color: magenta; }
</style>

<div class="art">
    <h2>CSS关键帧动画文本效果:逐行出场</h2>
    <p><b>思路</b>:用p标签装载每行文本,令其先待在div父容器右侧,再用CSS关键帧动画依次将p标签平移到默认时的位置,最后一句出场后间隔一定时间复位重来,整体动画循环往复并可暂停、继续。</p>
    <p><b>实现</b>:</p>
    <p>一、CSS和HTML </p>
    <p>父元素是一个div标签,绝对定位,宽度需要设置一个合适的值;子元素是段落标签p,相对定位以便无需操心布局且transform能对之进行控制;关键帧动画非常简单,平移到 0 处,就是回到默认时的原位置。p标签暂不出现在HTML代码中,它们将由JS动态生成:</p>
    <div class='mum'>
<cl-cd data-idx="1">&lt;<span class="tDarkRed">style</span>&gt;</cl-cd>
<cl-cd data-idx="2">#txtbox {</cl-cd>
<cl-cd data-idx="3">    <span class="tBlue">position:</span> absolute;</cl-cd>
<cl-cd data-idx="4">    <span class="tBlue">left:</span> 50px;</cl-cd>
<cl-cd data-idx="5">    <span class="tBlue">top:</span> 50px;</cl-cd>
<cl-cd data-idx="6">    <span class="tBlue">width:</span> 280px;</cl-cd>
<cl-cd data-idx="7">    <span class="tBlue">min-height:</span> 60px;</cl-cd>
<cl-cd data-idx="8">    <span class="tBlue">padding:</span> 10px 20px;</cl-cd>
<cl-cd data-idx="9">    <span class="tBlue">box-sizing:</span> border-box;</cl-cd>
<cl-cd data-idx="10">    <span class="tBlue">overflow:</span> hidden;</cl-cd>
<cl-cd data-idx="11">}</cl-cd>
<cl-cd data-idx="12">#txtbox p {</cl-cd>
<cl-cd data-idx="13">    <span class="tBlue">margin:</span> 8px 0;</cl-cd>
<cl-cd data-idx="14">    <span class="tBlue">position:</span> relative;</cl-cd>
<cl-cd data-idx="15">    <span class="tBlue">font:</span> normal 26px/30px sans-serif;</cl-cd>
<cl-cd data-idx="16">    <span class="tBlue">color:</span> navy;</cl-cd>
<cl-cd data-idx="17">    <span class="tBlue">text-shadow:</span> 1px 1px 1px gray;</cl-cd>
<cl-cd data-idx="18">    <span class="tBlue">animation:</span> 2s forwards;</cl-cd>
<cl-cd data-idx="19">}</cl-cd>
<cl-cd data-idx="20">@keyframes move { to { <span class="tBlue">transform:</span> translate(0); } }</cl-cd>
<cl-cd data-idx="21">&lt;<span class="tDarkRed">/style</span>&gt;</cl-cd>
<cl-cd data-idx="22">&nbsp;</cl-cd>
<cl-cd data-idx="23">&lt;<span class="tDarkRed">div</span> <span class="tRed">id</span>=<span class="tMagenta">"txtbox"</span>&gt;&lt;<span class="tDarkRed">/div</span>&gt;</cl-cd>
        </div>
        <p>基于上面的设计,@keyframes 属性制作的动画 transform: translate(0) 是不管用的,平移的尺寸按理应不能是 0,所以是不是 #txtbox p 选择器漏了一句?是的,漏了 transform: translate(280px); 属性设置,还有,animation 属性也不完整,漏了动画名称,这些,将由JS来完善和管理。</p>
        <p>二、JS</p>
        <p>首先需要几个全局变量:</p>
        <div class='mum'>
<cl-cd data-idx="1"><span class="tBlue">var</span> text = `西岳崚嶒竦处尊,诸峰罗立似儿孙。安得仙人九节杖,拄到玉女洗头盆。车箱入谷无归路,箭栝通天有一门。稍待秋风凉冷后,高寻白帝问真源。`;</cl-cd>
<cl-cd data-idx="2"><span class="tBlue">var</span> paras = [];</cl-cd>
<cl-cd data-idx="3"><span class="tBlue">var</span> reg = /<span class="tRed">[,。\n]</span>/;</cl-cd>
<cl-cd data-idx="4"><span class="tBlue">var</span> ww = txtbox.offsetWidth;</cl-cd>
        </div>
        <p>text 是待输出文本,反引号内的文本内容可以分行写;paras 是段落签数组,用来保存p标签元素;reg 是正则表达式,注意红色部分,中括号表示其里面的内容只要出现其中的一个便能匹配,这里设计了三个:① 汉语逗号,② 汉语句号,③换行符 \n,可以根据需要添加、删减或重新构造自己的正则;ww 是父div元素的宽度。</p>
    <p>接着处理一下文本,将text按正则描述的规则拆分成若干单位、放入临时数组 ar 中并且,① 对 ar 数组过滤空文本数组元素,② 封装每一个数组元素内容为p标签、令其移动到父div元素外围右侧,③ 将封装好的p标签追加到父div元素,④ 将p标签一一存放到全局数组变量 paras 中。这个功能用一个立即执行函数完成:</p>
    <div class='mum'>
<cl-cd data-idx="1">(<span class="tBlue">function</span> () {</cl-cd>
<cl-cd data-idx="2"><span class="tBlue">var</span> ar = text.split(reg).filter(item =&gt; item !==<span class="tMagenta">''</span>);</cl-cd>
<cl-cd data-idx="3">ar.forEach((p,k) =&gt; {</cl-cd>
<cl-cd data-idx="4">    <span class="tBlue">var</span> para = <span class="tRed">document</span>.createElement(<span class="tMagenta">'p'</span>);</cl-cd>
<cl-cd data-idx="5">    para.innerHTML = p;</cl-cd>
<cl-cd data-idx="6">    para.style.cssText += `<span class="tBlue">transform:</span> translate(${ww}px);`;</cl-cd>
<cl-cd data-idx="7">    txtbox.appendChild(para);</cl-cd>
<cl-cd data-idx="8">    paras.push(para);</cl-cd>
<cl-cd data-idx="9">});</cl-cd>
<cl-cd data-idx="10">})();</cl-cd>
        </div>
        <p>现在,paras 数组变量已经准备就绪,可以遍历它做一些实际性工作了:</p>
        <div class='mum'>
<cl-cd data-idx="1">paras.style.animationName = <span class="tMagenta">'move'</span>;</cl-cd>
<cl-cd data-idx="2"> </cl-cd>
<cl-cd data-idx="3">paras.forEach((p,k) =&gt; {</cl-cd>
<cl-cd data-idx="4">    p.onanimationend = () =&gt; {</cl-cd>
<cl-cd data-idx="5">      paras[(k+1) % paras.length].style.animationName = <span class="tMagenta">'move'</span>;</cl-cd>
<cl-cd data-idx="6">      <span class="tBlue">if</span>(k === paras.length - 1) setTimeout( () =&gt; parasReset(), 10000);</cl-cd>
<cl-cd data-idx="7">    };</cl-cd>
<cl-cd data-idx="8">});</cl-cd>
        </div>
        <p>上面,我们先是给第一个p标签 paras 指派关键帧动画名。接着,用 <span class="tRed">array</span>.forEach() 方法遍历了数组 <span class="tRed">paras</span>,批量定制了p元素的 onanimationend 事件(动画结束事件):当前 p 标签的该事件触发时,给下标为 <span class="tRed">(k+1) % paras.length</span> 的p标签设置动画名称。使用遍历索引加1取数组长度的余数获得数组元素下标是个巧妙的方法:遍历具有迭代特性,每次的 k 变量指向当前数组元素,它的下一个数组元素自然是 k+1,但当循环到最后,k+1 的值会等于数组长度值(数组元素总量值)从而非法(数组元素下标从0开始起算),而 k+1 取数组长度的余数,在前面均等于 k+1 本身,而当 k+1 等于数组长度时会得到 0,也就是回到第一个数组元素即给第一个数组元素指定动画。然后,要使得动画循环运行,我们需要加入一个处理机制(代码第 6 行):最后一个p标签关键帧动画结束时,使用定时器 setTimeout 间隔预定时间后调用该处理机制的函数 parasReset(),函数长如下酱紫:</p>
        <div class='mum'>
<cl-cd data-idx="1"><span class="tBlue">var</span> parasReset = () =&gt; {</cl-cd>
<cl-cd data-idx="2">    paras.forEach(p =&gt; {</cl-cd>
<cl-cd data-idx="3">      p.style.animationName = <span class="tMagenta">''</span>;</cl-cd>
<cl-cd data-idx="4">      p.style.transform = <span class="tMagenta">'translate(${ww}px)'</span>;</cl-cd>
<cl-cd data-idx="5">      setTimeout( () =&gt; { paras.style.animationName = <span class="tMagenta">'move'</span>; }, 500);</cl-cd>
<cl-cd data-idx="6">    });</cl-cd>
<cl-cd data-idx="7">};</cl-cd>
        </div>
        <p>函数 parasReset() 遍历存储p标签的数组 paras,清空所有p标签的动画(必须,否则无法继续执行后面的同名动画)并将之统统移动到父div盒子的右侧外围,最后,再用一个 setTimeout 定时器在N毫秒之后给第一个p标签指定动画名称(这里的定时器必须使用,因为JS是同步运行机制,CSS动画名交替则要求,如果赋予的是同名动画,则不能取消之后立马重新赋予,需要一个时间差)。</p>
        <p>至此,文本动画已经可以运行了,就差一个控制动画播放暂停的机制,我们用父div元素的窗体为载体,点击它时动画会在播放与暂停之间来回切换:</p>
        <div class='mum'>
<cl-cd data-idx="1">txtbox.onclick = () =&gt; {</cl-cd>
<cl-cd data-idx="2">    <span class="tBlue">var</span> state = <span class="tRed">window</span>.getComputedStyle(paras).getPropertyValue(<span class="tMagenta">'animation-play-state'</span>);</cl-cd>
<cl-cd data-idx="3">    paras.forEach(p =&gt; p.style.animationPlayState = state === <span class="tMagenta">'running'</span> ? <span class="tMagenta">'paused'</span> : <span class="tMagenta">'running'</span>);</cl-cd>
<cl-cd data-idx="4">};</cl-cd>
        </div>
        <p>最后,将上述的代码整合一下:</p>
        <div class='mum'>
<cl-cd data-idx="1">&lt;<span class="tDarkRed">style</span>&gt;</cl-cd>
<cl-cd data-idx="2">#txtbox {</cl-cd>
<cl-cd data-idx="3">    <span class="tBlue">position:</span> absolute;</cl-cd>
<cl-cd data-idx="4">    <span class="tBlue">left:</span> 50px;</cl-cd>
<cl-cd data-idx="5">    <span class="tBlue">top:</span> 50px;</cl-cd>
<cl-cd data-idx="6">    <span class="tBlue">width:</span> 280px;</cl-cd>
<cl-cd data-idx="7">    <span class="tBlue">min-height:</span> 60px;</cl-cd>
<cl-cd data-idx="8">    <span class="tBlue">padding:</span> 10px 20px;</cl-cd>
<cl-cd data-idx="9">    <span class="tBlue">box-sizing:</span> border-box;</cl-cd>
<cl-cd data-idx="10">    <span class="tBlue">overflow:</span> hidden;</cl-cd>
<cl-cd data-idx="11">}</cl-cd>
<cl-cd data-idx="12">#txtbox p {</cl-cd>
<cl-cd data-idx="13">    <span class="tBlue">margin:</span> 8px 0;</cl-cd>
<cl-cd data-idx="14">    <span class="tBlue">position:</span> relative;</cl-cd>
<cl-cd data-idx="15">    <span class="tBlue">font:</span> normal 26px/30px sans-serif;</cl-cd>
<cl-cd data-idx="16">    <span class="tBlue">color:</span> navy;</cl-cd>
<cl-cd data-idx="17">    <span class="tBlue">text-shadow:</span> 1px 1px 1px gray;</cl-cd>
<cl-cd data-idx="18">    <span class="tBlue">animation:</span> 2s forwards;</cl-cd>
<cl-cd data-idx="19">}</cl-cd>
<cl-cd data-idx="20">@keyframes move { to { <span class="tBlue">transform:</span> translate(0); } }</cl-cd>
<cl-cd data-idx="21">&lt;<span class="tDarkRed">/style</span>&gt;</cl-cd>
<cl-cd data-idx="22"> </cl-cd>
<cl-cd data-idx="23">&lt;<span class="tDarkRed">div</span> <span class="tRed">id</span>=<span class="tMagenta">"txtbox"</span>&gt;&lt;<span class="tDarkRed">/div</span>&gt;</cl-cd>
<cl-cd data-idx="24">&nbsp;</cl-cd>
<cl-cd data-idx="25">&lt;<span class="tDarkRed">script</span>&gt;</cl-cd>
<cl-cd data-idx="26"><span class="tBlue">var</span> text = `西岳崚嶒竦处尊,诸峰罗立似儿孙。安得仙人九节杖,拄到玉女洗头盆。车箱入谷无归路,箭栝通天有一门。稍待秋风凉冷后,高寻白帝问真源。`;</cl-cd>
<cl-cd data-idx="27"><span class="tBlue">var</span> paras = [];</cl-cd>
<cl-cd data-idx="28"><span class="tBlue">var</span> reg = /[,。\n]/;</cl-cd>
<cl-cd data-idx="29"><span class="tBlue">var</span> ww = txtbox.offsetWidth;</cl-cd>
<cl-cd data-idx="30"><span class="tGreen">//自执行函数 :处理文本+p标签封装+追加+存储</span></cl-cd>
<cl-cd data-idx="31">(<span class="tBlue">function</span> () {</cl-cd>
<cl-cd data-idx="32"><span class="tBlue">var</span> ar = text.split(reg).filter(item =&gt; item !==<span class="tMagenta">''</span>);</cl-cd>
<cl-cd data-idx="33">ar.forEach((p,k) =&gt; {</cl-cd>
<cl-cd data-idx="34">    <span class="tBlue">var</span> para = <span class="tRed">document</span>.createElement(<span class="tMagenta">'p'</span>);</cl-cd>
<cl-cd data-idx="35">    para.innerHTML = p;</cl-cd>
<cl-cd data-idx="36">    para.style.cssText += `<span class="tBlue">transform:</span> translate(${ww}px);`;</cl-cd>
<cl-cd data-idx="37">    txtbox.appendChild(para);</cl-cd>
<cl-cd data-idx="38">    paras.push(para);</cl-cd>
<cl-cd data-idx="39">});</cl-cd>
<cl-cd data-idx="40">})();</cl-cd>
<cl-cd data-idx="41">&nbsp;</cl-cd>
<cl-cd data-idx="42"><span class="tGreen">//p标签复位函数</span></cl-cd>
<cl-cd data-idx="43"><span class="tBlue">var</span> parasReset = () =&gt; {</cl-cd>
<cl-cd data-idx="44">    paras.forEach(p =&gt; {</cl-cd>
<cl-cd data-idx="45">      p.style.animationName = <span class="tMagenta">''</span>;</cl-cd>
<cl-cd data-idx="46">      p.style.transform = <span class="tMagenta">'translate(${ww}px)'</span>;</cl-cd>
<cl-cd data-idx="47">      setTimeout( () =&gt; { paras.style.animationName = <span class="tMagenta">'move'</span>; }, 500);</cl-cd>
<cl-cd data-idx="48">    });</cl-cd>
<cl-cd data-idx="49">};</cl-cd>
<cl-cd data-idx="50">&nbsp;</cl-cd>
<cl-cd data-idx="51"><span class="tGreen">//第一个p标签启用动画</span></cl-cd>
<cl-cd data-idx="52">paras.style.animationName = <span class="tMagenta">'move'</span>;</cl-cd>
<cl-cd data-idx="53">&nbsp;</cl-cd>
<cl-cd data-idx="54"><span class="tGreen">//遍历p标签 :动态生成所有标签的动画结束事件</span></cl-cd>
<cl-cd data-idx="55">paras.forEach((p,k) =&gt; {</cl-cd>
<cl-cd data-idx="56">    p.onanimationend = () =&gt; {</cl-cd>
<cl-cd data-idx="57">      paras[(k+1) % paras.length].style.animationName = <span class="tMagenta">'move'</span>;</cl-cd>
<cl-cd data-idx="58">      <span class="tBlue">if</span>(k === paras.length - 1) setTimeout( () =&gt; parasReset(), 10000);</cl-cd>
<cl-cd data-idx="59">    };</cl-cd>
<cl-cd data-idx="60">});</cl-cd>
<cl-cd data-idx="61">&nbsp;</cl-cd>
<cl-cd data-idx="62"><span class="tGreen">//父div元素点击事件 :切换动画播放暂停</span></cl-cd>
<cl-cd data-idx="63">txtbox.onclick = () =&gt; {</cl-cd>
<cl-cd data-idx="64">    <span class="tBlue">var</span> state = <span class="tRed">window</span>.getComputedStyle(paras).getPropertyValue(<span class="tMagenta">'animation-play-state'</span>);</cl-cd>
<cl-cd data-idx="65">    paras.forEach(p =&gt; p.style.animationPlayState = state === <span class="tMagenta">'running'</span> ? <span class="tMagenta">'paused'</span> : <span class="tMagenta">'running'</span>);</cl-cd>
<cl-cd data-idx="66">};</cl-cd>
<cl-cd data-idx="67">&lt;<span class="tDarkRed">/script</span>&gt;</cl-cd>
</div>
        <p>【提示】p标签在动态生成时使用 innerHTML 赋予其文本,这意味着 text 变量的赋值文本可以附带简单的HTML标签,诸如给特定关键词加粗体、前景色等修饰性标签。此外,可以通过CSS伪类选择器修饰对应的p标签,比如 :first-of-type、last-of-type 等。</p>
</div>

马黑黑 发表于 2024-6-29 13:06

本帖最后由 马黑黑 于 2024-6-29 14:03 编辑 <br /><br /><style>
#txtbox {
    position: relative;
    width: 280px;
    min-height: 60px;
    padding: 10px 20px;
    box-sizing: border-box;
    border: 1px solid gray;
}
#txtbox p {
    margin: 8px 0;
    position: relative;
    font: normal 26px/30px sans-serif;
    color: navy;
    text-shadow: 1px 1px 1px gray;
    animation: 2s forwards;
}
@keyframes move { to { transform: translate(0); } }
</style>

<div id="txtbox"></div>

<script>
var text = `西岳崚嶒竦处尊,诸峰罗立似儿孙。安得仙人九节杖,拄到玉女洗头盆。车箱入谷无归路,箭栝通天有一门。稍待秋风凉冷后,高寻白帝问真源。`;
var paras = [];
var reg = /[,。\n]/;
var ww = txtbox.offsetWidth;

(function () {
var ar = text.split(reg).filter(item => item !=='');
ar.forEach((p,k) => {
    var para = document.createElement('p');
    para.innerHTML = p;
    para.style.cssText += `transform: translate(${ww}px);`;
    txtbox.appendChild(para);
    paras.push(para);
});
})();

var parasReset = () => {
    paras.forEach(p => {
      p.style.animationName = '';
      p.style.transform = 'translate(${ww}px)';
      setTimeout( () => { paras.style.animationName = 'move'; }, 500);
    });
};

paras.style.animationName = 'move';

paras.forEach((p,k) => {
    p.onanimationend = () => {
      paras[(k+1) % paras.length].style.animationName = 'move';
      if(k === paras.length - 1) setTimeout( () => parasReset(), 10000);
    };
});

txtbox.onclick = () => {
    var state = window.getComputedStyle(paras).getPropertyValue('animation-play-state');
    paras.forEach(p => p.style.animationPlayState = state === 'running' ? 'paused' : 'running');
};
</script>

马黑黑 发表于 2024-6-29 14:05

二楼的演示,父div元素 position 属性值改为 relative,这是因为父div元素的父元素没有定位设置,默认会跑到页面的左上角区域。

另外,为了方便观察,将父div元素的 overflow: hidden; 属性设置拿掉。

樵歌 发表于 2024-6-29 16:13

马黑黑 发表于 2024-6-29 13:06
本帖最后由 马黑黑 于 2024-6-29 14:03 编辑
#txtbox {
    position: relative;


若是词,能分成两段演示么?{:4_176:}

樵歌 发表于 2024-6-29 16:14

能放到音画下面演示吗?

红影 发表于 2024-6-29 16:20

马黑黑 发表于 2024-6-29 14:05
二楼的演示,父div元素 position 属性值改为 relative,这是因为父div元素的父元素没有定位设置,默认会跑 ...

嗯嗯,拿掉 overflow: hidden; 看得更清楚了。当然做在帖子里的时候,再加上这句,去掉边框,就能让诗句一句句地进入了{:4_187:}

红影 发表于 2024-6-29 16:21

这个特别好,一直想要的效果。可以把写好的诗句弄到帖子里去了,太好了{:4_199:}

红影 发表于 2024-6-29 16:28

var reg = /[,。\n]/;如果正则里只留\n,或者用其他符号作为分段标志,是不是连标点都可以保留?

南无月 发表于 2024-6-29 17:30

马黑黑 发表于 2024-6-29 13:06
本帖最后由 马黑黑 于 2024-6-29 14:03 编辑
#txtbox {
    position: relative;


我还自己加了个框,把 overflow: hidden拿掉看效果

原来真的是这样看运行轨迹的{:4_173:}

南无月 发表于 2024-6-29 17:31

马黑黑 发表于 2024-6-29 14:05
二楼的演示,父div元素 position 属性值改为 relative,这是因为父div元素的父元素没有定位设置,默认会跑 ...


min-height: 60px;这一句在这里作用是啥。。有高有宽么?

南无月 发表于 2024-6-29 17:40

font: normal 26px/30px sans-serif;
这是一串语法糖,我认得{:4_173:}
别的关于运动控制的就先晕着吧
随意点击均可暂停,结束后字停10秒消失

马黑黑 发表于 2024-6-29 19:02

南无月 发表于 2024-6-29 17:40
font: normal 26px/30px sans-serif;
这是一串语法糖,我认得
别的关于运动控制的就先晕着吧


好滴

马黑黑 发表于 2024-6-29 19:03

南无月 发表于 2024-6-29 17:31
min-height: 60px;这一句在这里作用是啥。。有高有宽么?
min,最小,max,最大。CSS可以设置盒子的最小、最大宽高

马黑黑 发表于 2024-6-29 19:13

樵歌 发表于 2024-6-29 16:13
若是词,能分成两段演示么?

https://www.huachaowang.com/forum.php?mod=viewthread&tid=76864

马黑黑 发表于 2024-6-29 19:13

红影 发表于 2024-6-29 16:28
var reg = /[,。\n]/;如果正则里只留\n,或者用其他符号作为分段标志,是不是连标点都可以保留?

是滴

马黑黑 发表于 2024-6-29 19:14

樵歌 发表于 2024-6-29 16:14
能放到音画下面演示吗?

能,看上一个回复链接

马黑黑 发表于 2024-6-29 19:14

红影 发表于 2024-6-29 16:21
这个特别好,一直想要的效果。可以把写好的诗句弄到帖子里去了,太好了

这个帖子,你可以看看:

https://www.huachaowang.com/forum.php?mod=viewthread&tid=76864

马黑黑 发表于 2024-6-29 19:15

红影 发表于 2024-6-29 16:20
嗯嗯,拿掉 overflow: hidden; 看得更清楚了。当然做在帖子里的时候,再加上这句,去掉边框,就能让诗句 ...

{:4_191:}

南无月 发表于 2024-6-29 19:30

马黑黑 发表于 2024-6-29 19:02
好滴

因需施教啊。。好有松弛感的学习方式{:4_173:}

南无月 发表于 2024-6-29 19:31

马黑黑 发表于 2024-6-29 19:03
min,最小,max,最大。CSS可以设置盒子的最小、最大宽高

60是盒子,是每一行的高度么
页: [1] 2 3 4 5 6 7
查看完整版本: CSS关键帧动画文本效果:逐行出场