I have a project on jsFiddle:
jsFiddle Link
JavaScript:
var scroller = function() {
$('#holder div').animate({
left: ($t.attr('id') == 'prev' ? '-=' : '+=') + 3
}, 10, 'linear', function() {
if ($(this).position().left < -$('li:first-child', this).width()) {
w = $('li:first-child', this).totalWidth();
$('li:first-child', this).appendTo('ul', this);
$(this).css('left', $(this).position().left + w);
}
});
};
$.fn.extend({
totalWidth: function() {
return this.outerWidth() + parseInt(this.css('margin-left'), 10) + parseInt(this.css('margin-right'), 10);
}
});
wdth = 0;
$('#marquee ul li').each(function() {
wdth += $(this).totalWidth();
});
$('#holder div').width(wdth);
var to;
$('#prev, #next').css('top', ($('#marquee').outerHeight() - $('#prev').outerHeight()) / 2).live('mousedown mouseup', function(e) {
$t = $(this);
if (e.type == 'mousedown') {
to = setInterval(scroller, 15);
}
else {
clearInterval(to);
}
});
HTML:
<div id="marquee">
<div id="prev"><</div>
<div id="next">></div>
<div id="holder">
<div>
<ul>
<li>Part 1</li>
<li>Part 2</li>
<li>Part 3</li>
<li>Part 4</li>
<li>Part 5</li>
<li>Part 6</li>
<li>Part 7</li>
<li>Part 8</li>
<li>Part 9</li>
<li>Part 10</li>
</ul>
</div>
</div>
</div>
CSS:
* {
font-family: verdana;
font-size: 12px;
}
#marquee {
top: 50px;
position: relative;
width: 80%;
height: 34px;
background-color: #CCC;
margin: 0 auto;
padding: 0;
}
#holder {
overflow: hidden;
position: absolute;
left: 5px;
right: 5px;
top: 5px;
bottom: 5px;
}
#holder div {
position: absolute;
}
#marquee ul li {
display: inline-block;
float: left;
margin-left: 5px;
padding: 5px 7px;
background-color: #555;
}
#marquee ul li:nth-child(2n+1) {
background-color: #888;
}
#marquee ul li:first-child {
margin-left: 0;
}
#prev, #next {
position: absolute;
top: 10px;
background-color: #66F;
padding: 2px;
cursor: pointer;
z-index: 9002;
}
#prev {
left: -13px;
border-radius: 5px 0 0 5px;
}
#next {
right : -13px;
border-radius: 0 5px 5px 0;
}
what I am trying to achieve is a scrolling loop on mousedown, stopping on mouseup.
I have been able to make it scroll, and loop but it 'jumps' on every loop change.
Does anyone have any ideas?
I have edited the fiddle to remove the CSS rule, also edited the code slightly.
Originally when it scrolled left, it jumped back about 20px and this was made to seem worse by the CSS rule!
Also the animation goes on in 10ms but it loops every 15ms due to the fact that on mouseup the loop would continue for a bit.
The right does not loop because since I did not know how to do the left, I would not waste time making it scroll right erroneously when i could simply make it scroll correctly when it was ready.
I am not using a plugin because I want to learn how to do it myself (stubborn!)
Forked your fiddle and added code a) that eliminates jumpiness while scrolling and b) that checks and adds the first <li> to the end of the list (if there's space) while scrolling right (next)
Check this fiddle: http://jsfiddle.net/CRy4Q/15/
Related
Got a JS/JQuery issue I'm struggling to solve.
I'm building a simple one page site with a fixed header and anchor based scrolling navigation. When a user clicks a link the the scrollTop of the body is animated to the top of the relevant section. Included in this function is a calculation that subtracts the height of the header from the scroll distance to ensure the fixed header doesn't obscure the top of the section
The issue I'm having is because of a separate function that applies a class to the header if a user scrolls past a certain distance. This class causes a few properties to change and therefore the height of the header element changes.
This means that the value of $('header').outerHeight(); at the end of the scrolling animation is smaller than what it was when the animation began. This change means that the distance scrolled is wrong and the window ends up slightly too short of the desired location.
How do I allow for this change in value during the scrolling animation? Ideally I want everything to stay dynamic rather than specifying fixed heights/sizes. TIA.
$('a[href^="#"]').on("click", function() {
let headerHeight = $('header').outerHeight();
$('html, body').animate({
scrollTop: $($.attr(this, 'href')).offset().top - headerHeight
}, 500);
});
$(window).on('load resize scroll', function() {
if ($(window).scrollTop() >= 100 ) { // this refers to window
$('header').addClass('scroll');
} else {
$('header').removeClass('scroll');
}
});
body,html {
margin: 0;
padding: 0;
}
header {
padding: 30px 30px;
position:fixed;
left:0;
right: 0;
top: 0;
z-index:99;
transition: all .3s ease;
}
header h1 {
display:inline-block;
width:10%;
color: white;
}
header.scroll {
background: black;
padding: 15px 30px;
}
header nav {
display:inline-block;
width: 89%;
}
header nav ul {
margin: 0;
list-style: none;
text-align:right;
}
header nav ul li {
display:inline-block;
}
header nav ul li a {
color: white;
padding: 0 10px;
}
.hero {
height: 600px;
background: blue;
}
section h2 {
position: relative;
top: 50%;
transform: translateY(-50%);
margin: 0;
text-align: center;
color: white;
}
section {
height: 600px;
}
#one {
background: red;
}
#two {
background: green;
}
#three {
background: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
<h1>Title</h1>
<nav>
<ul>
<li>Section 1 </li>
<li>Section 2 </li>
<li>Section 3 </li>
</ul>
</nav>
</header>
<section class="hero"><h2>Hero</h2></section>
<section id="one"><h2>Section 1</h2></section>
<section id="two"><h2>Section 2</h2></section>
<section id="three"><h2>Section 3</h2></section>
If you run the above snippet and click on the link for "Section 1" at the top of the page. You can see the distance scrolled is slightly too short and the bottom of the .hero element is still visible due to the change in height.
Try this, I'm subtracting 30 from header's height because in start padding was "30px 30px" and then it's going to be "15px 30px" means header height should be:
height = actualHeight - - ,
and this required when your header is expanded(means header does not have class scroll) so I added condition.
$('a[href^="#"]').on("click", function() {
let headerHeight = $('header').outerHeight();
if(!$('header').hasClass('scroll')) {
headerHeight -= 30; //The padding removed
}
$('html, body').animate({
scrollTop: $($.attr(this, 'href')).offset().top - headerHeight
}, 500);
});
$(window).on('load resize scroll', function() {
if ($(window).scrollTop() >= 100 ) { // this refers to window
$('header').addClass('scroll');
} else {
$('header').removeClass('scroll');
}
});
body,html {
margin: 0;
padding: 0;
}
header {
padding: 30px 30px;
position:fixed;
left:0;
right: 0;
top: 0;
z-index:99;
transition: all .3s ease;
}
header h1 {
display:inline-block;
width:10%;
color: white;
}
header.scroll {
background: black;
padding: 15px 30px;
}
header nav {
display:inline-block;
width: 89%;
}
header nav ul {
margin: 0;
list-style: none;
text-align:right;
}
header nav ul li {
display:inline-block;
}
header nav ul li a {
color: white;
padding: 0 10px;
}
.hero {
height: 600px;
background: blue;
}
section h2 {
position: relative;
top: 50%;
transform: translateY(-50%);
margin: 0;
text-align: center;
color: white;
}
section {
height: 600px;
}
#one {
background: red;
}
#two {
background: green;
}
#three {
background: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<header>
<h1>Title</h1>
<nav>
<ul>
<li>Section 1 </li>
<li>Section 2 </li>
<li>Section 3 </li>
</ul>
</nav>
</header>
<section class="hero"><h2>Hero</h2></section>
<section id="one"><h2>Section 1</h2></section>
<section id="two"><h2>Section 2</h2></section>
<section id="three"><h2>Section 3</h2></section>
Ended up solving this by adding a callback to my animation function. The callback checks if the height of the header has changed since the function was first called and if it has, then the scrollTop is increased by this amount.
$('a[href^="#"]').on("click", function() {
let headerHeightOne = $('header').outerHeight();
$('html, body').animate({
scrollTop: $($.attr(this, 'href')).offset().top - headerHeightOne
}, 500, function() {
let headerHeightTwo = $('header').outerHeight();
let difference = headerHeightOne - headerHeightTwo;
if (difference > 0 ) {
$('html,body').animate({
scrollTop: $(window).scrollTop() + difference
}, 100);
}
});
});
I've tried various different things to implement this but nothing seems to work for me i am trying to make the current progress bar have functionality e.g goes according to when each slide changes, and also add tabs that will allow a user to jump to a slide on click.
Demo Fiddle
Html
<div class="omega_player">
<ul class="omega_slides">
<li>SLIDE 1</li>
<li style="background: #aaa;">SLIDE 2</li>
<li>SLIDE 3</li>
<li style="background: #aaa;">SLIDE 4</li>
</ul>
<ul class="omega_controls">
<div class="omega_timer"><div class="progress"></div></div>
<div class="omega_set">
<a onclick="return false" class="control_prev"><i class="fa fa-angle-left"></i></a>
<a onclick="return false" class="control_play"><i class="fa fa-play"></i></a>
<a onclick="return false" class="control_pause"><i class="fa fa-pause"></i></a>
<a onclick="return false" class="control_next"><i class="fa fa-angle-right"></i></a>
</div>
</ul>
</div>
JS
jQuery(document).ready(function ($) {
timer = setInterval(function () {
moveRight();
}, 8000);
var slideCount = $('.omega_player>.omega_slides>li').length;
var slideWidth = $('.omega_player>.omega_slides>li').width();
var slideHeight = $('.omega_player>.omega_slides>li').height();
var sliderUlWidth = slideCount * slideWidth;
$('.omega_player').css({ width: slideWidth, height: slideHeight });
$('.omega_player>.omega_slides').css({ width: sliderUlWidth, marginLeft: - slideWidth });
$('.omega_player>.omega_slides>li:last-child').prependTo('.omega_player>.omega_slides');
function moveLeft() {
$('.omega_player>.omega_slides').animate({
left: + slideWidth
}, 200, function () {
$('.omega_player>.omega_slides>li:last-child').prependTo('.omega_player>.omega_slides');
$('.omega_player>.omega_slides').css('left', '');
});
};
function moveRight() {
$('.omega_player>.omega_slides').animate({
left: - slideWidth
}, 200, function () {
$('.omega_player>.omega_slides>li:first-child').appendTo('.omega_player>.omega_slides');
$('.omega_player>.omega_slides').css('left', '');
});
};
$('.omega_player>.omega_controls>.omega_set>.control_prev').click(function () {
clearInterval(timer);
$('.omega_player>.omega_controls>.omega_set>.control_play').show();
$('.omega_player>.omega_controls>.omega_set>.control_pause').hide();
moveLeft();
});
$('.omega_player>.omega_controls>.omega_set>.control_next').click(function () {
clearInterval(timer);
$('.omega_player>.omega_controls>.omega_set>.control_play').show();
$('.omega_player>.omega_controls>.omega_set>.control_pause').hide();
moveRight();
});
$('.omega_player>.omega_controls>.omega_set>.control_play').click(function () {
$('.omega_player>.omega_controls>.omega_set>.control_play').hide();
$('.omega_player>.omega_controls>.omega_set>.control_pause').show();
moveRight();
timer = setInterval(function () {
moveRight();
}, 8000);
});
$('.omega_player>.omega_controls>.omega_set>.control_pause').click(function () {
clearInterval(timer);
$('.omega_player>.omega_controls>.omega_set>.control_play').show();
$('.omega_player>.omega_controls>.omega_set>.control_pause').hide()
});
return timer;
});
CSS
.omega_player {
position: relative;
overflow: hidden;
margin: 0 auto;
width: 950px;
border-radius: 4px;
}
.omega_player>.omega_slides {
position: relative;
margin: 0;
padding: 0;
height: 450px;
list-style: none;
}
.omega_player>.omega_slides>li {
position: relative;
display: block;
float: left;
margin: 0;
padding: 0;
width: 950px;
height: 450px;
background: #ccc;
text-align: center;
line-height: 300px;
}
.omega_player>.omega_controls {
bottom: 0;
left: 0;
right: 0;
height: 50px;
margin: 0;
padding: 0;
background: #333;
background: rgba(51,51,51,.8);
position: absolute;
z-index: 2;
width: 100%;
}
.omega_player>.omega_controls>.omega_set {
position: absolute;
right: 20px;
}
.omega_player>.omega_controls>li>.control_prev,
.omega_player>.omega_controls>li>.control_next {
position: absolute;
top: 40%;
z-index: 999;
display: block;
padding: 4% 3%;
width: auto;
height: auto;
background: #2a2a2a;
color: #fff;
text-decoration: none;
font-weight: 600;
font-size: 18px;
opacity: 0.8;
cursor: pointer;
}
.omega_player>.omega_controls>li>.control_prev:hover,
.omega_player>.omega_controls>li>.control_next:hover {
opacity: 1;
-webkit-transition: all 0.2s ease;
}
.omega_player>.omega_controls>li>.control_prev {
border-radius: 0 2px 2px 0;
}
.omega_player>.omega_controls>li>.control_next {
right: 0;
border-radius: 2px 0 0 2px;
}
.omega_player>.omega_controls>li>.control_play,
.omega_player>.omega_controls>li>.control_pause {
background-color: green;
color: #fff;
padding: 10px;
}
.omega_player>.omega_controls>li>.control_play {
display: none!important;
}
.omega_player>.omega_controls>.omega_set>a {
color: #FFF;
color: rgba(250,250,250,.95);
font-size: 20px;
vertical-align: middle;
padding: 10px;
display: inline-block;
cursor: pointer;
}
.omega_player>.omega_controls>.omega_set>:hover {
background: rgba(0,0,0,0.2);
color: #FFF;
}
.omega_player>.omega_controls>.omega_set>.control_prev,
.omega_player>.omega_controls>.omega_set>.control_next,
.omega_player>.omega_controls>.omega_set>.control_play,
.omega_player>.omega_controls>.omega_set>.control_pause {
font-size: 45px;
line-height: 0;
margin: 0;
height: 50px;
width: 50px;
padding: 0;
text-align: center;
transition: .1s ease-in-out;
border: 1px solid #FFF;
border-color: rgba(250,250,250,0.65);
border-top: 0;
border-bottom: 0;
float: left;
}
.omega_player>.omega_controls>.omega_set>.control_play,
.omega_player>.omega_controls>.omega_set>.control_pause {
border:0;
font-size: 25px;
line-height: 48px;
}
.omega_player>.omega_controls>.omega_set>.control_play {
display:none;
}
.omega_player>.omega_controls>.omega_timer {
background: #333;
background: rgba(51,51,51,.9);
height: 4px;
top: -4px;
position: absolute;
left: 0;
right: 0;
width: 100%;
}
.omega_player>.omega_controls>.omega_timer>.progress {
height: 4px;
display: inline-block;
background-color: #EB0000;
background: rgba(235, 0, 0, 0.86);
position: absolute;
width: 60%;
z-index: 999;
}
html,
body {margin:0;padding:0;font-family: sans-serif;font-size: 14px;}
Hope you can help thanks in advance!
Code with 4 Slides and Full Screen DEMO
Code with 8 Slides and Full Screen DEMO
Here you go. I have just written a function which will calculate progressbar's width based on number of elements present and active slide. Below is how the function looks like:
function progress(){
var activeElement=$('li:nth-child(2)').attr('data-slide');
//get the activeElement which will be always as 2nd child as per your code
var width=(increment*activeElement)+'%';
//increment variable will be based on `100/numberofslidespresent`
//each li should have a data-* property, say data-slide here, which will actually
//contain number in incremental order. Now multiply increment and activeElement
//and add % so that it will become something like 25%, 50% everytime.
$('.progress').animate({
'width':width //animate width of progressbar
},300);
}
Here is the complete code:
Html
<div class="omega_player">
<ul class="omega_slides">
<li data-slide="1">SLIDE 1</li>
<li data-slide="2" style="background: #aaa;">SLIDE 2</li>
<li data-slide="3">SLIDE 3</li>
<li data-slide="4" style="background: #aaa;">SLIDE 4</li>
<!--extra property added to each li which data-slide with incremental number-->
</ul>
<ul class="omega_controls">
<div class="omega_timer"><div class="progress"></div></div>
<div class="omega_set">
<a onclick="return false" class="control_prev"><i class="fa fa-angle-left"></i></a>
<a onclick="return false" class="control_play"><i class="fa fa-play"></i></a>
<a onclick="return false" class="control_pause"><i class="fa fa-pause"></i></a>
<a onclick="return false" class="control_next"><i class="fa fa-angle-right"></i></a>
</div>
</ul>
</div>
JS
var increment; // a global variable
jQuery(document).ready(function ($) {
timer = setInterval(function () {
moveRight();
}, 8000);
var slideCount = $('.omega_player>.omega_slides>li').length;
increment=100/slideCount; //get how much to increment parts should be
var slideWidth = $('.omega_player>.omega_slides>li').width();
var slideHeight = $('.omega_player>.omega_slides>li').height();
var sliderUlWidth = slideCount * slideWidth;
$('.omega_player').css({ width: slideWidth, height: slideHeight });
$('.omega_player>.omega_slides').css({ width: sliderUlWidth, marginLeft: - slideWidth });
$('.omega_player>.omega_slides>li:last-child').prependTo('.omega_player>.omega_slides');
progress();//call this function once prepended on page load
function moveLeft() {
$('.omega_player>.omega_slides').animate({
left: + slideWidth
}, 200, function () {
$('.omega_player>.omega_slides>li:last-child').prependTo('.omega_player>.omega_slides').addClass('active');
progress(); //after prepending call it once again
$('.omega_player>.omega_slides').css('left', '');
});
};
function moveRight() {
$('.omega_player>.omega_slides>li').removeClass('active')
$('.omega_player>.omega_slides').animate({
left: - slideWidth
}, 200, function () {
$('.omega_player>.omega_slides>li:first-child').appendTo('.omega_player>.omega_slides');
progress(); //after appending call it once again
$('.omega_player>.omega_slides').css('left', '');
});
};
//Your other functions here remains as it is so I haven't attached them
});
function progress(){
var activeElement=$('li:nth-child(2)').attr('data-slide');
var width=(increment*activeElement)+'%';
$('.progress').animate({
'width':width
},300);
}
CSS
On CSS part I just changed width mentioned for progressbar from 60% to
0%
I'm trying to create a menu that slides in and out from the right hand side of the screen for a mobile version of a site.
I have a 'ul' that starts off screen on page load due to its large margin. The plan is to have a button that will toggle that margin back and forth with '.animate' in order to hide and reveal the 'ul'.
The first chunk of code below works but won't repeat. So, on 'click', the menu appears, hides and then appears once more before it stops responding. This confused me so I tried a different route and went with an 'if' statement but now it just keeps sliding left despite the class definitely changing (i've checked it in the console).
Now i'm stumped! Can anyone help?
// MOBILE MENU
$(function() {
// create identical menu buttons with different classes
var $active = $("<div class='mm-active'><hr><hr><hr></div>");
var $inactive = $("<div class='mm-inactive'><hr><hr><hr></div>");
// append 'inactive' menu button to menu div
$(".mobile-menu").prepend($inactive);
$($inactive).click(function() {
$($inactive).hide();
$(this).next("ul").animate({'margin-left': '-='+90}, 1000);
$(".mobile-menu").prepend($active);
});
$($active).click(function() {
$(this).nextAll("ul").animate({'margin-left': '+='+90}, 1000);
$($active).remove();
$($inactive).show();
});
});
//And here with the 'if' statement...
$(function() {
// create identical menu buttons with different classes
var $mm_btn = $("<div><hr><hr><hr></div>");
var $classname = ($mm_btn).attr("class");
// append mobile menu button to menu div
$(".mobile-menu").prepend($mm_btn);
$($mm_btn).click(function() {
$($mm_btn).toggleClass('active');
if($classname === 'active') {
$(this).next("ul").animate({'margin-left': '+='+90}, 1000);
} else {
$(this).next("ul").animate({'margin-left': '-='+90}, 1000);
}
});
});
.mobile-menu {
position: absolute;
top: 5px;
right: 0;
width: 25px;
margin: 0 25px 0 0;
padding: 5px 0 8px 5px;
z-index: 1;
}
.mobile-menu hr {
border: 0;
height: 2px;
background: black;
}
.mobile-menu ul {
position: relative;
z-index: -1;
display: inline-block;
text-align: right;
margin-left: 50px;
margin-top: -50px;
padding: 50px 25px 5px 5px;
list-style: none;
}
.mobile-menu ul li {
padding: 3px;
}
<div class="mobile-menu">
<ul>
<li class="projects">projects</li>
<li>about</li>
<li>contact</li>
</ul>
</div>
In first case, when you are removing element all events are also removed: .remove()
In second case: $classname was set to empty string on page load and is never changed this is why only else is executed.
// MOBILE MENU
$(function() {
// create identical menu buttons with different classes
var $active = $("<div class='mm-active'><hr><hr><hr></div>");
// append 'inactive' menu button to menu div
$(".mobile-menu").prepend($active);
$($active).click(function() {
if ($active.hasClass('mm-active')) {
$(this).nextAll("ul").animate({
'margin-left': '-=' + 90
}, 1000);
} else {
$(this).nextAll("ul").animate({
'margin-left': '+=' + 90
}, 1000);
}
$active.toggleClass('mm-active');
});
});
body {
overflow: hidden;
}
.mobile-menu {
position: absolute;
top: 35px;
right: 0;
width: 25px;
margin: 0 25px 0 0;
padding: 5px 0 8px 5px;
z-index: 1;
}
.mobile-menu hr {
border: 0;
height: 2px;
background: black;
}
.mobile-menu ul {
position: relative;
z-index: -1;
display: inline-block;
text-align: right;
margin-left: 50px;
margin-top: -50px;
padding: 50px 25px 5px 5px;
list-style: none;
}
.mobile-menu ul li {
padding: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mobile-menu">
<ul>
<a href="projects.html">
<li class="projects">projects</li>
</a>
<a href="about.html">
<li>about</li>
</a>
<a href="contact.html">
<li>contact</li>
</a>
</ul>
</div>
I have a navigation of lets say 12 items, and when resolution gets smaller items drop in a new line. I need to make that when an item doesn't fit on a navigation anymore it should put a "MORE" dropdown button on the right side of nav. and put that item that doesn't fit in a dropdown.
If you don't understand me there is image below.
But the problem is that navigation items aren't always the same width because navigation items are generated from REST api.
I tryed to make jQuery script for calculating items width and adding them to navigation.
Here is the script I created, I made it in a hurry so it's really bad.
I need to help on how to properly calculate items witdh and navigation width and calculating when to add items to navigation or remove items from navigation.
Here is image if you don't get it: http://img.hr/aagV
/*
* Here we check how many items can we put on the navigation bar
* If item doesn't fit we clone it on the more dropdown button
*/
function removeMany() {
var i = $items.length - 1;
if (itemsWidth > navWidth) {
while (itemsWidth > navWidth) {
$($items[i]).removeClass('first-level-item').addClass('second-level-item');
dropdownItems.push($items[i]);
$($items[i]).removeClass('showed');
$items.pop();
i--;
getItemsWidth();
}
$nav.append($navMore);
dropdownItems.reverse().forEach(function (element, index, array) {
$('ul.second-level').append(element);
});
getItems();
}
}
//If window is resized to bigger resolution we need to put back items on the navbar
function addMany() {
var i = dropdownItems.length - 1;
if (dropdownItems.length != 0) {
do {
$('ul.first-level').append(dropdownItems.reverse()[i]);
$items.push(dropdownItems[i]);
dropdownItems.pop();
i--;
getItemsWidth();
} while (itemsWidth < navWidth);
$navMore.remove();
$items.each(function (i) {
$(this).addClass('first-level-item showed').removeClass('second-level-item');
});
if (!(dropdownItems != 0)) {
return;
} else {
$nav.append($navMore);
}
}
}
body {
margin: 0;
padding: 0;
border: 0; }
ul, li {
margin: 0;
padding: 0;
list-style: none; }
ul.second-level li {
display: block !important; }
ul.second-level li > a {
color: black; }
a {
color: #fff;
text-decoration: none;
text-transform: uppercase; }
.second-level-item a {
color: #333 !important; }
.navigation {
width: 960px;
max-width: 100%;
background: #211;
color: #aaa;
margin: 0 auto; }
.first-level .first-level-item {
display: inline-block;
padding: 10px; }
.first-level .item-more {
display: inline-block; }
.first-level .item-more .second-level-item {
display: inline-block; }
.second-level {
position: absolute;
top: 100%;
right: 0;
width: 200px;
background: #fff;
padding: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4); }
.has-second-level {
position: relative; }
.has-second-level .second-level {
display: none; }
.has-second-level:hover {
background: #fff;
color: #000; }
.has-second-level:hover .second-level {
display: block; }
/*# sourceMappingURL=style.css.map */
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>DropDown</title>
<link rel="stylesheet" href="css/reset.css"/>
<link rel="stylesheet" href="css/style.css"/>
</head>
<body>
<nav class="navigation">
<ul class="first-level">
<li class="first-level-item showed">Introduction to Irish Culture</li>
<li class="first-level-item showed">Cellular and Molecular Neurobiology</li>
<li class="first-level-item showed">Guitar foundations</li>
<li class="first-level-item showed">Startup Inovation</li>
<li class="first-level-item showed">Astrophysics</li>
<li class="first-level-item item-more has-second-level">
<span> More </span>
<ul class="second-level">
</ul>
</li>
</ul>
</nav>
<script src="https://code.jquery.com/jquery-2.1.1.js"></script>
</body>
</html>
If you have fixed-width list-items, then it is simple to collect extra list-items and push them into a separate list. Here is a simple example. Explanation is in the code comments.
View the snippet in full-screen and try changing the window width.
Also a Fiddle: http://jsfiddle.net/abhitalks/860LzgLL/
Full Screen: http://jsfiddle.net/abhitalks/860LzgLL/embedded/result/
Snippet:
var elemWidth, fitCount, fixedWidth = 120,
$menu = $("ul#menu"), $collectedSet;
// Assuming that the list-items are of fixed-width.
collect();
$(window).resize(collect);
function collect() {
// Get the container width
elemWidth = $menu.width();
// Calculate how many list-items can be accomodated in that width
fitCount = Math.floor(elemWidth / fixedWidth) - 1;
// Create a new set of list-items more than the fit count
$collectedSet = $menu.children(":gt(" + fitCount + ")");
// Empty the collection submenu and add the cloned collection set
$("#submenu").empty().append($collectedSet.clone());
}
* { box-sizing: border-box; margin: 0; padding: 0; }
div { position: relative; background-color: #ccc; height: 32px; overflow: visible; }
ul#menu, ol { height: 32px; max-width: 80%; overflow: hidden; }
ul#menu > li, ol > li { display: block; float: left; height: 32px; width: 120px; padding: 4px 8px; }
ol { position: absolute; right: 0; top: 0; overflow: visible; }
ol > li { min-width: 120px; }
ol ul { position: absolute; top: 120%; right: 10%; }
ol li ul > li { list-style: none; background-color: #eee; border: 1px solid gray; padding: 4px 8px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul id="menu">
<li>Option One</li><li>Option Two</li><li>Option Three</li>
<li>Option Four</li><li>Option Five</li><li>Option Six</li>
</ul>
<ol><li>Collected<ul id="submenu"></ul></li></ol>
</div>
Update:
This is regarding your query on differing / variable widths of list-items. There would be a minor change.
Also a Fiddle: http://jsfiddle.net/abhitalks/tkbmcupt/1/
Full Screen: http://jsfiddle.net/abhitalks/tkbmcupt/1/embedded/result/
Snippet:
var elemWidth, fitCount, varWidth = 0, ctr, $menu = $("ul#menu"), $collectedSet;
// Get static values here first
ctr = $menu.children().length; // number of children will not change
$menu.children().each(function() {
varWidth += $(this).outerWidth(); // widths will not change, so just a total
});
collect(); // fire first collection on page load
$(window).resize(collect); // fire collection on window resize
function collect() {
elemWidth = $menu.width(); // width of menu
// Calculate fitCount on the total width this time
fitCount = Math.floor((elemWidth / varWidth) * ctr) - 1;
// Reset display and width on all list-items
$menu.children().css({"display": "block", "width": "auto"});
// Make a set of collected list-items based on fitCount
$collectedSet = $menu.children(":gt(" + fitCount + ")");
// Empty the more menu and add the collected items
$("#submenu").empty().append($collectedSet.clone());
// Set display to none and width to 0 on collection,
// because they are not visible anyway.
$collectedSet.css({"display": "none", "width": "0"});
}
* { box-sizing: border-box; margin: 0; padding: 0; }
div { position: relative; background-color: #ccc; height: 32px; overflow: visible; }
ul#menu, ol { height: 32px; max-width: 80%; overflow: hidden; }
ul#menu > li, ol > li { display: block; float: left; height: 32px; white-space: nowrap; padding: 4px 8px; }
ol { position: absolute; right: 0; top: 0; overflow: visible; }
ol > li { min-width: 120px; }
ol ul { position: absolute; top: 120%; right: 10%; }
ol li ul > li { list-style: none; background-color: #eee; border: 1px solid gray; padding: 4px 8px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul id="menu">
<li>Option One</li><li>Option Two</li><li>Option Three</li>
<li>Option Four</li><li>Option Five</li><li>Option Six</li>
</ul>
<ol><li>Collected<ul id="submenu"></ul></li></ol>
</div>
Can and SHOULD be optimised (as it is quite inefficient from what i've tested), but that's up to you.
$(document).ready(function(){
var moreW = $(".more").outerWidth(), //width of your "more" element
totalW = -moreW, //cumulated width of list elements
totalN = $('.nav li').length - 1, //number of elements minus the "more" element
dw = document.documentElement.clientWidth;
$('.nav li').each(function(){
totalW += $(this).outerWidth();
});
function moveToDropdown(){
dw = document.documentElement.clientWidth;
//moves elements into the list
while(totalW > (dw - moreW)){
var temp = $(".nav li:nth-last-child(2)"); //element to be moved
totalW = totalW - temp.outerWidth();
$(".dropdown").append(temp.clone());
temp.remove();
}
//moves elements out of the list
var newList = $('.dropdown li').length; //check if we have elements
if(newList > 0){
var element = $('.dropdown li:last-child'), //element to be moved
elementW = $('.dropdown li:last-child').outerWidth(); //width of element to be moved
if(totalW + elementW < dw - moreW){
while(totalW + elementW < dw - moreW ){
var element = $('.dropdown li:last-child'),
elementW = $('.dropdown li:last-child').outerWidth();
totalW = totalW + elementW;
$(".nav > li:last-child").before(element.clone());
element.remove();
}
}
}
}
moveToDropdown();
$(window).resize(moveToDropdown)
});
.clearfix:after{
display:block;
content:'';
clear:both;
}
body,html{
width:100%;
height:100%;
margin:0;
padding:0;
}
ul{
list-style:none;
width:100%;
padding:0;
margin:0;
}
ul li{
float:left;
padding:5px;
}
.nav > li {
position:relative;
}
.nav ul{
position:absolute;
top:25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav clearfix">
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li>Item</li>
<li class="more">
more
<ul class="dropdown">
<!-- we'll add elements here -->
</ul>
</li>
</ul>
This question is too old, but i want to post my answer too. Maybe this is more cleaner and easier way. I have created a pen: https://codepen.io/sergi95/pen/bmNoML
<div id="mainMenu" class="main-menu">
<ul id="autoNav" class="main-nav">
<li>
home
</li>
<li>
about us
</li>
<li>
portfolio
</li>
<li>
team
</li>
<li>
blog
</li>
<li>
contact
</li>
<li id="autoNavMore" class="auto-nav-more">
more
<ul id="autoNavMoreList" class="auto-nav-more-list">
<li>
policy
</li>
</ul>
</li>
</ul>
const $mainMenu = $("#mainMenu");
const $autoNav = $("#autoNav");
const $autoNavMore = $("#autoNavMore");
const $autoNavMoreList = $("#autoNavMoreList");
autoNavMore = () => {
let childNumber = 2;
if($(window).width() >= 320) {
// GET MENU AND NAV WIDTH
const $menuWidth = $mainMenu.width();
const $autoNavWidth = $autoNav.width();
if($autoNavWidth > $menuWidth) {
// CODE FIRES WHEN WINDOW SIZE GOES DOWN
$autoNav.children(`li:nth-last-child(${childNumber})`).prependTo($autoNavMoreList);
autoNavMore();
} else {
// CODE FIRES WHEN WINDOW SIZE GOES UP
const $autoNavMoreFirst = $autoNavMoreList.children('li:first-child').width();
// CHECK IF ITEM HAS ENOUGH SPACE TO PLACE IN MENU
if(($autoNavWidth + $autoNavMoreFirst) < $menuWidth) {
$autoNavMoreList.children('li:first-child').insertBefore($autoNavMore);
}
}
if($autoNavMoreList.children().length > 0) {
$autoNavMore.show();
childNumber = 2;
} else {
$autoNavMore.hide();
childNumber = 1;
}
}
}
// INIT
autoNavMore();
$(window).resize(autoNavMore);
.main-menu {
max-width: 800px;
}
.main-nav {
display: inline-flex;
padding: 0;
list-style: none;
}
.main-nav li a {
padding: 10px;
text-transform: capitalize;
white-space: nowrap;
font-size: 30px;
font-family: sans-serif;
text-decoration: none;
}
.more-btn {
color: red;
}
.auto-nav-more {
position: relative;
}
.auto-nav-more-list {
position: absolute;
right: 0;
opacity: 0;
visibility: hidden;
transition: 0.2s;
text-align: right;
padding: 0;
list-style: none;
background: grey;
border-radius: 4px;
}
.auto-nav-more:hover .auto-nav-more-list {
opacity: 1;
visibility: visible;
}
The script that Abhitalks made did not work properly for different element sizes. I modified the code a little bit do that it does:
$(function() {
function makeMenuFit() {
//Get data
var menuSize = menu.width();
//Determine how many items that fit
var menuTotalWidth = 0;
var itemThatFit = 0;
for(var i = 0; i < menuItems.length; i++) {
menuTotalWidth += menuItems[i];
if(menuTotalWidth <= menuSize) {
itemThatFit++;
continue;
}
break;
}
menu.children().css({"display": "block", "width": "auto"});
var collectedSet = menu.children(":gt(" + (itemThatFit - 1) + ")");
$("#submenu").empty().append(collectedSet.clone());
collectedSet.css({"display": "none", "width": "0"});
}
var menu = $(".tabletNavigation > ul");
var menuItems = [];
menu.children().each(function() {
menuItems.push($(this).outerWidth());
});
$(window).resize(makeMenuFit);
makeMenuFit();
});
I've a menu code. When we mouse over it, a rectangular background animates to the mouse cursor and move back to active link, when mouse out. It works fine, when class of li tag is made active. But I need anchor tag to have class active.
live demo: http://insicdesigns.com/demo/css3/exp1/index.html
Please see the below code:
<div id="cmwmenu1" class="ddsmoothmenu ddcmwmenu" >
<ul>
<li class="active">Home</li>
<li>About</li>
<li>Blog</li>
<li>Services</li>
<li>Portfolio</li>
<li>Contacts</li>
<li>Back to Article</li>
<li>How it Works?</li>
</ul>
<div class="floatr"></div>
</div>
The live demo is working fine, but see their code. They have class active to list tag. My requirement is to have active tag in anchor, instead of li. If I do change, then this script isn't working.
I want it to be like below format and the javasript to work for below code.
<li><a class="active" href="">Home</a></li>
Javascript:
$(document).ready(function () {
var dleft = $('#cmwmenu1 li.active').offset().left - $('#cmwmenu1').offset().left;
var dwidth = $('#cmwmenu1 li.active').width() + "px";
$('.floatr').css({
"left": dleft+"px",
"width": dwidth
});
$('li').hover(function(){
var left = $(this).offset().left - ($(this).parents('#cmwmenu1').offset().left + 15);
var width = $(this).width() + "px";
var sictranslate = "translate("+left+"px, 0px)";
$(this).parent('ul').next('div.floatr').css({
"width": width,
"-webkit-transform": sictranslate,
"-moz-transform": sictranslate
});
},
function(){
var left = $(this).siblings('li.active').offset().left - ($(this).parents('#cmwmenu1').offset().left + 15);
var width = $(this).siblings('li.active').width() + "px";
var sictranslate = "translate("+left+"px, 0px)";
$(this).parent('ul').next('div.floatr').css({
"width": width,
"-webkit-transform": sictranslate,
"-moz-transform": sictranslate
});
})
});
Css:
#cmwmenu1 {
position: relative;
border: 1px solid #d6d6d6;
background: #fff;
padding: 15px;
-webkit-box-shadow: 0 3px 6px rgba(0,0,0,.25);
-moz-box-shadow: 0 3px 6px rgba(0,0,0,.25);
border-radius : 10px;
-moz-border-radius : 10px;
-webkit-border-radius : 10px;
background : -webkit-gradient(linear, left top, left bottom, from(rgb(240,240,240)), to(rgb(204,204,204)));
background : -moz-gradient(linear, left top, left bottom, from(rgb(240,240,240)), to(rgb(204,204,204)));
height: 18px;
}
a {
text-decoration: none;
color: #262626;
line-height: 20px;
}
ul {
margin: 0;
padding: 0;
z-index: 300;
position: absolute;
}
ul li {
list-style: none;
float:left;
text-align: center;
}
ul li a {
padding: 0 20px;
text-align: center;
}
.floatr {
position: absolute;
top: 10px;
z-index: 50;
width: 70px;
height: 30px;
border-radius : 8px;
-moz-border-radius : 8px;
-webkit-border-radius : 8px;
background : rgba(0,0,0,.20);
-webkit-transition: all .4s ease-in-out;
-moz-transition: all .4s ease-in-out;
}
how about this
var li = $('li');
li.click(function(){
$this = $(this);
li.removeClass('active').find('a').removeClass('active');
$this.addClass('active').find('a').addClass('active');
})