JueK3y
JueK3y

Reputation: 317

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?

Upvotes: 0

Views: 1365

Answers (1)

vanowm
vanowm

Reputation: 10201

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>

Upvotes: 1

Related Questions