Create a wiggle effect for a text

1.5k views Asked by At

So what I want to happen is that when viewing the Span the text is normal but as you scroll down it starts moving until it looks like such:

Before the effect:
Before the effect

While the effect occurs:
While the effect occurs

The header is represented by spans for each letter. In the initial state, the top pixel value for each is 0. But the idea as mentioned is that that changes alongside the scroll value.

I wanted to keep track of the scroll position through JS and jQuery and then change the pixel value as needed. But that's what I have been having trouble with. Also making it smooth has been another issue.

2

There are 2 answers

7
Mihailo On BEST ANSWER

Something like this will be the core of your JS functionality:

window.addEventListener('scroll', function(e) {
  var scrl = window.scrollY

  // Changing the position of elements that we want to go up
  document.querySelectorAll('.up').forEach(function(el){
    el.style.top = - scrl/30 +'px';
  });

  // Changing the position of elements that we want to go down
  document.querySelectorAll('.down').forEach(function(el){
    el.style.top = scrl/30 +'px';
  });
});

We're basically listening in on the scroll event, checking how much has the user scrolled and then act upon it by offsetting our spans (which i've classed as up & down)

JSBin Example

Something you can improve on yourself would be making sure that the letters wont go off the page when the user scrolls a lot.
You can do this with simple math calculation, taking in consideration the window's total height and using the current scrollY as a multiplier.

- As RokoC has pointed out there is room for performance improvements.
Implement some debouncing or other kinds of limiters

0
clabe45 On

Use the mathematical functions sine and cosine, for characters at even and odd indices respectively, as the graphs of the functions move up and down like waves. This will create a smooth effect:

Sine and cosine graphs

cos(x) == 1 - sin(x), so in a sense, each character will be the "opposite" of the next one to create that scattered look:

function makeContainerWiggleOnScroll(container, speed = 0.01, distance = 4) {
  let wiggle = function() {
    // y-axis scroll value
    var y = window.pageYOffset || document.body.scrollTop;
    // make div pseudo-(position:fixed), because setting the position to fixed makes the letters overlap
    container.style.marginTop = y + 'px';
    for (var i = 0; i < container.children.length; i++) {
      var span = container.children[i];
      // margin-top = { amplitude of the sine/cosine function (to make it always positive) } + { the sine/cosine function (to make it move up and down }
      // cos(x) = 1 - sin(x)
      var trigFunc = i % 2 ? Math.cos : Math.sin;
      span.style.marginTop = distance + distance * trigFunc(speed * y)/2 + 'px';
    }

  };
  window.addEventListener('scroll', wiggle);
  wiggle(); // init
}

makeContainerWiggleOnScroll(document.querySelector('h2'));
body {
  height: 500px;
  margin-top: 0;
}
span {
  display: inline-block;
  vertical-align: top;
}
<h2>
  <span>H</span><span>e</span><span>a</span><span>d</span><span>e</span><span>r</span>
</h2>

Important styling note: the spans' display must be set to inline-block, so that margin-top works.