Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I move (animate) an element from left to right while I scroll down with CSS and JS?

I have an image of an train sitting at the bottom base of a container that I'd like to move from the left edge of the browser and into the right edge while I scroll down.

The train shouldn't be visible when the page loads and should only start moving when I start scrolling down.

EDIT: If I scroll back up, the train should move backwards to its original position. As I understand it, this kind of motion is called Parallax.

I really have no idea how to achieve that in either CSS or jQuery.

Can someone please tell me what is the best to achieve this, with either pure CSS or a jQuery plugin.

DEMO https://jsfiddle.net/vq2tpavn/4/

HTML

<section id="first-section">
  <div class="container">
    <div class="row">
      <div class="col-md-12">
        <p class="text-center">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam fringilla diam quis turpis eleifend, ac molestie diam consectetur. In at augue tellus. Pellentesque efficitur efficitur nisl, suscipit blandit mauris. Quisque consectetur tincidunt suscipit. Nullam fermentum dictum quam vel volutpat. Phasellus eleifend molestie neque id varius. Aenean convallis ornare nisi vitae blandit. Phasellus imperdiet, diam vel congue blandit, quam felis vehicula tellus, eget lacinia dui quam vel metus. Proin eleifend volutpat magna et convallis. Nam pharetra, orci eu aliquet efficitur, turpis leo consequat purus, sed fringilla metus arcu ac elit.</p>

        <div id="trainMotion">
          <img src="http://i.imgur.com/uKxkshD.png" alt="Train" class="train">
        </div>
      </div>
    </div>
  </div>
</section>

<section id="second-section">
  <div class="container">
    <div class="row">
      <p class="text-center">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam fringilla diam quis turpis eleifend, ac molestie diam consectetur. In at augue tellus. Pellentesque efficitur efficitur nisl, suscipit blandit mauris. Quisque consectetur tincidunt suscipit. Nullam fermentum dictum quam vel volutpat. Phasellus eleifend molestie neque id varius. Aenean convallis ornare nisi vitae blandit. Phasellus imperdiet, diam vel congue blandit, quam felis vehicula tellus, eget lacinia dui quam vel metus. Proin eleifend volutpat magna et convallis. Nam pharetra, orci eu aliquet efficitur, turpis leo consequat purus, sed fringilla metus arcu ac elit.</p>
    </div>
  </div>
</section>

<section id="third-section">
  <div class="container">
    <div class="row">
      <p class="text-center">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam fringilla diam quis turpis eleifend, ac molestie diam consectetur. In at augue tellus. Pellentesque efficitur efficitur nisl, suscipit blandit mauris. Quisque consectetur tincidunt suscipit. Nullam fermentum dictum quam vel volutpat. Phasellus eleifend molestie neque id varius. Aenean convallis ornare nisi vitae blandit. Phasellus imperdiet, diam vel congue blandit, quam felis vehicula tellus, eget lacinia dui quam vel metus. Proin eleifend volutpat magna et convallis. Nam pharetra, orci eu aliquet efficitur, turpis leo consequat purus, sed fringilla metus arcu ac elit.</p>
    </div>
  </div>
</section>

CSS

*,
*:after,
*::before {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
html, body {
    width: 100%;
    height: 100%;
}
body {
    background-color: #191617;
}
section {
    padding: 130px 0;
}
section::before,
section::after {
    position: absolute;
    content: '';
    pointer-events: none;
}
#first-section {
    background-color: #dcdbdc;
    font-family: 'Oswald', sans-serif;
    font-size: 18px;
    font-weight: 300;
    line-height: 3rem;
}
#second-section {
    background-color: #f1646a;
    color: white;
    font-family: 'Oswald', sans-serif;
    font-size: 18px;
    font-weight: 300;
    line-height: 3rem;
}
#third-section {
    background-color: lightblue;
    color: white;
    font-family: 'Oswald', sans-serif;
    font-size: 18px;
    font-weight: 300;
    line-height: 3rem;
}

.train {
    display: block;
    max-width: 100%;
    position: absolute;
    bottom: -70px;
    opacity: 1;
    transition: all 0.9s ease-out;
    transform: translate(-50%, 100%);
}
like image 612
Halnex Avatar asked Mar 25 '17 01:03

Halnex


3 Answers

Check out this fiddle: https://jsfiddle.net/TimothyKanski/vq2tpavn/8/

You can get total page height and current scroll using some jquery methods. Then, I would imagine, you just need to use those values to get a percent, and move the train.

var current = $(window).scrollTop();
var total = $(window).height() - current;
var ele = $(".train");
var currPosition = ele.position().left + 320;
var trackLength = 300;
$(window).scroll(function (event) {
    current = $(window).scrollTop();
    var newPosition = trackLength * (current/total)
    ele.css({left:currPosition+newPosition+'px'});
});

EDIT:

To get the train to NOT cause a horizontal scrollbar, put overflow: hidden; in the css for Section:

Section{
  ...
  overflow: hidden;
}
like image 198
Timothy Kanski Avatar answered Oct 25 '22 16:10

Timothy Kanski


Maybe this could help:

https://jsfiddle.net/vq2tpavn/9/

I have amended your original Fiddle to translate the train from left to right based on your scroll position relative to the window height.

$(window).on('scroll',function(){
    var trainPosition = Math.round($(window).scrollTop() / $(window).height() * 100);
    $('.train').css('transform','translateX('+(trainPosition-50)+'%)');

});

The -50 is there in the application to match the translateX(-50%) you already had in the CSS.

like image 23
rorymorris89 Avatar answered Oct 25 '22 17:10

rorymorris89


Here's a minimally invasive version of your fiddle: https://jsfiddle.net/vq2tpavn/6/

JavaScript

var windowHeight =  Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
    train = document.getElementById('trainMotion');

window.addEventListener('scroll', function(event) {
      var offset = train.getBoundingClientRect().top - windowHeight;

      if (offset > 0) {
        train.classList.remove('choochoo');
        return;
      }

      if (train.className.indexOf('choocho') === -1) {
        train.classList.add('choochoo');
      }
});

Additional CSS

#trainMotion img {
    transform: translate(-50%, 0%);
}

#trainMotion.choochoo img {
    transition: all 0.9s ease-out;
    transform: translate(0%, 0%);
}

As a minor adaption, I moved the whole #trainMotion outside of the section (calculating the absolute position offsets within the padding relative to the window height was doing my head in at 3am).

(I haven't checked it for cross-browser compatibility - but in Chrome it works fine)


UPDATE (to reflect train going in both directions)

aka: This is a very poor mans parallax.

Here's the Fiddle: https://jsfiddle.net/vq2tpavn/12/

JavaScript

var windowHeight =  Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
    lastTop;

window.addEventListener('scroll', function(event) {
  var train = document.getElementById('trainMotion'),
      top = train.getBoundingClientRect().top,
      offset = top - windowHeight;

      if (offset > 0) {
        train.classList.remove('choochoo');
        return;
      }

      if (top < windowHeight / 2 && top > lastTop) {
        train.classList.remove('choochoo');
      }

      if (train.className.indexOf('choocho') === -1 && top < lastTop) {
        train.classList.add('choochoo');
      }

      lastTop = top;

});

CSS

#trainMotion img {
    transform: translate(-50%, 0%);
    transition: all 1s ease-out;
}

#trainMotion.choochoo img {
    transform: translate(0%, 0%);
}

HTML ...

<div id="trainMotion">
    <img src="http://i.imgur.com/uKxkshD.png" alt="Train">
</div>

<section id="second-section">
    ...
like image 33
Anna Fohlmeister Avatar answered Oct 25 '22 15:10

Anna Fohlmeister