http://codepen.io/leongaban/pen/YNBgqE
After you scroll the #tickers-col how do you get the correct updated top position of the div?
From the log no matter how far up the column goes, it still displays the original y position of the div:
colPos Object {x: 8, y: 8}
const tickersCol = document.getElementById("tickers-col");
// https://stackoverflow.com/questions/288699/get-the-position-of-a-div-span-tag
function getPos(el) {
for (var lx=0, ly=0;
el != null;
lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent);
return {x: lx,y: ly};
}
function mouseHover() {
const colPos = getPos(tickersCol);
console.log('colPos', colPos)
}
.container {
position: fixed;
font-family: Arial;
}
#tickers-col {
overflow-y: auto;
height: 400px;
}
li {
margin-bottom: 10px;
list-style: none;
padding: 5px 10px;
width: 120px;
color: white;
background: salmon;
border-radius: 4px;
cursor: pointer;
}
<div class="container">
<div id="tickers-col">
<ul>
<li onmouseenter="mouseHover()">aaa</li>
<li onmouseenter="mouseHover()">bbb</li>
<li onmouseenter="mouseHover()">ccc</li>
<li onmouseenter="mouseHover()">ddd</li>
<li onmouseenter="mouseHover()">eee</li>
<li onmouseenter="mouseHover()">fff</li>
<li onmouseenter="mouseHover()">ggg</li>
<li onmouseenter="mouseHover()">hhh</li>
<li onmouseenter="mouseHover()">iii</li>
<li onmouseenter="mouseHover()">jjj</li>
<li onmouseenter="mouseHover()">kkk</li>
<li onmouseenter="mouseHover()">lll</li>
<li onmouseenter="mouseHover()">mmm</li>
<li onmouseenter="mouseHover()">nnn</li>
<li onmouseenter="mouseHover()">ooo</li>
<li onmouseenter="mouseHover()">ppp</li>
<li onmouseenter="mouseHover()">qqq</li>
<li onmouseenter="mouseHover()">rrr</li>
<li onmouseenter="mouseHover()">sss</li>
<li onmouseenter="mouseHover()">ttt</li>
<li onmouseenter="mouseHover()">uuu</li>
<li onmouseenter="mouseHover()">vvv</li>
<li onmouseenter="mouseHover()">www</li>
<li onmouseenter="mouseHover()">yyy</li>
<li onmouseenter="mouseHover()">xxx</li>
<li onmouseenter="mouseHover()">zzz</li>
</ul>
</div>
</div>
Found the getPos function from here: Get the position of a div/span tag
So, I really don't understand what exactly you are trying to do but by definition the offsetTop property of an element will return the top position (in pixels) relative to the top of the offsetParent element.
So no matter how long you scroll, if the top distance between the element you are inspecting and it's parent does't change, your top value will not change.
Maybe the property you are looking for is scrollTop;
const getPos = (el) => {
for (var lx=0, ly=0;
el != null;
lx += el.offsetLeft, ly += el.scrollTop, el = el.offsetParent);
return { x:lx, y:ly };
}
Try the code blow.
Scroll and then hover on one of the divs, you can see the y-coordinate is getting updated.
const tickersCol = document.getElementById("tickers-col");
const getPos = (el) => {
for (var lx=0, ly=0;
el != null;
lx += el.offsetLeft, ly += el.scrollTop, el = el.offsetParent);
return { x:lx, y:ly };
}
function mouseHover() {
const colPos = getPos(tickersCol);
console.log('colPos', colPos)
}
.container {
position: fixed;
font-family: Arial;
}
#tickers-col {
overflow-y: auto;
height: 400px;
}
li {
margin-bottom: 10px;
list-style: none;
padding: 5px 10px;
width: 120px;
color: white;
background: salmon;
border-radius: 4px;
cursor: pointer;
}
<div class="container">
<div id="tickers-col">
<ul>
<li onmouseenter="mouseHover()">aaa</li>
<li onmouseenter="mouseHover()">bbb</li>
<li onmouseenter="mouseHover()">ccc</li>
<li onmouseenter="mouseHover()">ddd</li>
<li onmouseenter="mouseHover()">eee</li>
<li onmouseenter="mouseHover()">fff</li>
<li onmouseenter="mouseHover()">ggg</li>
<li onmouseenter="mouseHover()">hhh</li>
<li onmouseenter="mouseHover()">iii</li>
<li onmouseenter="mouseHover()">jjj</li>
<li onmouseenter="mouseHover()">kkk</li>
<li onmouseenter="mouseHover()">lll</li>
<li onmouseenter="mouseHover()">mmm</li>
<li onmouseenter="mouseHover()">nnn</li>
</ul>
</div>
</div>
Let me know if this is what you wanted.
After you scroll the #tickers-col how do you get the correct updated top position of the div?
div itself isn't moving when scrolling, instead only its direct children are moving.
So top position is : #ticker-col's offsetTop - ul's scrollTop , and your js code should look like this:
(function(){
var tc = document.querySelector("#tickers-col");
tc.addEventListener("scroll",function(){
console.log("colPos:", { x : tc.parentNode.offsetLeft,
y : tc.parentNode.offsetTop - tc.scrollTop,
});
});
})();
.container {
position: fixed;
font-family: Arial;
}
#tickers-col {
overflow-y: auto;
height: 400px;
}
li {
margin-bottom: 10px;
list-style: none;
padding: 5px 10px;
width: 120px;
color: white;
background: salmon;
border-radius: 4px;
cursor: pointer;
}
<div class="container">
<div id="tickers-col">
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
<li>ddd</li>
<li>eee</li>
<li>fff</li>
<li>ggg</li>
<li>hhh</li>
<li>iii</li>
<li>jjj</li>
<li>kkk</li>
<li>lll</li>
<li>mmm</li>
<li>nnn</li>
<li>ooo</li>
<li>ppp</li>
<li>qqq</li>
<li>rrr</li>
<li>sss</li>
<li>ttt</li>
<li>uuu</li>
<li>vvv</li>
<li>www</li>
<li>yyy</li>
<li>xxx</li>
<li>zzz</li>
</ul>
</div>
</div>
P.S.
onmouseenter="mouseHover()"
this thing looks ugly, if you need to set the same function for some number of elements > 2 as event listener the better approach would be like so
var collection =
Array.prototype.slice.call(
document.querySelectorAll('mycssselector')
).forEach(function(el){
el.addEventListener("myevent",/*callback*/function(){});
});
Right now my program can dynamically create rows of squares (2 rows of 12). When you double click on one of the squares, a color picker will pop up and then you can specify the color for that square.
However, I am trying to also implement a "shortcut" so that if you drag an already colored square onto another one, that new square will also be colored.
What I have done so far:
http://codepen.io/blazerix/pen/rrwPAK
var id_num = 1;
var picker = null;
$(function () {
$(document).on('click', ".repeat", function (e) {
e.preventDefault();
var $self = $(this);
var $parent = $self.parent();
if($self.hasClass("add-bottom")){
$parent.after($parent.clone(true).attr("id", "repeatable" + id_num));
id_num = id_num + 1;
//picker = null;
} else {
$parent.before($parent.clone(true).attr("id", "repeatable" + id_num));
id_num = id_num + 1;
//picker = null;
}
});
});
$(".startLEDs").draggable({
revert:true
});
I have tried to use the draggable feature from JQuery but noticed that when I try to drag the boxes, the entire div disappears. And, also I only want the boxes to be draggable and droppable, nothing else.
Any help or feedback is much appreciated!
Here is what I have so far, but due to the id attributes not being unique after cloning, it has some quirks.
Working Example: https://jsfiddle.net/Twisty/aqfn34bs/
HTML
<div class="bottomdiv">
<div class="container">
<div id="repeatable-0">
<button class="repeat add-top">Add above</button>
<ul class="repeatable">
<li class="startLEDs" id="sLED1"></li>
<li class="startLEDs" id="sLED2"></li>
<li class="startLEDs" id="sLED3"></li>
<li class="startLEDs" id="sLED4"></li>
<li class="startLEDs" id="sLED5"></li>
<li class="startLEDs" id="sLED6"></li>
<li class="startLEDs" id="sLED7"></li>
<li class="startLEDs" id="sLED8"></li>
<li class="startLEDs" id="sLED9"></li>
<li class="startLEDs" id="sLED10"></li>
<li class="startLEDs" id="sLED11"></li>
<li class="startLEDs" id="sLED12"></li>
<li class="endLEDs" id="eLED1"></li>
<li class="endLEDs" id="eLED2"></li>
<li class="endLEDs" id="eLED3"></li>
<li class="endLEDs" id="eLED4"></li>
<li class="endLEDs" id="eLED5"></li>
<li class="endLEDs" id="eLED6"></li>
<li class="endLEDs" id="eLED7"></li>
<li class="endLEDs" id="eLED8"></li>
<li class="endLEDs" id="eLED9"></li>
<li class="endLEDs" id="eLED10"></li>
<li class="endLEDs" id="eLED11"></li>
<li class="endLEDs" id="eLED12"></li>
</ul>
<div class="timeMilli">Time(ms):
<input type="text" name="time" form="form1">
</div>
<button class="repeat add-bottom">Add below</button>
</div>
</div>
</div>
I was looking at using sortable, and so I switched it to a unorganized list in my testing and then went back to draggable but still licked the list of colors versus links. I suspect you could revert back if you desired.
CSS
div.bottomdiv {
clear: both;
position: fixed;
bottom: 0;
height: 50%;
width: 100%;
font-size: 16px;
text-align: center;
overflow: auto;
}
.container {
margin-top: 60px;
float: left
}
.timeMilli {
position: relative;
display: inline-block;
}
ul.repeatable {
list-style-type: none;
margin: 0;
padding: 0;
width: 408px;
}
ul.repeatable li {
width: 30px;
height: 30px;
float: left;
margin: 1px 1px 1px 0;
background-color: #ccc;
border: 1px solid #000000;
}
b {
position: relative;
display: inline-block;
width: 30px;
height: 30px;
background-color: #ccc;
border: 1px solid #000000;
}
.repeat {
display: flex;
flex-direction: nowrap;
flex-wrap: nowrap;
}
.repeat > * {
flex: 0 0 30px;
}
Minor changes here for ul and li.
jQuery
$(function() {
function setColor(obj, r) {
obj.css('background-color', r);
obj.attr("data-color", r);
}
function makeDrag(obj) {
obj.draggable({
helper: "clone",
opacity: 0.85
});
}
function makeDrop(obj) {
obj.droppable({
accept: ".repeatable li",
drop: function(e, ui) {
if (ui.helper.data("color")) {
setColor($(this), ui.helper.data("color"));
makeDrag($(this));
}
}
});
}
$(document).on('click', ".repeat", function(e) {
e.preventDefault();
var $self = $(this);
var $parent = $self.parent();
var id_num = $("div[id^='repeatable']").length;
if ($self.hasClass("add-bottom")) {
$parent.after($parent.clone(true).attr("id", "repeatable-" + id_num));
makeDrop($("#repeatable-" + id_num + " .repeatable li"));
makeDrag($("#repeatable-" + id_num + " .repeatable li[data-color^='#']"));
} else {
$parent.before($parent.clone(true).attr("id", "repeatable-" + id_num));
makeDrop($("#repeatable-" + id_num + " .repeatable li"));
makeDrag($("#repeatable-" + id_num + " .repeatable li[data-color^='#']"));
}
});
$(".repeatable li").on("dblclick", function(e) {
$(this).spectrum({
color: "#f00",
change: function(color) {
setColor($(this), color.toHexString());
makeDrag($(this));
}
});
});
makeDrop($(".repeatable li"));
});
I didn't see a need for the id_num and picker variables in global.
Since we will be making a number of things change colors, draggable, and droppable, I created functions to do this repeatedly.
So draggable by itself would not accomplish what you needed. You need droppable to be able to action things when the dragged item is dropped. For example, it has an out and over event that you could color the box it's over while it's over it, and then revert the color once dragged out.
For now, we stick to basics: we set a color with a Double Click event, we can then drag that color to another nearby box, and the color for that box is set to the same color when dropped.
Now if we clone things before or after, things get sticky. Will look over it later, but this should get you moving forward for now.
I have the following menu—please find below the code snippet—and wanted to know if there is a possibility to remove the unwanted jiggling effect on mouse over the links (left side area). By jiggling, I don't mean the translation to the right effect. That is a well defined thing. Just try to move slowly the mouse at the very beginning of the link(s) and u'll see the unwanted effect. Any thoughts?
/* jQuery Storage API Plugin 1.7.4 https://github.com/julien-maurel/jQuery-Storage-API */
!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e("object"==typeof exports?require("jquery"):jQuery)}(function(e){function t(t){var r,i,n,o=arguments.length,s=window[t],a=arguments,u=a[1];if(2>o)throw Error("Minimum 2 arguments must be given");if(e.isArray(u)){i={};for(var f in u){r=u[f];try{i[r]=JSON.parse(s.getItem(r))}catch(c){i[r]=s.getItem(r)}}return i}if(2!=o){try{i=JSON.parse(s.getItem(u))}catch(c){throw new ReferenceError(u+" is not defined in this storage")}for(var f=2;o-1>f;f++)if(i=i[a[f]],void 0===i)throw new ReferenceError([].slice.call(a,1,f+1).join(".")+" is not defined in this storage");if(e.isArray(a[f])){n=i,i={};for(var m in a[f])i[a[f][m]]=n[a[f][m]];return i}return i[a[f]]}try{return JSON.parse(s.getItem(u))}catch(c){return s.getItem(u)}}function r(t){var r,i,n=arguments.length,o=window[t],s=arguments,a=s[1],u=s[2],f={};if(2>n||!e.isPlainObject(a)&&3>n)throw Error("Minimum 3 arguments must be given or second parameter must be an object");if(e.isPlainObject(a)){for(var c in a)r=a[c],e.isPlainObject(r)?o.setItem(c,JSON.stringify(r)):o.setItem(c,r);return a}if(3==n)return"object"==typeof u?o.setItem(a,JSON.stringify(u)):o.setItem(a,u),u;try{i=o.getItem(a),null!=i&&(f=JSON.parse(i))}catch(m){}i=f;for(var c=2;n-2>c;c++)r=s[c],i[r]&&e.isPlainObject(i[r])||(i[r]={}),i=i[r];return i[s[c]]=s[c+1],o.setItem(a,JSON.stringify(f)),f}function i(t){var r,i,n=arguments.length,o=window[t],s=arguments,a=s[1];if(2>n)throw Error("Minimum 2 arguments must be given");if(e.isArray(a)){for(var u in a)o.removeItem(a[u]);return!0}if(2==n)return o.removeItem(a),!0;try{r=i=JSON.parse(o.getItem(a))}catch(f){throw new ReferenceError(a+" is not defined in this storage")}for(var u=2;n-1>u;u++)if(i=i[s[u]],void 0===i)throw new ReferenceError([].slice.call(s,1,u).join(".")+" is not defined in this storage");if(e.isArray(s[u]))for(var c in s[u])delete i[s[u][c]];else delete i[s[u]];return o.setItem(a,JSON.stringify(r)),!0}function n(t,r){var n=a(t);for(var o in n)i(t,n[o]);if(r)for(var o in e.namespaceStorages)u(o)}function o(r){var i=arguments.length,n=arguments,s=(window[r],n[1]);if(1==i)return 0==a(r).length;if(e.isArray(s)){for(var u=0;u<s.length;u++)if(!o(r,s[u]))return!1;return!0}try{var f=t.apply(this,arguments);e.isArray(n[i-1])||(f={totest:f});for(var u in f)if(!(e.isPlainObject(f[u])&&e.isEmptyObject(f[u])||e.isArray(f[u])&&!f[u].length)&&f[u])return!1;return!0}catch(c){return!0}}function s(r){var i=arguments.length,n=arguments,o=(window[r],n[1]);if(2>i)throw Error("Minimum 2 arguments must be given");if(e.isArray(o)){for(var a=0;a<o.length;a++)if(!s(r,o[a]))return!1;return!0}try{var u=t.apply(this,arguments);e.isArray(n[i-1])||(u={totest:u});for(var a in u)if(void 0===u[a]||null===u[a])return!1;return!0}catch(f){return!1}}function a(r){var i=arguments.length,n=window[r],o=arguments,s=(o[1],[]),a={};if(a=i>1?t.apply(this,o):n,a._cookie)for(var u in e.cookie())""!=u&&s.push(u.replace(a._prefix,""));else for(var f in a)s.push(f);return s}function u(t){if(!t||"string"!=typeof t)throw Error("First parameter must be a string");g?(window.localStorage.getItem(t)||window.localStorage.setItem(t,"{}"),window.sessionStorage.getItem(t)||window.sessionStorage.setItem(t,"{}")):(window.localCookieStorage.getItem(t)||window.localCookieStorage.setItem(t,"{}"),window.sessionCookieStorage.getItem(t)||window.sessionCookieStorage.setItem(t,"{}"));var r={localStorage:e.extend({},e.localStorage,{_ns:t}),sessionStorage:e.extend({},e.sessionStorage,{_ns:t})};return e.cookie&&(window.cookieStorage.getItem(t)||window.cookieStorage.setItem(t,"{}"),r.cookieStorage=e.extend({},e.cookieStorage,{_ns:t})),e.namespaceStorages[t]=r,r}function f(e){var t="jsapi";try{return window[e]?(window[e].setItem(t,t),window[e].removeItem(t),!0):!1}catch(r){return!1}}var c="ls_",m="ss_",g=f("localStorage"),l={_type:"",_ns:"",_callMethod:function(e,t){var r=[this._type],t=Array.prototype.slice.call(t),i=t[0];return this._ns&&r.push(this._ns),"string"==typeof i&&-1!==i.indexOf(".")&&(t.shift(),[].unshift.apply(t,i.split("."))),[].push.apply(r,t),e.apply(this,r)},get:function(){return this._callMethod(t,arguments)},set:function(){var t=arguments.length,i=arguments,n=i[0];if(1>t||!e.isPlainObject(n)&&2>t)throw Error("Minimum 2 arguments must be given or first parameter must be an object");if(e.isPlainObject(n)&&this._ns){for(var o in n)r(this._type,this._ns,o,n[o]);return n}var s=this._callMethod(r,i);return this._ns?s[n.split(".")[0]]:s},remove:function(){if(arguments.length<1)throw Error("Minimum 1 argument must be given");return this._callMethod(i,arguments)},removeAll:function(e){return this._ns?(r(this._type,this._ns,{}),!0):n(this._type,e)},isEmpty:function(){return this._callMethod(o,arguments)},isSet:function(){if(arguments.length<1)throw Error("Minimum 1 argument must be given");return this._callMethod(s,arguments)},keys:function(){return this._callMethod(a,arguments)}};if(e.cookie){window.name||(window.name=Math.floor(1e8*Math.random()));var h={_cookie:!0,_prefix:"",_expires:null,_path:null,_domain:null,setItem:function(t,r){e.cookie(this._prefix+t,r,{expires:this._expires,path:this._path,domain:this._domain})},getItem:function(t){return e.cookie(this._prefix+t)},removeItem:function(t){return e.removeCookie(this._prefix+t)},clear:function(){for(var t in e.cookie())""!=t&&(!this._prefix&&-1===t.indexOf(c)&&-1===t.indexOf(m)||this._prefix&&0===t.indexOf(this._prefix))&&e.removeCookie(t)},setExpires:function(e){return this._expires=e,this},setPath:function(e){return this._path=e,this},setDomain:function(e){return this._domain=e,this},setConf:function(e){return e.path&&(this._path=e.path),e.domain&&(this._domain=e.domain),e.expires&&(this._expires=e.expires),this},setDefaultConf:function(){this._path=this._domain=this._expires=null}};g||(window.localCookieStorage=e.extend({},h,{_prefix:c,_expires:3650}),window.sessionCookieStorage=e.extend({},h,{_prefix:m+window.name+"_"})),window.cookieStorage=e.extend({},h),e.cookieStorage=e.extend({},l,{_type:"cookieStorage",setExpires:function(e){return window.cookieStorage.setExpires(e),this},setPath:function(e){return window.cookieStorage.setPath(e),this},setDomain:function(e){return window.cookieStorage.setDomain(e),this},setConf:function(e){return window.cookieStorage.setConf(e),this},setDefaultConf:function(){return window.cookieStorage.setDefaultConf(),this}})}e.initNamespaceStorage=function(e){return u(e)},g?(e.localStorage=e.extend({},l,{_type:"localStorage"}),e.sessionStorage=e.extend({},l,{_type:"sessionStorage"})):(e.localStorage=e.extend({},l,{_type:"localCookieStorage"}),e.sessionStorage=e.extend({},l,{_type:"sessionCookieStorage"})),e.namespaceStorages={},e.removeAllStorages=function(t){e.localStorage.removeAll(t),e.sessionStorage.removeAll(t),e.cookieStorage&&e.cookieStorage.removeAll(t),t||(e.namespaceStorages={})}});
var storage;
jQuery(function () {
storage=jQuery.localStorage;
jQuery('nav:visible ul li').click(function (e) {
//Set the aesthetics (similar to :hover)
storage.set('link',jQuery('nav:visible ul li').index(jQuery(this)));
jQuery('nav:visible ul li')
.not(".clicked").removeClass('hovered')
.filter(this).addClass("clicked hovered")
.siblings().toggleClass("clicked hovered", false);
}).hover(function () {
jQuery(this).addClass("hovered")
}, function () {
jQuery(this).not(".clicked").removeClass("hovered")
});
var pageSize = 4,
$links = jQuery(".pagedMenu li"),
count = $links.length,
numPages = Math.ceil(count / pageSize),
curPage = 1;
showPage(curPage);
function showPage(whichPage) {
var previousLinks = (whichPage - 1) * pageSize,
nextLinks = (previousLinks + pageSize);
$links.show();
$links.slice(0, previousLinks).hide();
$links.slice(nextLinks).hide();
showPrevNext();
}
function showPrevNext() {
if ((numPages > 0) && (curPage < numPages)) {
jQuery("#nextPage").removeClass('hidden');
jQuery("#msg").text("(" + curPage + " of " + numPages + ")");
} else {
jQuery("#nextPage").addClass('hidden');
}
if ((numPages > 0) && (curPage > 1)) {
jQuery("#prevPage").removeClass('hidden');
jQuery("#msg").text("(" + curPage + " of " + numPages + ")");
} else {
jQuery("#prevPage").addClass('hidden');
}
}
jQuery("#nextPage").on("click", function () {
showPage(++curPage);
storage.set('page',curPage);
});
jQuery("#prevPage").on("click", function () {
showPage(--curPage);
storage.set('page',curPage);
});
if(storage.isSet('page')){
var page= storage.get('page');
curPage = page;
showPage(page);
}
if(storage.isSet('link')){
var link = storage.get('link')+1;
jQuery('nav:visible ul li:nth-child('+link+')').addClass("clicked hovered");
var newUrl = jQuery('nav:visible ul li:nth-child('+link+') a').attr('href');
if(newUrl!=location.href)location.href=newUrl;
}
});
.hidden {
display: none;
}
body {
font: normal 1.0em Arial, sans-serif;
}
nav.pagedMenu {
color: red;
font-size: 2.0em;
line-height: 1.0em;
width: 8em;
position: fixed;
top: 50px;
}
nav.pagedMenu ul {
list-style: none;
margin: 0;
padding: 0;
}
nav.pagedMenu ul li {
height: 1.0em;
padding: 0.15em;
position: relative;
border-top-right-radius: 0em;
border-bottom-right-radius: 0em;
-webkit-transition:
-webkit-transform 220ms, background-color 200ms, color 500ms;
transition: transform 220ms, background-color 200ms, color 500ms;
}
nav.pagedMenu ul li.hovered {
-webkit-transform: translateX(1.5em);
transform: translateX(1.5em);
}
nav ul li:hover a {
transition: color, 1200ms;
color: red;
}
nav.pagedMenu ul li span {
display:block;
font-family: Arial;
position: absolute;
font-size:1em;
line-height: 1.25em;
height:1.0em;
top:0; bottom:0;
margin:auto;
right: 0.01em;
color: #F8F6FF;
}
a {
color: gold;
transition: color, 1200ms;
text-decoration: none;
}
#pagination, #prevPage, #nextPage {
font-size: 1.0em;
color: gold;
line-height: 1.0em;
padding-top: 250px;
padding-left: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<nav class="pagedMenu">
<ul style="font-size: 28px;">
<li class="" style="margin-bottom: 5px;">Link 1</li>
<li class="" style="margin-bottom: 5px;">Link 2</li>
<li class="" style="margin-bottom: 5px;">Link 3</li>
<li class="" style="margin-bottom: 5px;">Link 4</li>
<li class="" style="margin-bottom: 5px;">Link 5</li>
<li class="" style="margin-bottom: 5px;">Link 6</li>
<li class="" style="margin-bottom: 5px;">Link 7</li>
<li class="" style="margin-bottom: 5px;">Link 8</li>
<li class="" style="margin-bottom: 5px;">Link 9</li>
<li class="" style="margin-bottom: 5px;">Link 10</li>
<li class="" style="margin-bottom: 5px;">Link 11</li>
<li class="" style="margin-bottom: 5px;">Link 12</li>
</ul>
</nav>
<div id="pagination">
Previous
Next
<span id="msg"></span>
</div>
Jsfiddle here
I think you don't need jQuery at all
Replace:
nav.pagedMenu ul li.hovered {
-webkit-transform: translateX(1.5em);
transform: translateX(1.5em);
}
nav ul li:hover a {
transition: color, 1200ms;
color: red;
}
With:
nav.pagedMenu ul li:hover a {
transition: padding-left 500ms,color 1200ms;
padding-left:1.5em;
color: red;
}
http://jsfiddle.net/dh7920rq/
The problem with your implementation is that: when your <li> is hovered, it moves to the right, but your mouse is still at the original position, causing mouseout immediately which causes the unwanted effect.
If we don't move the <li>, but instead increase the padding-left of the <a>, the mouse is still inside the <li> (or increase margin-left of the <a>)
http://jsfiddle.net/dh7920rq/1/
Updated:
Use jQuery to keep the state as requested by the OP:
Replace:
nav.pagedMenu ul li.hovered {
-webkit-transform: translateX(1.5em);
transform: translateX(1.5em);
}
nav ul li:hover a {
transition: color, 1200ms;
color: red;
}
With:
nav.pagedMenu ul li.hovered a{
transition: margin-left 500ms,transition: color 1200ms;
margin-left:1.5em;
color: red;
}
The idea is the same: http://plnkr.co/edit/880ZtUiCwbRNGBNGuURU?p=preview
You can do this effect by giving padding to the a element.
Jsfiddle
I have a horizontal tab menu. These tabs are all li elements. I show always 5 of them at once. To the left and right I have buttons which scrolls these tabs to either side. I am just not sure how to achieve that. Can I put the next 5 tabs in a different div which will be shown on click? That wouldnt be the best solution, would it? Can I do this somehow with JavaScript or jQuery?
Thanks.
You can do this w/ jQuery. Easier if all of the tabs are the same width. You can position the UL inside a DIV that has overflow: hidden and position: relative. Then the UL can slide around inside the DIV using the animate() method (or the css() method). Check them out on http://api.jquery.com.
Here's an example:
<!DOCTYPE HTML>
<html>
<head>
<style>
* { margin: 0; padding: 0; }
body { padding: 30px; }
div#tabs { width: 360px; height: 30px; overflow: hidden; position: relative; }
ul { display: block; float: left; width: 1080px; position: absolute; left: -360px; }
li { display: block; float: left; width: 70px; height: 30px; font-size: 12px; border: 1px solid #333; }
button { float: left; width: 100px; margin: 20px; }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script>
$(document).ready(function()
{
$("button").click(function()
{
var tabs_list = $("div#tabs > ul");
if($(this).is("#left"))
{
tabs_list.animate({ left: "-=360" }, 500);
}
else if($(this).is("#right"))
{
tabs_list.animate({ left: "+=360" }, 500);
}
});
});
</script>
</head>
<body>
<div id="tabs">
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
<li>four</li>
<li>five</li>
<li>six</li>
<li>seven</li>
<li>eight</li>
<li>nine</li>
<li>ten</li>
<li>eleven</li>
<li>twelve</li>
<li>thirteen</li>
<li>fourteen</li>
<li>fifteen</li>
</ul>
</div>
<button id="left">scroll left</button>
<button id="right">scroll right</button>
</body>
</html>
This would need some more work in order to de-activate or hide the scroll buttons when you've reached the beginning or end of the tabs list, but this should get you started.
I like Elliot's solution. I have another one, which will work if the tabs are of different lengths. It does it by hiding and showing the individual "li"s as you click the "right" and "left" buttons. The code also takes care of moving the tabs 5 at a time, both left and right, and handles the end cases.
<!DOCTYPE HTML>
<html>
<head>
<style>
#left, #right {float: left; position: relative; margin: 0; padding: 0;}
#tabs {float: left; position: relative; list-style: none; margin: 0; padding: 0;}
#tabs li {float: left; display: none; border: 2px solid #000; width: 50px; text-align: center;};
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var tabs = $('#tabs li'), number_of_tabs = tabs.length;
var tabs_visible = Math.min(5, number_of_tabs), low_tab = 0, high_tab = (tabs_visible - 1);
$(tabs).filter(function(index){return (index < tabs_visible);}).show();
$('#left, #right').each(function(){
$(this).click(function(){
if ($(this).is('#right')) {
var high_tab_new = Math.min((high_tab + tabs_visible), (number_of_tabs - 1));
var low_tab_new = high_tab_new - tabs_visible + 1;
$(tabs).filter(function(index){
return (index >= low_tab) && (index < low_tab_new);
}).hide();
$(tabs).filter(function(index){
return (index > high_tab) && (index <= high_tab_new);
}).show();
low_tab = low_tab_new;
high_tab = high_tab_new;
} else {
var low_tab_new = Math.max((low_tab - tabs_visible), 0);
var high_tab_new = low_tab_new + tabs_visible - 1;
$(tabs).filter(function(index){
return (index > high_tab_new) && (index <= high_tab);
}).hide();
$(tabs).filter(function(index){
return (index >= low_tab_new) && (index < low_tab);
}).show();
low_tab = low_tab_new;
high_tab = high_tab_new;
}
});
});
</script>
</head>
<div id="nav3">
<button id="left">left</button>
<ul id="tabs">
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
<li>E</li>
<li>F</li>
<li>G</li>
<li>H</li>
<li>I</li>
</ul>
<button id="right">right</button>
</div>
</body>
</html>
Though I am not sure how would the tab look like, I am assuming that with the 5 tabs you are showing different set of page content.
I am suggesting a simple solution (Design) with Javascript. See if it works.
Have a variable to store the current View index. e.g. _currentView.
Place the content of 5 tabs in 5 views (When I say views there are many ways to establish it, ranging from using div object to using .net multiview control).
By default keep their visibility off.
Create a method, that'll accept the _currentView as the parameter. In this method, just make the current view visible.
On the click of left and right arrow, increment or decrement the _currentView value and call the method that activates the current view.
Please see if this helps you.