javascripthtmlcsscss-animationsblurry

Blurry text animation in CSS


When I was looking at examples of three.js I came across the page of Lusion.
The title heading "Realise your creative ideas" has an animation which displays the text first blurry and then clear.
I tried to reproduce this:

@keyframes test {
  from {
    opacity: 0;
    visibility: hidden;
    filter: blur(0.2ex);
  }
  to {
    opacity: 1;
    visibility: visible;
    filter: blur(0ex);
  }
}

body p {
  font-size: 32px;
  text-align: center;
}

body #one {
  animation: test 2.6s linear;
}

body #two {
  animation: test 2s linear;
}

body #three {
  animation: test 1.5s linear;
}

body #four {
  animation: test 2s linear;
}

body #five {
  animation: test 2.6s linear;
}
<p>
  <span id="one">T</span>
  <span id="two">i</span>
  <span id="three">t</span>
  <span id="four">l</span>
  <span id="five">e</span>
</p>

But the whole thing is a bit annoying, because you have to do it for every single letter.
Besides, my result doesn't look as good as Lusion's.

Is it possible to do it easier / better? Maybe with a JS library (maybe three.js)?
Or is the only solution the way via CSS keyframes?


Solution

  • Using javascript:

    "use strict";
    document.addEventListener("DOMContentLoaded", e => 
    {
      randBlur(document.getElementsByClassName("randBlur"));
      setTimeout(()=>randBlur([document.getElementById("delayed")]), 3000);
    });
    
    function randBlur(els, randDurationMin, randDurationMax)
    {
      if (!els)
        return;
    
      if (randDurationMin === undefined)
        randDurationMin = 0.7; //min animation duration (in sec)
    
      if (randDurationMax === undefined)
        randDurationMax = 1.7; //min animation duration (in sec)
    
      if (randBlur.list === undefined)
      {
        randBlur.style = document.createElement("style");
        document.head.appendChild(randBlur.style);
        randBlur.list = {};
        randBlur.applyStyle = () =>
        {
          randBlur.style.innerHTML = "";
          for(let i in randBlur.list)
            randBlur.style.textContent += '[randBlur="' + i + '"]{animation:randblur ' + i + 's linear}';
        }
      }
    
      const span = document.createElement("span"),
            text = document.createTextNode(""),
            rand = () =>
            {
              const duration = parseFloat((Math.random() * (randDurationMax - randDurationMin) + randDurationMin).toFixed(2));
              randBlur.list[duration] = "";
              return duration;
            },
            randBlurChildren = el =>
            {
              if (el.nodeType == el.TEXT_NODE)
              {
                for(let n = 0, ws, box; n < el.textContent.length; n++)
                {
                  ws = el.textContent[n].match(/\s/);
                  box = (ws ? text : span).cloneNode(false);
                  box.textContent = el.textContent[n];
                  if (!ws)
                  {
                    box.setAttribute("randBlur", rand());
                  }
                  el.parentNode.insertBefore(box, el);
                }
                el.parentNode.removeChild(el);
              }
              else
              {
                const children = Object.assign([], el.childNodes);
                for(let c = 0; c < children.length; c++)
                {
                  if (!children[c].hasAttribute || !children[c].hasAttribute("randBlur"))
                    randBlurChildren(children[c]);
                    
                }
              }
            };
    
      for (let i = 0; i < els.length; i++)
        randBlurChildren(els[i]);
    
      randBlur.applyStyle();
    }
    @keyframes randblur {
      from {
        opacity: 0;
        visibility: hidden;
        filter: blur(0.2ex);
      }
      to {
        opacity: 1;
        visibility: visible;
        filter: blur(0ex);
      }
    }
    
    body {
      font-size: 1.1em;
      text-align: center;
    }
    
    h2,h3
    {
      display: inline;
    }
    
    h2
    {
      color: green;
    }
    
    p
    {
      white-space: pre;
    }
    <p class="randBlur">&lt;P&gt; element with юникод text 😎
    and whitespaces</p>
    <span class="randBlur">Even <h3> elements with <h2>children</h2></h3> animated.</span>
    <span id="delayed">Can be applied at any time, but only once</span>
    <h1 class="randBlur">Practically any HTML tag can be used</h1>