Search code examples
htmlcsscss-animationskeyframe

CSS writing animation alternate infinite cuts last letter off


I want to create a writing animation which is infinite and alternate. Everything works fine but for some reason the last letter does always get cut off.

I hope somebody can explain why it gets cut off and how to fix this.

My code:

body {
  height: 100vh;
  font-family: monospace;
  display: flex;
  justify-content: center;
  align-items: center;
}

li {
  list-style-type: none;
}

.first {
  font-size: 2.5rem;
  position: relative;
  width: max-content;
}

.first::before,
.first::after {
  content: '';
  position: absolute;
  height: 3.5rem;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.first::before {
  background-color: white;
  animation: typewriter 1.5s steps(7) alternate infinite;
}

.first::after {
  width: .125rem;
  background-color: black;
  animation: typewriter 1.5s steps(7) alternate infinite, blink 500ms steps(7) infinite;
}

@keyframes typewriter {
  to {
    left: 100%;
  }
}

@keyframes blink {
  to {
    background: transparent;
  }
}
<li class="first">student</li>


Solution

  • Here is a generic method from my article: https://dev.to/afif/a-scalable-css-only-typewriter-effect-2opn

    body {
      height: 100vh;
      font-family: monospace;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    li {
      list-style-type: none;
    }
    
    .first {
      font-size: 2.5rem;
    }
    
    .type {
      font-size:50px;
      display:inline-flex;
    }
    
    .type span {
      height:1.2em;
      width:0%;
      word-break:break-all;
      overflow: hidden;
      animation:
        c 0.2s infinite steps(1),  
        t 3s linear infinite alternate;
    }
    .type span:before {
      content:" ";
      display:inline-block;
    }
    
    @keyframes t{
      90%,100% {width:100%}
    }
    
    @keyframes c{
      0%,100%{box-shadow:2px 0 0 #0000}
      50%    {box-shadow:2px 0 0 #000 }
    }
    <li class="first type"><span>student</span></li>

    Using your method, update the code like below. You have to consider 8 steps and add 1ch to the final left value

    body {
      height: 100vh;
      font-family: monospace;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    li {
      list-style-type: none;
    }
    
    .first {
      font-size: 2.5rem;
      position: relative;
      width: max-content;
    }
    
    .first::before,
    .first::after {
      content: '';
      position: absolute;
      top:0;
      left:0;
      right:0;
      bottom:0;
    }
    
    .first::before {
      background-color: white;
      animation: typewriter 1.5s steps(8) alternate infinite;
    }
    
    .first::after {
      width: .125rem;
      background-color: black;
      animation: 
       typewriter 1.5s steps(8) alternate infinite,
       blink 500ms steps(8) infinite;
    }
    
    @keyframes typewriter {
      to {
        left: calc(100% + 1ch);
      }
    }
    
    @keyframes blink {
      to {
        background: transparent;
      }
    }
    <li class="first">student</li>