4
\$\begingroup\$

I am making a responsive horizontal scroll UI. The horizontal scroll position is calculated according to the mouse horizontal position:

$(document).ready(function() {
  var docWidth = $('body').width(),
    slidesWidth = $('#imgs').width(),
    rangeX = slidesWidth - docWidth,
    $images = $('#imgs');

  $(window).on('resize', function() {
    var docWidth = $('body').width(),
      slidesWidth = $('#imgs').width(),
      rangeX = slidesWidth - docWidth;
  })

  $(document).on('mousemove', function(e) {
    var mouseX = e.pageX,
      percentMouse = mouseX * 100 / docWidth,
      offset = percentMouse / 100 * slidesWidth - percentMouse / 200 * docWidth;

    $images.css({
      '-webkit-transform': 'translate3d(' + -offset + 'px,0,0)',
      'transform': 'translate3d(' + -offset + 'px,0,0)'
    });
  });
})
body,html {
  margin: 0;
  overflow: hidden;
  height: 100%;
}
#imgs {
  position: absolute;
  top: 0; left: 0;
  width: 150%; height: 100%;
  display: flex;
  justify-content: space-around;
  align-items: center;
  margin: 0 25%;
  /* transition: transform .1s; */
}
#imgs > div {
  max-width: 9%;
  perspective: 500px;
  z-index: 1;
}
#imgs img {
  display: block;
  max-width: 100%;
  height: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="imgs">
  <div><img src="https://farm9.staticflickr.com/8461/8048823381_0fbc2d8efb.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6217/6216951796_e50778255c.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6083/6055581292_d94c2d90e3.jpg" alt="" /></div>
  <div><img src="https://farm8.staticflickr.com/7187/6895047173_d4b1a0d798.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6139/5986939269_10721b8017.jpg" alt="" /></div>
  <div><img src="https://farm9.staticflickr.com/8461/8048823381_0fbc2d8efb.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6217/6216951796_e50778255c.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6083/6055581292_d94c2d90e3.jpg" alt="" /></div>
  <div><img src="https://farm8.staticflickr.com/7187/6895047173_d4b1a0d798.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6139/5986939269_10721b8017.jpg" alt="" /></div>
</div>

This works pretty well in the browsers I tested. And other than general performance enhancement I am concerned about this issue:
When the mouse comes out of the window and back in, the images snap to the new position. I tried to make that snap smoother with transition:transform .1s on the #imgs element (commented out in the CSS) but:

  • in chrome, it is a little janky
  • in Firefox and edge it is very janky even on small mouse moves
