How to use scrollTo() function in Vanilla JS? - javascript

What's wrong with my code? scrollTo() goes to the wrong position when I click and anchor with href value using hash # (div element ID).
This is my code, I just want to scroll to the comment element, but still overlap on the fixed header (bootstrap 5 fixed header).
if (document.querySelectorAll('a').length) {
document.querySelectorAll('a').forEach( anchor => {
anchor.addEventListener('click', event => {
let URL = event.target.href.split('#');
if (typeof URL[1] != undefined) {
let element = document.getElementById(URL[1]);
let offset = element.offsetTop;
let navigation = document.getElementById('main-navigation').clientHeight
let scroll = offset - navigation;
window.scrollTo(0, scroll);
}
});
});
}
Anyone can help me?

Call event.preventDefault() in the click handler, otherwise after your call to scrollTo, the page's hash will change, with an automatic scroll to the anchored element overriding yours.
document.querySelectorAll('a').forEach( anchor => {
anchor.addEventListener('click', event => {
let URL = event.target.href.split('#');
if (typeof URL[1] != undefined) {
let element = document.getElementById(URL[1]);
let offset = element.offsetTop;
let navigation = document.querySelector('.over').clientHeight
let scroll = offset - navigation;
window.scrollTo(0, scroll);
event.preventDefault(); // avoid internal scroll to anchor
}
});
});
.over {
height: 50px;
background: salmon;
position: sticky;
top: 0;
}
#foo {
margin-top: 250vh;
height: 250vh;
}
#foo
<div class="over"></div>
<div id="foo">Target element</div>

You can achieve that by using the scrollIntoView() function. see the below example. you have to target the element to scroll:
let i = 0;
function myFunction() {
if(i === 0){
const elmnt = document.getElementById("content");
elmnt.scrollIntoView();
i += 1
}
else {
const elmnt = document.getElementById("content2");
elmnt.scrollIntoView();
}
}
#myDIV {
height: 250px;
width: 250px;
overflow: auto;
background: green;
}
#content {
margin:500px;
height: 800px;
width: 2000px;
background-color: coral;
}
#content2 {
margin:500px;
height: 800px;
width: 2000px;
background-color: red;
}
<p>Click the button to scroll to section.</p>
<button onclick="myFunction()">Scroll</button>
<div id="myDIV">
<div id="content">
Some text inside an element.
</div>
<div id="content2">
Some text inside an element.
</div>
</div>

