Is scrollTop, and scrollLeft for overflow hidden elements reliable? - javascript

I accidentally discovered that scrollTop, and scrollLeft on an element work even when an element is overflow: hidden. Can this behaviour be relied on?
Supposedly scrollTop, and scrollLeft are supposed to be zero for elements without scrollbars, and setting them on such elements is supposed to have no effect.

Yes, even if an element has CSS overflow set to hidden,
Javascript Element.scrollTop(), Element.scrollLeft() allows you to manipulate the element's scroll position if the element contains overflowing children.
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollLeft
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop
Here's a quick use case:
Animate gallery using scrollLeft
var GAL = $("#gal"),
n = GAL.find(">*").length;
c = 0;
$("button").on("click", function(){
GAL.animate({ scrollLeft: (++c%n) * GAL.width() });
});
#gal {
height: 40vh;
overflow: hidden; /* !! */
white-space:nowrap;
font-size: 0;
} #gal>* {
font-size: 1rem;
display: inline-block;
vertical-align: top;
width: 100%;
height: inherit;
background: 50% / cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="gal">
<div style="background-image:url(//placehold.it/800x600/cf5);"></div>
<div style="background-image:url(//placehold.it/800x600/f0f);"></div>
<div style="background-image:url(//placehold.it/800x600/444);"></div>
</div>
<button>scrollLeft</button>
Not sure yet why Chrome does not do the following but:
Firefox will remember your gallery scroll-position on historyBack (navigating back to the page where you scrolled your gallery)

Related

How do I find out if a DOM element is a scroll container?

Is there a way to find out if an DOM element has scroll capabilities without checking its styles?
Currently, I'm looking for overflow: auto or scroll on the element. I'd like to know a JavaScript method that can check if the element is the scroll container for a deeply-nested child element.
[EDIT]
This isn't to find out if it's got a scrollbar showing; I wanna know if it's a container that would display a scrollbar if the contents extend past the container height.
In my experience, the browser is doing this naturally sometimes, but I can't figure out why. That tells me there's something on the container in JS saying "I will display scrollbars when the content is larger".
I was thinking it could have something to do with height: 100% and position: absolute, but then there are bound to be other situations as well.
Strangely, the browser is showing these elements as overflow: visible from the user-agent stylesheet, but it should never show scrollbars in that case.
You can compare the clientHeight of the element com the scroll height of it.
I made a function that makes it.
var myDiv = document.querySelector("#my_div_1");
var myDiv2 = document.querySelector("#my_div_2");
console.log("There's scroll in my_div 1 = " + hasScrollY(myDiv));
console.log("There's scroll in my_div 2 = " + hasScrollY(myDiv2));
function hasScrollY(elem) {
return elem.clientHeight < elem.scrollHeight;
}
#my_div_1 {
background-color: lightblue;
height: 50px;
overflow-y: scroll;
}
#my_div_2 {
background-color: lightgreen;
height: 60px;
overflow-y: scroll;
}
p {
height: 20px;
}
<div id="my_div_1">
<p>
This is a div with overflow
</p>
</div>
<br>
<div id="my_div_2">
<p>
This is a div without overflow
</p>
</div>

How to remove a div but prevent the scroll position to be changed?

What do i want to achive?
I want to remove a div which isnt visible(for the user not the css atribute) anymore on the screen because i let the html and body scroll to a div with jquery(scrollTop). Now i want to remove the div which was visible beforr i scrolled down with jquery.
Edit: After removing the .header div, the #begining should be the top of the page and the .header div should be removed forever.
What is the problem?
After i scrolled down and removed the div with the following line of code: $('.header').css('display','none'); the scroll position changes.
Code to scroll down and remove the div.
function scrollToBegining(){
$('html, body').animate({
scrollTop: $("#begining").offset().top
}, 750);
setTimeout(function(){
$('.header').css('display','none');
},750);
}
Problem visualized:
GIF of the problem (Watch to understand better)
This is odd, but I think a better choice is to slideUp the div instead of scrolling:
function scrollToBegining(){
$('.header').slideUp(750);
}
Obviously, rename the function since it's no longer scrolling.
You can use visibility: hidden to hide the div but reserve its space. Also, sometimes the scroll position has to be changed when you use display: none.
visibility: hidden
is what you are looking for, but another solution I use with this kind of issue is instead of scrolling down to your second div, have the initial div shrink its height in a uniform animation until it is 0. This prevents the weird shuddering scroll issue you are experiencing
document.querySelector('#header h1').addEventListener('click', closeHeader)
function closeHeader(){
document.querySelector('#header').classList.add("hidden");
}
#header {
height: 300px;
width: 100%;
background: red;
text-align: center;
}
#content {
height: 1000px;
width: 100%;
background: yellow;
text-align: center;
}
.hidden {
display: none !important;
margin: 0 !important;
padding: 0 !important;
}
<div id="header">
<h1>
HEADER
</h1>
</div>
<div id="content">
CONTENT
</div>

Check if element can be scrolled to the left or right

