JSFiddle - React, Tailwind, and code Playground

by Miklos Nagy

HTML

<div class="bg">
<div class="fg">

</div>
</div>

CSS

.bg {
  width: 500px;
  height: 300px;
  position: relative;
  background: url(http://www.raywhite.com.lb/wp-content/uploads/2015/03/loremipsumtext.jpg);
}
.fg {
  position: absolute;
  left: 0px;
  top: 0px;
  width: 180px;
  height: 80px;
  border: 1px solid white;
  background: url(http://typostrate.com/wp-content/uploads/2013/07/tumblr_mpeitohQzd1qgnue7o2_r1_1280.jpg);
  background-position: 0px 0px;
}

JavaScript

// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          function( callback ){
            window.setTimeout(callback, 1000 / 60);
          };
})();

(function(d, w){
	var $bg = d.querySelector('.bg');
	var $fg = d.querySelector('.fg');
  var rect = $bg.getBoundingClientRect(),
  		fgRect = $fg.getBoundingClientRect(),
  		width = Math.round(fgRect.width/2), 
      height = Math.round(fgRect.height/2),
      maxTop = rect.bottom - height,
      maxLeft = rect.right - width;
  var raf = w.requestAnimFrame;
  
  $bg.addEventListener('mousemove', function(e){
  	var x = Math.min(e.clientX, maxLeft), 
    	 	y = Math.min(e.clientY, maxTop);
    var relativePos = [Math.max(0,x-rect.left-width)+'px',Math.max(0, y-rect.top-height)+'px'];
    raf(function(){
    	$fg.style.transform = 'translate(' + relativePos.join(', ')+')';
    	$fg.style.backgroundPosition = '-'+relativePos.join(' -');
    })
  })
})(document, window)