Most importantly you need to stop the default behavior. When an internal link is clicked the default action is to jump to that link. You need to override that.
Next, we can make a couple of little tweaks. First, only select internal links with an attribute selector that selects a tags where the href start with "#". Next, instead of splitting the url from the href, grab the raw value directly from the attribute.
//Get internal links
document.querySelectorAll("a[href^='#']").forEach(function(el) {
el.addEventListener("click", function(e) {
//Stops the inbuild scroll
e.preventDefault();
//Get the id straight from the attribute
let selector = this.getAttribute("href");
//Get the target element
let element = document.querySelector(selector);
//you know the rest
let offset = element.offsetTop;
let navigation = document.getElementById('main-navigation').clientHeight
let scroll = offset - navigation;
window.scrollTo(0, scroll);
});
});
/*CSS Purely for demo purposes.*/
.fixed-top {
background-color: #EEE;
padding: 15px;
}
article:first-of-type{
margin-top:90px;
}
article {
min-height: 50vh;
border-bottom: 1px solid black;
}
nav {
background-color: #ECECEC;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<div class="fixed-top" id="main-navigation">Some Top Stuff
<nav>
Article 1
Article 2
Article 3
</nav>
</div>
<article id="art1">
<h1>Article 1</h1>
</article>
<article id="art2">
<h1>Article 2</h1>
</article>
<article id="art3">
<h1>Article 3</h1>
</article>

Related

How to create a horizontal, circular/scrollable menu?

How can we make a horizontal row of link elements (with variable width/text length) with overflow hidden (or without, depending on how this is usually done..) function so that the last element is positioned behind the first and so on in each left or right direction, to create a circular scroll?
I have this so far:
const horizontalContainer = document.querySelector('.horizontal-container')
const horizontalLinks = document.querySelectorAll('.horizontal-link')
let touchStart = 0
let touchX = 0
let isDragging = false
const handleTouchStart = (e) => {
touchStart = e.clientX || e.touches[0].clientX
isDragging = true
}
const handleTouchMove = (e) => {
if (!isDragging) return
touchX = e.clientX || e.touches[0].clientX
touchStart = touchX
horizontalLinks.forEach(element => {
element.style.transform = "translate(" + (touchStart) + "px," + "0px)";
})
}
const handleTouchEnd = () => {
isDragging = false
}
horizontalContainer.addEventListener('mousedown', handleTouchStart)
horizontalContainer.addEventListener('mousemove', handleTouchMove)
horizontalContainer.addEventListener('mouseleave', handleTouchEnd)
horizontalContainer.addEventListener('mouseup', handleTouchEnd)
horizontalContainer.addEventListener('selectstart', () => { return false })
.horizontal-container {
display: flex;
overflow-x: hidden;
width: 100%;
}
.horizontal-container::-webkit-scrollbar {
display: none;
}
.horizontal-link {
padding-left: 20px;
padding-right: 20px;
right: 0;
}
<div class="horizontal-container">
<div class="horizontal-link">
ONE
</div>
<div class="horizontal-link">
TWO
</div>
<div class="horizontal-link">
THREE
</div>
<div class="horizontal-link">
FOUR
</div>
<div class="horizontal-link">
FIVE
</div>
</div>
Edit: Unless you have the time to show me an example, I'm more than happy with just an explanation for how this can be done calculating translate: transform(x,y) to reposition the links when the left or right position of a link div of variable width reaches the right or left position of the screen depending on the screen width, which can also be variable, so that what the exact amount of overflow that peeks outside the viewport on the right will peek out the same amount on the left side of the viewport.
Edit2: Even though I know little about programming or the Javascript language (yet) I do know that this is not a "carousel" which is much easier to implement, that I already have created on my own so I know every detail of it. And a scrollbar is also programmed to move between a left end or right end position - this cannot be used here without a lot of ugly hacks so a new scrolling function needs to be implemented from scratch. I also know that jQuery will not help me to understand or learn more, and that this is nothing one would use - ever - whether you are an amateur or not.
What you are requesting is a carousel pattern. You can configure a carousel to show multiple slides at once. In this case each "slide" would be a menu item.
I have mocked up an example using https://kenwheeler.github.io/slick/
The only downfall is that it snaps to each slide, which may or may not be what you want. If it is not what you want then you would be best looking at other slider alternatives.
But the main point is that what you are requesting is normally done with a slider/carousel pattern. You just need to look at it differently, and you are not limited to show one "slide" at a time.
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel#1.8.1/slick/slick.css"/>
<div class="menu-slider" style="width: 400px;">
<div style="padding:20px;">Link 1</div>
<div style="padding:20px;">Another Link 2</div>
<div style="padding:20px;">Yet Another Link 3</div>
<div style="padding:20px;">Menu Link 4</div>
<div style="padding:20px;">Link 5</div>
<div style="padding:20px;">Menu Link 6</div>
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/slick-carousel#1.8.1/slick/slick.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('.menu-slider').slick({
dots: false,
infinite: true,
centerMode: false,
variableWidth: true
});
});
</script>
Here's a working solution for one that will "fill" its parent in order to create the effect.
I was working on an alternative that didn't fill but it still needs more work.
$(function () {
init();
});
let base_width = 0;
function init() {
setupMenu();
}
function handleScroll(event) {
if (base_width === 0) {
// no need to do anything
return;
}
const $menu = $(event.currentTarget);
const scroll_left = $menu[0].scrollLeft;
// check backwards scroll
if (scroll_left <= base_width) {
const new_left = 2 * base_width - (base_width - scroll_left);
$menu[0].scrollLeft = new_left;
return;
}
if (scroll_left < base_width * 2) {
return;
}
// get remainder
const new_left = scroll_left % (base_width * 2);
$menu[0].scrollLeft = new_left + base_width;
}
function setupMenu() {
const $menu = $("#menu-fill");
const $parent = $menu.parent();
const menu_width = $menu.width();
const parent_width = $parent.width();
if (menu_width >= parent_width) {
// no need to duplicate
return;
}
base_width = menu_width;
// setup a base to clone
const $template = $menu.clone();
// get num times to duplicate to "fill" menu (i.e. allow scrolling)
// NOTE: we duplicate 1 "extra" so that we can scroll "backwards"
const num_duplicate = Math.ceil(parent_width / menu_width) + 2;
for (let i = 0; i < num_duplicate; i++) {
const $new_menu = $template.clone();
$menu.append($new_menu.children());
$new_menu.remove();
}
$menu[0].scrollLeft = base_width;
$menu.scroll(handleScroll)
}
* {
box-sizing: border-box;
font-family: sans-serif;
}
*::-webkit-scrollbar {
background-color: transparent;
height: 6px;
width: 6px;
border-radius: 3px;
}
*::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 3px;
}
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
.wrap {
width: 250px;
height: 100px;
border: 2px solid #777;
margin: 0 auto 20px auto;
}
.wrap.fill {
width: 500px;
}
.menu {
display: inline-flex;
max-width: 100%;
overflow: auto;
}
.item {
padding: 5px 10px;
background-color: #426ac0;
color: #fff;
border-right: 1px solid #1d3464;
white-space: nowrap;
}
.item:last-child {
border-right: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrap fill">
<div class="menu" id="menu-fill">
<div class="item">Item 1</div>
<div class="item">Number 2</div>
</div>
</div>

sidebar toggle background opacity not close

I created a sidebar toggle and also gave background opacity but when I click another area or when closed the sidebar the background opacity didn't close. when I click the button the dropdown-content show and the background-opacity show but when I click again on the button the dropdown content closed but the background opacity does not close. How I did it. Please help me. I gave the code below. If someone can help me it will be very helpful for me. I try so many times but in the end, I can't do it. 😥
function toggleDropDown(id) {
document.querySelectorAll('.dropdown-content').forEach(el => el.id === id ? el.classList.toggle('show') : el.classList.remove("show"));
document.body.style.backgroundColor = "rgba(0,0,0,0.4)";
}
document.addEventListener('click', (e) => {
// cases where we want to close the dropdown
if (e.target.closest(".dropdown") === null) {
document.querySelectorAll('.dropdown-content').forEach(el => el.classList.remove("show"));
}
});
*{margin:0;padding:0;}
.dropdown-content{
position: fixed;
width: 30%;
height:100%;
background-color: rgb(255,0,0);
margin-left: 20%;
top:0;
display:none;
z-index:100;
}
.dropbtn{width:20%}
.show{display:block;}
<div class="dropdown">
<button class="dropbtn" onclick="toggleDropDown('openContent')">open</button>
<div class="dropdown-content" id="openContent">Hello, Div</div>
</div>
<h1>Hello World, Heading 1</h1>
First, I would suggest to create a variable that keeps track of the current state of dropdown – which is either true or false.
Plus, I don’t see the benefit in using document.querySelectorAll and having to loop over every element, when you could just directly get the element by addressing its id (openContent)... unless you would want to reuse the function for other cases?
As you are also listening on a click event on the document, we have to watch out for event bubbling by calling e.stopPropagation. In the case of the button for example, this means that we only fire the event for the button but not for the document. Since the button is a child of the document, it would otherwise detect a click event for both and fire twice.
const dropdownContent = document.getElementById("openContent");
let dropDownVisible = false;
function toggleDropDown(e) {
// we need this to prevent the event bubbling from the dropdown button to the document
e.stopPropagation();
// set the dropDownVisible state to the opposite it has been before
dropDownVisible = !dropDownVisible;
if (dropDownVisible) {
dropdownContent.classList.add("show");
document.body.classList.add("bgcolor");
} else {
dropdownContent.classList.remove("show");
document.body.classList.remove("bgcolor");
}
}
// we need this to prevent the event bubbling from the dropdown to the document
dropdownContent.addEventListener("click", (e) => {
e.stopPropagation();
});
// listen for click events on the document
document.addEventListener("click", (e) => {
// -> if the dropdown is visible, toggle its state
dropDownVisible && toggleDropDown(e);
});
* {
margin: 0;
padding: 0;
}
.dropdown-content {
position: fixed;
width: 30%;
height: 100%;
background-color: rgb(255, 0, 0);
margin-left: 20%;
top: 0;
display: none;
z-index: 100;
}
.dropbtn {
width: 20%;
}
.show {
display: block;
}
.bgcolor {
background-color: rgba(0, 0, 0, 0.4);
}
<body>
<div class="dropdown">
<button class="dropbtn" onclick="toggleDropDown(event)">
open
</button>
<div class="dropdown-content" id="openContent">Hello, Div</div>
</div>
<h1>Hello World, Heading 1</h1>
</body>
You will have to remove also the "body" background.
document.body.style.backgroundColor = "initial";
function toggleDropDown(id) {
document.querySelectorAll('.dropdown-content').forEach(el => el.id === id ? el.classList.toggle('show') : el.classList.remove("show"));
document.body.style.backgroundColor = "rgba(0,0,0,0.4)";
}
document.addEventListener('click', (e) => {
// cases where we want to close the dropdown
if (e.target.closest(".dropdown") === null) {
document.querySelectorAll('.dropdown-content').forEach(el => el.classList.remove("show"));
document.body.style.backgroundColor = "initial";
}
});
*{margin:0;padding:0;}
.dropdown-content{
position: fixed;
width: 30%;
height:100%;
background-color: rgb(255,0,0);
margin-left: 20%;
top:0;
display:none;
z-index:100;
}
.dropbtn{width:20%}
.show{display:block;}
<div class="dropdown">
<button class="dropbtn" onclick="toggleDropDown('openContent')">open</button>
<div class="dropdown-content" id="openContent">Hello, Div</div>
</div>
<h1>Hello World, Heading 1</h1>
Add class to body document.body.classList.add('bgcolor'); and remove after close the dropdown
function toggleDropDown(id) {
document.querySelectorAll('.dropdown-content').forEach(el => el.id === id ? el.classList.toggle('show') : el.classList.remove("show"));
document.body.classList.add('bgcolor');
}
document.addEventListener('click', (e) => {
// cases where we want to close the dropdown
if (e.target.closest(".dropdown") === null) {
document.querySelectorAll('.dropdown-content').forEach(el => el.classList.remove("show"));
document.body.classList.remove('bgcolor');
}
});
*{margin:0;padding:0;}
.dropdown-content{
position: fixed;
width: 30%;
height:100%;
background-color: rgb(255,0,0);
margin-left: 20%;
top:0;
display:none;
z-index:100;
}
.dropbtn{width:20%}
.show{display:block;}
.bgcolor{
background-color:rgba(0,0,0,0.4);
}
<div class="dropdown">
<button class="dropbtn" onclick="toggleDropDown('openContent')">open</button>
<div class="dropdown-content" id="openContent">Hello, Div</div>
</div>
<h1>Hello World, Heading 1</h1>

Modify code to take textContent from li instead of thumbnail img src?

I found (and tweaked) the code below that was designed for switching the larger img src with the src of thumbnails in a list, but I'm not sure how to adjust it to use something like https://picsum.photos/id/CLICKED_LI_textContent/200/200 as the URL instead of pulling from a thumbnail's src.
For some more context here's the original post in which I was looking into this
How can I change img src from list of (non-image) items?
I haven't taken any JS classes, so I'm not sure how every component of the script works. I'm more comfortable with pure HTML and CSS, but think JS is the answer for making this work more smoothly.
(I did add the jquery script src to the document for this)
Sorry the code is a little ugly, I would have added the script and style tags and such but I ran out of time while posting this
$("#list li").click(function(e) {
// if i use this getting undefined
// var src = $(this).attr("src");
// so i use this method
var target = e.target;
var src = target.src;
console.log(src);
$("#display").fadeOut(function() {
$(this).on('load', function() {
$(this).fadeIn();
});
$(this).attr("src", src);
});
//record which thumb was clicked
$("#list li").removeClass("active"); //remove class
$(this).addClass("active"); //apply class to selected thumb
});
//move next
$("#left-arrow").click(function() {
if ($("#list li.active").next("#list li").length > 0) {
$("#list li.active").next().children( 'img' ).trigger("click");
} else {
$("#list li:first > img").trigger("click"); //go to first
}
return false;
});
//move previous
$("#right-arrow").click(function() {
if ($("#list li.active").prev("#list li").length > 0) {
$("#list li.active").prev().children( 'img' ).trigger("click");
} else {
$("#list li:last > img").trigger("click"); //go to end
}
return false;
});
//click the first thumb to begin
$("#list li:first > img").trigger("click");
.container {
display: flex;
}
.active {
border-bottom: 1px solid #990000;
}
.list {
width: 200px;
cursor: pointer;
padding: 0.25rem;
}
list > li * {
/* so only the li tag can be event.target, and none of it's children */
pointer-events: none;
}
.display {
max-width: 500px;
max-height: 500px;
}
<div class="container">
<div class="list">
<ul id="list">
<li>237</li>
<li>240</li>
<li>100</li>
<li>301</li>
</ul>
$larr; $rarr;
</div>
<div class="show">
<img src="https://picsum.photos/id/237/200/200" class="display" id="display">
</div>
</div>
Here is a pure javascript solution. The only difference is that it lacks the fading between the images.
I tried to write the code as pedagogic as possible, using variables as explanations. The code goes more with your original thread, where you had a bunch of images with different file endings. I gave the image an alt attribute, so you can see the change.
A short explanation:
Use an array for the images.
Create your list through javascript, using the array.
Add click listeners to your #list, where you read the .textContent. I added pointer-events: none; to any children to the li tags so they don't trigger the click listener.
Add click listeners to your prev/next buttons, where you check which index that the currently visible image has in the array (from 0 to 3 in imageArr) and then adds +1 och -1 to that index.
[edit] Added code for updating the CSS.
const listEl = document.getElementById('list');
const imgElement = document.querySelector('.right > img');
let imageArr = ["237.jpg", "240.gif", "100.jpeg", "301.png"]; // 1
let currentImage = '';
document.getElementById('next').addEventListener('click', () => shiftImage(1));
document.getElementById('prev').addEventListener('click', () => shiftImage(-1));
listEl.addEventListener('click', displayImage);
function updateImage(imageName) {
const subfolder = 'images/';
changeActive(imageName, currentImage); /* ADDED in EDIT */
currentImage = imageName;
imgElement.src = subfolder + imageName;
imgElement.alt = imageName;
}
/* ADDED in EDIT */
function changeActive(newImage, oldImage) {
if (oldImage) {
let oldIndex = imageArr.indexOf(oldImage);
toggleActiveClass(oldIndex);
}
let currentIndex = imageArr.indexOf(newImage);
toggleActiveClass(currentIndex);
}
/* ADDED in EDIT */
function toggleActiveClass(imageIndex) {
let liElements = listEl.childNodes;
liElements[imageIndex].classList.toggle('active');
}
function shiftImage(direction) {
let currentIndex = imageArr.indexOf(currentImage);
let newIndex = currentIndex + direction;
if (newIndex < 0) { newIndex = imageArr.length - 1; }
else if (newIndex >= imageArr.length) { newIndex = 0; }
let newImageName = imageArr[newIndex];
updateImage(newImageName);
}
function displayImage(event) {
let liElement = event.target;
updateImage(liElement.textContent);
}
function constructImageLinks() { // 2
let htmlOutput = '';
for (let imageSrc of imageArr) {
htmlOutput += `<li>${imageSrc}</li>`;
}
listEl.innerHTML = htmlOutput;
}
constructImageLinks();
updateImage(imageArr[0]);
section {
display: flex;
}
section ul {
margin-top: 0px;
}
section > .left li {
cursor: pointer;
padding: 0.25rem;
}
section > .left li.active {
background-color: pink;
}
section > .left li > * {
pointer-events: none;
}
section > div {
padding: 1rem;
}
section > .right > img {
width: 200px;
border: 1px solid;
padding: 0.5rem;
}
<section>
<div class="left">
<ul id="list"></ul>
<button id="prev">Previous</button>
<button id="next">Next</button>
</div>
<div class="right">
<img>
</div>
</section>
JSFiddle - Link
HTML
<div class="container">
<div class="list">
<ul id="list">
<li>237</li>
<li>240</li>
<li>100</li>
<li>301</li>
</ul>
$larr; $rarr;
</div>
<div class="show">
<img src="https://picsum.photos/id/240/200/200" class="display" id="display">
</div>
</div>
Javascript
// HELPER FUNCTIONS
function getImageURL(id, width=200, height=200){
return "https://picsum.photos/id/"+ id + "/" + width + "/" + height;
}
function removeActive(){
let lis = $('#list li');
for(let i=0;i<lis.length;i++){
$(lis[i]).removeClass('active');
}
}
// HANDLE EVENTS
$(document).on('click', "#list li", async (e)=>{
await $('#display').fadeOut();
removeActive();
let li = $(e.target);
li.addClass('active');
let image_id = parseInt($(e.target).html());
let image_url = getImageURL(image_id);
$('#display').attr('src', image_url);
await $('#display').fadeIn();
});
//move next
$(document).on('click', "#left-arrow", (e)=>{
// Handler Here
});
//move previous
$(document).on('click', "#right-arrow", (e)=>{
// Handler Here
});
CSS
.active {
border-bottom: 1px solid #990000;
}
.list {
width: 200px;
cursor: pointer;
padding: 0.25rem;
}
list > li * {
/* so only the li tag can be event.target, and none of it's children */
pointer-events: none;
}
.display {
max-width: 500px;
max-height: 500px;
}
.container {
display: flex;
}

How to apply a function that affects the parent of each element with a certain class name?

I have a series of divs with the class name x that are inside of other divs with the class name item. The item divs are inside a section of the main.
What I want to do is create a function that applies equally to every x class div by affecting their respective parent (in this case changing their CSS).
I coded this:
var openbtn = document.getElementsByClassName("x")[0];
openbtn.onclick = function() {
document.body.parentElement.style.backgroundColor = "red";
}
However, this only works on the first x class <div>. When it works, it changes the background color of the section, or main or body element, and not the x class div parent (the item class div).
If you want to handle this with a handler on each .x element, you have to add a handler to each .x element. (But you may not want to do that, keep reading.) That would look like this:
var openbtns = document.getElementsByClassName("x");
for (var n = 0; n < openbtns.length; ++n) {
openbtns[n].addEventListener("click", xClickHandler);
}
...where xClickHandler uses this (or event.currentTarget) to know which .x element was clicked:
function xClickHandler() {
this.parentElement.style.backgroundColor = "red"; // I suggest using a class instead of doing this, btw
}
But, if all of these .x elements are within the same overall container, you can do it with event delegation, like this:
document.querySelector("selector-for-the-overall-container").addEventListener("click", function(event) {
// Find the `.x` that was clicked (which may be `event.target` or may be
// an ancestor node of it
var x = event.target.closest(".x");
if (x && this.contains(x)) {
x.parentElement.style.backgroundColor = "red"; // Again, suggest using a class
}
});
More:
closest
contains
Live Example using the HTML from your comment:
document.getElementById("items").addEventListener("click", function(event) {
// Find the `.x` that was clicked (which may be `event.target` or may be
// an ancestor node of it
var x = event.target.closest(".x");
if (x && this.contains(x)) {
x.parentElement.style.backgroundColor = "red"; // Again, suggest using a class
}
});
.x {
display: inline-block;
width: 10px;
height: 10px;
background-color: blue;
}
section {
background-color: yellow;
padding: 8px;
}
<main id="items">
<section id="design">
<div class="item">
<div class="x"></div>
<h1>Design stuff</h1>
</div>
</section>
<section id="art">
<div class="item">
<h1>Art stuff</h1>
<div class="x"></div>
</div>
</section>
</main>
Add the event listener to each element using a for of loop:
var openbtnList = document.getElementsByClassName("x");
for (let x of openbtnList) {
x.addEventListener("click", clickX, false);
};
function clickX() {
this.parentElement.classList.toggle("red"); // sstyle.backgroundColor = "red";
}
main {
display: flex;
}
.item {
width: 80px;
height: 100px;
padding: 30px;
}
.item::before {
content: " ";
background: url(http://placekitten.com/80/100) center/cover;
width: 80px;
height: 100px;
position: absolute;
}
.x::before {
content: "X";
color: white;
font: 30px/30px sans-serif;
padding: 10px;
position: absolute;
}
.red {
background: rgba(255, 0, 0, 0.5);
}
<main>
<div class="item">
<div class="x"></div>
</div>
<div class="item">
<div class="x"></div>
</div>
<div class="item">
<div class="x"></div>
</div>
</main>

js vertical slider with arrows

The thing is that I need to make a vertical images slider,so that when i press arrow down/arrow up every image changes it's position (the highest one goes bottom,the previous take it's place)
what it should look like:
what i have got so far:
$(function(){
var $vsliderboxes = $('#vsliderboxes'),
$vslidernav = $('#vslidernav'),
boxHeight = $vsliderboxes.height(),
current_index = 0;
function clickslide(){
clearInterval(intervalTimer);
clearTimeout(timeoutTimer);
timeoutTimer = setTimeout(function () {
intervalTimer = window.setInterval(autoslide, 2000);
}, 2500);
var index = $(this).index();
current_index = index;
$vsliderboxes.children().stop().animate({
top : (boxHeight * index * -1)
}, 500);
}
function autoslide(){
current_index++;
if (current_index >= $vsliderboxes.children().children().length) {
current_index = 0;
}
$vslidernav.find('a').eq(current_index).trigger('click');
}
$vslidernav.find('a').click(clickslide);
var intervalTimer = window.setInterval(autoslide, 2000),
timeoutTimer = null;
});
#vslidernav ul {
list-style: none;
padding: 0;
}
#vslidernav ul a {
padding: 0;
cursor: pointer;
height: 50px;
}
#vslidernav ul a:active {
color: #9C9A99;
}
#vslidernav ul a li {
height: 50px;
}
#vslidernav ul .active li {
}
.#vslidernav ul a:active {
background: transparent;
color: #9C9A99;
}
.vslider {
display: inline-block;
}
#vslidernav {
float: left;
width: 100px;
z-index: 1;
height: 250px;
}
#vsliderboxes {
position : relative;
overflow : hidden;
}
#vsliderboxes div {
height: 250px;
width: 900px;
}
#vsliderboxs-inner {
position : relative;
width : 900px;
height : 250px;
}
<div class="vslider">
<div id="vslidernav">
<ul>
<a id="1">
<li><img src="img/arrtop.gif"></li>
</a>
<a id="2">
<li><img src="img/arrdown.gif"></li>
</a>
<a id="3">
<li></li>
</a>
</ul>
</div>
<div id="vsliderboxes">
<div id="vsliderboxs-inner">
<div id="box1" class="active"><img src="img/slide1.gif"></div>
<div id="box2" class="inactive"><img src="img/slide2.gif"></div>
<div id="box3" class="inactive"><img src="img/slide3.gif"></div>
</div>
</div>
</div>
thanks for any advice
I think, that it isn't possible to solve this issue like you try to.
Because, when you work with the "top" property, you can't take one image from the top and append it to the other end because appending the image, will move the other images to another place --> the top property wouldn't be correct any more.
I think the contributed sliders (e.g. http://www.jssor.com/demos/vertical-slider.slider) work with the transform CSS property.
transform: translate3d()
Try to research about this property.
Roko C. Buljan answered on this page: loop carousel jquery
He uses a scrollTop loop for your problem.
I've also written a simple slider some time ago. I have now implemented the Roku C. Buljan method. Feel free to look at my code on Bitbucket.
https://bitbucket.org/d-stone/jqueryslider
An excerpt may help you:
value = prev_or_next == 'next' ? self.globals.slide_height : 0;
last = $('#container').find('> div:last');
first = $('#container').find('> div:first');
if(prev_or_next == 'prev') { // click on "next"-button
first.before(last); // put last element before first
settings.elements.inner.scrollTop(self.globals.slide_height); // set the scrollTop to 1 slide-height
}
// animation itself:
$('#container').stop().animate({scrollTop: value}, {
duration: settings.slide_speed,
done: function() {
if(prev_or_next == 'next') {
// put first item after last
last.after(first);
}
}
});
I'd advise you to validate your HTML (W3C Validator). There are some errors inside.
Invalid HTML can be the reason for some CSS and Javascript Errors.

Categories

Resources