Reputation: 460
I am currently playing around with a menu animation. I achieved the desired result but it's not optimised and I can't manage to create a function to loop through the elements and apply the correct effect.
What I am basically doing is going through all LI after and before the LI hovered and reducing/fading the elements based on their positions. So the further the LI is from the hovered one the smaller and transparent it gets.
My solution is obviously not flexible as I need to run through all the values again if I add/remove a LI.
I would be interested to know how you would simplify that.
The code is quite simple.
$(document).ready(function(){
$("ul li").on("mouseover", function(){
$("ul li").removeClass("current");
var liLength = $("ul li").length;
$(this).css({
"width": "42",
"opacity": "1"
}).prevAll().eq(0).css({
"width": "35",
"opacity": "0.8333333334"
}).prevAll().eq(0).css({
"width": "28",
"opacity": "0.6666666667"
}).prevAll().eq(0).css({
"width": "21",
"opacity": "0.5"
}).prevAll().eq(0).css({
"width": "14",
"opacity": "0.3333333333"
}).prevAll().eq(0).css({
"width": "7",
"opacity": "0.16666666667"
});
$(this).css({
"width": "42",
"opacity": "1"
}).nextAll().eq(0).css({
"width": "35",
"opacity": "0.8333333334"
}).nextAll().eq(0).css({
"width": "28",
"opacity": "0.6666666667"
}).nextAll().eq(0).css({
"width": "21",
"opacity": "0.5"
}).nextAll().eq(0).css({
"width": "14",
"opacity": "0.3333333333"
}).nextAll().eq(0).css({
"width": "7",
"opacity": "0.16666666667"
});
$("ul li").on("mouseout", function(){
$("ul li").removeClass("current").css({
"width": "21",
"opacity": "1"
});
});
});
});
html, body, ul{
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.container{
height: 100%;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
align-items: center;
}
ul{
display: block;
position: relative;
height: auto;
}
ul li{
list-style:none;
background: #232323;
border-top: 10px solid #fff;
border-bottom: 10px solid #fff;
border-right: 10px solid #fff;
height: 10px;
width: 21px;
translate3d(0,0,0);
-webkit-transition: all 200ms linear;
transition:all 200ms linear;
}
ul li.current{
background: blue;
}
.exp{
position: fixed;
top: 0;
right: 0;
background: grey;
width: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
The key elements :
The bigger element should be 42px wide and opacity : 1 The smaller element should be 7px wide and opacity : 0.2
The size should decrease as follow : (42 - 7) / x-elements * index of the element compared to its position from the hovered element.
The opacity should decrease as follow : (1 - 0.2) / x-elements * index of the element compared to its position from the hovered element.
The Prototype : Codepen
Thanks a lot!
Upvotes: 2
Views: 99
Reputation: 7614
I've done a similar thing as DaniP. Although his code is much more optimised. I'm posting here more due to the fact that I spent a lot of time putting this together :)
Like I said, have a look at Dani's codepen, it's a lot less code, however if you need to spread out the functions with additional variables, have a look at my fiddle below:
https://jsfiddle.net/uyazymmu/2/
The code is really simple and goes through a few basic steps:
li
'sHere's the code:
$(document).ready(function() {
$('li').mouseenter(function() {
var li_index = $(this).index() + 1; // mark the position of the li
var li_total = $('li').length; //total li's
$(this).css({ //initial CSS
'width': '42px',
'opacity': '1'
});
$(this).prevAll().each(function() { //loop through all previous li's
var prev_index = $(this).index() + 1;
var distance = li_index - prev_index;
var opacity = 1 - (0.2 * distance);
var width = 42 - (7 * distance);
$(this).css({
'width': width + 'px',
'opacity': opacity
});
});
$(this).nextAll().each(function() { // loop through all the next li's
var next_index = $(this).index() + 1;
var distance = next_index - li_index;
var opacity = 1 - (0.2 * distance);
var width = 42 - (7 * distance);
$(this).css({
'width': width + 'px',
'opacity': opacity
});
});
});
$('li').mouseleave(function() {
$('li').each(function() {
$(this).css({ //reset everything
'width': '21px',
'opacity': '1'
});
});
});
});
html,
body,
ul {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
.container {
height: 100%;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
align-items: center;
}
ul {
display: block;
position: relative;
height: auto;
}
ul li {
list-style: none;
background: #232323;
border-top: 20px solid #fff;
border-bottom: 20px solid #fff;
border-right: 40px solid #fff;
height: 2px;
width: 21px;
translate3d(0, 0, 0);
-webkit-transition: all 200ms linear;
transition: all 200ms linear;
}
ul li.current {
background: blue;
}
.exp {
position: fixed;
top: 0;
right: 0;
background: grey;
width: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
Upvotes: 2
Reputation: 38252
You can iterate through each collection of elements and use the index
as indicator; try something like this:
$(this).css({"width": "42","opacity":"1"})
.prevAll().each(function(index){
$(this).css({
"width": ((42-7)/(index+1))+"px",
"opacity": ((1-0.2)/(index+1))
})
})
Upvotes: 2