I have a web page with three divs that are synced together.
+----------+
| TOP |
+---+----------+
| | ||
| L | CENTER ||
| |_________||
+---+----------+
<!--Rough HTML-->
<div>
<div class="topbar-wrapper">
<div class="topbar"></div>
</div>
<div class="container">
<div class="sidebar-wrapper">
<div class="sidebar"></div>
</div>
<div class="center-wrapper"> <!-- Set to the window size & overflow:scroll -->
<div class="center"></div> <!-- Has the content -->
</div>
</div>
</div>
The center div has scroll bars, both horizontal and vertical. The top and left divs do not have scroll bars. Instead, when the horizontal scroll bar is moved, the scroll event updates the top div's margin-left appropriately. Likewise when the vertical scroll bar is moved, the margin-top is updated. In both cases, they are set to a negative value.
$('.center-wrapper').scroll(function(e) {
$('.sidebar').css({marginTop: -1 * $(this).scrollTop()});
$('.topbar').css({marginLeft: -1 * $(this).scrollLeft()});
});
This works fine in Chrome and Firefox. But in Safari, there is a delay between moving the scroll bar and the negative margin being properly set.
Is there a better way to do this? Or is there some way to get rid of the lag in Safari?
EDIT:
Check out this Fiddle to see the lag in Safari: http://jsfiddle.net/qh2K3/
Let me know if this JSFiddle works better. I experienced the same "lag" on my end too (Safari 7 on OS X) and these small CSS changes significantly improved it. My best guess is that Safari is being lazy and has not turned on its high-performance motors. We can force Safari to turn it on using some simple CSS:
.topbar-wrapper, .sidebar-wrapper, .center-wrapper {
-webkit-transform: translateZ(0);
-webkit-backface-visibility: hidden;
-webkit-perspective: 1000;
}
This enables hardware accelerated CSS in Safari by offloading some of the work to the GPU. It improves rendering in the browser, which may have been the issue in the delay.
I've had this issue a few times, where safari seems to be lagging when incrementally moving elements based on events like this.
Here's how I've solved the problem in the past.
In browsers that support hardware acceleration, using any "3d" CSS property will enable the hardware acc.
If 3D transforms is supported, we might as well use translate3d to move the elements, as that makes for smoother movements than shifting pixels.
This means we first have to figure out the right prefix for the CSS transform property, then check support for 3D transforms. If we have support, translate the elements, if not shift pixels.
By figuring out the prefixes and 3D support without libraries it should be just about as fast as it can get, and has no dependencies.
var parent = document.querySelector('.center-wrapper'),
sidebar = document.querySelector('.sidebar'),
topbar = document.querySelector('.topbar'),
has3D = false,
transform = null,
transforms = {
'webkitTransform' : '-webkit-transform',
'OTransform' : '-o-transform',
'msTransform' : '-ms-transform',
'MozTransform' : '-moz-transform',
'transform' : 'transform'
};
for (var k in transforms) if (k in parent.style) transform = k;
if ( transform !== null ) {
sidebar.style[transform] = 'translate3d(0,0,0)'; // start hardware acc
topbar.style[transform] = 'translate3d(0,0,0)'; // start hardware acc
// check support
var s = window.getComputedStyle(sidebar).getPropertyValue(transforms[transform]);
has3D = s !== undefined && s.length > 0 && s !== "none";
}
if (has3D) {
parent.onscroll = function (e) {
sidebar.style[transform] = 'translate3d(0px, '+ (this.scrollTop * -1) +'px, 0px)';
topbar.style[transform] = 'translate3d('+ (this.scrollLeft * -1) +'px, 0px, 0px)';
}
}else{
parent.onscroll = function (e) {
sidebar.style.marginTop = (this.scrollTop * -1) + 'px';
topbar.style.marginLeft = (this.scrollLeft * -1) + 'px';
}
}
FIDDLE
Remember to put this after the elements in the DOM, as in right before </body>, or if that's not possible, it has to be wrapped in a DOM ready handler.
As a sidenote, querySelector is not supported in IE7 and below, if that's an issue you have to polyfill it.
Caching selectors will help.
Changing :
$('.center-wrapper').scroll(function(e) {
$('.sidebar').css({marginTop: -1 * $(this).scrollTop()});
$('.topbar').css({marginLeft: -1 * $(this).scrollLeft()});
});
To :
var _scroller = $('.center-wrapper'),
_swrapper = $('.sidebar-wrapper'),
_twrapper = $('.topbar-wrapper');
_scroller.scroll(function (e) {
_swrapper.scrollTop(_scroller.scrollTop());
_twrapper.scrollLeft(_scroller.scrollLeft());
});
.scroll() will be working very hard if it has to recreate jquery objects $(this) each time.
Wrote this in a comment last night, and while not been able to test yet, actually felt today that this is should be added as directly relates to performance.
We can try it out - here
More / The Methods - making them native too
There are also another jquery method calls we can cut out too. .scrollTop() and .scrollLeft() by caching and returning the native _scrollernative = _scroller.get(0) to make use of the readily available properties scrollLeft.
Like :
var _scroller = $('.center-wrapper'),
_scrollernative = _scroller.get(0),
_swrapper = $('.sidebar-wrapper').get(0),
_twrapper = $('.topbar-wrapper').get(0);
_scroller.scroll(function (e) {
_swrapper.scrollTop = _scrollernative.scrollTop;
_twrapper.scrollLeft = _scrollernative.scrollLeft;
});
We can try this here
I appreciate that your code might be looking at more than one of these controls on the page, and that's why you have used classes and needing to find S(this) instead of using ID's.
For that I would still use the above caching methods but before that we need to create them one by one. ( caching before we initialise the scroll() function per instance )
(function() {
var _scroller = $('.center-wrapper'),
_swrapper = $('.sidebar-wrapper').get(0),
_twrapper = $('.topbar-wrapper').get(0);
function setScrollers(_thisscroller) {
_scrollernative = _thisscroller.get(0);
/* start the scroll listener per this event */
_thisscroller.scroll(function (e) {
_swrapper.scrollTop = _scrollernative.scrollTop;
_twrapper.scrollLeft = _scrollernative.scrollLeft;
});
}
_scroller.each(function() { setScrollers($(this)); });
})();
We can try this here
But As I see that .sidebar-wrapper and .topbar-wrapper are unique, mabye .center-wrapper is unique too.
So how about finally using id's for these elements to shorten everything up.
var _scroller = document.getElementById('center-wrapper'),
_swrapper = document.getElementById('sidebar-wrapper'),
_twrapper = document.getElementById('topbar-wrapper');
_scroller.onscroll = function() {
_swrapper.scrollTop = _scroller.scrollTop;
_twrapper.scrollLeft = _scroller.scrollLeft;
};
We can try this here
Instead of using marginTop & marginLeft to change margins of .sidebar & .topbar use scrollTop & scrollLeft for the overflowing divs .sidebar-wrapper & .topbar-wrapper and see if it now works in Safari:
Demo Fiddle
$('.center-wrapper').scroll(function(e) {
$('.sidebar-wrapper').scrollTop($(this).scrollTop());
$('.topbar-wrapper').scrollLeft($(this).scrollLeft());
});
Try this fiddle made to look best in safari and tested
Related
I'm working on a project over at github pages, which I replace a bootstrap .dropdown with .dropup if the div's overflow-y: scroll will cause the dropdown menu to be cutoff / overflow. You can see the function working properly at this jsfiddle. Notice if you click on the ellipsis icon to the right on the top rows, it will drop down, if you click on the icon on the bottom rows, it will drop up.
Now, my actual implementation (github page), the code is exactly the same (below), but it wants to replace all .dropdown classes with .dropup when opened, including the top-most row which gets cut off, seen in the photo below.
I've been struggling with this for a week and can't quite figure it out. I've tried a few different things that I thought fixed it but ended up just being a hack and didn't work on mobile, or replaced some but not all etc.
Here is the Javascript / jQuery I'm using, which can be seen in the jsfiddle and my github source here.
$(document).on("shown.bs.dropdown", ".dropdown", function () {
// calculate the required sizes, spaces
var $ul = $(this).children(".dropdown-menu");
var $button = $(this).children(".song-menu");
var ulOffset = $ul.offset();
// how much space would be left on the top if the dropdown opened that direction
var spaceUp = (ulOffset.top - $button.height() - $ul.height()) - $('#playlist').scrollTop();
// how much space is left at the bottom
var spaceDown = $('#playlist').scrollTop() + $('#playlist').height() - ((ulOffset.top + 10) + $ul.height());
// switch to dropup only if there is no space at the bottom AND there is space at the top, or there isn't either but it would be still better fit
if (spaceDown < 0 && (spaceUp >= 0 || spaceUp > spaceDown))
$(this).addClass("dropup");
}).on("hidden.bs.dropdown", ".dropdown", function() {
// always reset after close
$(this).removeClass("dropup");
});
Edit:
To clear up any confusion, here's an example of the behavior without my added .dropup function. jsfiddle Notice when you click the last menu item, it opens the menu but requires scrolling. I specifically want to remove the .dropdown class and add .dropup in this case, so no scrolling is required.
It took some basic math, but I managed to figure out what you desired to do. This code changes the bootstrap classes between dropup and dropdown depending on the room available for a normal dropdown.
I calculated this by detracting the height of the button, dropdownmenu and how far the button was scrolled down in the scrollContainer from the height of the scrollContainer. I got the value how much the div was scrolled down by using the buttons offset and detracting the offset from the scrollContainer.
Here is my jQuery (I selected the .playlist class because this was attached to your scrollContainer, but you should replace it by an id or select it by other means):
$(".dropdown, .dropup").click(function(){
var dropdownClassCheck = $(this).hasClass('dropdown');
var buttonOffset = $(this).offset().top;
var scrollboxOffset = $('.playlist').offset().top;
var buttonHeight = $(this).height();
var scrollBoxHeight = $('.playlist').height();
var dropDownButtonHeight = $(this).children('ul').height();
dropdownSpaceCheck = scrollBoxHeight>buttonOffset-scrollboxOffset+buttonHeight+dropDownButtonHeight;
if(dropdownClassCheck && !dropdownSpaceCheck){
$(this).removeClass('dropdown').addClass('dropup');
}
else if(!dropdownClassCheck && dropdownSpaceCheck){
$(this).removeClass('dropup').addClass('dropdown');
}
});
A working JSFiddle
Let me know if there are parts of the code that could be improved/done easier or if there are any problems with my solution.
I have not thoroughly checked, but .scrollTop() is probably why the code fails when combined with other elements in the DOM, so here is a solution without it:
function checkHeights(){
// LOOP through each dropdown
$('.dropdown,.dropup').each(function(index,element){
var $dropDown = $(element),
$dropDownMenu = $dropDown.find('.dropdown-menu'),
dropDownTop = $dropDown.offset().top,
visibleHeight = $dropDown.height(),
hiddenHeight = $dropDownMenu.height(),
ddTop = dropDownTop - hiddenHeight,
ddBottom = dropDownTop + visibleHeight + hiddenHeight;
// LOOP through all parents
$dropDown.parents().each(function(ix,el){
var $el = $(el);
// CHECK if any of them have overflow property set
if( $el.css('overflow') !== 'visible' ){
var limitTop = $el.offset().top,
limitBottom = limitTop + $el.height();
// CHECK if parent is better fit when dropped upside
if( limitBottom < ddBottom && ( ddTop - limitTop ) > ( limitBottom - ddBottom ) )
$dropDown.removeClass('dropdown').addClass('dropup');
else
$dropDown.removeClass('dropup').addClass('dropdown');
// BREAK LOOP
return false;
}
});
});
}
$(document).ready(function() {
checkHeights();
$('.playlist').scroll(checkHeights);
});
JS Fiddle here.
This one does not require any class or id given to it except for dropdown,dropdown-menu, and dropup (all of which are Bootstrap defaults) and would work fine even if there are multiple playlists on page.
UPDATE
The code is modified and wrapped in a function in order to allow being called when scroll event fires.
I think that the problem it's that you have a big header, and the jsFiddle don't. So ulOffset.top it's always big, and spaceDown is always negative
Replace parent div.dropdown with div.dropup.
Is there a way to get elements which is:
Inside a div with overflow: scroll
Is in viewport
Just like the following picture, where active div (5,6,7,8,9) is orange, and the others is green (1-4 and >10) :
I just want the mousewheel event to add "active" class to div 5,6,7,8,9 (currently in viewport). View my JSFiddle
$('.wrapper').bind('mousewheel', function (e) {
//addClass 'active' here
});
You could do something like this. I would have re-factored it, but only to show the concept.
Firstly I would attach this to scroll event and not mousewheel. There are those among us that likes to use keyboard for scrolling, and you also have the case of dragging the scrollbar. ;) You also have the case of touch devices.
Note that with this I have set overflow:auto; on wrapper, thus no bottom scroll-bar.
With bottom scrollbar you would either have to live with it becoming tagged as in-view a tad to early, or tumble into the world of doing a cross-browser calculating of IE's clientHeight. But the code should hopefully be OK as a starter.
»»Fiddle««
function isView(wrp, elm)
{
var wrpH = $(wrp).height(),
elmH = $(elm).height(),
elmT = $(elm).offset().top;
return elmT >= 0 &&
elmT + elmH < wrpH;
}
$('.wrapper').bind('scroll', function (e) {
$('div.box').each(function(i, e) {
if (isView(".wrapper", this)) {
$(this).addClass('active');
} else {
$(this).removeClass('active');
}
});
});
Note that you should likely refactor in such a way that .wrapper height is only retrieved once per invocation, or if it is static, at page load etc.
Update; a modified version of isView(). Taking position of container into account. This time looking at dolphins in the pool.
»»Fiddle««
function isView(pool, dolphin) {
var poolT = pool.offset().top,
poolH = pool.height(),
dolpH = dolphin.height(),
dolpT = dolphin.offset().top - poolT;
return dolpT >= 0 && dolpT + dolpH <= poolH;
}
I want the javascript code to show a div in slow motion.
function showDiv(divID)
{
if(document.getElementById(divID).style.display=='none')
{
document.getElementById(divID).style.display='block';
}
}
Here div appears, but not in slow motion. Can anyone help ??
Thanks in advance
Dev..
There is no need of jQuery in this atall , its just a basic I am using your function to explain how thats done.
function showDiv(divID)
{
if(document.getElementById(divID).style.display=='none')
{
document.getElementById(divID).style.display='block';
}
}
What your function is doing is basically removing the whole Element from BOX Model ( the toggle of block and none removes the element totally from the BOX Model so it doesnt occupies any space or anything , this but may / may not cause some layout issues );
Now to animate it in slow motion you need a timing function.
a timing function is a simple mathematical function which gives the value of the property ( opacity in your case ) for a given time or depending on other parameters .
Other then that you also need to use properties like opacity in order to fade it (Opacity is a CSS property that defines the transparency of an element and its childrens )
So let us begin with a very basic show / hide using setTimeout Function in JS.
function getValue(t,dir){
if( dir > 0){
return 0.5*t; /* Y = mx + c */
}else{
return 1-(0.5*t);
}
/*
Here the slope of line m = 0.5.
t is the time interval.
*/
}
function animator(divID){
if(!(this instanceof animator)) return new animator(divID); /* Ignore this */
var Node = document.getElementById(divID),
start = new Date.getTime(), // The initiation.
now = 0,
dir = 1,
visible = true;
function step( ){
now = new Date.getTime();
var val = getValue( now - start,dir)
Node.style.opacity = val;
if( dir > 0 && val > 1 || dir < 0 && val < 0 ){
visible = !(visible*1);
// Optionally here u can call the block & none
if( dir < 0 ) { /* Hiding and hidden*/
Node.style.display = 'none'; // So if were repositioning using position:relative; it will support after hide
}
/* Our animation is finished lets end the continous calls */
return;
}
setTimeout(step,100); // Each step is executated in 100seconds
}
this.animate = function(){
Node.style.display = 'block';
dir *= -1;
start = new Date.getTime();
setTimeout(step,100);
}
}
now you can simply call the function
var magician = new animator('divName');
then toggle its animation by
magician.animate();
Now playing with the timing function you can create whatever possibilities you want as in
return t^2 / ( 2 *3.23423 );
or even higher polynomial equations like
return t^3+6t^2-38t+12;
As you can see our function is very very basic but it explains the point of how to make animations using pure js . you can later on use CSS3 module for animation and trigger those classes with javascript :-)
Or perhaps write a cross browser polyfill using CSS3 where available ( it is faster ) , and JS if not :-) hope that helps
Crossbrowser solution (without jQuery) :
HTML :
<div id="toChange" ></div>
CSS :
#toChange
{
background-color:red;
width:200px;
height:200px;
opacity:0;//IE9, Firefox, Chrome, Opera, and Safari
filter:alpha(opacity=0);//IE8 and earlier
}
Javascript :
var elem=document.getElementById("toChange");
var x=0;
function moreVisible()
{
if(x==1)clearInterval(t);
x+=0.05;
elem.style.opacity=x;
elem.style.filter="alpha(opacity="+(x*100)+")";
}
var t=setInterval(moreVisible,25);
Fiddle demonstration : http://jsfiddle.net/JgxW6/1/
So you have a few jQuery answers but I wouldn't recommend jQuery if fading the div is all you want.
Certainly jQuery makes things easier but it is a lot of overhead for a single simple functionality.
Here is someone that did it with pure JS:
Fade in and fade out in pure javascript
And a CSS3 example:
How to trigger CSS3 fade-in effect using Javascript?
You can use jquery $.show('slow') for the same, if you want to do the same without using jquery then you might be required to code something to show the effect yourself, you may have a look at source of jquery's show function http://james.padolsey.com/jquery/#v=1.6.2&fn=show . alternatively , you can also use fadein() for fade in effect in jquery
Yes you can do it using Jquery. Here is my sample example
$('#divID').click(function() {
$('#book').show('slow', function() {
// Animation complete.
});
});
For details clik here
Thanks.
I am trying to move the page to a <div> element.
I have tried the next code to no avail:
document.getElementById("divFirst").style.visibility = 'visible';
document.getElementById("divFirst").style.display = 'block';
scrollIntoView works well:
document.getElementById("divFirst").scrollIntoView();
full reference in the MDN docs:
https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollIntoView
You can use an anchor to "focus" the div. I.e:
<div id="myDiv"></div>
and then use the following javascript:
// the next line is required to work around a bug in WebKit (Chrome / Safari)
location.href = "#";
location.href = "#myDiv";
For Chrome and Firefox
I've been looking a bit into this and I figured this one out which somehow feels like the most natural way to do it. Of course, this is my personal favorite scroll now. :)
const y = element.getBoundingClientRect().top + window.scrollY;
window.scroll({
top: y,
behavior: 'smooth'
});
For IE, Edge and Safari supporters
Note that window.scroll({ ...options }) is not supported on IE, Edge and Safari. In that case it's most likely best to use
element.scrollIntoView(). (Supported on IE 6). You can most likely (read: untested) pass in options without any side effects.
These can of course be wrapped in a function that behaves according to which browser is being used.
The best, shortest answer that what works even with animation effects:
var scrollDiv = document.getElementById("myDiv").offsetTop;
window.scrollTo({ top: scrollDiv, behavior: 'smooth'});
If you have a fixed nav bar, just subtract its height from top value, so if your fixed bar height is 70px, line 2 will look like:
window.scrollTo({ top: scrollDiv-70, behavior: 'smooth'});
Explanation:
Line 1 gets the element position
Line 2 scroll to element position; behavior property adds a smooth animated effect
We can implement by 3 Methods:
Note:
"automatic-scroll" => The particular element
"scrollable-div" => The scrollable area div
Method 1:
document.querySelector('.automatic-scroll').scrollIntoView({
behavior: 'smooth'
});
Method 2:
location.href = "#automatic-scroll";
Method 3:
$('#scrollable-div').animate({
scrollTop: $('#automatic-scroll').offset().top - $('#scrollable-div').offset().top +
$('#scrollable-div').scrollTop()
})
Important notice: method 1 & method 2 will be useful if the scrollable area height is "auto". Method 3 is useful if we using the scrollable area height like "calc(100vh - 200px)".
You can set focus to element. It works better than scrollIntoView
node.setAttribute('tabindex', '-1')
node.focus()
node.removeAttribute('tabindex')
Try this:
var divFirst = document.getElementById("divFirst");
divFirst.style.visibility = 'visible';
divFirst.style.display = 'block';
divFirst.tabIndex = "-1";
divFirst.focus();
e.g #:
http://jsfiddle.net/Vgrey/
Here's a function that can include an optional offset for those fixed headers. No external libraries needed.
function scrollIntoView(selector, offset = 0) {
window.scroll(0, document.querySelector(selector).offsetTop - offset);
}
You can grab the height of an element using JQuery and scroll to it.
var headerHeight = $('.navbar-fixed-top').height();
scrollIntoView('#some-element', headerHeight)
Update March 2018
Scroll to this answer without using JQuery
scrollIntoView('#answer-44786637', document.querySelector('.top-bar').offsetHeight)
To scroll to a given element, just made this javascript only solution below.
Simple usage:
EPPZScrollTo.scrollVerticalToElementById('signup_form', 20);
Engine object (you can fiddle with filter, fps values):
/**
*
* Created by Borbás Geri on 12/17/13
* Copyright (c) 2013 eppz! development, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
var EPPZScrollTo =
{
/**
* Helpers.
*/
documentVerticalScrollPosition: function()
{
if (self.pageYOffset) return self.pageYOffset; // Firefox, Chrome, Opera, Safari.
if (document.documentElement && document.documentElement.scrollTop) return document.documentElement.scrollTop; // Internet Explorer 6 (standards mode).
if (document.body.scrollTop) return document.body.scrollTop; // Internet Explorer 6, 7 and 8.
return 0; // None of the above.
},
viewportHeight: function()
{ return (document.compatMode === "CSS1Compat") ? document.documentElement.clientHeight : document.body.clientHeight; },
documentHeight: function()
{ return (document.height !== undefined) ? document.height : document.body.offsetHeight; },
documentMaximumScrollPosition: function()
{ return this.documentHeight() - this.viewportHeight(); },
elementVerticalClientPositionById: function(id)
{
var element = document.getElementById(id);
var rectangle = element.getBoundingClientRect();
return rectangle.top;
},
/**
* Animation tick.
*/
scrollVerticalTickToPosition: function(currentPosition, targetPosition)
{
var filter = 0.2;
var fps = 60;
var difference = parseFloat(targetPosition) - parseFloat(currentPosition);
// Snap, then stop if arrived.
var arrived = (Math.abs(difference) <= 0.5);
if (arrived)
{
// Apply target.
scrollTo(0.0, targetPosition);
return;
}
// Filtered position.
currentPosition = (parseFloat(currentPosition) * (1.0 - filter)) + (parseFloat(targetPosition) * filter);
// Apply target.
scrollTo(0.0, Math.round(currentPosition));
// Schedule next tick.
setTimeout("EPPZScrollTo.scrollVerticalTickToPosition("+currentPosition+", "+targetPosition+")", (1000 / fps));
},
/**
* For public use.
*
* #param id The id of the element to scroll to.
* #param padding Top padding to apply above element.
*/
scrollVerticalToElementById: function(id, padding)
{
var element = document.getElementById(id);
if (element == null)
{
console.warn('Cannot find element with id \''+id+'\'.');
return;
}
var targetPosition = this.documentVerticalScrollPosition() + this.elementVerticalClientPositionById(id) - padding;
var currentPosition = this.documentVerticalScrollPosition();
// Clamp.
var maximumScrollPosition = this.documentMaximumScrollPosition();
if (targetPosition > maximumScrollPosition) targetPosition = maximumScrollPosition;
// Start animation.
this.scrollVerticalTickToPosition(currentPosition, targetPosition);
}
};
Similar to #caveman's solution
const element = document.getElementById('theelementsid');
if (element) {
window.scroll({
top: element.scrollTop,
behavior: 'smooth',
})
}
A method i often use to scroll a container to its contents.
/**
#param {HTMLElement} container : element scrolled.
#param {HTMLElement} target : element where to scroll.
#param {number} [offset] : scroll back by offset
*/
var scrollAt=function(container,target,offset){
if(container.contains(target)){
var ofs=[0,0];
var tmp=target;
while (tmp!==container) {
ofs[0]+=tmp.offsetWidth;
ofs[1]+=tmp.offsetHeight;
tmp=tmp.parentNode;
}
container.scrollTop = Math.max(0,ofs[1]-(typeof(offset)==='number'?offset:0));
}else{
throw('scrollAt Error: target not found in container');
}
};
if your whish to override globally, you could also do :
HTMLElement.prototype.scrollAt=function(target,offset){
if(this.contains(target)){
var ofs=[0,0];
var tmp=target;
while (tmp!==this) {
ofs[0]+=tmp.offsetWidth;
ofs[1]+=tmp.offsetHeight;
tmp=tmp.parentNode;
}
container.scrollTop = Math.max(0,ofs[1]-(typeof(offset)==='number'?offset:0));
}else{
throw('scrollAt Error: target not found in container');
}
};
If you simply want to scroll to the bottom of a list that is inside a div, you can do this.
<body>
<div class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box">6</div>
<div class="box">7</div>
<div class="box">8</div>
<div class="box">9</div>
</div>
<button>Scroll To</button>
<script>
const btn = document.querySelector("button");
const container = document.querySelector(".container");
btn.addEventListener("click",()=>{
const toplast = document.querySelector(".container").lastElementChild;
toplast.scrollIntoView();
})
</script>
</body>
example output
Focus can be set on interactive elements only... Div only represent a logical section of the page.
Perhaps you can set the borders around div or change it's color to simulate a focus. And yes Visiblity is not focus.
Due to behavior "smooth" doesn't work in Safari, Safari ios, Explorer. I usually write a simple function utilizing requestAnimationFrame
(function(){
var start;
var startPos = 0;
//Navigation scroll page to element
function scrollTo(timestamp, targetTop){
if(!start) start = timestamp
var runtime = timestamp - start
var progress = Math.min(runtime / 700, 1)
window.scroll(0, startPos + (targetTop * progress) )
if(progress >= 1){
return;
}else {
requestAnimationFrame(function(timestamp){
scrollTo(timestamp, targetTop)
})
}
};
navElement.addEventListener('click', function(e){
var target = e.target //or this
var targetTop = _(target).getBoundingClientRect().top
startPos = window.scrollY
requestAnimationFrame(function(timestamp){
scrollTo(timestamp, targetTop)
})
}
})();
I think that if you add a tabindex to your div, it will be able to get focus:
<div class="divFirst" tabindex="-1">
</div>
I don't think it's valid though, tabindex can be applied only to a, area, button, input, object, select, and textarea. But give it a try.
You can't focus on a div. You can only focus on an input element in that div. Also, you need to use element.focus() instead of display()
After looking around a lot, this is what finally worked for me:
Find/locate div in your dom which has scroll bar.
For me, it looked like this :
"div class="table_body table_body_div" scroll_top="0" scroll_left="0" style="width: 1263px; height: 499px;"
I located it with this xpath : //div[#class='table_body table_body_div']
Used JavaScript to execute scrolling like this :
(JavascriptExecutor) driver).executeScript("arguments[0].scrollLeft = arguments[1];",element,2000);
2000 is the no of pixels I wanted to scroll towards the right.
Use scrollTop instead of scrollLeft if you want to scroll your div down.
Note : I tried using scrollIntoView but it didn't work properly because my webpage had multiple divs. It will work if you have only one main window where focus lies.
This is the best solution I have come across if you don't want to use jQuery which I didn't want to.
In case you want to use html, you could just use this:
a href="samplewebsite.com/subdivision.html#id
and make it an html link to the specific element id. Its basically getElementById html version.
try this function
function navigate(divId) {
$j('html, body').animate({ scrollTop: $j("#"+divId).offset().top }, 1500);
}
Pass the div id as parameter it will work I am using it already
I am looking for some native JavaScript, or jQuery plugin, that meets the following specification.
Sequentially moves over a set of images (ul/li)
Continuous movement, not paging
Appears infinite, seamlessly restarts at beginning
Ability to pause on hover
Requires no or minimal additional plugins
I realize this sounds simple enough. But I have looked over the web and tried Cycle and jCarousel/Lite with no luck. I feel like one should exist and wanted to pose the question before writing my own.
Any direction is appreciated. Thanks.
you should check out Nivo Slider, I think with the right configuration you can it to do what you want.
You can do that with the jQuery roundabout plugin.
http://fredhq.com/projects/roundabout/
It might require another plugin.
Both answers by MoDFoX and GSto are good. Usually I would use one of these, but these plugins didn't meet the all the requirements. In the end this was pretty basic, so I just wrote my own. I have included the JavaScript below. Essentially it clones an element on the page, presumably a ul and appends it to the parent container. This in effect allows for continuous scrolling, right to left, by moving the element left and then appending it once out of view. Of course you may need to tweak this code depending on your CSS.
// global to store interval reference
var slider_interval = null;
var slider_width = 0;
var overflow = 0;
prepare_slider = function() {
var container = $('.sliderGallery');
if (container.length == 0) {
// no gallery
return false;
}
// add hover event to pause slider
container.hover(function() {clearInterval(slider_interval);}, function() {slider_interval = setInterval("slideleft()", 30);});
// set container styles since we are absolutely positioning elements
var ul = container.children('ul');
container.css('height', ul.outerHeight(true) + 'px');
container.css('overflow', 'hidden')
// set width and overflow of slider
slider_width = ul.width();
overflow = -1 * (slider_width + 10);
// set first slider attributes
ul.attr('id', 'slider1');
ul.css({"position": "absolute", "left": 0, "top": 0});
// clone second slider
var ul_copy = ul.clone();
// set second slider attributes
ul.attr('id', 'slider2');
ul_copy.css("left", slider_width + "px");
container.append(ul_copy);
// start time interval
slider_interval = setInterval("slideleft()", 30);
}
function slideleft() {
var copyspeed = 1;
var slider1 = $('#slider1');
var slider2 = $('#slider2');
slider1_position = parseInt(slider1.css('left'));
slider2_position = parseInt(slider2.css('left'));
// cross fade the sliders
if (slider1_position > overflow) {
slider1.css("left", (slider1_position - copyspeed) + "px");
}
else {
slider1.css("left", (slider2_position + slider_width) + "px");
}
if (slider2_position > overflow) {
slider2.css("left", (slider2_position - copyspeed) + "px");
}
else {
slider2.css("left", (slider1_position + slider_width) + "px");
}
}