I want the textblocks on my website to get bigger/popup when I scroll down to them. How can I do that?
I tried to google how to do that but I couldn´t figure that out.
You need to use the IntersectionObserver API to detect when the text block is visible, then apply a CSS class.
Try this:
const element = document.querySelector('.text-block-1');
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
element.classList.add('visible');
}
});
observer.observe(element);
And then use the visible class, like this:
.visible { color: red; font-size: 24px; }
Note that if you have multiple HTML elements using the same class, you will need to use document.querySelectorAll and create a loop to observe all elements.
This example will make the font size of the text blocks increase to 24px as they are scrolled into view.
window.addEventListener('scroll', function() {
var textBlock1 = document.getElementById('text-block-1');
var textBlock2 = document.getElementById('text-block-2');
// Get the position of the text blocks relative to the viewport
var rect1 = textBlock1.getBoundingClientRect();
var rect2 = textBlock2.getBoundingClientRect();
// Check if the text blocks are within the viewport
if (rect1.top < window.innerHeight && rect1.bottom > 0) {
textBlock1.style.fontSize = '24px';
}
if (rect2.top < window.innerHeight && rect2.bottom > 0) {
textBlock2.style.fontSize = '24px';
}
});
Related
I'm trying to make the elements on the page fade in on scroll. Easy enough right? Not for me.
HTML is a standard list.
CSS sets all elements to opacity 0 prior to scrolling.
I'm trying to use Native JavaScript only.
// get current page body
var actBody = document.getElementById('acts-body');
// on scroll function
actBody.onscroll = function(){
// get screen height
var screenPosition = window.innerHeight;
// get all text elements
var artistName = document.getElementsByClassName('artist');
// loop through all elements
for(var i = 0; i < artistName.length; i++){
// get each elements position from top
var positionFromTop = artistName[i].getBoundingClientRect().top;
// if element is in viewport add class
if(positionFromTop - screenPosition <= 0){
artistName[i].classList.add('txt-fadeIn');
}
else{
artistName[i].classList.remove('txt-fadeIn');
}
console.log(artistName[i]);
}
i think it should solve it
if(screenPosition - positionFromTop <= 0){
artistName[i].classList.add('txt-fadeIn');
}
I'm trying to pin some divs in place and fade them in and out as a user scrolls down. My code looks like this so far:
$(window).on("load",function() {
var fadeDuration = 500;
function fade() {
// compute current window boundaries
var windowTop = $(window).scrollTop(),
windowBottom = windowTop + $(window).innerHeight(),
focusElt = null;
// find our focus element, the first visible .copy element,
// with a short-circuiting loop
$('.imgdiv').toArray().some(function(e, i) {
var objectTop = $(e).offset().top;
if ((objectTop >= windowTop) && (objectTop <= windowBottom)) {
focusElt = e;
return true;
}
console.log(focusElt);
});
// obscure all others
$('.focus').not(focusElt)
.removeClass('focus')
.fadeTo(fadeDuration, 0);
// focus on our focus element; if was the previous focus, nothing
// to do; but if it wasn't focus / wasn't showing before, make
// it visible and have class focus
$(focusElt).not('.focus')
.addClass('focus')
.fadeTo(fadeDuration, 1);
}
fade(); //Fade in completely visible elements during page-load
$(window).scroll(function() {fade();}); //Fade in elements during scroll
});
Here's the corresponding fiddle that almost does what I'm looking for, but instead of the green "Fade In" blocks moving upward and fading, I want them pined in place near the top of the window. As the "IMG DIVs" move past them they will fade and reappear with each new "IMG DIV". Here, I'm focusing on the particular green block and fading it when it becomes the focus element. Instead, what I need to do is, focus on the IMG DIV blocks, add a "pinned" class to the green blocks when they reach the top of the page, and fade the green blocks in and out.
Does anyone have any advice?
Part 2 of my question is how to do this with native JavaScript, and not rely on jQuery's dependency.
Ok, so lets split your first issue into two issues :)
First of all, you want to (in general) do something when some element becomes visible in the viewport and when it becomes invisible. So, basically, all you need is function like that:
watchElementIsInViewport(
$('.imgdiv'),
doSomethingWhenElementAppearedInViewport,
doSomethingWhenElementOutOfViewport
);
You know, that when element becomes visible, you want to show some other element. When element becomes invisible, you want to hide that related element. So now, define those two functions:
function doSomethingWhenElementAppearedInViewport(element) {
// retrieve text related with the element
var $copy = $(element).next('.copy');
// fade it in
$copy.fadeTo(500, 1);
}
function doSomethingWhenElementGotOutOfViewport(element) {
// retrieve text related with the element
var $copy = $(element).next('.copy');
// fade it out
$copy.fadeTo(500, 0);
}
What about watchElementIsInViewport? There is no magic inside, only logic you already created, but decoupled from showing of finding elements.
function watchElementIsInViewport($elements, elementAppearedInViewport, elementGotOutOfViewport) {
var currentlyVisible = [ ];
// retrieve positions once, assume it won't change during script is working
var positions = getVerticalBoundaries($elements);
function _scrollHandler() {
var viewportTop = window.scrollY;
var viewportBottom = viewportTop + window.innerHeight;
$elements.each(function(index, element) {
var elementPosition = positions[index];
/* if you wish to check if WHOLE element is in viewport
* var elementIsInViewport = (elementPosition.top >= viewportTop) &&
* (elementPosition.bottom <= viewportBottom);
*/
var elementIsInViewport = (elementPosition.top < viewportBottom) &&
(elementPosition.bottom > viewportTop);
var elementIndexInCurrentlyVisible = currentlyVisible.indexOf(element);
// if element is visible but was not visible before
if(elementIsInViewport && (elementIndexInCurrentlyVisible === -1)) {
elementAppearedInViewport(element);
currentlyVisible.push(element);
// if element is not visible but was visible before
} else if(!elementIsInViewport && (elementIndexInCurrentlyVisible !== -1)) {
elementGotOutOfViewport(element);
currentlyVisible.splice(elementIndexInCurrentlyVisible, 1);
}
});
}
// initial check & update
_scrollHandler();
// check & update on every scroll
$(window).on('scroll', _scrollHandler);
}
And that's all. Working example.
I am using jQuery to append text into a textarea
var box = $('<textarea></textarea>')
.attr({id: 'log_viewer',
readonly: '',
cols: 100,
rows: 40})
.appendTo($(outputEntity));
When data is received from a WebSocket, it's appended to the content of the textarea:
ws.onmessage = function(msg) {
var data = decodeURIComponent(msg.data);
data = data.replace('<', '<');
data = data.replace('>', '>');
box.append(data);
}
What I need is for this box to scroll to the bottom automatically, so that the viewport is always centered on the last page of output. Following some other Stack Overflow suggestions on this topic, I tried:
$('#log_viewer').scrollTop = $('#log_viewer')[0].scrollHeight - $('#log_viewer').height();
However, that doesn't work -- at least, not in Chrome or Firefox on Linux, which is all I have access to. The box doesn't scroll.
How do I make this box auto-scroll to the bottom-most page from JS? Is using append() to add output somehow interfering with the underlying dimension detection mechanisms? Is append() even the right way to go there?
Or perhaps I should use not use a textarea at all, but rather a DIV with a scroll bar? Admittedly, I'm rather behind the times on HTML + CSS and don't know exactly how to best accomplish that and still get the monospace-formatted, wrapped output I'm after.
Thanks much for any suggestions!
SOLVED:
http://jsfiddle.net/Ua9qc/
var h1 = $('#log_viewer')[0].scrollHeight,
h2 = $('#log_viewer').height();
$('#log_viewer').scrollTop(h1 - h2);`
I am not sure this will help you. If you wanna scroll certain element at the bottom, you can use this function to scroll by passing div id. Add these function to script
function scrollme(id)
{
var scrollElem = scrollableElement('html', 'body');
var targetOffset = $(id).offset().top;
$(scrollElem).animate({scrollTop: targetOffset-100}, 1000, function() {
});
}
function scrollableElement(els)
{
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}
}
}
return [];
}
How do you find the current width of a <div> in a cross-browser compatible way without using a library like jQuery?
document.getElementById("mydiv").offsetWidth
element.offsetWidth (MDC)
You can use clientWidth or offsetWidth Mozilla developer network reference
It would be like:
document.getElementById("yourDiv").clientWidth; // returns number, like 728
or with borders width :
document.getElementById("yourDiv").offsetWidth; // 728 + borders width
All Answers are right, but i still want to give some other alternatives that may work.
If you are looking for the assigned width (ignoring padding, margin and so on) you could use.
getComputedStyle(element).width; //returns value in px like "727.7px"
getComputedStyle allows you to access all styles of that elements. For example: padding, paddingLeft, margin, border-top-left-radius and so on.
Another option is to use the getBoundingClientRect function. Please note that getBoundingClientRect will return an empty rect if the element's display is 'none'.
var elem = document.getElementById("myDiv");
if(elem) {
var rect = elem.getBoundingClientRect();
console.log(rect.width);
}
You can also search the DOM using ClassName. For example:
document.getElementsByClassName("myDiv")
This will return an array. If there is one particular property you are interested in. For example:
var divWidth = document.getElementsByClassName("myDiv")[0].clientWidth;
divWidth will now be equal to the the width of the first element in your div array.
Actually, you don't have to use document.getElementById("mydiv") .
You can simply use the id of the div, like:
var w = mydiv.clientWidth;
or
var w = mydiv.offsetWidth;
etc.
call below method on div or body tag onclick="show(event);"
function show(event) {
var x = event.clientX;
var y = event.clientY;
var ele = document.getElementById("tt");
var width = ele.offsetWidth;
var height = ele.offsetHeight;
var half=(width/2);
if(x>half)
{
// alert('right click');
gallery.next();
}
else
{
// alert('left click');
gallery.prev();
}
}
The correct way of getting computed style is waiting till page is rendered. It can be done in the following manner. Pay attention to timeout on getting auto values.
function getStyleInfo() {
setTimeout(function() {
const style = window.getComputedStyle(document.getElementById('__root__'));
if (style.height == 'auto') {
getStyleInfo();
}
// IF we got here we can do actual business logic staff
console.log(style.height, style.width);
}, 100);
};
window.onload=function() { getStyleInfo(); };
If you use just
window.onload=function() {
var computedStyle = window.getComputedStyle(document.getElementById('__root__'));
}
you can get auto values for width and height because browsers does not render till full load is performed.
This question already has answers here:
Check if element is visible in DOM
(27 answers)
Closed 6 years ago.
In JavaScript, how would you check if an element is actually visible?
I don't just mean checking the visibility and display attributes. I mean, checking that the element is not
visibility: hidden or display: none
underneath another element
scrolled off the edge of the screen
For technical reasons I can't include any scripts. I can however use Prototype as it is on the page already.
For the point 2.
I see that no one has suggested to use document.elementFromPoint(x,y), to me it is the fastest way to test if an element is nested or hidden by another. You can pass the offsets of the targetted element to the function.
Here's PPK test page on elementFromPoint.
From MDN's documentation:
The elementFromPoint() method—available on both the Document and ShadowRoot objects—returns the topmost Element at the specified coordinates (relative to the viewport).
I don't know how much of this is supported in older or not-so-modern browsers, but I'm using something like this (without the neeed for any libraries):
function visible(element) {
if (element.offsetWidth === 0 || element.offsetHeight === 0) return false;
var height = document.documentElement.clientHeight,
rects = element.getClientRects(),
on_top = function(r) {
var x = (r.left + r.right)/2, y = (r.top + r.bottom)/2;
return document.elementFromPoint(x, y) === element;
};
for (var i = 0, l = rects.length; i < l; i++) {
var r = rects[i],
in_viewport = r.top > 0 ? r.top <= height : (r.bottom > 0 && r.bottom <= height);
if (in_viewport && on_top(r)) return true;
}
return false;
}
It checks that the element has an area > 0 and then it checks if any part of the element is within the viewport and that it is not hidden "under" another element (actually I only check on a single point in the center of the element, so it's not 100% assured -- but you could just modify the script to itterate over all the points of the element, if you really need to...).
Update
Modified on_top function that check every pixel:
on_top = function(r) {
for (var x = Math.floor(r.left), x_max = Math.ceil(r.right); x <= x_max; x++)
for (var y = Math.floor(r.top), y_max = Math.ceil(r.bottom); y <= y_max; y++) {
if (document.elementFromPoint(x, y) === element) return true;
}
return false;
};
Don't know about the performance :)
As jkl pointed out, checking the element's visibility or display is not enough. You do have to check its ancestors. Selenium does this when it verifies visibility on an element.
Check out the method Selenium.prototype.isVisible in the selenium-api.js file.
http://svn.openqa.org/svn/selenium-on-rails/selenium-on-rails/selenium-core/scripts/selenium-api.js
Interesting question.
This would be my approach.
At first check that element.style.visibility !== 'hidden' && element.style.display !== 'none'
Then test with document.elementFromPoint(element.offsetLeft, element.offsetTop) if the returned element is the element I expect, this is tricky to detect if an element is overlapping another completely.
Finally test if offsetTop and offsetLeft are located in the viewport taking scroll offsets into account.
Hope it helps.
This is what I have so far. It covers both 1 and 3. I'm however still struggling with 2 since I'm not that familiar with Prototype (I'm more a jQuery type of guy).
function isVisible( elem ) {
var $elem = $(elem);
// First check if elem is hidden through css as this is not very costly:
if ($elem.getStyle('display') == 'none' || $elem.getStyle('visibility') == 'hidden' ) {
//elem is set through CSS stylesheet or inline to invisible
return false;
}
//Now check for the elem being outside of the viewport
var $elemOffset = $elem.viewportOffset();
if ($elemOffset.left < 0 || $elemOffset.top < 0) {
//elem is left of or above viewport
return false;
}
var vp = document.viewport.getDimensions();
if ($elemOffset.left > vp.width || $elemOffset.top > vp.height) {
//elem is below or right of vp
return false;
}
//Now check for elements positioned on top:
//TODO: Build check for this using Prototype...
//Neither of these was true, so the elem was visible:
return true;
}
/**
* Checks display and visibility of elements and it's parents
* #param DomElement el
* #param boolean isDeep Watch parents? Default is true
* #return {Boolean}
*
* #author Oleksandr Knyga <oleksandrknyga#gmail.com>
*/
function isVisible(el, isDeep) {
var elIsVisible = true;
if("undefined" === typeof isDeep) {
isDeep = true;
}
elIsVisible = elIsVisible && el.offsetWidth > 0 && el.offsetHeight > 0;
if(isDeep && elIsVisible) {
while('BODY' != el.tagName && elIsVisible) {
elIsVisible = elIsVisible && 'hidden' != window.getComputedStyle(el).visibility;
el = el.parentElement;
}
}
return elIsVisible;
}
You can use the clientHeight or clientWidth properties
function isViewable(element){
return (element.clientHeight > 0);
}
Prototype's Element library is one of the most powerful query libraries in terms of the methods. I recommend you to check out the API.
A few hints:
Checking visibility can be a pain, but you can use the Element.getStyle() method and Element.visible() methods combined into a custom function. With getStyle() you can check the actual computed style.
I don't know exactly what you mean by "underneath" :) If you meant by it has a specific ancestor, for example, a wrapper div, you can use Element.up(cssRule):
var child = $("myparagraph");
if(!child.up("mywrapper")){
// I lost my mom!
}
else {
// I found my mom!
}
If you want to check the siblings of the child element you can do that too:
var child = $("myparagraph");
if(!child.previous("mywrapper")){
// I lost my bro!
}
else {
// I found my bro!
}
Again, Element lib can help you if I understand correctly what you mean :) You can check the actual dimensions of the viewport and the offset of your element so you can calculate if your element is "off screen".
Good luck!
I pasted a test case for prototypejs at http://gist.github.com/117125. It seems in your case we simply cannot trust in getStyle() at all. For maximizing the reliability of the isMyElementReallyVisible function you should combine the following:
Checking the computed style (dojo has a nice implementation that you can borrow)
Checking the viewportoffset (prototype native method)
Checking the z-index for the "beneath" problem (under Internet Explorer it may be buggy)
One way to do it is:
isVisible(elm) {
while(elm.tagName != 'BODY') {
if(!$(elm).visible()) return false;
elm = elm.parentNode;
}
return true;
}
Credits: https://github.com/atetlaw/Really-Easy-Field-Validation/blob/master/validation.js#L178
Try element.getBoundingClientRect().
It will return an object with properties
bottom
top
right
left
width -- browser dependent
height -- browser dependent
Check that the width and height of the element's BoundingClientRect are not zero which is the value of hidden or non-visible elements. If the values are greater than zero the element should be visible in the body. Then check if the bottom property is less than screen.height which would imply that the element is withing the viewport. (Technically you would also have to account for the top of the browser window including the searchbar, buttons, etc.)
Catch mouse-drag and viewport events (onmouseup, onresize, onscroll).
When a drag ends do a comparison of the dragged item boundary with all "elements of interest" (ie, elements with class "dont_hide" or an array of ids). Do the same with window.onscroll and window.onresize. Mark any elements hidden with a special attribute or classname or simply perform whatever action you want then and there.
The hidden tests are pretty easy. For "totally hidden" you want to know if ALL corners are either inside the dragged-item boundary or outside the viewport. For partially hidden you're looking for a single corner matching the same test.
I don't think checking the element's own visibility and display properties is good enough for requirement #1, even if you use currentStyle/getComputedStyle. You also have to check the element's ancestors. If an ancestor is hidden, so is the element.
Check elements' offsetHeight property. If it is more than 0, it is visible. Note: this approach doesn't cover a situation when visibility:hidden style is set. But that style is something weird anyways.
Here is a sample script and test case. Covers positioned elements, visibilty: hidden, display: none. Didn't test z-index, assume it works.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<style type="text/css">
div {
width: 200px;
border: 1px solid red;
}
p {
border: 2px solid green;
}
.r {
border: 1px solid #BB3333;
background: #EE9999;
position: relative;
top: -50px;
height: 2em;
}
.of {
overflow: hidden;
height: 2em;
word-wrap: none;
}
.of p {
width: 100%;
}
.of pre {
display: inline;
}
.iv {
visibility: hidden;
}
.dn {
display: none;
}
</style>
<script src="http://www.prototypejs.org/assets/2008/9/29/prototype-1.6.0.3.js"></script>
<script>
function isVisible(elem){
if (Element.getStyle(elem, 'visibility') == 'hidden' || Element.getStyle(elem, 'display') == 'none') {
return false;
}
var topx, topy, botx, boty;
var offset = Element.positionedOffset(elem);
topx = offset.left;
topy = offset.top;
botx = Element.getWidth(elem) + topx;
boty = Element.getHeight(elem) + topy;
var v = false;
for (var x = topx; x <= botx; x++) {
for(var y = topy; y <= boty; y++) {
if (document.elementFromPoint(x,y) == elem) {
// item is visible
v = true;
break;
}
}
if (v == true) {
break;
}
}
return v;
}
window.onload=function() {
var es = Element.descendants('body');
for (var i = 0; i < es.length; i++ ) {
if (!isVisible(es[i])) {
alert(es[i].tagName);
}
}
}
</script>
</head>
<body id='body'>
<div class="s"><p>This is text</p><p>More text</p></div>
<div class="r">This is relative</div>
<div class="of"><p>This is too wide...</p><pre>hidden</pre>
<div class="iv">This is invisible</div>
<div class="dn">This is display none</div>
</body>
</html>
Here is a part of the response that tells you if an element is in the viewport.
You may need to check if there is nothing on top of it using elementFromPoint, but it's a bit longer.
function isInViewport(element) {
var rect = element.getBoundingClientRect();
var windowHeight = window.innerHeight || document.documentElement.clientHeight;
var windowWidth = window.innerWidth || document.documentElement.clientWidth;
return rect.bottom > 0 && rect.top < windowHeight && rect.right > 0 && rect.left < windowWidth;
}