\$\endgroup\$
  • 1
    \$\begingroup\$ Have you tried -ms-transform: .1s; and -webkit-transform: .1s;? \$\endgroup\$ – Joshua Dawson May 25 '16 at 16:18
  • \$\begingroup\$ @JoshDawson the transform property doesn't take a time as value (developer.mozilla.org/en-US/docs/Web/CSS/transform) \$\endgroup\$ – web-tiki May 26 '16 at 7:41
  • \$\begingroup\$ Sorry @web-tiki, I meant transition: transform .1s \$\endgroup\$ – Joshua Dawson May 26 '16 at 15:37
  • \$\begingroup\$ @JoshDawson sorry but I still don't understand what you mean. Do you mean add prefixes on the transition or the transform property? \$\endgroup\$ – web-tiki May 27 '16 at 9:17
  • 1
    \$\begingroup\$ Sure. Also maybe `jquery.animate({ left: xxx}) might work better. \$\endgroup\$ – Joshua Dawson May 27 '16 at 15:38
4
\$\begingroup\$

Your project is looking great! But I have a few thoughts on how to improve the clarity of your javascript code:


Unused code

Your window.resize handler doesn't end up doing anything. Functions create a new scope for variables, so since you're redeclaring docWidth and slidesWidth with var, you don't actually affect the initially declared variables. The reason why all your code still works is that the body's width and the slide's width don't actually change when the window is resized. I'm not sure if this is different on mobile or even why the widths aren't changing (maybe it has something to do with your css) but you ought to either change the handler to something like:

$(window).on('resize', function() {
  docWidth = $('body').width();
  slidesWidth = $images.width(); // stay consistent with this variable
  rangeX = slidesWidth - docWidth;
})

Or just remove it to prevent confusion if the widths aren't affected by resizing.

You also don't end up using rangeX in your code. Consider removing it.


More straightforward calculation

I think you could simplify the way you calculate the offset in your document.mousemove handler by eliminating the mousePercent variable:

$(document).on('mousemove', function(e) {
  var mouseX = e.pageX,
    offset = mouseX / docWidth * slidesWidth - mouseX / 2;

  $images.css({
    '-webkit-transform': 'translate3d(' + -offset + 'px,0,0)',
    'transform': 'translate3d(' + -offset + 'px,0,0)'
  });
});

This way you don't multiply by 100 and then divide by it right after, and you also have fewer variables to worry about.


Unnecessary functionality

You don't use the 3d aspect of translate so why not just use the 2d version:

$images.css({
  '-o-transform': 'translate(' + -offset + 'px, 0)', // opera 11.5
  '-ms-transform': 'translate(' + -offset + 'px, 0)', // IE9
  '-moz-transform': 'translate(' + -offset + 'px, 0)', // firefox 3.5-15
  '-webkit-transform': 'translate(' + -offset + 'px, 0)',
  'transform': 'translate(' + -offset + 'px,0)'
});

More concise and direct jquery syntax

Another option would be to use jquery's built in methods for creating events instead of using on:

$(document).ready(function() {
  var docWidth = $('body').width(),
    slidesWidth = $('#imgs').width(),
    rangeX = slidesWidth - docWidth,
    $images = $('#imgs');

  $(window).resize(function() {
    var docWidth = $('body').width(),
      slidesWidth = $('#imgs').width(),
      rangeX = slidesWidth - docWidth;
  })

  $(document).mousemove(function(e) {
    var mouseX = e.pageX,
      percentMouse = mouseX * 100 / docWidth,
      offset = percentMouse / 100 * slidesWidth - percentMouse / 200 * docWidth;

    $images.css({
      '-webkit-transform': 'translate3d(' + -offset + 'px,0,0)',
      'transform': 'translate3d(' + -offset + 'px,0,0)'
    });
  });
});

Once again, great work so far! I wish I could have helped more with the snapping issue. I have a few ideas--mouseenter, jquery.stop().animate()--but none that are fully developed. Good luck figuring it out!

\$\endgroup\$
  • \$\begingroup\$ Thx for your review. I added your suggestions to the codepen, it does make the JS clearer and shorter. \$\endgroup\$ – web-tiki May 28 '16 at 9:20
2
\$\begingroup\$

This seems to work in IE and FF:

  transition: transform .1s; /* default */
  -webkit-transition: transform .1s; /* Webkit browsers (safari...) */
  -moz-transition: transform .1s; /* Mozilla browsers (Firefox) */
  -o-transition: transform .1s; /* Opera browser */
  -ms-transition: transform .1s; /* Microsoft browsers (IE...) */

I don't have other browsers to test this on but according to Can I use...:

transform browser support

$(document).ready(function() {
  var docWidth = $('body').width(),
    slidesWidth = $('#imgs').width(),
    rangeX = slidesWidth - docWidth,
    $images = $('#imgs');

  $(window).on('resize', function() {
    var docWidth = $('body').width(),
      slidesWidth = $('#imgs').width(),
      rangeX = slidesWidth - docWidth;
  })

  $(document).on('mousemove', function(e) {
    var mouseX = e.pageX,
      percentMouse = mouseX * 100 / docWidth,
      offset = percentMouse / 100 * slidesWidth - percentMouse / 200 * docWidth;

    $images.css({
      '-webkit-transform': 'translate3d(' + -offset + 'px,0,0)',
      'transform': 'translate3d(' + -offset + 'px,0,0)'
    });
  });
})
body,html {
  margin: 0;
  overflow: hidden;
  height: 100%;
}
#imgs {
  position: absolute;
  top: 0; left: 0;
  width: 150%; height: 100%;
  display: flex;
  justify-content: space-around;
  align-items: center;
  margin: 0 25%;
  transition: transform .1s; /* default */
  -webkit-transition: transform .1s; /* Webkit browsers (safari...) */
  -moz-transition: transform .1s; /* Mozilla browsers (Firefox) */
  -o-transition: transform .1s; /* Opera browser */
  -ms-transition: transform .1s; /* Microsoft browsers (IE...) */
}
#imgs > div {
  max-width: 9%;
  perspective: 500px;
  z-index: 1;
}
#imgs img {
  display: block;
  max-width: 100%;
  height: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="imgs">
  <div><img src="https://farm9.staticflickr.com/8461/8048823381_0fbc2d8efb.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6217/6216951796_e50778255c.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6083/6055581292_d94c2d90e3.jpg" alt="" /></div>
  <div><img src="https://farm8.staticflickr.com/7187/6895047173_d4b1a0d798.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6139/5986939269_10721b8017.jpg" alt="" /></div>
  <div><img src="https://farm9.staticflickr.com/8461/8048823381_0fbc2d8efb.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6217/6216951796_e50778255c.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6083/6055581292_d94c2d90e3.jpg" alt="" /></div>
  <div><img src="https://farm8.staticflickr.com/7187/6895047173_d4b1a0d798.jpg" alt="" /></div>
  <div><img src="https://farm7.staticflickr.com/6139/5986939269_10721b8017.jpg" alt="" /></div>
</div>

\$\endgroup\$
  • \$\begingroup\$ Thx for the answer but 1. My target audience will only require the -webkit- prefix (-moz- stopped at FF15 and -o- is only for opera 11.5) 2. -ms-transition has never existed 3. As I said in my question the transition property doesn't work in FF (very janky) and chrome doesn't handle it very well either. \$\endgroup\$ – web-tiki May 26 '16 at 7:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.