让CSS动画结束后光标停止闪烁

3

我已设置了一个闪烁光标动画,并有两行文本。

我希望在文本出现时出现光标,并在第一行结束时消失 - 但保留在第二行闪烁

有人提出了一个非常相似的问题,但解决方案使光标完全不可见:

停止css动画结尾处的闪烁光标

我测试了这个答案代码(在几个浏览器上),它根本不起作用。

以下是我的代码:

代码:

.typewriter1 p {
  overflow: hidden;
  border-right: .15em solid #00aeff;
  white-space: nowrap;
  margin: 0 auto;
  letter-spacing: 0;
  color: #fff;
  padding-left: 10px;
  animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite;
}

.typewriter2 p {
  overflow: hidden;
  /* Ensures the content is not revealed until the animation */
  border-right: .15em solid #00aeff;
  white-space: nowrap;
  margin: 0 auto;
  letter-spacing: 0;
  color: #fff;
  padding-left: 10px;
  opacity: 0;
  animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite, slidein 1s ease 3.5s forwards;
  animation-delay: 3.5s;
}


/* The typing effect */

@keyframes typing {
  from {
    width: 0
  }
  to {
    width: 100%
  }
}

@keyframes slidein {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}


/* The typewriter cursor effect */

@keyframes blink-caret {
  from,
  to {
    border-color: #00aeff
  }
  50% {
    border-color: transparent;
  }
}
<div class="typewriter1">
  <p>A well defined plan will identify problems,</p>
</div>
<div class="typewriter2">
  <p> address challenges, and help restore confidence.</p>
</div>

3个回答

2

目前只有示例2得到了完全的解释。示例3与问题完全相同,只是做了一些微小的更改。

示例1 — 为背景图片和渐变重新设计

HTML

首先,我们可以清理HTML。这是一个单独的段落,所以让我们将它放在一个段落元素中:

<p class="typewriter">
  A well defined plan will identify problems,
  address challenges, and help restore confidence.
</p>

其次,我们需要逐行显示文本,因此我们将每行文本包装在嵌套的元素中,并使用换行符手动断开每行:

<p class="typewriter">
  <span class="slide">
    <span class="inner-slide">A well defined plan will identify problems, 
  </span>
  </span><br>
  <span class="slide">
    <span class="inner-slide">address challenges, and help restore confidence.      </span>
  </span>
</p>

完整示例1

当前限制:我们必须为left设置一个固定的像素宽度。

.typewriter {
  position: relative;
  height: 500px;
  margin: 0 auto;
  width: 310px;
  overflow: hidden;
}

.typewriter .slide,
.inner-slide {
  display: inline-block;
  overflow: hidden;
  height: 1.1em;
}

.typewriter .slide {
  position: relative;
  animation: typing 2s steps(30, end) forwards, blink-caret .75s step-end infinite;
  left: -310px;
  border-right: .15em solid transparent;
}

.typewriter .slide:nth-of-type(1) {
  animation: typing 2s steps(30, end) forwards, blink-caret .75s step-end 2.6;
}

.inner-slide {
  position: relative;
  animation: typing2 2s steps(30, end) forwards;
  white-space: nowrap;
  left: 310px;
}

.typewriter .slide:nth-of-type(2),
.typewriter .slide:nth-of-type(2) .inner-slide {
  animation-delay: 2s;
}

@keyframes typing {
  from {
    left: -310px;
  }
  to {
    left: 0;
  }
}

@keyframes typing2 {
  from {
    left: 310px;
  }
  to {
    left: 0;
  }
}


/*The typewriter cursor effect */

@keyframes blink-caret {
  0,
  100% {
    border-color: transparent
  }
  50% {
    border-color: #00aeff
  }
}

