Наверное многие программеры сталкивались с такой фигней, когда надо повесить, например, анимацию на кнопку, которая состоит из нескольких слоев (включая текстовый заголовок). Если слои вложены друг в друга по простому, без всяких position:relative и position:absolute, то делается это довольно-таки просто. Но как быть, если кнопка имеет неопределенную форму, и дочерние слои, например, вылазят за границы кнопки?
Самый простой метод, без выноса мозга, это перекрыть все слои одним верхним, прозрачным, и на него повесть все события. И в большинстве вариантов верстки таких кнопок это проходит на ура.. Но, все-таки, бывают случаи, когда «эстетическая» красота интерфейса очень важна. Например, ссылка под кнопкой должна откликаться отдельно (как ссылка), но в то же время подсвечивать всю кнопку.
Превью скрипта и полный исходник примера под катом.
var f = function() { var items = []; /* ---------- place your code below -------------- */ /* --------- and replace this example ------------ */ //here construct the array with your buttons items.push({button: document.getElementById("my-hover-btn")}); //--------------------------- var item; //here find and push to this array elements for your animation for (var c in items) { if (!items.hasOwnProperty(c)) continue; item = items[c]; item.bg = $(item.button).find(".bg")[0]; item.link = $(item.button).find(".title")[0]; //here define the callback function for your animation which will handle //"on", "off" and "stop" conditions and pass doneCb to jQuery item.animate = function(cond, doneCb) { switch(cond) { case "on": $(item.bg).animate({opacity: 1}, 300, doneCb); $(item.link).animate({color: "#f26522"}, 300); break; case "off": $(item.bg).animate({opacity: 0}, 300, doneCb); $(item.link).animate({color: "#000"}, 300); break; default://stop $(item.bg).stop(true, true); $(item.link).stop(true, true); } }; } /* ------------------------------------------------ */ return items; }; (function(f) { var ct = 0;//current try var mt = 200;//max try count var it = 300;//retry timeout var jc = "jquery/jquery.color.js"; var jq = "jquery/jquery-1.10.2.min.js"; var h = document.getElementsByTagName("HEAD")[0]; var i = window.setInterval(function() { ct++; if (ct > mt) { window.clearInterval(i); return } var r; if (typeof $ == "undefined") { if (jq) { r = document.createElement("SCRIPT"); r.type = "text/javascript"; r.async = true; r.src = jq; h.appendChild(r); jq = ""; } return; } if (jc) { for (var c in h.childNodes) { if ((typeof h.childNodes[c].tagName != "undefined") && (h.childNodes[c].tagName == "SCRIPT") && h.childNodes[c].src) { if (h.childNodes[c].src.indexOf("jquery.color.js") != -1) { jc = ""; break; } } } if (!jc) return; r = document.createElement("SCRIPT"); r.type = "text/javascript"; r.async = true; r.src = jc; h.appendChild(r); jc = ""; return; } window.clearInterval(i); //snippet worker var proc = function(items) { var apply = function(item, cond) { if (cond == "on") { if ((item.state == 1) || (item.state == 2)) return; if (item.state == 3) item.animate(""); item.animate("on", item.done); item.state = 1; } else { if ((item.state == 0) || (item.state == 3)) return; if (item.state == 1) item.animate(""); item.animate("off", item.done); item.state = 3; } }; var done = function() { this.state = 3 - this.state; }; var fover = function(item) { var rel = arguments[1].relatedTarget ? arguments[1].relatedTarget : arguments[1].fromElement; if (rel && isButton(rel, item.button)) return; apply(item, "on"); }; var fout = function(item) { var rel = arguments[1].relatedTarget ? arguments[1].relatedTarget : arguments[1].toElement; if (rel && isButton(rel, item.button)) return; apply(item, "off"); }; var isButton = function(node, parent) { if (typeof node != "object" || (typeof node.parentNode == "undefined")) return false; if ((typeof parent != "object") || (typeof node.childNodes == "undefined")) return false; var res = $(parent).find(node); if (typeof res[0] != "undefined") return true; return false; }; var start = function(items) { for (var c in items) { if (!items.hasOwnProperty(c)) continue; var item = items[c]; $(item.button).mouseover(fover.bind(fover, item)); $(item.button).mouseout(fout.bind(fout, item)); item.done = done.bind(item); item.state = 0; } }; start(items); }; proc(f()); }, 300); })(f);