baltasaurus
baltasaurus

Reputation: 11

CSS typewriter animation with flexbox

What I'm trying to create is a typewriter effect that types out the first portion of the quote, pauses, types the second portion, pauses, then types the author.

The problem I'm currently trying to solve is the border-right blinking cursor line getting animated all the way up to the end of the flexbox container.

Btw, I'm also using the AOS library by Michael Snik. Not sure if what I'm trying to do has any interactions with that library.

Thanks again for your help.

div#slogan {
  background-color: white;
  margin-right: 5%;
  margin-left: 5%;
  display: flex;
  justify-content: space-around;
  align-items: center;
  padding: 4rem 2rem;
}

div#slogan .quote {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  flex: 50%;
  padding: 3rem 0;
  height: 300px;
}

.typewriter {
  padding-right: 10px;
  overflow: hidden;
  white-space: nowrap;
  border-right: 2px solid black;
  margin: 0 auto;
  animation: typing 4s steps(40, end), blink-caret 0.75s step-end infinite;
}

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

@keyframes blink-caret {
  from,
  to {
    border-color: transparent;
  }
  50% {
    border-color: black;
  }
}
<div id="slogan" data-aos="fade-up" data-aos-duration="1500">
        <div class="quote">
          <h3 class="typewriter">The best way to predict the future</h3>
          <h1>is to invent it.</h1>
          <h4>- Alan Kay</h4>

Upvotes: 0

Views: 634

Answers (2)

dale landry
dale landry

Reputation: 8600

You could set your keyframe animation to 50%. this would stop the cursor animation at 50% and not allow it to continue to the end of the elements width border.

@keyframes typing {
  from {
    width: 0;
  }
  to {
    width: 50%;
  }
}

The animation will stop once it runs keyframes at 50%.

The issue with the example below is that the percentage in the @keyframes of your elements text is not scalable using a hard set percentage of it relative to the width of its boundary and will need to be adjusted to the amount of width in percent that your text takes up each time new text is used, therefor it is not scalable.

div#slogan {
  background-color: white;
  margin-right: 5%;
  margin-left: 5%;
  display: flex;
  justify-content: space-around;
  align-items: center;
  padding: 4rem 2rem;
}

div#slogan .quote {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  flex: 50%;
  padding: 3rem 0;
  height: 300px;
}

.typewriter {
  padding-right: 10px;
  overflow: hidden;
  white-space: nowrap;
  border-right: 2px solid black;
  margin: 0 auto;
  animation: typing 4s steps(40, end), blink-caret 0.75s step-end infinite;
}

@keyframes typing {
  from {
    width: 0;
  }
  to {
    width: 50%;
  }
}

@keyframes blink-caret {
  from,
  to {
    border-color: transparent;
  }
  50% {
    border-color: black;
  }
}
<div id="slogan" data-aos="fade-up" data-aos-duration="1500">
        <div class="quote">
          <h3 class="typewriter">The best way to predict the future...</h3>
          <h1>...is to invent it.</h1>
          <h4>- Alan Kay</h4>

You could use Javascript to do this... Adopted from css tricks

Create a function that increments over your string and then prints out the characters like a typewriter using a setTimeout() function to print the characters with a delay.

Bonus: add a delay animation to display your h1 and h4 tags after the typing animation has finished.

var aText = new Array(
  "The best way to predict the future"
);
var iSpeed = 120; // time delay of print out
var iIndex = 0; // start printing array at this position
var iArrLength = aText[0].length; // the length of the text array
var iScrollAt = 20; // start scrolling up at this many lines

var iTextPos = 0; // initialize text position
var sContents = ''; // initialize contents variable
var iRow; // initialize current row
var invent = document.getElementById('invent');
var author = document.getElementById('author');

function typewriter() {
  sContents = ' ';
  iRow = Math.max(0, iIndex - iScrollAt);
  var destination = document.getElementsByClassName("typewriter")[0];
  invent.style.opacity = '0';
  author.style.opacity = '0';
  
  while (iRow < iIndex) {
    sContents += aText[iRow++] + '<br />';
  }
  destination.innerHTML = sContents + aText[iIndex].substring(-1, iTextPos);
  if (iTextPos++ == iArrLength) {
    iTextPos = 0;
    iIndex++;
    if (iIndex != aText.length) {
      iArrLength = aText[iIndex].length;
      setTimeout("typewriter()", 500);
    } else {
      setTimeout(function() {
        invent.style.transition = 'opacity 2s ease-in-out';
        invent.style.opacity = '1';
      }, 500);
      setTimeout(function() {
        author.style.transition = 'opacity 3s ease-in-out';
        author.style.opacity = '1';
      }, 800);
    }
  } else {
    setTimeout("typewriter()", iSpeed);
  }
}


typewriter();
div#slogan {
  background-color: white;
  margin-right: 5%;
  margin-left: 5%;
  display: flex;
  justify-content: space-around;
  align-items: center;
  padding: 4rem 2rem;
}

div#slogan .quote {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  flex: 50%;
  padding: 3rem 0;
  height: 300px;
}

.typewriter {
  padding-right: 10px;
  overflow: hidden;
  white-space: nowrap;
  border-right: 2px solid black;
  margin: 0 auto;
  animation: typing 4s steps(40, end), blink-caret 0.80s step-end infinite;
}

@keyframes blink-caret {
  from,
  to {
    border-color: transparent;
  }
  50% {
    border-color: black;
  }
}
<div id="slogan" data-aos="fade-up" data-aos-duration="1500">
  <div class="quote">
    <h3 class="typewriter"></h3>
    <h1 id="invent">is to invent it.</h1>
    <h4 id="author">- Alan Keys</h4>
  </div>
</div>

Upvotes: 2

Temani Afif
Temani Afif

Reputation: 272817

animate max-width instead of width

div#slogan {
  background-color: white;
  margin-right: 5%;
  margin-left: 5%;
  display: flex;
  justify-content: space-around;
  align-items: center;
  padding: 4rem 2rem;
}

div#slogan .quote {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  flex: 50%;
  padding: 3rem 0;
  height: 300px;
}

.typewriter {
  padding-right: 10px;
  overflow: hidden;
  white-space: nowrap;
  border-right: 2px solid black;
  margin: 0 auto;
  animation: typing 4s steps(40, end), blink-caret 0.75s step-end infinite;
}

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

@keyframes blink-caret {
  from,
  to {
    border-color: transparent;
  }
  50% {
    border-color: black;
  }
}
<div id="slogan" data-aos="fade-up" data-aos-duration="1500">
        <div class="quote">
          <h3 class="typewriter">The best way to predict the future</h3>
          <h1>is to invent it.</h1>
          <h4>- Alan Kay</h4>

Upvotes: 2

Related Questions