I am trying to create a data-grid where I am not displaying all the records in the beginning and want to render them when scrolled. Is there a way I can set a scroll size based on the amount of data that I have and change the data in the dev when user scrolls.
I know there are grid's out there but I do not want to use them and want to know what are the different ways to do it.
I have tried looking into the scroll event and I did not find anything about the scroll direction or the current offset. Is there any documentation I can find. or even a technical name to search for would help me.
You can search for a "infinity scroll" with javascript and html.
EXAMPLE HTML: `<ul id='infinite-list'></ul>`
EXAMPLE CSS: `#infinite-list {
/* We need to limit the height and show a scrollbar */
width: 200px;
height: 300px;
overflow: auto;
/* Optional, only to check that it works with margin/padding */
margin: 30px;
padding: 20px;
border: 10px solid black;
}
/* Optional eye candy below: */
li {
padding: 10px;
list-style-type: none;
}
li:hover {
background: #ccc;
}`
EXAMPLE JAVASCRIPT: `var listElm = document.querySelector('#infinite-list');
// Add 20 items.
var nextItem = 1;
var loadMore = function() {
for (var i = 0; i < 20; i++) {
var item = document.createElement('li');
item.innerText = 'Item ' + nextItem++;
listElm.appendChild(item);
}
}
// Detect when scrolled to bottom.
listElm.addEventListener('scroll', function() {
if (listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) {
loadMore();
}
});
// Initially load some items.
loadMore();
`
Related
I have this page (https://www.datacoral.com/architecture/) that has a left sidebar with five bullet points. What I want to happen is as the user scrolls past these five div's on the right hand column, the text in one of these bullet points adds a class called 'bolder' and the text become a font-weight of 700 to let the user know what point they are in on the page. As the pass by that same div, the class disappears and ends up in the next bullet point since you're now passing by another div.
I've got it partially working but it's not hitting the right point of the div at all. Seems to add the class as you are passing the bottom of the div instead of the top.
This is the code I'm currently working with. Anyone know what I might be doing wrong so this can function properly?
Note: Should mention I'm basically duplicating this code five times and just swapping out the numbers.
jQuery(function(){
jQuery(window).scroll(function() {
var scroll = jQuery(window).scrollTop(); // how many pixels you've scrolled
var os = jQuery('#guide_body-0').offset().top; // pixels to the top of div1
var ht = jQuery('#guide_body-0').height(); // height of guide_body-0 in pixels
if(scroll > os + ht){
jQuery('.scroll-nav-0').addClass('bolder');
}
});
});
I think firing a function on scroll like that gets a little bit crazy. I always delay the function until the scrolling has stopped.
As far as the catch point, i think your code is applying the classes when the element has moved out of view. i would use the bottom of the browser screen as a reference point.
Think about it like this:
$(window).scrollTop() returns 0 at the top of the page.
$('#guide_body-0').offset().top returns 1000px.
So $(window).scrollTop() is equal to $('#guide_body-0').offset().top when that element is at the top of the screen.
Add $('#guide_body-0').height() to the equation and that puts the scroll position (the top of the screen) at the bottom of the element.
What you need to do is check if the offset.top property of the element is in a scroll position which puts it above the bottom of the screen.
UPDATE
The code here is for a custom solution. But if you are looking for a way to just add simple animations to elements as they scroll into view, check out wow.js and animate.css
https://wowjs.uk/
https://animate.style/
// Init variable for timer
let timer;
// Get target element
const el = $("#4");
// Get viewport height
const screen = window.innerHeight;
// Fire callback on window scroll
$(window).scroll(function() {
// Clear timeout just in case
clearTimeout(timer);
// Check if the element already has the class
if (!el.hasClass("active")) {
// Set a delay timer then run the function
timer = setTimeout(check_el_pos, 300);
}
});
function check_el_pos() {
// Clear the timer
clearTimeout(timer);
// Get current scroll position
let scroll_pos = $(window).scrollTop();
// This is the math here. Add scroll position to screen height and you get the bottom of the screen. When that value equals the top offset of the element, we are there.
if (scroll_pos + screen > el.offset().top) {
console.log(scroll_pos + screen);
console.log(el.offset().top);
// Add the classes to the element. Boom, we're done.
el.removeClass("active").addClass("active");
}
}
body,
html {
padding: 0;
margin: 0;
}
.example-grid {
list-style: none;
padding: 0;
margin: 0;
width: 100%;
display: grid;
grid-gap: 40px;
}
.example-grid>li {
list-style: none;
padding: 0;
margin: 0;
width: 100%;
height: 65vh;
background: slategray;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: #fff;
font-size: 2em;
line-height: 1em;
transition: background-color 1s;
transition-timing-function: ease-out;
}
.example-grid>li:nth-child(even) {
background: coral;
}
.example-grid>li.active {
background: aquamarine;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="example-grid">
<li id="1">1</li>
<li id="2">2</li>
<li id="3">3</li>
<li id="4">4</li>
<li id="5">5</li>
<li id="6">6</li>
<li id="7">7</li>
</ul>
I´ve searched the web 100 of times to find something that is like that what I want. I found nothing and tried to do it myself. After two days I give up because of many reasons. So I´m asking you all here if some one can do it for me. Think about a sticks header, you scroll down a website and the header goes with it fixed on the top. So my imagine was, every time the header hits a section with data-color="#2D2D2D", the headers background color will change to it. But wait, I want that it happens linear with a background image, so if he scrolls back its the coloring linear to the color before.
Here is the article I´ve seen. But there its just a image and it is in the content.
https://codyhouse.co/demo/fixed-background-effect/index.html
Here is my Pen (It was just a try)
http://codepen.io/muuvmuuv/pen/MarxYx
Here is a img
I have made a basic example accordiong to your needs, just have a look and tell me if I understood what you said. I have added some extra explanation in the js code and the fiddle is at the end of this post.
A basic HTML markup
<heade id="webHeader">
<nav>
<ul>
<li>Nav item 1</li>
<li>Nav item 2</li>
<li>Nav item 3</li>
</ul>
</nav>
</heade>
<section id="section-1" data-color="#330000"></section>
<section id="section-2" data-color="#00B200"></section>
<section id="section-3" data-color="#803380"></section>
I am going for SCSS but you can easly update to basic CSS (I assumed that the sticky header is by default so I have added a padding to body with the same value as the header height)
$headerHeight: 100px;
body {
padding-top: $headerHeight;
}
#webHeader {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: $headerHeight;
background: #000F1F; /*default background color and fallback if there is no section available for it*/
nav {
padding: 40px;
float: right;
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #fff;
font-weight: 700;
text-decoration: none;
}
}
}
section {
width: 100%;
height: 500px;
background-color: grey;
border-bottom: 1px dashed #fff;
}
And the jQuery code.
(function($){
// cache dom elements
var $header = $('#webHeader');
var $window = $(window);
var headerHeight = $header.outerHeight(true);
var colors = []; // add colors here
var sections = []; // add sections positions
$('section').each(function(){
var $this = $(this);
colors.push($this.data('color'));
sections.push($this.position().top);
});
// duplicate first color
colors.unshift(colors[0]);
$window.on('scroll', function(){
var position = $window.scrollTop() + headerHeight;
var index = inInterval(position, sections);
var distance = position - sections[index];
$header.attr('style', linearGradient( colors[index+1], colors[index], distance ) );
}).trigger('scroll');
// trigger scroll when the page is loaded to update the header color to the current position
})(jQuery);
// Treat array elements as intervals
function inInterval(value, array) {
// cache array length
var arrLen = array.length;
// Add one more value at the end of array to avoid having problems on last item
array.push(array[arrLen-1]*2);
for (var i = 0; i < arrLen+1; i++)
if (value >= array[i] && value <= array[i+1])
return i;
}
function linearGradient(start, end, distance) {
var distanceStart = distance + '%';
var distanceEnd = 100 - distance + '%';
return "background: -webkit-gradient(linear, left top, left bottom, color-stop(0, "+ start +"), color-stop("+ distanceStart +", "+ start +"), color-stop("+ distanceStart +", "+ end +"), color-stop(100, "+ end +")";
}
You can see it working in this fiddle. I would make some updates but I am bit busy for moment, but I recommend you to read more about jQuery debounce and give a try to smart scroll (useful to call bit less scroll events - good for performance)
I hope is what you are looking for :)
There is a div, style fixed 60px from top. I want when I scroll down and the distance of div from top reached 10px, the div stop there for the rest of scrolling also when I scroll up it goes back to the old style 60px from top. I did a lot of search but I did not found anything like this. But there is a code which calculate distance from top:
var scrollTop = $(window).scrollTop(),
elementOffset = $('#my-element').offset().top,
distance = (elementOffset - scrollTop);
Here's one way to do it using pure javascript. You can replace some of the selectors like document.getElementById with jQuery selectors like $("id") if you like.
window.onscroll = function(){
var el = document.getElementById('sticky'),
s = window.pageYOffset || document.documentElement.scrollTop, // how much page is scrolled
t = document.getElementById('main').getBoundingClientRect().top; // top of main div
if(s > t){
el.style.position = 'fixed'; //make position fixed instead of absolute
}else{
el.style.position = ''; //clear styles if back to original position
}
}
body {
min-height: 200em;
margin: 0;
padding: 0;
}
header {
background: black;
color: white;
padding: .5em;
}
#main { position: relative; } /* important so the sticky box positions relative to this */
#sticky {
background: cornflowerblue;
padding: .5em;
position: absolute;
right: 1em;
top: 1em;
width: 10em;
color: white;
}
<header>This is just a page header or toolbar.</header>
<section id="main">
<div id="sticky">This should stick to the top when scrolled.</div>
</section>
Here's a jQuery solution. If we're more than 10px from the top of the page add a is-sticky class to the element which you can then style with CSS.
// store the element in a variable
var element = $('.item'),
visible = false;
// on scroll
$(window).scroll(function() {
/**
* store the scroll distance in px
* from the top of the viewport
*/
var scroll = $(window).scrollTop();
/**
* if the scroll is greater than or equal
* to 10px add a class of .is-sticky to the element
* otherwise we're less than 10px from the top
* of the document and therefore don't want
* the element to have the .is-sticky class
*/
if(scroll >= 10) {
if(!visible) {
element.addClass('is-sticky');
visible = true;
}
} else {
if(visible) {
element.removeClass('is-sticky');
visible = false;
}
}
});
I'm currently working on my pfolio website and im quite far but not there yet...
http://thinkagain.nu/?page_id=2501 See this page I have this navigation bullets / dots on the right which you can navigate through the projects. I got it working for so far that if you click a bullet / dot it becomes selected (orange color) but what I want is that it also becomes selected state when you scroll down the sections, so without clicking on it.
So when your scrolling the 2nd project, the 2nd bullet / dot becomes selected, 3rd project makes the 3rd bullet / dot become selected and so on.
This is my code:
CSS:
#floatnav {
position: fixed;
right: -50px;
top: 50%;
width: 8em;
margin-top: -2.5em;
}
.bullit {
background-color:#242424;
-moz-border-radius:17px;
-webkit-border-radius:17px;
border-radius:17px;
border:0px solid #000000;
display:inline-block;
cursor:pointer;
color:#ffffff;
font-family:arial;
font-size:12px;
padding:5px 5px;
text-decoration:none;
text-shadow:0px 1px 0px #2f6627;
box-shadow: inset 1px 4px 9px -6px;
box-shadow: 2px 2px 1px #888888;
}
.bullit:hover {
background-color:#ebebeb;
box-shadow: inset 1px 4px 9px -6px;
}
.bullit.active {
position:relative;
top:1px;
background:orange;
}
HTML:
<ul id="floatnav">
</ul>
Jquery/javascript:
$('#floatnav a').click(function() {
$('#floatnav a').removeClass('active'); /*Remove previous*/
$(this).addClass('active'); /*Active clicked*/
})
If anyone could help me it would be greatly appreciated! Thanks in advance.
Nick
Try this (see example http://jsfiddle.net/shtrih/Z3BTd/)
$(window).on('scroll', function () {
var positions = [],
elements = [],
scrolltop = $(this).scrollTop()
;
$('> div', '#main').each(function() {
var pos = Math.abs($(this).position().top - scrolltop);
positions.push(pos);
elements[ pos ] = this.id;
});
var array_min = Math.min.apply(null, positions);
var current_element_id = elements[ array_min ];
console.log(current_element_id);
$('a', '#floatnav').removeClass('active');
$('a[href="#'+ current_element_id +'"]', '#floatnav').addClass('active');
});
Used materials:
JavaScript: min & max Array values?
How to know the end of scrolling event for a <div> tag
http://jqapi.com/
Here is some code that I hope it will help you understand and use on your website:
http://jsfiddle.net/dragulceo/KMnmb/1/
Notice that I included an external link to a jQuery plugin - jQuery throttle / debounce
You need to register a scroll handler and because the scroll handler is triggered many times you should use throttle method so that you don't affect the scrolling speed (avoid hiccups).
onScrollCallback = $.throttle(250, function () {
var el;
floatNavs.find('a.active').removeClass('active');
el = getVisibleElement();
if(el) {
floatNavs.find('a[href="#' + $(el).attr('id') + '"]').addClass('active');
}
});
$(document).on('scroll', onScrollCallback);
So now the browser triggers scroll event the code - moderately - will check to see which div is on screen and then add the active class for the a element that has the target the same with the id attribute.
The function that finds the element on screen is this one:
//gets the div on screen
getVisibleElement = function () {
var scrl = window.scrollY,
height = jQuery(window).height(),
elHeight,
i;
for (i = 0; i< numberEls; i++) {
item = $(targetEls[i]);
pos = item.position();
elHeight = item.height();
// the criteria if the element is on screen is that
// the topX position is greater then the scrolled pixels
// minus half of the element. There can be variations
// depending on the scrolled items
if (pos.top > scrl - elHeight / 2) {
return targetEls[i];
}
}
return false;
}
And as you can see in the comments you can play with or change the condition that determines when the element is on screen depending on the height of the scrolled elements.
I've a sticked element which gets the top-alignment from current scroll-offset. Problem is, that the layout is not "retriggerd" if the space from it is free. So there stays a ghost-gap where the sticked element was...
http://fiddle.jshell.net/pPc4V/
The markup is pretty simple:
...
as well as the js:
var $win = $(this);
var sticked = document.querySelector('a.sticked');
$win.on('scroll', function () {
var scrollTop = $win.scrollTop();
sticked.style.top = scrollTop + 'px';
// $win.resize();
});
...and the css looks good so far:
a {
display: inline-block;
width: 90px;
height: 90px;
background: deepskyblue;
}
.sticked {
position: relative;
top: 0;
left: 0;
background: tomato;
}
I tried to trigger the resize-event on scroll (as you see above uncommented), but no success! Any ideas, how to retrigger the layout so that the free-gap is filled with the next floated element?
Update
To clarify what I mean I made a simple image-timelime:
Step 1
Step 2
Step 3
The issue is that you are setting position fixed on an element which is displayed inline. That will cause that space to occur. I have redid your jsFiddle with proper alignment.
To fix it, I added the class "stuck" only when the document's scrollTop position is greater than the scrollTop position of your target element.
jsFiddle: http://fiddle.jshell.net/pPc4V/44/
HMTL:
<div id="grid">
etc...
</div>
CSS:
#grid {
height:1000px;
overflow:hidden;
float:left
}
#grid > a {
display: inline-block;
width: 90px;
height: 90px;
background: deepskyblue;
}
.stuck {
position: fixed;
background: navy !important;
}
JS:
$(window).on('scroll', function () {
var $doc = $(document),
parentElement = $('#grid'),
childToGetStuck = parentElement.find('a:nth-child(5)');
if ($doc.scrollTop() > childToGetStuck.scrollTop()) {
childToGetStuck.addClass('stuck');
//console.log($('.stuck').scrollTop())
} else {
childToGetStuck.removeClass('stuck');
}
});