Посмотри еще на такой вариант
https://css-tricks.com/examples/MagicLine/
P.S. Если говорить о том, как это происходит, то вот код из указанного источника:
(function($) {
'use strict';
var globals = {
mobileWindowWidth: 100,
images: []
};
var oldAnim = $.fn.animate;
$.fn.animate = function(prop) {
if ('background-position' in prop) {
prop.backgroundPosition = prop['background-position'];
delete prop['background-position'];
}
if ('backgroundPosition' in prop) {
prop.backgroundPosition = '(' + prop.backgroundPosition + ')';
}
return oldAnim.apply(this, arguments);
};
function toArray(strg) {
strg = strg.replace(/left|top/g, '0px');
strg = strg.replace(/right|bottom/g, '100%');
strg = strg.replace(/([0-9\.]+)(\s|\)|$)/g, "$1px$2");
var res = strg.match(/(-?[0-9\.]+)(px|\%|em|pt)\s(-?[0-9\.]+)(px|\%|em|pt)/);
return [parseFloat(res[1], 10), res[2], parseFloat(res[3], 10), res[4]];
}
$.fx.step.backgroundPosition = function(fx) {
if (!fx.bgPosReady) {
var start = $.curCSS(fx.elem, 'backgroundPosition');
if (!start) { //FF2 no inline-style fallback
start = '0px 0px';
}
start = toArray(start);
fx.start = [start[0], start[2]];
var end = toArray(fx.end);
fx.end = [end[0], end[2]];
fx.unit = [end[1], end[3]];
fx.bgPosReady = true;
}
var nowPosX = [];
nowPosX[0] = ((fx.end[0] - fx.start[0]) * fx.pos) + fx.start[0] + fx.unit[0];
nowPosX[1] = ((fx.end[1] - fx.start[1]) * fx.pos) + fx.start[1] + fx.unit[1];
fx.elem.style.backgroundPosition = nowPosX[0] + ' ' + nowPosX[1];
};
$(function() {
var $navMarker = $('<span class="navMarker"></span>').appendTo('.siteNav'),
$initElement = $('.siteNav > ul > li > a.active').length !== 0 ? $('.siteNav > ul > li > a.active').parent() : $('.siteNav > ul > li:first-child > a').parent(),
isCurrent = $('.siteNav > ul > li a.active').length !== 0,
initIndex = $('.siteNav > ul > li').index($initElement),
$hatNav = $('.hatNav'),
$window = $(window),
getMarkerCSS = function($el, idx, isCurrent) {
return {
'left': $el.position().left + parseInt($el.children("a").css('padding-left')) + 'px',
'top': $el.height() + $el.position().top + parseInt($el.css("padding-top")) + 'px',
'width': $el.width() - 20 + 'px',
'opacity': isCurrent ? 1 : 0,
'background-position': '-' + idx * 200 + 'px 0'
};
},
$siteHeader = $('.siteHeader');
$navMarker.css(getMarkerCSS($initElement, initIndex, isCurrent));
$('.siteNav > ul > li').on('mouseenter', function(e) {
if ($(window).width() > globals.mobileWindowWidth) {
var $this = $(this),
index = $('.siteNav > ul > li').index($this);
$navMarker.stop().animate(getMarkerCSS($this, index, true));
$this.children("ul").children("li").each(function(idx) {
$(this).stop(true, true).delay(100 * idx).fadeIn();
});
}
}).on('mouseleave', function() {
if ($(window).width() > globals.mobileWindowWidth) {
var $this = $(this);
$this.children("ul").children("li").stop(true, true).fadeOut();
}
}).find("a").on('touchstart', function(e) {
//e.preventDefault();
});
$('.siteNav').on('mouseleave', function(e) {
if (isCurrent) {
$navMarker.stop().animate(getMarkerCSS($initElement, initIndex, isCurrent));
} else {
$navMarker.stop().animate({
'opacity': 0
});
}
});
});
$(window).on({
resize: function() {
if ($(window).width() <= globals.mobileWindowWidth) {
$(".siteNav li ul li").show();
} else {
$(".siteNav").removeClass("hover").find("li ul li").hide();
}
}
});
}(jQuery));