I would like to display indicators for a certain div to show that it can be scrolled right or left depending on its state. To do so I would need to know if element can be scrolled to respective positions, e.g. if there is content to be seen on the right show indicator and after scrolling show another indicator on the left to indicate that users can now scroll there as well. I have a simple setup like this one: https://jsfiddle.net/udv8u596/
(You can scroll horizontally, scrollbar is hidden intentionally)
HTML:
<div class="scroll-container">
<div class="scroll-content">
Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally
</div>
</div>
CSS:
.scroll-container {
width: 80%;
margin: 0 auto;
background: cyan;
overflow-y: hidden;
height: 36px;
}
.scroll-content {
padding: 10px 0;
height: 50px;
white-space: nowrap;
overflow-x: scroll;
overflow-y: hidden;
}
To check if an element is overflowing along the x-axis, you can simply compare its computed width, accessible via jQuery's .width() method, and its scrollWidth, a native JS function:
var $ele = $('.scroll-content'),
overflowing = $ele[0].scrollWidth > $ele.width();
You can then check the boolean value of overflowing if the element is overflowing or not. However, note that if you want this variable to be updated if the window resizes, a little more work has to be done:
var $ele = $('.scroll-content'),
overflowing = function() {
if($ele[0].scrollWidth > $ele.width()) {
return true;
} else {
return false;
}
};
console.log(overflowing());
$(window).resize(function() {
console.log(overflowing());
});
Here's a fiddle with the above logic implemented, with some slight modifications: https://jsfiddle.net/teddyrised/udv8u596/5/
Ilya basically you need to check your element right postion. On way of achieving this is to set the inner element to have absolute oistion and get right postion with jQuery
parseInt($('.scroll-content').css('right')) >= 0
I have modified you code as: https://jsfiddle.net/udv8u596/4/
In this example before animating the element it checks if the righ position is bigger than 0.
Please not that righ position is calculated based on the parent element. Left position is set to be 0 in the css but righ postion will be calculated in this example is ~-250.
I hope this gives you an idea how to solve your problem.
Here's a quick start for what you are looking for :
HTML
<div class="scroll-container">
<div class="mask">
<div class="scroll-content">
Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally Scroll Me Horizontally
</div>
</div>
</div>
<div class="scrollRight">Scroll Right »</div>
<div class="scrollLeft">» Scroll Left </div>
CSS
.scroll-container {
width: 80%;
margin: 0 auto;
background: cyan;
overflow-y: hidden;
overflow-x: hidden;
height: 36px;
}
.mask{
position:relative;
overflow-x: hidden;
overflow-y: hidden;
height: 36px;
width: 100%;
}
.scroll-content {
position:absolute;
padding: 10px 0;
height: 50px;
white-space: nowrap;
overflow-x: visible;
width:auto;
}
.scrollRight, .scrollLeft{
font-size:10px;
display:none;
}
JS
var contentWidth = $(".scroll-content").width();
var containerWidth = $(".scroll-container").width();
if(contentWidth>containerWidth){
$(".scrollRight").show();
}
$("body").on("click", ".scrollRight", function(){
var scrollValue = contentWidth-containerWidth;
$(".scroll-content").animate({"margin-left":"-"+scrollValue+"px"});
$(".scrollRight").hide();
$(".scrollLeft").show();
})
$("body").on("click", ".scrollLeft", function(){
var scrollValue = contentWidth-containerWidth;
$(".scroll-content").animate({"margin-left":"0px"});
$(".scrollRight").show();
$(".scrollLeft").hide();
})
See Update JSFiddle

Element changes place when position fixed applied

When I apply position: fixed with Javascript my element moves a few pixels down and gets fixed in another position, some pixels down, instead of just staying where is was.
Why is this?
// html
<div id="container">
<div id="myDiv"></div>
</div>
// CSS
#container {
height: 2000px;
}
#myDiv {
margin-top: 50px;
width: 100px;
height: 50px;
background-color: #88a;
}
// Javascript
myDiv.style.position = 'fixed';
I find this behaviour at least in Chrome and FF.
http://jsfiddle.net/bSM8h/
When you apply position:fixed, also do:
pin.addEventListener('click', function () {
myDiv.style.position = 'fixed';
myDiv.style.top = '50px';
myDiv.style.marginTop = '0';
});
http://jsfiddle.net/bSM8h/2/
*edit*
By default browsers do body{padding:5px;} that is why a good idea is to html5boilerplate your css's
*end edit*
For some reason (see explanation here), margin-top also pushed the container with it. Once applied position:fixed, the container sprung back to the top of the page (lost the margin) and was positioned 5px from the top of page.
before position:fixed
after position:fixed
Just add this to your CSS:
body {
margin:0;
padding:0;
}
This will prevent the extra padding added by the browser defaults.

How do you vertically align the body tag of an HTML document?

I have a webpage that is horizontally centered but is rather short - it only takes up half the vertical page. I want it to be centered. How can I center the tag vertically? I cannot have a static height, so that is not an option. if CSS is not powerful enough, can I use Javascript to accomplish this? Thanks!
Two primary ways, neither of which is especially perfect, but widely used:
1) if your content really is a fixed, known height, then you CSS position it with
position: absolute;
top: 50%;
margin-top: here, set a pixel value that's equal to: -1 * (content height / 2)
2) If you don't care if it works the same way in IE7 and below, set CSS as follows:
html { display: table; }
body { display: table-cell; vertical-align: middle; }
If you don't mind adding non-semantic markup, you can do this:
html:
<div class="pusher"></div>
<div class="center"></div>
CSS:
html, body {
height: 100%;
}
.pusher {
height: 100%;
margin-bottom: -50%;
}
.center {
background: green;
width: 400px;
height: 200px;
margin: 0 auto;
}
http://jsfiddle.net/Jsqqk/
If you do care about semantic markup, and have to support older browsers, then you'll have to resort to JavaScript for this. Here's one solution using jQuery:
var $window = $(window),
$container = $('#container');
$window.resize(function(){
$container.css('margin-top',
Math.max(($window.height() / 2) - ($container.height() / 2), 0)
);
}).resize();
And here's the fiddle: http://jsfiddle.net/dw3rc/
I've often done this with setting height:50% and padding-top:25% but that's not always suitable.
This page identifies a different technique that might work:
http://www.jakpsatweb.cz/css/css-vertical-center-solution.html

Categories

Resources