body {
  background: linear-gradient(to bottom right, #CCC 0, #F00 100%) no-repeat;
}
<p class="typewriter">
  <span class="slide">
        <span class="inner-slide">A well defined plan will identify problems, 
      </span>
  </span><br>
  <span class="slide">
        <span class="inner-slide">address challenges, and help restore confidence.</span>
  </span>
</p>

示例二 — 原版。适用于纯色背景

HTML

首先,我们可以整理 HTML。这是一个段落,所以让我们使用一个段落元素来包裹它:

<p class="typewriter">
  A well defined plan will identify problems,
  address challenges, and help restore confidence.
</p>

其次,我们需要逐行逐个显示文本内容,因此我们会将每一行用 span 元素包裹,并在需要处手动添加换行符:

<p class="typewriter">
  <span>A well defined plan will identify problems,</span><br>
  <span> address challenges, and help restore confidence.</span>
</p>

CSS

现在我们需要一个元素来覆盖文本并作为动画光标。我们可以使用一个伪元素,它将从100%的宽度开始,并具有左边框,如下所示:

.typewriter > span::before {
  content: '';
  border-left: .15em solid #00aeff; 
  position: absolute; 
  background: white; 
  height: 1.1em; 
  right: -5px; 
  width: 100%; 
}
  • 高度应足以覆盖包括基线以下的所有文本。
  • 正确的负值会将其拉出其父级,因此光标不会显示在第一行,这要归功于父级上的overflow-hidden
  • 它从100%宽度开始,然后动画变为0。
  • 它相对于具有相对位置的span进行绝对定位。

为了保持光标在最后一行,我们需要给它一个0的右边值:

.typewriter > span:last-of-type::before {
  right: 0;
}

现在它将不再被拉出父元素。

第二行需要延迟与动画运行时间相同的时间:

.typewriter > span:nth-of-type(2)::before {
  animation-delay: 2s;
}

由于我们希望段落的宽度由文本的宽度决定,而跨度接受宽度,因此我们需要将它们设置为内联块:

.typewriter,
.typewriter > span {
  display: inline-block;
}

最后,我们将打字动画反转,从100%到0:
@keyframes typing {
  from {
    width: 100%
  }
  to {
    width: 0
  }
}

完整示例2

.typewriter,
.typewriter > span {
  display: inline-block;
}

.typewriter > span {
  position: relative;
  overflow: hidden;
  padding-right: 4px;
}

.typewriter > span::before {
  content: '';
  position: absolute;
  border-left: .15em solid #00aeff;
  background: white;
  height: 1.1em;
  right: -5px;
  width: 100%;
  animation: blink-caret .75s step-end infinite, typing 2s steps(30, end) forwards;
}

.typewriter > span:nth-of-type(2)::before {
  animation-delay: 2s;
}

.typewriter > span:last-of-type::before {
  right: 0;
}



/* The typing effect*/

@keyframes typing {
  from {
    width: 100%
  }
  to {
    width: 0
  }
}


/*The typewriter cursor effect */

@keyframes blink-caret {
  from,
  to {
    border-color: #00aeff
  }
  50% {
    border-color: transparent
  }
}
<p class="typewriter">
  <span>A well defined plan will identify problems,</span><br>
  <span> address challenges, and help restore confidence.</span>
</p>

示例3 —— 使用问题中的示例

根据第一条线的插入符号适当更改迭代计数。在此示例中,该值为4.1。此动画将迭代4.1次,然后停止:

animation: blink-caret .75s step-end 4.1

将创建插入符号的边框更改为透明:

border-right: .15em solid transparent

并且动画被翻转了:

@keyframes blink-caret {
  0,
  100% {
    border-color: transparent
  }
  50% {
    border-color: #00aeff
  }
}

现在停止状态是透明的,并且第一行会在第一行消失。

完整示例3

body {
width: 330px;
}

.typewriter1 p {
  overflow: hidden;
  border-right: .15em solid transparent;
  white-space: nowrap;
  margin: 0 auto;
  letter-spacing: 0;
  padding-left: 10px;
  animation: typing 3.5s steps(40, end), blink-caret .75s step-end 4.1;
}

.typewriter2 p {
  overflow: hidden;
  /* Ensures the content is not revealed until the animation */
  border-right: .15em solid transparent;
  white-space: nowrap;
  margin: 0 auto;
  letter-spacing: 0;

  padding-left: 10px;
  opacity: 0;
  animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite, slidein 1s ease 3.5s forwards;
  animation-delay: 3.5s;
}


/* The typing effect */

@keyframes typing {
  from {
    width: 0
  }
  to {
    width: 100%
  }
}

@keyframes slidein {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}


/* The typewriter cursor effect */

@keyframes blink-caret {
  0,
  100% {
    border-color: transparent
  }
  50% {
    border-color: #00aeff
  }
}
<div class="typewriter1">
  <p>A well defined plan will identify problems,</p>
</div>
<div class="typewriter2">
  <p> address challenges, and help restore confidence.</p>
</div>


这很棒 - 除了使用“background: white;”来隐藏揭示之前的文本部分。我忘了提到这是在一个有图案的背景上运行,这使得白色背景非常明显。 - Richard Miller
@RichardMiller - 好的,我已经添加了另外两个例子。请查看第三个例子,它是根据你的问题稍作修改后的HTML和CSS。第一个例子是我自己新创建的。感谢你的挑战。 - misterManSam
第三次就是魅力所在 - 非常感谢。在最后一个“@keyframes blink-caret”代码片段中,我确实会收到一些警告 - 看起来它不喜欢0、100的表述方式。但是,它能够正常工作。 :) - Richard Miller

0

我刚把 infinite.typewriter1 p { 改成了5。

.typewriter1 p {
  overflow: hidden;
  border-right: .15em solid #00aeff;
  white-space: nowrap;
  margin: 0 auto;
  letter-spacing: 0;
  color: #fff;
  padding-left: 10px;
  animation: typing 3.5s steps(40, end), blink-caret .75s step-end 5;
}

.typewriter2 p {
  overflow: hidden;
  /* Ensures the content is not revealed until the animation */
  border-right: .15em solid #00aeff;
  white-space: nowrap;
  margin: 0 auto;
  letter-spacing: 0;
  color: #fff;
  padding-left: 10px;
  opacity: 0;
  animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite, slidein 1s ease 3.5s forwards;
  animation-delay: 3.5s;
}


/* The typing effect */

@keyframes typing {
  from {
    width: 0
  }
  to {
    width: 100%
  }
}

@keyframes slidein {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}


/* The typewriter cursor effect */

@keyframes blink-caret {
  from,
  to {
    border-color: #00aeff
  }
  50% {
    border-color: transparent;
  }
}
<div class="typewriter1">
  <p>A well defined plan will identify problems,</p>
</div>
<div class="typewriter2">
  <p> address challenges, and help restore confidence.</p>
</div>


这将在第一行末留下一个不闪烁的光标。我需要完成的动画在第一行末没有光标,在第二行末有一个闪烁的光标。 - Richard Miller

0

如果您不一定要编写自己的动画,TypeIt(https://typeitjs.com)API可以通过更少的自定义代码实现:

https://codepen.io/alexmacarthur/pen/MWWEPxa

const secondInstance = new TypeIt('.typewriter2 p');
const firstInstance = new TypeIt('.typewriter1 p', {
  afterComplete: function (instance) {
    document.querySelector('.typewriter1 p .ti-cursor').remove();
    secondInstance.go();
  }
}).go();

这种方法的唯一缺点是您对动画本身的控制较少(您需要覆盖库提供的CSS动画)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接