JQuery Hover Flicker On Dropdowns - javascript

I'm trying to toggle between the categories in the JSFiddle below, it works fine aside from there's a flicker when hides and shows the new content.
Is there a way to fix this?
https://jsfiddle.net/0q7fzh6u/1/
Cheers
// Overlay dropdown menu
var menuItem = $(".header-categories-item");
var categoriesDropdown = $(".header-categories-dropdown");
menuItem.hover(function() {
$("body").toggleClass("overlay-visible");
$(this).children(categoriesDropdown).toggleClass("categories-dropdown-visible");
});
.header-categories {
position: relative;
clear: both;
background: #fff;
z-index: 10;
}
.header-categories-list {
margin-bottom: 0;
}
.header-categories-item {
display: inline-block;
vertical-align: top;
letter-spacing: 0.2rem;
line-height: 1;
font-size: 13px;
padding-top: 15px;
padding-bottom: 15px;
padding-left: 15px;
padding-right: 15px;
}
.header-categories-item a {
color: #000;
}
.header-categories-item-block {
display: block;
padding: 0;
border-top: 1px solid $black;
}
/* overlay */
#site-overlay {
visibility: hidden;
opacity: 0;
z-index: 5;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #999;
transition: .25s;
}
.overlay-visible #site-overlay {
visibility: visible;
opacity: 1;
}
/* Dropdown */
.header-categories-dropdown {
visibility: hidden;
opacity: 0;
position: absolute;
top: 100%;
left: 0;
width: 100%;
min-height: 300px;
padding: 15px 0;
background: #fff;
}
li {
padding-bottom: 15px;
padding-left: 15px;
padding-right: 15px;
}
.header-categories-dropdown.categories-dropdown-visible {
visibility: visible;
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
HTML
<div id="site-overlay"></div>
<div class="header-categories pull-right hidden-xs hidden-sm">
<ul class="header-categories-list list-unstyled">
<li class="header-categories-item header-categories-item-active">category name 1
<ul class="header-categories-dropdown list-unstyled">
<li>test 1</li>
<li>test 2</li>
</ul>
</li>
<li class="header-categories-item header-categories-item-active">category name 2
<ul class="header-categories-dropdown list-unstyled">
<li>test 3</li>
<li>test 4</li>
</ul>
</li>
</ul>
</div>

What's causing this problem is that there is a gap between the li tags .header-categories-item, so whenever you hover over this gap you get the flick
You can remove the gap by adding margin-right: -5px; to .header-categories-item
See updated fiddle

If you remove the whitespace between the two li-tags, the flicker is gone.
I don't know how to remove the gap in CSS, though. Removing it by margin-right: -5px as Chiller has proposed seems not very reliable to me - maybe the gap is smaller or bigger in a different browser?
Edit
Found a solution: You can set font-size: 0; on the ul to remove the gap.
// Overlay dropdown menu
var menuItem = $(".header-categories-item");
var categoriesDropdown = $(".header-categories-dropdown");
menuItem.hover(function() {
$("body").toggleClass("overlay-visible");
$(this).children(categoriesDropdown).toggleClass("categories-dropdown-visible");
});
.header-categories {
position: relative;
clear: both;
background: #fff;
z-index: 10;
}
.header-categories-list {
margin-bottom: 0;
font-size: 0;
}
.header-categories-item {
display: inline-block;
vertical-align: top;
letter-spacing: 0.2rem;
line-height: 1;
font-size: 13px;
padding-top: 15px;
padding-bottom: 15px;
padding-left: 15px;
padding-right: 15px;
}
.header-categories-item a {
color: #000;
}
.header-categories-item-block {
display: block;
padding: 0;
border-top: 1px solid $black;
}
/* overlay */
#site-overlay {
visibility: hidden;
opacity: 0;
z-index: 5;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #999;
transition: .25s;
}
.overlay-visible #site-overlay {
visibility: visible;
opacity: 1;
}
/* Dropdown */
.header-categories-dropdown {
visibility: hidden;
opacity: 0;
position: absolute;
top: 100%;
left: 0;
width: 100%;
min-height: 300px;
padding: 15px 0;
background: #fff;
}
li {
padding-bottom: 15px;
padding-left: 15px;
padding-right: 15px;
}
.header-categories-dropdown.categories-dropdown-visible {
visibility: visible;
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
HTML
<div id="site-overlay"></div>
<div class="header-categories pull-right hidden-xs hidden-sm">
<ul class="header-categories-list list-unstyled">
<li class="header-categories-item header-categories-item-active">category name 1
<ul class="header-categories-dropdown list-unstyled">
<li>test 1</li>
<li>test 2</li>
</ul>
</li>
<li class="header-categories-item header-categories-item-active">category name 2
<ul class="header-categories-dropdown list-unstyled">
<li>test 3</li>
<li>test 4</li>
</ul>
</li>
</ul>
</div>
So either this, or you remove the whitespace in the HTML code:
<!-- ... -->
</li><li class="header-categories-item header-categories-item-active">
<!-- ... -->
// Overlay dropdown menu
var menuItem = $(".header-categories-item");
var categoriesDropdown = $(".header-categories-dropdown");
menuItem.hover(function() {
$("body").toggleClass("overlay-visible");
$(this).children(categoriesDropdown).toggleClass("categories-dropdown-visible");
});
.header-categories {
position: relative;
clear: both;
background: #fff;
z-index: 10;
}
.header-categories-list {
margin-bottom: 0;
}
.header-categories-item {
display: inline-block;
vertical-align: top;
letter-spacing: 0.2rem;
line-height: 1;
font-size: 13px;
padding-top: 15px;
padding-bottom: 15px;
padding-left: 15px;
padding-right: 15px;
}
.header-categories-item a {
color: #000;
}
.header-categories-item-block {
display: block;
padding: 0;
border-top: 1px solid $black;
}
/* overlay */
#site-overlay {
visibility: hidden;
opacity: 0;
z-index: 5;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #999;
transition: .25s;
}
.overlay-visible #site-overlay {
visibility: visible;
opacity: 1;
}
/* Dropdown */
.header-categories-dropdown {
visibility: hidden;
opacity: 0;
position: absolute;
top: 100%;
left: 0;
width: 100%;
min-height: 300px;
padding: 15px 0;
background: #fff;
}
li {
padding-bottom: 15px;
padding-left: 15px;
padding-right: 15px;
}
.header-categories-dropdown.categories-dropdown-visible {
visibility: visible;
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
HTML
<div id="site-overlay"></div>
<div class="header-categories pull-right hidden-xs hidden-sm">
<ul class="header-categories-list list-unstyled">
<li class="header-categories-item header-categories-item-active">category name 1
<ul class="header-categories-dropdown list-unstyled">
<li>test 1</li>
<li>test 2</li>
</ul>
</li><li class="header-categories-item header-categories-item-active">category name 2
<ul class="header-categories-dropdown list-unstyled">
<li>test 3</li>
<li>test 4</li>
</ul>
</li>
</ul>
</div>
Both work, but I'd prefer the CSS solution (or both).

Related

Toggle active nav-link

I have a problem with toggling the active nav-link using JavaScript. I think my CSS is causing some problems but I do not know why.
I have the CSS code down at the bottom if that is any help. I have linked Jquery and my own name.js document correctly in my HTML head. I want to toggle the active link when it is visited.
var header = document.getElementById("nav-bar")
var toggled_nav = document.getElementsByClassName("nav-item")
for (var i = 0; i < toggled_nav.length; i++) {
toggled_nav[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
}
#nav-bar {
margin: 27px auto 0;
position: relative;
width: 610px;
height: 50px;
background-color: #34495e;
border-radius: 8px;
font-size: 0;
}
#nav-bar a {
line-height: 50px;
height: 100%;
font-size: 15px;
display: inline-block;
position: relative;
z-index: 1;
text-decoration: none;
text-transform: uppercase;
text-align: center;
color: white;
cursor: pointer;
}
#nav-bar .animation {
position: absolute;
height: 100%;
top: 0;
z-index: 0;
transition: all .5s ease 0s;
border-radius: 8px;
}
a:nth-child(1) {
width: 100px;
}
a:nth-child(2) {
width: 110px;
}
a:nth-child(3) {
width: 180px;
}
a:nth-child(4) {
width: 110px;
}
a:nth-child(5) {
width: 110px;
}
nav .start-home,
a:nth-child(1):hover~.animation {
width: 100px;
left: 0;
background-color: #1abc9c;
}
nav .start-about,
a:nth-child(2):hover~.animation {
width: 110px;
left: 100px;
background-color: #fcf75e;
}
nav .start-blog,
a:nth-child(3):hover~.animation {
width: 180px;
left: 210px;
background-color: #3498db;
}
nav .start-portefolio,
a:nth-child(4):hover~.animation {
width: 90px;
left: 400px;
background-color: #9b59b6;
}
nav .start-contact,
a:nth-child(5):hover~.animation {
width: 110px;
left: 500px;
background-color: #e67e22;
}
<nav id="nav-bar">
<a class="nav-item" href="#">HOME</a>
<a class="nav-item" href="#">POKEMON</a>
<a class="nav-item" href="#">LEAUGE OF LEGENDS</a>
<a class="nav-item" href="#">API-DOC</a>
<a class="nav-item" href="#">ABOUT US</a>
<div class="animation start-home"></div>
</nav>
I simplified your code and created specific active classes for each nav. You can give the parent the click handler and refer to the children through e.target since in this case the children take up the full space of the parent.
var header = document.getElementById("nav-bar")
header.addEventListener("click",function(e){
has_class = header.querySelector(".active");
if(has_class)has_class.classList.remove("active");
e.target.classList.add("active");
});
#nav-bar {
margin: 27px auto 0;
position: relative;
width: 610px;
height: 50px;
background-color: #34495e;
border-radius: 8px;
font-size: 0;
}
#nav-bar a {
line-height: 50px;
height: 100%;
font-size: 15px;
display: inline-block;
position: relative;
z-index: 1;
text-decoration: none;
text-transform: uppercase;
text-align: center;
color: white;
cursor: pointer;
}
#nav-bar .animation {
position: absolute;
height: 100%;
top: 0;
z-index: 0;
transition: all .5s ease 0s;
border-radius: 8px;
}
.active{
border-radius: 8px;
}
a:nth-child(1) {
width: 100px;
}
a:nth-child(2) {
width: 110px;
}
a:nth-child(3) {
width: 180px;
}
a:nth-child(4) {
width: 110px;
}
a:nth-child(5) {
width: 110px;
}
a:nth-child(1).active{
background:#1abc9c;
}
nav .start-home, a:nth-child(1):hover~.animation {
width: 100px;
left: 0;
background-color: #1abc9c;
}
a:nth-child(2).active{
background:#fcf75e;
}
nav .start-about, a:nth-child(2):hover~.animation {
width: 110px;
left: 100px;
background-color: #fcf75e;
}
a:nth-child(3).active{
background:#3498db;
}
nav .start-blog, a:nth-child(3):hover~.animation {
width: 180px;
left: 210px;
background-color: #3498db;
}
a:nth-child(4).active{
background:#9b59b6;
}
nav .start-portefolio, a:nth-child(4):hover~.animation {
width: 90px;
left: 400px;
background-color: #9b59b6;
}
a:nth-child(5).active{
background:#e67e22;
}
nav .start-contact, a:nth-child(5):hover~.animation {
width: 110px;
left: 500px;
background-color: #e67e22;
}
<nav id="nav-bar">
<a class="nav-item" href="#">HOME</a>
<a class="nav-item" href="#">POKEMON</a>
<a class="nav-item" href="#">LEAUGE OF LEGENDS</a>
<a class="nav-item" href="#">API-DOC</a>
<a class="nav-item" href="#">ABOUT US</a>
<div class="animation start-home"></div>
</nav>
For the first two .nav-item I see they are referring to different files. So in their curresponding files, you can mark them active.
For rest of the three .nav-item you can use (I am using JQuery since you mentioned it)
$('#nav-bar').on('click', '.nav-item', function(e) {
$('.nav-item.active', e.currentTarget).removeClass('active');
$(this).addClass('active');
}
make sure the css for the .active is being applied correctly.
You could do something like this; where you remove the active class for each item and then add it to the one that was clicked.
let items = document.querySelectorAll(".nav-item")
items.forEach(item => {
item.addEventListener("click", event => {
const current = document.querySelector('.active')
current.classList.remove('active')
item.classList.add("active")
})
})

Javascript event listener overwrites another event listener

so I am trying to create a multilevel navigation for a mobile device and I am running into some issues. I am still learning javascript so please bare with me. Here is a link to the codepen:
https://codepen.io/maciekmat/pen/yLepYKq
So when you press the menu in the top right, a menu will open down. Then I would like to be able to go into sub categories. For example click Test Open, .active class will be assigned, and another menu slides in. Now I would like to have a go back button that essentially removes the .active class.
However what I think is happening, the event listener listens to the whole parent, and anywhere you click inside the subnavigation, it registers it as a click, and runs the .active class. When I click to go back, its like .active is removed and applied back instantly. Any help please?
I tried doing the event.currentEvent !== event.target if statement but had no luck
const nav = document.getElementById('menuIcon')
const dropdown = document.getElementById('menuDropdown')
nav.addEventListener('click', function() {
dropdown.classList.toggle('nav-is-toggled')
});
const grabNavLinks = document.querySelectorAll('.sub-nav-link');
const grabBackLinks = document.querySelectorAll('.nav-link.back');
const subNavLinks = Array.from(grabNavLinks);
const backLinks = Array.from(grabBackLinks);
for (let i = 0; i < subNavLinks.length; i++) {
subNavLinks[i].addEventListener("click", function() {
this.querySelector('.sub-nav').classList.add('active');
});
}
for (let i = 0; i < backLinks.length; i++) {
backLinks[i].addEventListener("click", function() {
document.querySelector('.sub-nav').classList.remove('active');
});
}
#import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght#300;400;600;700&display=swap");
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: "Open sans", sans-serif;
background: #F9F9F9;
box-sizing: border-box;
}
a, p, h1, h2, h3 {
margin: 0;
padding: 0;
text-decoration: none;
}
ul, li {
padding: 0;
margin: 0;
}
header {
background: white;
padding: 24px 30px;
display: flex;
flex-direction: column;
z-index: 10;
position: relative;
}
.top-nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.top-nav .logo {
background: url("images/tcb-logo-brand.svg") no-repeat;
width: 150px;
height: 50px;
background-size: contain;
background-position: center;
}
.top-nav .navigation {
display: flex;
justify-content: space-between;
width: 132px;
height: 26px;
}
.top-nav .navigation .nav-item {
width: 23px;
height: 26px;
margin-left: 10px;
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
.top-nav .navigation .nav-item.menu {
background-image: url("images/menu-icon.svg");
}
.top-nav .navigation .nav-item.notification {
background-image: url("images/bell-icon.svg");
}
.top-nav .navigation .nav-item.my-account {
background-image: url("images/acc-icon.svg");
}
.search {
margin-top: 16px;
}
.search input[type=search] {
outline: none;
border: none;
background: #F6F6F6;
width: 100%;
height: 50px;
font-size: 16px;
padding: 10px 0 10px 20px;
background-image: url("images/search-icon.svg");
background-repeat: no-repeat;
background-position: right 15px top 50%;
}
.search input[type=search]::placeholder {
color: #B7B7B7;
}
span.nav-title {
display: none;
}
nav.main-nav {
width: 100%;
background: #F6F6F6;
transform: translateY(-100%);
z-index: 0;
position: relative;
transition: all 0.3s ease-in-out;
position: absolute;
padding-bottom: 50px;
overflow: hidden;
}
nav.main-nav ul {
padding-top: 2px;
position: relative;
}
nav.main-nav li {
list-style: none;
}
nav.main-nav a {
color: #6D6D6D;
font-size: 16px;
width: 100%;
height: 100%;
display: block;
padding: 18px 30px;
border-bottom: 1px solid #E9E9E9;
}
nav.main-nav li.nav-link.arrow {
background: url("images/right-arrow.svg") no-repeat;
background-position: right 30px top 50%;
}
nav.main-nav ul.sub-nav {
background: #cecece;
width: 100%;
display: flex;
flex-direction: column;
transform: translateX(100%);
overflow: hidden;
visibility: hidden;
opacity: 0;
position: absolute;
top: 0;
left: 0;
transition: transform 0.2s ease;
}
.sub-nav-link > .sub-nav.active {
transform: translateX(0);
visibility: visible;
opacity: 1;
}
nav.nav-is-toggled {
position: static;
opacity: 1;
transform: translateY(0);
transition: all 0.3s ease-in-out;
}
<header>
<div class="top-nav">
<div class="logo"></div>
<div class="navigation">
<div id="menuIcon" class="nav-item menu">test</div>
<div class="nav-item notification"></div>
<div class="nav-item my-account"><span class="nav-title">My Account</span></div>
</div>
</div>
<div class="search">
<input type="search" name="search" id="search" placeholder="Search by store...">
</div>
</header>
<nav id="menuDropdown" class="main-nav">
<ul class="main-nav-ul">
<li class="nav-link">Test</li>
<li class="nav-link arrow sub-nav-link">Test Open
<ul class="sub-nav">
<li class="nav-link back">Go Back</li>
<li class="nav-link">Test</li>
<li class="nav-link">Test</li>
<li class="nav-link">Test</li>
</ul>
</li>
<li class="nav-link">Test</li>
<li class="nav-link">Test</li>
<li class="nav-link arrow sub-nav-link">Test Open
<ul class="sub-nav">
<li class="nav-link back">Go Back</li>
<li class="nav-link">Test</li>
<li class="nav-link">Test</li>
</ul>
</li>
<li class="nav-link">Test</li>
</ul>
</nav>
<script src="navigation.js"></script>
Go read on event bubbling and how it bubbles through the DOM tree. However due to the way it passes from parent to child (that's it bubbles down the tree) you should call event.stopPropagation(); So that the previous event doesnt bubble into the backLinks event listener.
This is what you should do
for (let i = 0; i < backLinks.length; i++) {
backLinks[i].addEventListener("click", function(event) {
event.stopPropagation();
document.querySelector('.sub-nav').classList.remove('active');
});
}

How to animate menu background changing image?

i am trying to animate when i hover a li.. background image will be the zoom out
$(function () {
var image = $('.menu').find('img').attr('src');
$('.menu ul li').mouseover(function () {
var currentImage = $(this).attr('data-img');
$(this).parent().parent().parent().parent().find('img').attr('src', currentImage); })});
::-webkit-scrollbar{display: none; visibility: hidden;}
body{margin: 0; background: burlywood; }
.menu { position: relative; text-align: center; margin: auto; height: 100%; padding-top: 2%; padding-bottom: 10%; z-index: 99;}
.menu li{ display: block; font-size: 1.5rem; font-family: "Raleway SemiBold", Serif, sans-serif; padding-bottom: 20px;}
.menu li+li{margin-top: 30px;}
.menu a{ font-size: 3.5rem;}
.navigationGif{ position: fixed; top: 0; bottom: 0; left: 0; right: 0; animation: menuBG 0.7s ease-in;}
.homeGif{ position: fixed;}
.menu img{ width: 100%; }
#keyframes menuBG { from{ opacity: 0; transform: scale(1.05); }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="menu">
<div class="navigationGif">
<div class=""> <img src="https://images.unsplash.com/photo-1532109513327-3b32b2a9bd57?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" alt="" class="src"> </div> </div>
<div class="menu"> <div class="data"><ul>
<li>Navigation</li>
<li data-img="https://images.unsplash.com/photo-1532109513327-3b32b2a9bd57?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" class="navLink home active"><span>H</span><span>o</span><span>m</span><span>e</span></li>
<li data-img="https://images.unsplash.com/photo-1589986118236-64c32953ab27?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" class="navLink works">Works</li>
<li data-img="https://images.unsplash.com/photo-1589892889837-e0236f8dd22e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=753&q=80" class="navLink about">About</li>
<li data-img="https://images.unsplash.com/photo-1558567083-b8cb6bb5f7d9?ixlib=rb-1.2.1&auto=format&fit=crop&w=763&q=80" class="navLink contact">Contact</li></ul> </div></div></div>
Try to reset the animation, also avoid too many parent() call as possible by select closest element or create better class names.
So here I make a small modification to get what you need, by add a class name to the background img that trigger animation, every time you change the hover to other menu item (LI element) it will toggle the class name so the animation will restart each time.
$(function () {
var image = $('.menu').find('img').attr('src');
var lastImage
$('.menu ul li.navLink').mouseover(function () {
var currentImage = $(this).attr('data-img');
$('.navigationGif img').attr('src', currentImage);
if(lastImage !== currentImage) {
$('.navigationGif').removeClass('animation')
setTimeout(() => {
$('.navigationGif').addClass('animation')
}, 10);
lastImage = currentImage
}
})
});
::-webkit-scrollbar {
display: none;
visibility: hidden;
}
body {
margin: 0;
background: burlywood;
}
.menu {
position: relative;
text-align: center;
margin: auto;
height: 100%;
padding-top: 2%;
padding-bottom: 10%;
z-index: 99;
}
.menu li {
display: block;
font-size: 1.5rem;
font-family: "Raleway SemiBold", Serif, sans-serif;
padding-bottom: 20px;
}
.menu li+li {
margin-top: 30px;
}
.menu a {
font-size: 3.5rem;
}
.navigationGif {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.navigationGif.animation {
animation: menuBG 0.7s ease-in;
}
.homeGif {
position: fixed;
}
.menu img {
width: 100%;
}
#keyframes menuBG {
from {
opacity: 0;
transform: scale(1.05);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="menu">
<div class="navigationGif animation">
<div class=""> <img
src="https://images.unsplash.com/photo-1532109513327-3b32b2a9bd57?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80"
alt="" class="src"> </div>
</div>
<div class="menu">
<div class="data">
<ul>
<li>Navigation</li>
<li
data-img="https://images.unsplash.com/photo-1532109513327-3b32b2a9bd57?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80"
class="navLink home active"><a href=""
class="navItem"><span>H</span><span>o</span><span>m</span><span>e</span></a></li>
<li
data-img="https://images.unsplash.com/photo-1589986118236-64c32953ab27?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80"
class="navLink works">Works</li>
<li
data-img="https://images.unsplash.com/photo-1589892889837-e0236f8dd22e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=753&q=80"
class="navLink about">About</li>
<li
data-img="https://images.unsplash.com/photo-1558567083-b8cb6bb5f7d9?ixlib=rb-1.2.1&auto=format&fit=crop&w=763&q=80"
class="navLink contact">Contact</li>
</ul>
</div>
</div>
</div>

"Place dots" in HTML/CSS/JS slideshow

I'm trying to make a slideshow with those little navigation or placeholder dots along the bottom - the slideshow itself is working, but in the minimal example here, there's only one dot showing up at the bottom. I can't figure out what I'm doing wrong - researched, left it for a couple days and came back to it, now time for a question...
Here's the code I'm working with:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html {
background-color: lightblue;
}
body {
width:1024px;
height:768px;
margin-left: auto;
margin-right: auto;
border-style: solid;
background: lightgreen;
position: relative;
}
div#banner{
position: absolute;
top:50px;
width: 100%;
height: 120px;
background: pink;
text-align: center;
padding-top: 0px;
padding-bottom: 0px;
font-size:1.5em;
}
div#minibanner{
position: absolute;
top:0px;
height:50px;
width: 100%;
background: orange;
text-align: center;
}
div#slideContainer {
position:absolute;
left:200px;
top:170px;
height:558px;
width:794px;
padding-top: 30px;
padding-left:30px;
font-size: 2em;
background: yellow;
}
div#sidenav{
position: absolute;
top:170px;
left:0px;
width: 200px;
height:558px;
}
.contentSlide{
display: none;
}
div#bottomnav{
position: absolute;
bottom:0px;
height:40px;
width: 100%;
background: pink;
text-align: center;
}
.dot {
position:absolute;
bottom:60px;
cursor: pointer;
height: 15px;
width: 15px;
margin: 22px 22px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active, .dot:hover {
background-color: #717171;
}
.fade {
-webkit-animation-name: fade;
-webkit-animation-duration: 1.5s;
animation-name: fade;
animation-duration: 1.5s;
}
#-webkit-keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
#keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
.prev, .next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -22px;
color: red;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
.prev {
left:0;
}
.prev:hover, .next:hover {
background-color: rgba(0,0,0,0.8);
}
</style>
</head>
<body>
<div id="minibanner"><h3>Title of Presentation: testing, testing testing</h3></div>
<div id="banner"><h1>Introduction</h1></div>
<div id="sidenav">
<ul>
<li>home</li>
<li>Introduction</li>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
<li>Conclusion</li>
</ul>
</div>
<div id="slideContainer">
<div class="contentSlide fade">
<p>Here's an outline:
<ul>
<li>Introduction</li>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
<li>Conclusion</li>
</ul>
</p>
</div>
<div class="contentSlide fade">
<p>Here are some themes:
<ul>
<li>Theme 1</li>
<li>Theme 2</li>
<li>Theme 3</li>
</ul>
</p>
</div>
<div class="contentSlide fade">
<p>...and the conclusions:
<ul>
<li>Conclusion A</li>
<li>Conclusion B</li>
<li>Conclusion C</li>
<li>Conclusion D</li>
<li>Conclusion E</li>
</ul>
</p>
</div>
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
<div style="text-align:center">
<span class="dot" onclick="currentSlide(1)"></span>
<span class="dot" onclick="currentSlide(2)"></span>
<span class="dot" onclick="currentSlide(3)"></span>
</div>
<div id="bottomnav"><p>footer</p></div>
<script>
var slideIndex = 1;
showSlides(slideIndex);
// Next/previous controls
function plusSlides(n) {
showSlides(slideIndex += n);
}
// Thumbnail image controls
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("contentSlide");
var dots = document.getElementsByClassName("dot");
if (n > slides.length) {slideIndex = 1;}
if (n < 1) {slideIndex = slides.length;}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
}
</script>
</body>
</html>
Anybody have an idea where the first two dots are and how I can fix it so the three dots are in a row?
You don't have two missing dots; all your dots are sitting on top of each other!
You gave each dot position: absolute, but they didn't have separate left or right values, so they just ended up sitting on top of each other.
The solution to this is simple: make their parent position: absolute and let the dots just be position: static.
Once you do this, the other problem you'll notice is that the dots appear off-center to the left because they are positioned relative to the overall page, whereas you probably want them centered in the yellow area.
Moving the dots' wrapper inside #slideContainer will fix this problem because #slideContainer is also position: absolute, and absolute positioning works in relation to an element's nearest positioned ancestor (i.e., any element above it in the tree that is either position: relative, position: absolute, or position: sticky).
var slideIndex = 1;
showSlides(slideIndex);
// Next/previous controls
function plusSlides(n) {
showSlides(slideIndex += n);
}
// Thumbnail image controls
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("contentSlide");
var dots = document.getElementsByClassName("dot");
if (n > slides.length) {
slideIndex = 1;
}
if (n < 1) {
slideIndex = slides.length;
}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex - 1].style.display = "block";
dots[slideIndex - 1].className += " active";
}
html {
background-color: lightblue;
}
body {
width: 1024px;
height: 768px;
margin-left: auto;
margin-right: auto;
border-style: solid;
background: lightgreen;
position: relative;
}
div#banner {
position: absolute;
top: 50px;
width: 100%;
height: 120px;
background: pink;
text-align: center;
padding-top: 0px;
padding-bottom: 0px;
font-size: 1.5em;
}
div#minibanner {
position: absolute;
top: 0px;
height: 50px;
width: 100%;
background: orange;
text-align: center;
}
div#slideContainer {
position: absolute;
left: 200px;
top: 170px;
height: 558px;
width: 794px;
padding-top: 30px;
padding-left: 30px;
font-size: 2em;
background: yellow;
}
div#sidenav {
position: absolute;
top: 170px;
left: 0px;
width: 200px;
height: 558px;
}
.contentSlide {
display: none;
}
div#bottomnav {
position: absolute;
bottom: 0px;
height: 40px;
width: 100%;
background: pink;
text-align: center;
}
.dots-wrapper {
position: absolute;
bottom: 60px;
left: 50%;
transform: translateX(-50%);
display: flex;
}
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 22px 22px;
background-color: #bbb;
border-radius: 50%;
display: block;
transition: background-color 0.6s ease;
}
.active,
.dot:hover {
background-color: #717171;
}
.fade {
-webkit-animation-name: fade;
-webkit-animation-duration: 1.5s;
animation-name: fade;
animation-duration: 1.5s;
}
#-webkit-keyframes fade {
from {
opacity: .4
}
to {
opacity: 1
}
}
#keyframes fade {
from {
opacity: .4
}
to {
opacity: 1
}
}
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -22px;
color: red;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
user-select: none;
}
.next {
right: 0;
border-radius: 3px 0 0 3px;
}
.prev {
left: 0;
}
.prev:hover,
.next:hover {
background-color: rgba(0, 0, 0, 0.8);
}
<div id="minibanner">
<h3>Title of Presentation: testing, testing testing</h3>
</div>
<div id="banner">
<h1>Introduction</h1>
</div>
<div id="sidenav">
<ul>
<li>home</li>
<li>Introduction</li>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
<li>Conclusion</li>
</ul>
</div>
<div id="slideContainer">
<div class="contentSlide fade">
<p>Here's an outline:
<ul>
<li>Introduction</li>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
<li>Conclusion</li>
</ul>
</p>
</div>
<div class="contentSlide fade">
<p>Here are some themes:
<ul>
<li>Theme 1</li>
<li>Theme 2</li>
<li>Theme 3</li>
</ul>
</p>
</div>
<div class="contentSlide fade">
<p>...and the conclusions:
<ul>
<li>Conclusion A</li>
<li>Conclusion B</li>
<li>Conclusion C</li>
<li>Conclusion D</li>
<li>Conclusion E</li>
</ul>
</p>
</div>
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
<div class="dots-wrapper" style="text-align:center">
<span class="dot" onclick="currentSlide(1)"></span>
<span class="dot" onclick="currentSlide(2)"></span>
<span class="dot" onclick="currentSlide(3)"></span>
</div>
</div>
<div id="bottomnav">
<p>footer</p>
</div>
Your dots (aka pips) have an absolute position so they're all going to overlap. Absolute positioning does exactly what it says and puts things at an exact position. It will ignore the normal "flow" that HTML typically does (also known as "has layout"), even though you've got them displaying as inline-block.
Instead, you should wrap them in a container element and position that accordingly. Then, the pips inside the container will "have layout" and flow side-by-side according to the inline-block display type.
Here's a basic working example
.slideshow {
position: relative;
width: 100%;
height: 80vh;
background: rebeccapurple;
}
.navigation {
position: absolute;
bottom: 20px;
width: 100%;
text-align: center; /* buttons align like text */
}
.pip {
display: inline-block;
width: 10px;
height: 10px;
padding: 0;
border: 0;
border-radius: 9999px;
cursor: pointer;
background: rgba(255, 255, 255, 0.5);
}
.pip--active {
background: rgba(255, 255, 255, 1);
}
<div class="slideshow">
<div class="navigation">
<button type="button" class="pip pip--active"></button>
<button type="button" class="pip"></button>
<button type="button" class="pip"></button>
</div>
</div>
Notice that I've used buttons instead of links for the pips. This is because the pips don't actually link anywhere when clicked; They simply updates the state of the slideshow.

