Background
I am more formally trained in backend/server-side coding. Over my career I have often found myself thrown into front-end coding. I have spent the last year and a half learning JavaScript/CSS3 on an "on Demand" basis. I feel like I am getting the hang of it, doing fancier things to meet UX requirements like animations and being able to layout a page without relying too much on a framework like Bootstrap.
Code
In this sample, I have put together an animated flyout menu for a profile image in a header. The idea is, you click on your profile image, and a menu animates to opacity 1, click it again, and the menu animates to opacity 0. For the sake of simplicity, the profile image is simply a cyan circle shaped div . If you would be so kind as to point out any flaws, or better practices I can adopt to make this code more readable/reliable/maintainable, it would be appreciated.
To see a working demo, I have built it in codepen: http://codepen.io/anon/pen/dNxeRN
HTML
<div class="header">
<a href="#" class="logo">
My Logo And Brand
</a>
<div class="profile-image">
</div>
<div class="fly-over">
<ul>
<li>Account settings</li>
<li>My Profile</li>
<li>Logout</li>
</ul>
</div>
</div>
CSS
*{
margin: 0;
padding: 0;
font-family: helvetica, arial, sans-serif;
}
.header {
padding-top: 5px;
width: 1000px;
height: 60px;
border-bottom: 1px solid darkgrey;
position: relative;
}
a.logo {
display: inline-block;
font-size: 25px;
margin-top: 14px;
margin-left: 10px;
text-decoration:none;
color: black;
}
.profile-image {
width: 50px;
height: 50px;
background-color: cyan;
border: 2px solid grey;
border-radius: 50px;
cursor: pointer;
float:right;
margin-right: 50px;
}
.fly-over{
position: absolute;
display: none;
width: 300px;
border-radius: 5px;
box-shadow: 1px 1px 10px 1px rgba(0,0,0,.3);
text-align: left;
right: 36px;
top: 80px;
}
.fly-over ul,
.fly-over ul li {
margin: 0px;
padding: 0px;
}
.fly-over ul li {
list-style-type: none;
padding-left: 20px;
padding-top: 10px;
padding-bottom: 10px;
border-bottom: 1px solid lightgrey;
cursor: pointer;
transition: color, background-color 333ms;
}
.fly-over ul li:hover{
background-color: #888888;
color: white;
}
.fly-over:after{
content: " ";
display:block;
position: absolute;
width: 0px;
height: 0px;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid grey;
bottom: 100%;
left: 250px;
}
.fly-over.show{
display: block;
}
.animation-fade-in,
.animation-fade-out{
display: block;
animation-name: fadeIn;
animation-duration: 333ms;
animation-timing-functon: ease-out;
animation-fill-mode: forwards;
animation-direction: normal;
}
.animation-fade-out{
animation-direction: reverse;
}
@keyframes fadeIn{
0%{
opacity: 0;
}
100%{
opacity: 1;
}
}
JS
var el = document.getElementsByClassName("profile-image")[0];
var menuState = {
visible: false
};
el.addEventListener('click', function(){
var flyOverEl = document.getElementsByClassName("fly-over")[0];
function onFadeInAnimationEnd(){
this.classList.add('show');
this.classList.remove('animation-fade-in');
menuState.visible = true;
this.removeEventListener('animationend', onFadeInAnimationEnd);
}
function onFadeOutAnimationEnd(){
this.classList.remove('animation-fade-out');
menuState.visible = false;
this.removeEventListener('animationend', onFadeOutAnimationEnd);
}
if(menuState.visible){
flyOverEl.classList.remove("show");
flyOverEl.addEventListener("animationend", onFadeOutAnimationEnd)
flyOverEl.classList.add("animation-fade-out");
}
else{
flyOverEl.addEventListener("animationend", onFadeInAnimationEnd)
flyOverEl.classList.add("animation-fade-in");
}
})