let slideIndex = 0;
showSlides();
function showSlides() {
let i;
let slides = document.getElementsByClassName("slides");
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slideIndex++;
if (slideIndex > slides.length) {
slideIndex = 1
}
slides[slideIndex - 1].style.display = "block";
setTimeout(showSlides, 1000); // Change image every 1 seconds
}
.project-card {
height: 300px;
border: 1px dashed red;
}
.project-screenshots {
width: 100%;
margin: auto;
position: relative;
overflow: hidden;
}
.project-screenshots li img {
width: 100%;
}
.fade {
animation-name: fade;
animation-duration: 2.5s;
}
#keyframes fade {
from {
scale: 1.2;
}
to {
scale: 1;
}
}
<div class="project-card">
<ul class="project-screenshots" id="slider">
<li class="slides fade"><img src="https://1.bp.blogspot.com/-GgceYGYr2pk/YPCQp8loxqI/AAAAAAAACXU/Y795AFD-cN8PMV0V2__z2n1B3KFagE8qgCNcBGAsYHQ/s16000/1.jpg">
</li>
<li class="slides fade"><img src="https://1.bp.blogspot.com/-pl0VR_xS5Cw/YPCQp1scezI/AAAAAAAACXc/oB9xc6k8RuY5rPksMSy01f3iUn8zSIFzwCNcBGAsYHQ/s16000/2.jpg">
</li>
<li class="slides fade"><img src="https://1.bp.blogspot.com/-dt6CL2fiBq0/YPCQp0zmK6I/AAAAAAAACXY/0PevDL7pvx87mefb4oCnO613N1UitdicQCNcBGAsYHQ/s16000/3.jpg">
</li>
<li class="slides fade"><img src="https://1.bp.blogspot.com/-T_V-s57aVDo/YPCQrWayswI/AAAAAAAACXg/h1ifJGnBuXovvBdGDNvmhg-DXIVK4Xw9QCNcBGAsYHQ/s16000/4.jpg">
</li>
<li class="slides fade"><img src="https://1.bp.blogspot.com/-TNT1a5M1v3o/YPCQrWmn_fI/AAAAAAAACXk/p8nx_OB2R6Aw172WIv5vuB8jF-qWDsHlwCNcBGAsYHQ/s16000/5.jpg">
</li>
</ul>
</div>
<div class="project-card">
<ul class="project-screenshots">
<li class="slides fade"><img src="https://1.bp.blogspot.com/-GgceYGYr2pk/YPCQp8loxqI/AAAAAAAACXU/Y795AFD-cN8PMV0V2__z2n1B3KFagE8qgCNcBGAsYHQ/s16000/1.jpg">
</li>
<li class="slides fade"><img src="https://1.bp.blogspot.com/-pl0VR_xS5Cw/YPCQp1scezI/AAAAAAAACXc/oB9xc6k8RuY5rPksMSy01f3iUn8zSIFzwCNcBGAsYHQ/s16000/2.jpg">
</li>
<li class="slides fade"><img src="https://1.bp.blogspot.com/-dt6CL2fiBq0/YPCQp0zmK6I/AAAAAAAACXY/0PevDL7pvx87mefb4oCnO613N1UitdicQCNcBGAsYHQ/s16000/3.jpg">
</li>
<li class="slides fade"><img src="https://1.bp.blogspot.com/-T_V-s57aVDo/YPCQrWayswI/AAAAAAAACXg/h1ifJGnBuXovvBdGDNvmhg-DXIVK4Xw9QCNcBGAsYHQ/s16000/4.jpg">
</li>
<li class="slides fade"><img src="https://1.bp.blogspot.com/-TNT1a5M1v3o/YPCQrWmn_fI/AAAAAAAACXk/p8nx_OB2R6Aw172WIv5vuB8jF-qWDsHlwCNcBGAsYHQ/s16000/5.jpg">
</li>
</ul>
</div>
In this code, I have two cards. Each one should have its own carousel. But in the output I'm getting the carousel alternatively. I know its because I have used the same class name for the slides and used the same JavaScript code. I can change them and write the same JavaScript code multiples times. But I want a minimal solution for this.
target all the parent elements
use a better class naming convention
use setInterval to toggle a class on your items LI elements like .is-active
set in CSS the desired is-active styles
set a (if needed) mouseenter and mouseleave (or with pointer events) Events to pause the interval if the mouse is over your slider
const sliderify = (elSlider) => {
const elsItems = elSlider.children;
let itv = null;
let i = 0;
const anim = () => {
elsItems[i].classList.remove("is-active");
i += 1;
i %= elsItems.length;
elsItems[i].classList.add("is-active");
};
const play = () => itv = setInterval(anim, 3000);
const stop = () => clearInterval(itv);
elSlider.addEventListener("pointerenter", stop);
elSlider.addEventListener("pointerleave", play);
// Init:
anim(); // Show first items
play(); // Loop!
};
document.querySelectorAll(".slider").forEach(sliderify);
* {
margin: 0;
box-sizing: border-box;
}
.slider {
padding: 0;
height: 100px; /* as you need */
position: relative;
overflow: hidden;
}
.slider-item {
position: absolute;
top:0;
left: 0;
width: 100%;
height: 100%;
scale: 1.2;
transition: 0.4s;
opacity: 0;
pointer-events: none;
}
.slider-item.is-active {
opacity: 1;
scale: 1;
pointer-events: auto;
}
.slider-item img {
position: absolute;
top:0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
<ul class="slider">
<li class="slider-item"><img src="https://1.bp.blogspot.com/-T_V-s57aVDo/YPCQrWayswI/AAAAAAAACXg/h1ifJGnBuXovvBdGDNvmhg-DXIVK4Xw9QCNcBGAsYHQ/s16000/4.jpg">
</li>
<li class="slider-item"><img src="https://1.bp.blogspot.com/-TNT1a5M1v3o/YPCQrWmn_fI/AAAAAAAACXk/p8nx_OB2R6Aw172WIv5vuB8jF-qWDsHlwCNcBGAsYHQ/s16000/5.jpg">
</li>
<li class="slider-item"><img src="https://1.bp.blogspot.com/-GgceYGYr2pk/YPCQp8loxqI/AAAAAAAACXU/Y795AFD-cN8PMV0V2__z2n1B3KFagE8qgCNcBGAsYHQ/s16000/1.jpg">
</li>
<li class="slider-item"><img src="https://1.bp.blogspot.com/-pl0VR_xS5Cw/YPCQp1scezI/AAAAAAAACXc/oB9xc6k8RuY5rPksMSy01f3iUn8zSIFzwCNcBGAsYHQ/s16000/2.jpg">
</li>
<li class="slider-item"><img src="https://1.bp.blogspot.com/-dt6CL2fiBq0/YPCQp0zmK6I/AAAAAAAACXY/0PevDL7pvx87mefb4oCnO613N1UitdicQCNcBGAsYHQ/s16000/3.jpg">
</li>
</ul>
<ul class="slider">
<li class="slider-item"><img src="https://1.bp.blogspot.com/-GgceYGYr2pk/YPCQp8loxqI/AAAAAAAACXU/Y795AFD-cN8PMV0V2__z2n1B3KFagE8qgCNcBGAsYHQ/s16000/1.jpg">
</li>
<li class="slider-item"><img src="https://1.bp.blogspot.com/-pl0VR_xS5Cw/YPCQp1scezI/AAAAAAAACXc/oB9xc6k8RuY5rPksMSy01f3iUn8zSIFzwCNcBGAsYHQ/s16000/2.jpg">
</li>
<li class="slider-item"><img src="https://1.bp.blogspot.com/-dt6CL2fiBq0/YPCQp0zmK6I/AAAAAAAACXY/0PevDL7pvx87mefb4oCnO613N1UitdicQCNcBGAsYHQ/s16000/3.jpg">
</li>
<li class="slider-item"><img src="https://1.bp.blogspot.com/-T_V-s57aVDo/YPCQrWayswI/AAAAAAAACXg/h1ifJGnBuXovvBdGDNvmhg-DXIVK4Xw9QCNcBGAsYHQ/s16000/4.jpg">
</li>
<li class="slider-item"><img src="https://1.bp.blogspot.com/-TNT1a5M1v3o/YPCQrWmn_fI/AAAAAAAACXk/p8nx_OB2R6Aw172WIv5vuB8jF-qWDsHlwCNcBGAsYHQ/s16000/5.jpg">
</li>
</ul>
Related
How to make it so that when you click on the button again, it hides its menu
The script works so that when opening another "btn", the one that is active is hidden, + if you click outside the menu field, all are hidden.
How do I make it so that when I click on the active button again, its menu is hidden
<ul class="first_menu">
<li class="menu_item">
<button class="menu_btn">1 btn</button>
<div class="dropdown">
<ul class="dropdown__list">
<li class="dropdown__item">
1 Подпункт
</li>
<li class="dropdown__item">
2 Подпункт
</li>
<li class="dropdown__item">
3 Подпункт
</li>
</ul>
</div>
</li>
<li class="menu_item">
<button class="menu_btn">2 btn</button>
<div class="dropdown">
<ul class="dropdown__list">
<li class="dropdown__item">
1 Подпункт
</li>
<li class="dropdown__item">
2 Подпункт
</li>
<li class="dropdown__item">
3 Подпункт
</li>
</ul>
</div>
</li>
<li class="menu_item">
<button class="menu_btn">3 btn</button>
<div class="dropdown">
<ul class="dropdown__list">
<li class="dropdown__item">
1 Подпункт
</li>
<li class="dropdown__item">
2 Подпункт
</li>
<li class="dropdown__item">
3 Подпункт
</li>
</ul>
</div>
</li>
</ul>
.first_menu {
position: relative;
justify-content: center;
display: flex;
}
.menu_item,.dropdown__item {
list-style-type: none;
}
.menu_btn {
cursor: pointer;
border: none;
padding: 25px;
background-color: black;
color: #ffffff;
font-weight: bold;
}
.dropdown {
transition: all 1s;
position: absolute;
top: 0;
transform: translateY(-100%);
background-color: black;
}
.dropdown__item {
text-align: center;
padding-bottom: 20px;
}
.dropdown__link {
text-decoration: none;
color: white;
font-weight: bold;
}
.active {
top: 100px;
transition: all 1s;
transform: translateY(-30%);
}
const btn = document.querySelectorAll('.menu_btn')
btn.forEach(function(item, i){
item.addEventListener('click', (e) => {
let currentBtn = e.currentTarget;
let nextElemt = currentBtn.nextElementSibling;
document.querySelectorAll('.dropdown.active').forEach(function(item, i) {
item.classList.remove('active')
})
nextElemt.classList.add('active')
const menuOff = document.querySelector('.first_menu');
document.addEventListener('click', function(e) {
const click = e.composedPath().includes(menuOff);
if(!click) {
nextElemt.classList.remove('active')
}
})
})
})
Check whether the associated dropdown's classList contains the class that opens the dropdown. If it does, then instead of adding the class, remove it - by using classList.toggle.
You should also not be adding an event listener to the document every time there's a click. Add one unconditionally, once, on pageload, and check if the click is inside the .first-menu to determine whether you need to remove the active dropdowns.
const removeActive = () => {
document.querySelector('.dropdown.active')?.classList.remove('active');
};
for (const button of document.querySelectorAll('.menu_btn')) {
button.addEventListener('click', (e) => {
const thisDropdown = e.currentTarget.nextElementSibling;
const thisCurrentlyOpen = thisDropdown.classList.contains('active');
removeActive();
thisDropdown.classList.toggle('active', !thisCurrentlyOpen);
})
}
document.addEventListener('click', function(e) {
if (!e.target.closest('.first_menu')) {
removeActive();
}
});
const removeActive = () => {
document.querySelector('.dropdown.active')?.classList.remove('active');
};
for (const button of document.querySelectorAll('.menu_btn')) {
button.addEventListener('click', (e) => {
const thisDropdown = e.currentTarget.nextElementSibling;
const thisCurrentlyOpen = thisDropdown.classList.contains('active');
removeActive();
thisDropdown.classList.toggle('active', !thisCurrentlyOpen);
})
}
document.addEventListener('click', function(e) {
if (!e.target.closest('.first_menu')) {
removeActive();
}
});
.first_menu {
position: relative;
justify-content: center;
display: flex;
}
.menu_item,
.dropdown__item {
list-style-type: none;
}
.menu_btn {
cursor: pointer;
border: none;
padding: 25px;
background-color: black;
color: #ffffff;
font-weight: bold;
}
.dropdown {
transition: all 1s;
position: absolute;
top: 0;
transform: translateY(-100%);
background-color: black;
}
.dropdown__item {
text-align: center;
padding-bottom: 20px;
}
.dropdown__link {
text-decoration: none;
color: white;
font-weight: bold;
}
.active {
top: 100px;
transition: all 1s;
transform: translateY(-30%);
}
<ul class="first_menu">
<li class="menu_item">
<button class="menu_btn">1 btn</button>
<div class="dropdown">
<ul class="dropdown__list">
<li class="dropdown__item">
1 Подпункт
</li>
<li class="dropdown__item">
2 Подпункт
</li>
<li class="dropdown__item">
3 Подпункт
</li>
</ul>
</div>
</li>
<li class="menu_item">
<button class="menu_btn">2 btn</button>
<div class="dropdown">
<ul class="dropdown__list">
<li class="dropdown__item">
1 Подпункт
</li>
<li class="dropdown__item">
2 Подпункт
</li>
<li class="dropdown__item">
3 Подпункт
</li>
</ul>
</div>
</li>
<li class="menu_item">
<button class="menu_btn">3 btn</button>
<div class="dropdown">
<ul class="dropdown__list">
<li class="dropdown__item">
1 Подпункт
</li>
<li class="dropdown__item">
2 Подпункт
</li>
<li class="dropdown__item">
3 Подпункт
</li>
</ul>
</div>
</li>
</ul>
Have a sidebar on my website but when I load the page it plays the animation of it closing. how would I stop this?
I have a class #sidebar thats the class in its normal state and a class active that makes it move out
#sidebar {
margin-left: -250px;
width: 250px;
position: fixed;
top: 0;
left: 0;
height: 100vh;
z-index: 0;
background: #222222;
color: #fff;
transition: 0.3s;
visibility: hidden;
}
#sidebar.active {
width: 250px;
margin-left: 0px;
transition: 0.3s;
z-index: 999;
visibility: visible;
}
Javascript for changing the active class
$(document).ready(function () {
$("#sidebar").mCustomScrollbar({
theme: "minimal"
});
$('#sidebarCollapse').on('click', function () {
$('#sidebar, #content').toggleClass('active');
$('.collapse.in').toggleClass('in');
$('a[aria-expanded=true]').attr('aria-expanded', 'false');
});
});
UPDATE
Html code for the sidebar. if it helps I am using mustache js for templating if that is of importance to this
<!-- Sidebar -->
<nav id="sidebar">
<div class="sidebar-header">
<h3>Admin Panel</h3>
</div>
<ul class="list-unstyled components">
<p>Admin controls</p>
<li>
Menu's
<ul class="collapse list-unstyled" id="menuSubmenu">
<li>
Add
</li>
<li>
Edit
</li>
</ul>
</li>
<li>
Categories
<ul class="collapse list-unstyled" id="catSubmenu">
<li>
Add
</li>
<li>
Edit
</li>
</ul>
</li>
<li>
Dish's
<ul class="collapse list-unstyled" id="dishSubmenu">
<li>
Add
</li>
<li>
Edit
</li>
</ul>
</li>
<li>
Staff
<ul class="collapse list-unstyled" id="staffSubmenu">
<li>
Register
</li>
<li>
Delete
</li>
</ul>
</li>
<li>
Site settings
</li>
<li>
<a id="logout" href="/logout" class="btn btn-primary">Sign out</a>
</li>
</ul>
</nav>
Can you try below CSS
#sidebar {
position: absolute;
top: 0;
left: -250px;
bottom: 0;
width: 250px;
height: 100vh;
z-index: 999;
background: #222222;
color: #fff;
transition: 0.3s;
}
#sidebar.active {
left: 0;
}
Plus you have to pass active class to your sidebar also if you want to be active by default
<nav id="sidebar" class="active">
js
const navItems = document.querySelectorAll('.navbar__items')
const dropDown = document.querySelectorAll('.dropdown')
dropDown.forEach(element => {
element.addEventListener('click',()=>{
{
navItems.forEach(nav =>{
nav.classList.toggle('drop')
})
}
})
})
HTML
<ul class="navbar">
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
</ul>
CSS
.navbar{
position: relative;
}
.navbar__items{
position: absolute;
display: none;
}
.drop{
display: block;
}
I have a navbar and each of these navbar items have dropdown items. I want to show these dropdown items when I click on the 'dropdown' class. But the problem is when I click on one of them all the dropdowns are visible. How do I show only the list I've clicked on?
Enter the below code
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.dropbtn {
background-color: #3498DB;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropbtn:hover, .dropbtn:focus {
background-color: #2980B9;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
overflow: auto;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown a:hover {background-color: #ddd;}
.show {display: block;}
</style>
</head>
<body>
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Click</button>
<div id="myDropdown" class="dropdown-content">
Clicked
Clicked
Clicked
</div>
</div>
<script>
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
}
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
</script>
</body>
</html>
As mentioned in comments it is better to use Event Delegation technique.
The algorithm is quite simple:
Add listener on the parent element
On click check if dropdown-opener was clicked
Get drop-down which I need to open
Close other dropdowns
Open dropdown from 3.
const allDropdowns = document.querySelectorAll('.navbar__items')
const DROP_CLASS = 'drop';
const navbar = document.querySelector('.navbar');
navbar.addEventListener('click', ({target}) => {
if (!target.classList.contains('dropdown')) return;
const parent = target.parentNode;
const navItems = parent
.querySelector('.navbar__items');
allDropdowns.forEach(el => el !== navItems && el.classList.remove(DROP_CLASS));
if (navItems) {
navItems.classList.toggle(DROP_CLASS);
}
});
.navbar{
position: relative;
}
.navbar__items{
position: absolute;
left: 80px;
display: none;
}
.drop{
display: block;
}
<ul class="navbar">
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
</ul>
Use the event target to get the parentNode, then use the parentNode to query the hidden element as all your elements are grouped in the same parent/child grouping. Also you can set an initial class for hidden, display: none; in each element and add it on click. A forEach loop sets each elements display to none using the hidden class on click.
const navItems = document.querySelectorAll('.navbar__items')
const dropDown = document.querySelectorAll('.dropdown')
// callback function that passes in the event => e from your listener
function showDropdown (e){
// set each navbar__items element display: none using hidden class
navItems.forEach(el => el.classList.add('hidden'))
// query the specific .navbar__items in the event.targets group
let dd = e.target.parentNode.querySelector('.navbar__items')
// remove the hidden class a nd show the dropdown for this event.target
dd.classList.remove('hidden')
}
// iterate over the dropdown element
dropDown.forEach(element => {
// function showDropdown on click
element.addEventListener('click', showDropdown)
})
.navbar {
position: relative;
}
.navbar__items {
position: absolute;
left: 75px;
}
.hidden {
display: none;
}
<ul class="navbar">
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items hidden">
<li>clicked 1</li>
<li>clicked 1</li>
<li>clicked 1</li>
</ul>
</li>
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items hidden">
<li>clicked 2</li>
<li>clicked 2</li>
<li>clicked 2</li>
</ul>
</li>
<li class="nav-menu">
<div class="dropdown">click</div>
<ul class="navbar__items hidden">
<li>clicked 3</li>
<li>clicked 3</li>
<li>clicked 3</li>
</ul>
</li>
</ul>
Rather than using addEventlistener you should add onclick method in html to every drop-down with same method name but change the ul class name with for each drop-down and then pass class name in method and then toggle the drop-down with parameter class name.
For example,
function onClick(item) {
if (document.getElementsByClassName(item).classList.contains('hidden')) {
document.getElementsByClassName('dropdown').classList.remove('hidden');
}
if (!document.getElementsByClassName(item)[0].classList.contains('hidden')) {
document.getElementsByClassName('dropdown').classList.add('hidden');
}
}
<ul class="navbar">
<li class="nav-menu">
<div class="dropdown" onclick="onClick('navbar_items1')">click</div>
<ul class="navbar__items1 hidden">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
<li class="nav-menu">
<div class="dropdown" onclick="onClick('navbar_items2')">click</div>
<ul class="navbar__items2 hidden">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
<li class="nav-menu">
<div class="dropdown" onclick="onClick('navbar_items3')">click</div>
<ul class="navbar__items3 hidden">
<li>clicked</li>
<li>clicked</li>
<li>clicked</li>
</ul>
</li>
</ul>
i have a typical carousel when i click left button if marginLeft is 0 it doesn't slide but i don't know what limited value to set for the slider when i click right button.
i tried calculating the images width and the margin space between them to set the limit value for the right button so slider doesn't slide past it but that doesn't work if you see it on another device because it's width is higher.
codepen : https://codepen.io/anon/pen/bXBaYW?editors=1010
// caoursel
const carousel = document.getElementById('carousel');
const leftArrow = carousel.querySelector('.carousel-left-arrow');
const rightArrow = carousel.querySelector('.carousel-right-arrow');
const slides = carousel.querySelector('.slides');
const slideImgs = carousel.querySelectorAll('.slide img');
let marginLeft = 0;
// works fine
function scrollLeft() {
if (getComputedStyle(slides).marginLeft >= '0px') return;
marginLeft += 310;
slides.style.marginLeft = marginLeft + "px";
}
// need to set right slide a limited value.
function scrollRight() {
if (getComputedStyle(slides).marginLeft <= '-1240px') return; // dont scroll past this value
marginLeft -= 310;
slides.style.marginLeft = marginLeft + "px";
}
leftArrow.addEventListener('click', scrollLeft);
rightArrow.addEventListener('click', scrollRight);
i want the slider to stop sliding when i reach the last image.
What you need to do is to not hardcode the width of the .slides container in CSS and JS.
Thus allowing you to dynamically compute the width of the .slides container, and the remaining space you can scroll/slide.
Below is an illustration of the variable and their values in relation to the whole component.
remainingSpaceToScroll will tell you how much space you have on the right, so you can not exceed the limit. The value of it can be found with simple math, by subtracting the sum of parentWidth and currentScroll from the value in scrollWidth.
Here is the code from your example updated so you can inspect.
I've removed the space between the slides for the simplicity sake.
https://codepen.io/anon/pen/BXpaNv
const carousel = document.getElementById("carousel");
const leftArrow = carousel.querySelector(".carousel-left-arrow");
const rightArrow = carousel.querySelector(".carousel-right-arrow");
const slides = carousel.querySelector(".slides");
const slideImgs = carousel.querySelectorAll(".slide img");
let marginLeft = 0;
let carouselImageWidth = 300;
function scrollLeft() {
let parentWidth = carousel.offsetWidth;
let scrollWidth = parseInt(getComputedStyle(slides).width, 10);
let currentScroll = Math.abs(
parseInt(getComputedStyle(slides).marginLeft, 10)
);
let remainingSpaceToScroll = currentScroll;
if (remainingSpaceToScroll <= 0) {
return;
} else if (remainingSpaceToScroll >= carouselImageWidth) {
marginLeft = -(currentScroll - carouselImageWidth);
} else {
marginLeft = -(currentScroll - remainingSpaceToScroll);
}
slides.style.marginLeft = marginLeft + "px";
}
function scrollRight() {
let parentWidth = carousel.offsetWidth;
let scrollWidth = parseInt(getComputedStyle(slides).width, 10);
let currentScroll = Math.abs(
parseInt(getComputedStyle(slides).marginLeft, 10)
);
let remainingSpaceToScroll = scrollWidth - (parentWidth + currentScroll);
if (remainingSpaceToScroll <= 0) {
return;
} else if (remainingSpaceToScroll >= carouselImageWidth) {
marginLeft = -(currentScroll + carouselImageWidth);
} else {
marginLeft = -(currentScroll + remainingSpaceToScroll);
}
slides.style.marginLeft = marginLeft + "px";
}
leftArrow.addEventListener("click", scrollLeft);
rightArrow.addEventListener("click", scrollRight);
HTML below:
<p>click right arrow till end</p>
<div id="carousel">
<span class="carousel-left-arrow arrow"><</span>
<ul class="slides">
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
<li class="slide">
<a href="#">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500">
</a>
</li>
</ul>
<span class="carousel-right-arrow arrow">></span>
</div>
CSS below:
#carousel {
width: 90%;
margin: 0 auto;
margin-top: 20px;
overflow: hidden;
position: relative;
height: 122px;
}
#carousel .arrow {
position: absolute;
top: 32%;
background-color: rgba(255, 255, 255, 0.7);
border: 1px solid #000;
border-radius: 0%;
cursor: pointer;
width: 20px;
z-index: 1;
}
#carousel .arrow img {
margin-top: 10px;
max-width: 100%;
}
#carousel .carousel-left-arrow {
width: 25px;
left: 0;
margin-left: 5px;
}
#carousel .carousel-right-arrow {
right: 0;
width: 25px;
}
#carousel .slides {
overflow: hidden;
list-style: none;
padding: 0;
transition: 0.2s;
margin-left: 0;
margin-right: 0;
border: 1px solid red;
height: 120px;
position: absolute;
left: 0;
top: 0;
margin: 0;
display: flex;
}
#carousel .slide {
float: left;
margin: 0;
text-decoration: none;
color: whitesmoke;
}
#carousel .slide > a {
display: block;
}
#carousel .slides img {
width: 300px;
display: block;
}
I have class that have background image and this background image have fixed navbar and some text on it. How can I make this background image to be slideshow with another two images. Can someone help me with this without damaging the fixed navbar and the text on it?
Here is my codes
<div id="home" class="intro route bg-image" >
<nav class="navbar navbar-b navbar-trans navbar-expand-md fixed-top" id="mainNav">
<div class="container">
<a class="navbar-brand js-scroll" href="#page-top"><%= image_tag "logo.png",class: "logo",alt: "eric chism trail to welness logo" %></a>
<button class="navbar-toggler collapsed" type="button" data-toggle="collapse" data-target="#navbarDefault"
aria-controls="navbarDefault" aria-expanded="false" aria-label="Toggle navigation">
<span></span>
<span></span>
<span></span>
</button>
<div class="navbar-collapse collapse justify-content-end" id="navbarDefault">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link js-scroll active" href="#home">Home</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll" href="#about">About</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll" href="#service">Services</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll" href="#work">Portfolio</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll" href="#contact">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="overlay-itro"></div>
<div class="intro-content display-table">
<div class="table-cell">
<div class="container">
<h1 class="intro-title mb-4">Eric Chism Trail to Wellness</h1>
<p class="intro-subtitle"> provides a customized journey to complete health and wellness</span><strong class="text-slider"></strong></p>
<!-- <p class="pt-3"><a class="btn btn-primary btn js-scroll px-4" href="#about" role="button">Learn More</a></p> -->
</div>
</div>
</div>
</div>
css file
.intro {
height: 100vh;
position: relative;
color: #fff;
background-image: url(asset-path("attachment_1550437745.png"));
}
.intro .intro-content {
text-align: center;
position: absolute;
}
I have created a very raw, pure CSS solution, as good starting point for you. Using different animations and delays you could achieve some really awesome effects.
body {
margin: 0;
padding: 0;
}
.route {
height: 100vh;
position: relative;
color: #fff;
}
.navbar {
position: fixed;
}
.slide {
position: relative;
height: 100%;
width: 33.33%;
margin: 0;
float: left;
}
.slide-1 {
background-image: url(https://picsum.photos/1200/800?image=11);
}
.slide-2 {
background-image: url(https://picsum.photos/1200/800?image=12);
}
.slide-3 {
background-image: url(https://picsum.photos/1200/800?image=13);
}
.slideshow {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 0;
overflow: hidden;
color: #000;
}
.slideshow-inner {
position: relative;
height: 100%;
width: 300%;
animation: move 20s ease infinite;
}
.intro .intro-content {
text-align: center;
position: absolute;
}
#keyframes move {
0% {
transform: translate(0, 0);
}
33.33% {
transform: translate(-33.33%, 0);
}
66.66% {
transform: translate(-66.66%, 0);
}
}
<div id="home" class="route bg-image">
<div class="slideshow">
<div class="slideshow-inner">
<div class="slide slide-1"><span>Some Text</span></div>
<div class="slide slide-2"><span>Some Text</span></div>
<div class="slide slide-3"><span>Some Text</span></div>
</div>
</div>
<nav class="navbar navbar-b navbar-trans navbar-expand-md fixed-top" id="mainNav">
<div class="container">
<div class="navbar-collapse collapse justify-content-end" id="navbarDefault">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link js-scroll active" href="#home">Home</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll" href="#about">About</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll" href="#service">Services</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll" href="#work">Portfolio</a>
</li>
<li class="nav-item">
<a class="nav-link js-scroll" href="#contact">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
</div>
Presumably you mean a time-based slideshow rather than one where the user presses buttons. The various options are all typically handled with JavaScript. As your background element has children, I would extend your existing code by adding new classes corresponding to new background images, and switching between them.
.bg1 {
background-image: url(asset-path("img1.png"));
}
.bg2 {
background-image: url(asset-path("img2.png"));
}
.bg3 {
background-image: url(asset-path("img3.png"));
}
Then add the first class to your background element:
<div id="home" class="intro route bg-image bg1" >
and include JS code to cycle through the classes, like below - included as part of a snippet so you can see the effect.
function updateSlide() {
const bgCount = 3; //This needs to match the number of background classes - main weakness of this snippet
const bgElem = document.getElementById('home'); // Background element
let foundClasses = []; //List of background classes found
let bgIndex = 0;
for(let classIndex = 0; classIndex < bgElem.classList.length; classIndex++) { // Using a full for in case the element somehow gets multiple background classes
const thisClass = bgElem.classList.item(classIndex);
if(thisClass.substr(0, 2) == 'bg') {
foundClasses += thisClass;
bgIndex = parseInt(thisClass.substr(2)) + 1;
}
}
if(bgIndex > bgCount) {
bgIndex = 1;
}
bgElem.classList.add('bg' + bgIndex); //Apply the new class
bgElem.classList.remove(foundClasses); //Remove all previous background classes
}
setInterval(updateSlide, 2000); // Change every 2 seconds
#home {
display: block;
}
.bg1 {
background: red;
}
.bg2 {
background: yellow;
}
.bg3 {
background: green;
}
<div id="home" class="bg1">Test</div>
Long-term, you would want the cycling script to get its background-count from a Rails variable or the HTML instead of a hard-coded value.