Add horizontal scroll indicator to DIV - javascript

I want to show an horizontal scroll indicator for a scrollable DIV container.
After some testing I'm pretty sure that it's not possible wit pure CSS.
I found a snippet in an answer for a similar question.
Unfortunately I couldn't figure out how to change the script to my needs.
I'm using a simple DIV container with some elements in it.
Here's my code:
<div class="container">
<div class="scroll-wrapper">
<div class="scroll-container">
<ul class="list-inline text-white text-center">
<li class="list-inline-item" style="width: 200px;">
<div class="py-5 bg-dark"><h1 class="py-5">1</h1></div>
</li>
<li class="list-inline-item" style="width: 400px;">
<div class="py-5 bg-dark"><h1 class="py-5">2</h1></div>
</li>
[....]
</ul>
</div>
</div>
<div class="scroll-indicator">
<div class="scroll-indicator-bar"></div>
</div>
<div class="d-flex justify-content-between">
<button>Prev</button>
<button>Next</button>
</div>
</div>
And the CSS:
.scroll-wrapper {
width: 100%;
overflow-x: scroll;
overflow-y: hidden;
position: relative;
white-space: nowrap;
}
.scroll-indicator {height: 4px; width: 100%; background-color: #ddd; margin-bottom: 2rem;}
.scroll-indicator-bar {height: 4px; width: 20%; background-color: #000;}
Working example
Is there any way to animate the scrollbar indicator with CSS and/or jQuery?
EDIT: I found another good example here: https://codepen.io/mahish/pen/RajmQw
I tried to use the code in my example but the prev/next buttons doesn't work. And I also don't know how to use the scroll position to show and move a scroll indicator.
Here's the JS code from the example (change to my class names):
// duration of scroll animation
var scrollDuration = 300;
// paddles
var leftPaddle = document.getElementsByClassName('left-paddle');
var rightPaddle = document.getElementsByClassName('right-paddle');
// get items dimensions
var itemsLength = $('.item').length;
var itemSize = $('.item').outerWidth(true);
// get some relevant size for the paddle triggering point
var paddleMargin = 20;
// get wrapper width
var getMenuWrapperSize = function() {
return $('.scroll-wrapper').outerWidth();
}
var menuWrapperSize = getMenuWrapperSize();
// the wrapper is responsive
$(window).on('resize', function() {
menuWrapperSize = getMenuWrapperSize();
});
// size of the visible part of the menu is equal as the wrapper size
var menuVisibleSize = menuWrapperSize;
// get total width of all menu items
var getMenuSize = function() {
return itemsLength * itemSize;
};
var menuSize = getMenuSize();
// get how much of menu is invisible
var menuInvisibleSize = menuSize - menuWrapperSize;
// get how much have we scrolled to the left
var getMenuPosition = function() {
return $('.scroll-container').scrollLeft();
};
// finally, what happens when we are actually scrolling the menu
$('.scroll-container').on('scroll', function() {
// get how much of menu is invisible
menuInvisibleSize = menuSize - menuWrapperSize;
// get how much have we scrolled so far
var menuPosition = getMenuPosition();
var menuEndOffset = menuInvisibleSize - paddleMargin;
// show & hide the paddles
// depending on scroll position
if (menuPosition <= paddleMargin) {
$(leftPaddle).addClass('hidden');
$(rightPaddle).removeClass('hidden');
} else if (menuPosition < menuEndOffset) {
// show both paddles in the middle
$(leftPaddle).removeClass('hidden');
$(rightPaddle).removeClass('hidden');
} else if (menuPosition >= menuEndOffset) {
$(leftPaddle).removeClass('hidden');
$(rightPaddle).addClass('hidden');
}
// print important values
$('#print-wrapper-size span').text(menuWrapperSize);
$('#print-menu-size span').text(menuSize);
$('#print-menu-invisible-size span').text(menuInvisibleSize);
$('#print-menu-position span').text(menuPosition);
});
// scroll to left
$(rightPaddle).on('click', function() {
$('.scroll-container').animate( { scrollLeft: menuInvisibleSize}, scrollDuration);
});
// scroll to right
$(leftPaddle).on('click', function() {
$('.scroll-container').animate( { scrollLeft: '0' }, scrollDuration);
});

You can have your own custom horizontal scroll behavior with vanilla js, you just need to handle mousedown, mouseup and mousemove events, calculate the needed scroll value and move your elements using transform: translateX() style, and to keep track with these values,
I did some changes and added some js code, check the snippet bellow:
const scrollBar = document.getElementById('myBar');
const scrollBarWrapper = document.getElementById('barWrapper');
const scrollContent = document.getElementById('scroll-container');
scrollBar.style.width = ((scrollContent.offsetWidth * scrollBarWrapper.offsetWidth) / scrollContent.scrollWidth) + 'px';
let isScrolling = false;
let cursorX = 0;
let translateXValue = 0;
scrollBar.addEventListener('mousedown', function(e) {
e.preventDefault();
isScrolling = true;
cursorX = e.clientX;
});
document.addEventListener('mouseup', function(e) {
if (isScrolling) {
e.preventDefault();
isScrolling = false;
translateXValue += (e.clientX - cursorX);
}
});
document.addEventListener('mousemove', function(e) {
if (isScrolling && cursorX !== e.clientX) {
e.preventDefault();
const translateAmount = (translateXValue + (e.clientX - cursorX));
const scrollLength = (barWrapper.offsetWidth - scrollBar.offsetWidth);
const barScroll = Math.min(Math.max(0, translateAmount), scrollLength);
const contentTranslateRatio = (barScroll * scrollContent.scrollWidth) / scrollContent.offsetWidth;
scrollBar.style.transform = 'translateX(' + barScroll + 'px)';
scrollContent.style.transform = 'translateX(' + -contentTranslateRatio + 'px)';
}
});
.scroll-wrapper {
width: 100%;
overflow: hidden;
position: relative;
white-space: nowrap;
}
.scroll-indicator {height: 6px; width: 100%; background-color: #ddd; margin-bottom: 2rem;}
.scroll-indicator-bar {height: 6px; width: 20%; background-color: #000;}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container" id="container">
<div class="scroll-wrapper">
<div class="scroll-container" id="scroll-container">
<ul class="list-inline text-white text-center">
<li class="list-inline-item" style="width: 200px;">
<div class="py-5 bg-dark"><h1 class="py-5">1</h1></div>
</li>
<li class="list-inline-item" style="width: 400px;">
<div class="py-5 bg-dark"><h1 class="py-5">2</h1></div>
</li>
<li class="list-inline-item" style="width: 300px;">
<div class="py-5 bg-dark"><h1 class="py-5">3</h1></div>
</li>
<li class="list-inline-item" style="width: 150px;">
<div class="py-5 bg-dark"><h1 class="py-5">4</h1></div>
</li>
<li class="list-inline-item" style="width: 250px;">
<div class="py-5 bg-dark"><h1 class="py-5">5</h1></div>
</li>
<li class="list-inline-item" style="width: 300px;">
<div class="py-5 bg-dark"><h1 class="py-5">6</h1></div>
</li>
<li class="list-inline-item" style="width: 200px;">
<div class="py-5 bg-dark"><h1 class="py-5">7</h1></div>
</li>
<li class="list-inline-item" style="width: 400px;">
<div class="py-5 bg-dark"><h1 class="py-5">8</h1></div>
</li>
<li class="list-inline-item" style="width: 300px;">
<div class="py-5 bg-dark"><h1 class="py-5">9</h1></div>
</li>
</ul>
</div>
</div>
<div class="scroll-indicator" id="barWrapper">
<div class="scroll-indicator-bar" id="myBar"></div>
</div>
<div class="d-flex justify-content-between">
<button>Prev</button>
<button>Next</button>
</div>
</div>
by this code you have a dynamic scrollbar width dynamic width based on the content, and you can manage your own scroll behavior,
then, you can add custom next() and previous() functions to add translate for both scrollbar and content, as implemented in mousemove handler

I found a solution by using SimpleBar: https://github.com/Grsmto/simplebar/tree/master/packages/simplebar

Related

Get the id of current section on scroll in JavaScript

I'm trying to build a dot navigation kind of thing, i.e., when you click on each "div" it takes you to the specific section, which is currently implemented.
But, also while scrolling I need to change the current state of this div's to active. How do I do that?
An image on how the dot navigation looks.
I was looking how to get scroll positions of each section and assign them to each variables and run some function.
<div class="dot-navigation">
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
</div>
Listen for scroll events, find the currently displayed region, and highlight the navigation elements as necessary.
window.addEventListener('DOMContentLoaded', updateNav);
window.addEventListener('scroll', updateNav);
function updateNav() {
const currentRegion = [...document.querySelectorAll(".region:not([id=''])")]
.find(e=>e.getBoundingClientRect().top>=0)
if(currentRegion) {
window.location.hash = `#${currentRegion.id}`;
[...document.querySelectorAll(`a:not([href='#${currentRegion.id}'])`)]
.forEach(a=>a.classList.remove('red'))
document.querySelector(`a[href='#${currentRegion.id}']`)?.classList.add('red')
}
}
a { text-decoration:none; color: black}
.red { color: red; }
.region { margin-left: 100px; min-height: 500px; }
.dot-navigation { position:fixed }
<div class="dot-navigation">
<div>o</div>
<div>o</div>
<div>o</div>
<div>o</div>
<div>o</div>
<div>o</div>
</div>
<div class="region" id="home">home...</div>
<div class="region" id="about">about...</div>
<div class="region" id="services">services...</div>
<div class="region" id="clients">clients...</div>
<div class="region" id="reviews">reviews...</div>
<div class="region" id="contactus">contactus...</div>
Thanks, Angelina for your comment.
I found this to be useful https://www.youtube.com/watch?v=fAAk9CATILc
let section = document.querySelectorAll("section");
let dotNav = document.querySelectorAll(".dot-navigation div a");
window.onscroll = () => {
section.forEach((sec) => {
let top = window.scrollY;
let offset = sec.offsetTop - 200;
let height = sec.offsetHeight;
let id = sec.getAttribute("id");
if (top >= offset && top < offset + height) {
dotNav.forEach((dot) => {
dot.classList.remove("navDot-active");
document.querySelector(".dot-navigation div a[href*=" + id + "]").classList.add("navDot-active");
});
}
});
};

Scroll on div without triggering full page scroll in angular

I have a website which have one page scroll feature using this - https://alvarotrigo.com/angular-fullpage/
Now in this website, In one page I want to create a division inside which the fullpage scroll feature is disabled and I can scroll that division as normal - like this https://stackblitz.com/edit/angular-kqvraz?file=src%2Fapp%2Fapp.component.html
What I have done till now -
app.component.html
<app-navbar></app-navbar>
<div fullpage id="fullpage2" [options]="config" (ref)="getRef($event)">
<div class="section" id="banner">
//first section
</div>
<div class="section" id="demos">
//second section
</div>
<div class="section" id="prod-solution">
// third section
</div>
<div class="section" id="scroll-solution">
<div style="height: 200px; border: 1px solid; overflow: auto;">
// div where I want to disable full page scroll and enable normal scroll
<div>
Please scroll
<div style="height: 1000px; width: 1000px;"></div>
</div>
</div>
</div>
</div>
app.component.ts
export class AppComponent {
config: any;
fullpage_api: any;
constructor() {
// for more details on config options please visit fullPage.js docs
this.config = {
// fullpage options
licenseKey: 'YOUR LICENSE KEY HERE',
anchors: ['firstPage', 'secondPage', 'thirdPage', 'fourthPage', 'lastPage'],
menu: '#menu',
// fullpage callbacks
afterResize: () => {
console.log("After resize");
},
afterLoad: (origin, destination, direction) => {
console.log(origin.index);
}
};
}
getRef(fullPageRef) {
this.fullpage_api = fullPageRef;
}
}
You should catch the wheel event on the DIV that shouldn't trigger the fullpage scroll and only scroll this element.
Code
Modify the section of your code to match the following one:
<div style="height: 200px; border: 1px solid; overflow: auto;">
<!-- add a scroll event listener -->
<div (wheel)="blockScroll($event)">
Please scroll
<div style="height: 1000px; width: 1000px;"></div>
</div>
</div>
Add the event listener in your app.component.ts:
blockScroll(e) {
let delta = e.deltaY || -e.detail;
e.currentTarget.scrollTop += delta * 30;
e.stopPropagation();
e.preventDefault();
}
Demo
I added a scrolling container in "Section 2" that will only scroll its own content without triggering the fullpage scroll.
Demo on StackBlitz
If you want other scroll events like touch to be handled as well you need to add the relevant event to the <div> as well.
For scrolling on pages higher than 100vh, We want scrolling to be done normally and when we get to the bottom of the page, do a full scroll.
For this purpose, you can use the fullpage.js package, which requires a license. But by typescript, it can be easily implemented.
sample in stackblitz
in file.html use (mousewheel):
<div class="container" id="main-container"
(mousewheel)="changeMouseWheel($event)">
<div class="panel" id="el1"></div>
<div class="panel" id="el2"></div>
<div class="panel" id="el3"></div>
<div class="panel" id="el4"></div>
<div class="panel" id="el5"></div>
<div class="panel" id="el6">
<h1>whit long height</h1>
</div>
</div>
in fil.css:
.panel{
width: 100%;
height: 100vh;
}
#el1 {background-color: antiquewhite}
#el2 {background-color: aliceblue}
#el3 {background-color: beige}
#el4 {background-color: aqua}
#el5 {background-color: #00ffae
}
#el6 {height: 200vh; background-color: #6200ff
}
in file.ts:
changeMouseWheel(e) {
const sectionCount = document.querySelectorAll('.panel').length;
const windowHeight = window.innerHeight;
if (e.deltaY < 0 && this.sectionNumber > 1) {
if (this.hold === false) {
this.hold = true;
this.sectionNumber -= 1;
const element = document.getElementById(`el${this.sectionNumber}`);
this.scroll(element.offsetTop, 0);
setTimeout(() => {
this.hold = false;
}, 500);
e.preventDefault();
}
}
if (e.deltaY > 0 && this.sectionNumber < sectionCount) {
const currentElement = document.getElementById(`el${this.sectionNumber}`);
if (((currentElement.offsetTop + currentElement.offsetHeight) - windowHeight) <= document.documentElement.scrollTop) {
if (this.hold === false) {
this.hold = true;
this.sectionNumber += 1;
console.log(`#el${this.sectionNumber}`);
const nextElement = document.getElementById(`el${this.sectionNumber}`);
this.scroll(nextElement.offsetTop, 0);
setTimeout(() => {
this.hold = false;
}, 500);
e.preventDefault();
}
}
}
}
scroll(topData: number, leftData: number) {
window.scrollTo({
top: topData,
left: leftData,
behavior: 'smooth'
});
}

Activate partial visible tab and display complete tab on click of it from the list of horizontal tabs

Currently, I'm having a list of tabs visible horizontally. On click of tab it should show me the complete text tab.
Expected Behavior:
When i click on the partly visible tab, it should show me the complete tab by moving left side, same thing should be applicable if I'm doing it from right side(Scroll right if it is first tab).
Text content is dynamic, it can have any number of words. We need to fit it dynamically.
Example:
https://jsfiddle.net/kzLexmh9/1/
In my current example "HelloWorldFour" is partially displaying. OnClick it should show me the full text by moving the scroll content to left.
HTML:
<div class="group" id="frames">
<div class="item frames-item">HelloWorldOne</div>
<div class="item frames-item">HelloWorldTwo</div>
<div class="item frames-item">HelloWorldThree</div>
<div class="item frames-item">HelloWorldFour</div>
<div class="item frames-item">HelloWorldFive</div>
<div class="item frames-item">HelloWorldSix</div>
<div class="item frames-item">HelloWorldSeven</div>
<div class="item frames-item">HelloWorldEight</div>
<div class="item frames-item">HelloWorldNine</div>
<div class="item frames-item">HelloWorldTen</div>
<div class="item frames-item">HelloWorldEleven</div>
<div class="item frames-item">HelloWorldTwelve</div>
</div>
Script:
$("#frames").on('click', function (e) {
if (e.target.classList.contains('item')) {
e.target.parentNode.scrollLeft = e.target.offsetLeft;
}
});
CSS:
body {
background: red;
}
.group{
width: 400px;
display: flex;
position: relative; /* This is important for the js offsetLeft property */
overflow-x: scroll;
}
.item{
width: 200px;
background: #eee;
margin-right: 10px;
}
Is something like this what you're looking for? This will work on any of the "HelloWorld" boxes..
EDIT:
So I was finally able to get this to work... It is essentially a two part process.. I have added examples to the demo snippet showing how each step works.
How this works:
Calculate the position to scroll the div (that we just clicked) all the way to the left side of the parent container (this was my previous answer)
Calculate the 'offset' needed to scroll the div (that we just clicked) back to the right
Scroll to that position
These calculations are determined before any scrolling is performed, so it is a seamless scroll - the calculation is a two part process, but the scrolling is done using the final calculation.
There are 3 demos in this snippet, make sure to scroll down all the way to test them all.
$(".item1").on('click', function(event) {
finalSolution(this, "#frames1", 400);
});
$(".item2").on('click', function(event) {
zeroLeftOnly(this, "#frames2", 800);
});
$(".item3").on('click', function(event) {
animatedSteps(this, "#frames3", 800);
});
function finalSolution(element, container, scrollSpeed) {
const zeroLeft = $(element).position().left + $(container).scrollLeft();
const offsetLeft = $(container).width() - $(element).width();
const scrollTo = zeroLeft - offsetLeft;
$(container).animate({ scrollLeft: scrollTo }, scrollSpeed);
}
function zeroLeftOnly(element, container, scrollSpeed) {
const zeroLeft = $(element).position().left + $(container).scrollLeft();
$(container).animate({ scrollLeft: zeroLeft }, scrollSpeed);
}
function animatedSteps(element, container, scrollSpeed) {
const zeroLeft = $(element).position().left + $(container).scrollLeft();
$(container).animate({ scrollLeft: zeroLeft }, scrollSpeed);
const offsetLeft = $(container).width() - $(element).width();
const scrollTo = zeroLeft - offsetLeft;
setTimeout(() => {
$(container).animate({ scrollLeft: scrollTo }, scrollSpeed);
}, 1000);
}
body {
background: red;
}
h3{
color: white;
text-decoration: underline white;
margin: 5px;
}
.group {
border: 1px solid black;
padding: 5px 0px;
width: 400px;
height: 38px;
display: flex;
position: relative;
/* This is important for the js offsetLeft property */
overflow-x: scroll;
}
.item1,
.item2,
.item3 {
width: 200px;
background: #eee;
margin-right: 10px;
cursor: pointer;
}
.clickme {
background: lightblue;
}
p {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h3>Final Solution</h3>
<p><i><b><small>Click on 'HelloWorldFour' (the light blue block)</small></b></i></p>
<div class="group" id="frames1">
<div class="item1 frames-item">HelloWorldOne</div>
<div class="item1 frames-item">HelloWorldTwo</div>
<div class="item1 frames-item">HelloWorldThree</div>
<div class="clickme item1 frames-item">HelloWorldFour</div>
<div class="item1 frames-item">HelloWorldFive</div>
<div class="item1 frames-item">HelloWorldSix</div>
<div class="item1 frames-item">HelloWorldSeven</div>
<div class="item1 frames-item">HelloWorldEight</div>
<div class="item1 frames-item">HelloWorldNine</div>
<div class="item1 frames-item">HelloWorldTen</div>
<div class="item1 frames-item">HelloWorldEleven</div>
<div class="item1 frames-item">HelloWorldTwelve</div>
</div><br /><hr />
<h3>Each step is animated here - to show how the underlying calculation works.</h3>
<p><i><b><small>Click on 'HelloWorldFour' (the light blue block)</small></b></i></p>
<div class="group" id="frames3">
<div class="item3 frames-item">HelloWorldOne</div>
<div class="item3 frames-item">HelloWorldTwo</div>
<div class="item3 frames-item">HelloWorldThree</div>
<div class="clickme item3 frames-item">HelloWorldFour</div>
<div class="item3 frames-item">HelloWorldFive</div>
<div class="item3 frames-item">HelloWorldSix</div>
<div class="item3 frames-item">HelloWorldSeven</div>
<div class="item3 frames-item">HelloWorldEight</div>
<div class="item3 frames-item">HelloWorldNine</div>
<div class="item3 frames-item">HelloWorldTen</div>
<div class="item3 frames-item">HelloWorldEleven</div>
<div class="item3 frames-item">HelloWorldTwelve</div>
</div><br /><hr />
<h3>Using only 'zeroLeft' - this was my first, older, answer.</h3>
<p><i><b><small>Click on 'HelloWorldFour' (the light blue block)</small></b></i></p>
<div class="group" id="frames2">
<div class="item2 frames-item">HelloWorldOne</div>
<div class="item2 frames-item">HelloWorldTwo</div>
<div class="item2 frames-item">HelloWorldThree</div>
<div class="clickme item2 frames-item">HelloWorldFour</div>
<div class="item2 frames-item">HelloWorldFive</div>
<div class="item2 frames-item">HelloWorldSix</div>
<div class="item2 frames-item">HelloWorldSeven</div>
<div class="item2 frames-item">HelloWorldEight</div>
<div class="item2 frames-item">HelloWorldNine</div>
<div class="item2 frames-item">HelloWorldTen</div>
<div class="item2 frames-item">HelloWorldEleven</div>
<div class="item2 frames-item">HelloWorldTwelve</div>
</div>
You are just nearby solution. Just try this it to display clicked item at center of group div.
e.target.parentNode.scrollLeft = e.target.offsetLeft - e.target.parentNode.offsetWidth/2 ;

Dynamically cover 2 divs with CSS

I have 2 divs that I need a shade over after a user action. The divs are just two divs next to each other:
<div class="bought">content</div>
<div class="class2">content</div>
Here is the CSS which is made visible via jQuery:
#view-hint .body > .img .bought {
display:none;
cursor:pointer;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index:2;
background: rgba(0,0,0,0.75);
}
When the event fires this is what it looks like:
That bottom white area needs to be covered dynamically as well.
The approach I thought to take was to wrap both div's in another div but it breaks the look of everything. So I tried to make the top div longer based off size but it's still not perfect...
var originalHeight = $('.bought').height();
var windowWidth = $(window).width();
if (windowWidth < 710) {
$('.bought').css('height', originalHeight * 0.6);
} else if (windowWidth > 710 && windowWidth < 1000) {
$('.bought').css('height', originalHeight * 0.698);
} else if (windowWidth > 1000 && windowWidth < 1300) {
$('.bought').css('height', originalHeight * 0.699);
} else if (windowWidth > 1300 && windowWidth < 1600) {
$('.bought').css('height', originalHeight * 0.865);
} else if (windowWidth > 1600 && windowWidth < 2000) {
$('.bought').css('height', originalHeight * 1.035);
} else {
$('.bought').css('height', "662px");
}
This mostly works for all size screens, but if you change the zoom it still causes issues.
How can I make it where both of these divs are covered by the CSS dynamically?
Edit:
Here is the full HTML with an added wrapper and an image that results:
<div id="test123">
<div class="bought">
<div class="row">
<div class="col">
<div class="body">
<?php if(Request::is('user/*')) { ?>
<div id="boughtquestion">Did you buy this for <?php echo $user->firstName ?>?</div>
<div class="options">
<!-- <a id="boughtyes" class="cbutton whiteonpurple" onclick="markPurchased(event)">Yes</a> -->
<a id="boughtyes" class="cbutton whiteonpurple">Yes</a>
<a id="boughtno" class="cbutton whiteonpurple">No</a>
</div>
<?php } else { ?>
<div>Bought?</div>
<p>Click here to send hinters a message to let them know.<br />And yes, it can still be a surprise!</p>
<?php } ?>
</div>
</div>
</div>
</div>
<div class="markedaspurchased">
<div class="row">
<div class="col">
<div class="body">
<div id="markedpurchased">Marked as Purchased</div>
<p id="markedmessage">Marking as purchased prevents duplicate gift giving. Dont worry <?php echo $user->firstName ?> doesn't get notified but you can let <?php echo ($user->gender == 'female' ? 'him' : 'her') ?> know by sending a message!</p>
<p><a id="sendmessagebutton" class="cbutton whiteonpurple purchasebutton">Send message to let them know</a></p>
<p><a id="anonymousbutton" class="cbutton whiteonpurple purchasebutton">Send anonymous message</a></p>
<p><a id="secretbutton" class="cbutton whiteonpurple purchasebutton">Keep it a secret</a></p>
</div>
</div>
</div>
</div>
</div>
<p class="description"></info-coverp>
<div class="options">
<a class="buy cbutton whiteonpurple" target="_blank">Buy</a>
<a class="hint cbutton whiteonblack" target="_blank">Hint</a>
</div>
<div class="info">
<div class="bar"></div>
<div class="rehints">10 REHINTS</div>
<div class="hinter">
<div class="picture monophoto">
<div class="text">BO</div>
<div class="img" style="background-image: url();" onclick=""></div>
</div>
<div class="content">
<div class="one">Hinted by:</div>
<div class="two"></div>
</div>
</div>
<div class="partnertext">Partnered Hint</div>
<div style="clear:both;"></div>
</div>
</div>
Since you're using Jquery, why not give the divs a separate class and then use .wrapAll to create a wrapper...then position the overlay on top of that.
$(".wrapped").wrapAll('<div class="overlay" />');
.overlay {
display: inline-block;
position: relative;
}
.overlay::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapped bought">content 1</div>
<div class="wrapped class2">content 2</div>

How to get the last visible element in jQuery?

Please take a look at this:
http://jsfiddle.net/SHfz4/
Technically all those blue boxes are visible as in none are displayed as none so I can't use something like this:
$('.row .inner .item:visible:last');
Because that will give box 27 each time.
As you can see some boxes are visible and other's are not depending on the size of your view port, resizing will cause more boxes to go out of view or come into view.
I need a way to get the last visible item in a row. How to do this?
P.S. I have been snippets posted here on SO that show how to tell if an element is in view but some of those scripts were returning true even when they shouldn't and all of them required a specific element to be checked against, but my case requires me to just ask for the last and not specifically test a given element.
CSS:
.row { border: 1px solid red; height: 50px; overflow: hidden; }
.row .inner { width: 1000px; }
.row .inner .item { box-shadow: inset 0 0 8px blue; width: 50px; height: 50px; float: left; line-height: 50px; }
HTML:
<div class="row">
<div class="inner">
<div class="item item-1">1</div>
<div class="item item-2">2</div>
<div class="item item-3">3</div>
<div class="item item-4">4</div>
<div class="item item-5">5</div>
<div class="item item-6">6</div>
<div class="item item-7">7</div>
<div class="item item-8">8</div>
<div class="item item-9">9</div>
<div class="item item-10">10</div>
<div class="item item-11">11</div>
<div class="item item-12">12</div>
<div class="item item-13">13</div>
<div class="item item-14">14</div>
<div class="item item-15">15</div>
<div class="item item-16">16</div>
<div class="item item-17">17</div>
<div class="item item-18">18</div>
<div class="item item-19">19</div>
<div class="item item-20">20</div>
<div class="item item-21">21</div>
<div class="item item-22">22</div>
<div class="item item-23">23</div>
<div class="item item-24">24</div>
<div class="item item-25">25</div>
<div class="item item-26">26</div>
<div class="item item-27">27</div>
</div>
</div>
Does this snippet do what you expect?
var items = document.querySelectorAll('div[class^=item]')
,row = items[0].offsetParent
,rightBoundary = row.clientLeft+row.clientWidth
,bottomBoundary = row.clientTop+row.clientHeight
,found = null;
for (var i=0;i<items.length;i+=1){
if (items[i].offsetLeft > rightBoundary ||
items[i].offsetTop > bottomBoundary){
found = items[i-1];
break;
}
}
// reports div.item item-17
See this fork of your jsFiddle
[edit] added a check for [invisible] items below the first row of items, see the full screen version of the jsFiddle
var timeout = '';
$(window).resize(function () {
clearTimeout(timeout);
timeout = setTimeout(function () {
var $row = $('.row'),
rWidth = $row.width(),
$item = $row.find('.item').filter(function () {
var $this = $(this),
l = $this.width() + $this.position().left;
return l >= rWidth;
}).first();
}, 60);
}).resize();
http://jsfiddle.net/EkA3K/

Categories

Resources