Additional Navigation bar on click

I have a navigation bar with the section "Contracts" and I was wondering if it were possible, and how would I go about adding an additional navigation bar to expand underneath when this button is tagged, (For example, on the Apple Store site, when you click a product, this adds another bar)
I can provide my entire CSS style sheet if needed! I think this will require JavaScript but I'm trying to keep it as pure CSS for now!
All help is greatly appreciated!
HTML Code: This is the Navigation HTML
<header>
<div class="title">
<img src="img/logo2.png"/>
</div>
<div class="navbar">
<ul>
<li style="float: left">Home</li>
<li>Contracts</li>
<li>About Us</li>
<li>Other</li>
<li> Release Notes</li>
<li> <a target="_blank" href="http://www.phpartnership.com">Pinnacle Health Partnership</a></li>
</ul>
</div>
</header>
Creates this
CSS Code: My entire stylesheet
body {
background-color: #fff;
margin: 0;
font-family: Arial;
color: #333;
}
header {
background-color: #333;
position: fixed;
top: 0;
width: 100%;
}
.navbar {
display: block;
text-align: center;
}
.navbar ul {
list-style-type: none;
padding: 0;
margin: 0;
overflow: hidden;
}
.navbar li {
display: inline-block;
vertical-align: middle;
-webkit-transform: translateZ(0);
transform: translateZ(0);
box-shadow: 0 0 1px rgba(0, 0, 0, 0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-moz-osx-font-smoothing: grayscale;
position: relative;
overflow: hidden;
}
.navbar li:before {
content: "";
position: absolute;
z-index: -1;
left: 50%;
right: 50%;
bottom: 0;
background: white;
height: 4px;
-webkit-transition-property: left, right;
transition-property: left, right;
-webkit-transition-duration: 0.3s;
transition-duration: 0.3s;
-webkit-transition-timing-function: ease-out;
transition-timing-function: ease-out;
}
.navbar li:hover:before, navbar li:focus:before, .navbar li:active:before {
left: 0;
right: 0;
}
.navbar li a {
padding: 25px;
display: block;
height: 100%;
color: white;
text-decoration: none;
}
.title {
height: 80px;
padding: 2px;
background-color: #fff;
}
.container {
margin-top: 150px;
padding-top: 50px;
}
.home {
margin-top: 10px;
text-align: center;
padding: 40px !important;
}
.wrap {
width: 100%;
margin: 0 auto;
}
.left_col {
float: left;
width: 50%;
}
.right_col {
float: right;
width: 50%;
}
.right_col img {
width: 80%;
margin-top: 50px;
border: 2px solid black;
border-radius: 5px;
}
.left_col img {
width: 80%;
margin-top: 50px;
border: 2px solid black;
border-radius: 5px;
}
This is the JavaScript I tried to use to hide and show the div on click
<script>
$(index.php).ready(function(){
``$("#contract").click(function(){
$("<div class="contracts">").toggle();
});
});
</script>
guess you want smth like this : jsfiddle
first add jQuery to your local environment
use this <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
add it in the head section of your html. for more info check how to install jQuery
added html inside the .navbar
<ul class="aditional">
<li>test1</li>
<li>test2</li>
<li>test3</li>
<li>test4</li>
</ul>
added css :
.aditional {
position:absolute;
top:100%;
width:100%;
background:#000;
display:none;
}
.aditional li {
color:#fff;
}
added js :
$('.navbar ul li:nth-child(2) a').click(function() {
$(".aditional").slideToggle()
});
OR if you want a more responsive solution
check this :jsfiddle with target
use data-target on the li a like this
<li>Contracts</li>
<li>About Us</li>
added html :
<ul class="aditional contracts">
<li>test1</li>
<li>test2</li>
<li>test3</li>
<li>test4</li>
</ul>
<ul class="aditional aboutus">
<li>about</li>
<li>about</li>
<li>about</li>
<li>about</li>
</ul>
jq added :
$('.navbar ul li a').click(function() {
$(".aditional").slideUp()
var target = '.' + $(this).data('target');
$(target).slideDown();
})
OR u can target the href of the li a. simply add this
<li>Contracts</li>
<li>About Us</li>
------
<ul class="aditional" id ="contract">
....
<ul class="aditional" id ="about">
....
and js :
$('.navbar ul li a').click(function() {
$(".aditional").slideUp()
var target = $(this).attr('href');
$(target).slideDown();
})
see here jsfiddle
one of these solutions should work for you . let me know

Categories