Javascript: how can I judge an element is in viewport? - javascript

I have a <ul> element. It's CSS overflow property is scroll.
I have several list elements in the list, such that there is a scrollbar.
<ul style="overflow: scroll; height: 100px;">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
...
<li></li> // how can I judge if this element is in the viewport?
</ul>
How can I determine if a specific list item is visible in that list?
Also, if it's not currently visible, what property can I use to make it scroll into view?
PS: No libraries, please (jQuery, MooTools, etc).

This is a function I just came up with.
I did some testing on the jsFiddle link at the end of this answer, and it seems consistent.
function elementInViewOfParent(elem) {
var container = elem.parentNode;
return (container.scrollTop + container.offsetHeight) >= elem.offsetTop &&
(container.scrollTop - elem.offsetHeight) <= elem.offsetTop;
}
jsFiddle example - Just scroll it wherever you want, and click the button.
It checks for the red LI's visiblity, in this example.

If you are okay with using jQuery, this will scroll so that elem is visible and at the top.
function scrollTo(elem) {
var offset = $(elem).offset();
$(window).scrollTop(offset.top);
}
(You could even animate the scroll: jQuery scroll to element).
Another solution would be to use <a target="foo"></a>, and the change the URL fragment to scroll to a particular element, but you specifically asked to be able to tell from JavaScript, which this does not allow you to do.

Related

Why does element prepend removed scroll position?

I have a structure like
<div id="parent">
<div>...</div>
<div>...</div>
<div>...</div>
<div>...</div>
</div>
Where the children of parent are scrollable.
If I take on of the elements from inside parent after scrolling.
const child = parent.children[3];
I have a scroll position
child.scrollTop; // Maybe 269px
And when I add it back
parent.prepend(child);
The child looses its scroll position
child.scrollTop; // 0px
My question here is, why does the scroll position get lost in this case?
Full demonstration of what is happening.
Because when you prepend(element) it's actually first removed from the DOM then reinserted at the new position. While it's removed from the DOM, it doesn't have a CSS box anymore, no defined size, no scrolling box. When appended again all the scrolling info is reset.
const elem = document.querySelector("ul");
elem.scrollTop = elem.scrollHeight;
console.log("before", elem.scrollTop);
elem.remove();
console.log("after", elem.scrollTop);
console.log("scrollHeight", elem.scrollHeight);
console.log("height", elem.getBoundingClientRect().height);
ul { max-height: 50px; overflow: scroll }
<ul>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
Note that there is an active discussion to maybe add a "move" operation to the DOM APIs, but it's not quite sure yet what this would look like, nor if it would solve this use case.
If you wish to maintain the scrolling position, you'd have to store it before calling .prepend() and set it back after.
Without the full demonstration I would have never understood what you were talking about.
You're moving an child. In other words you first remove it and then you insert it. Once an element is removed, scrollTop makes no sense and is reset.
A solution is to scroll the element down again after it has been inserted:
app.prepend(lastChild);
lastChild.scrollTop = lastChild.scrollHeight;
That seems to work fine.

How to hide this dropdownmenu on mouseout

I have a dropdownmenu working as shown on jsfiddle example here
How can I get the dropdownmenu to be hidden on mouseout? I have added:
onmouseout="hidediv()";
to the div that contains the drop down menu - but, when you click the link that makes the drop down menu appear - as you move your mouse over the drop down menu it disappears - sometimes. Other times it hangs around as you mouseover the first item in the list, but when you move over the second item in the list - the menu disappears. I don't understand as the mouseout should apply to the whole div.
Change onmouseout to onmouseleave.
From MDN:
Similar to mouseout, [mouseleave] differs in that it doesn't bubble and that it
isn't sent until the pointer has moved from its physical space and the
one of all its descendants.
Fiddle
You have two completely independent elements for the menu and the button. Make the menu list ul#dvMenu a sub-item of the ul under #navcontainer, like this:
<ul>
<li></li>
<li></li>
<li>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</li>
</ul>
BTW, you don't need to have a surrounding div, you can apply all those styles directly to the unordered list. This way you won't leave the context of the element, hence avoiding the unintended hide. Also, bind onmouseout="hidemenu();" to the main <ul>.

Get element underneath another element?

Just wondering the best way to tackle this.
Let's say I have a fixed navbar that sits exactly centered vertically.
As I'm scrolling, I want to find out the element behind the nav bar.
Lets say I have a nav like so:
<nav>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</nav>
And then sections like so:
<section id="about"></section>
<section id="services"></section>
<section id="contact"></section>
If I give them all a fixed height of say 1000px so that we are able to scroll properly, how can I detect when the navbar is say over the 'services' section, so I can append an active class etc.
I was going to detect the scroll position from the top of the document, and compare that to the top positions of the sections which I'd be able to find out where the navbar is located from there, but is this the best way to tackle this?
Example: http://jsfiddle.net/c8jhajde/

jquery toggle and smooth scroll clashing on same page

I am using jquery toggle plugin along with the smoothscroll plugin on a single page website. now, the problem is that the hidden text in the toggle function is not allowing the smoothscroll jquery to function properly. suppose we click 'item a' in the nav option and it is supposed to scroll to the 'item a' section div in a smooth manner, it does so haphazardly and also takes into account the height of the hidden text in toggle function which is about 100px. Hence, there is neither a smooth scroll but also a difference of 100px of the desired result.
For reference, i am using html5 and have 4 sections on the page, as provided in code below.
Here is the code for toggle function:
`$(document).ready(function(){
//Hide the tooglebox when page load
$(".togglebox").hide();
//slide up and down when click over heading 2
$("h2").click(function(){
// slide toggle effect set to slow you can set it to fast too.
$(this).toggleClass("active").next(".togglebox").slideToggle("slow");
return true;
});
});`
here is the code for navigation menu (supposed to scroll on the same page):
<nav>
<ul>
<li>Home</li>
<li>Our Works</li>
<li>About Us</li>
<li>Contact Us</li>
</ul>
</nav>
i am using the smoothscroll plugin located at:http://css-tricks.com/snippets/jquery/smooth-scrolling/
can someone please guide me why these 2 jquery are clashing.
PS: i am also using a jquery slideshow, but that has no effect as far as i can tell, coz i removed that, and nothing changed.
It's difficult to tell based on what you've posted, but using the .hide() method, which is comparable to setting the CSS property to display: none, could cause the browser to incorrectly calculate height. I would try setting visibility: hidden , and then when active visibility: visible.

Get height of DIV and its content with JQuery

I have a div which contains several elements:
<div class="menuItem designMenu" id="dMenu">
<ul class="menuList menu">
<li class="menuHeader">Design</li>
<li class="projectHeader">Mother</li>
<li class="projectBody">Some text here</li>
<li class="more">More</li>
</ul>
</div>
I need to get the height of the dMenu items that I can animate it upwards, including all the content inside. My Javascript currently:
var designHeight = $("#dMenu").height();
Returns nothing.
I've tried offsetHeight, scrollHeight, and everything else Google turns up. I'm running the jQuery at the end of the body, inside a document ready function.
The reason to get the height to animate, instead of doing it manually, is that a: I'd like to learn how and b: I don't yet know how many items will be in the div.
Are the lis within the ul floated? If so, and the parent does not have overflow: hidden the parent collapses and therefor has no height. Try (if possible) adding overflow: hidden to the parent element, or hard code a height in your CSS.
I'm using scrollHeight to get at what I want. I also, embarrassingly, noticed as I was fiddling with things I was loading my JS before loading JQuery. So ashamed I didn't spot that.

Categories