Show element if another element is outside screen (JS) - javascript

If element1 is outside visible area, element2 should be visible. If element1 is inside visible area, element2 should be hidden. (I would like not to use jQuery if possible) This I have so far.
function check(){
var div1 = document.getElementById("element1");
var div2 = document.getElementById("element2");
if(div1.top > (window.top + viewport.height )) {
div2.style.display = "none";
}
else {
div2.style.display = "block";
}
}
With this I get the error 'viewport is not defined'. I know it has to be defined but dont really know how to.

You should attach the function to the scroll event on what element is scrolling and checking that scroll position with the end (as bottom position) of your element1 to check.
This is an example:
function check(){
var div1 = document.getElementById("element1");
var div2 = document.getElementById("element2");
if(document.documentElement.scrollTop > (div1.clientTop + div1.clientHeight )) {
div2.style.display = "block";
}
else {
div2.style.display = "none";
}
}
window.onscroll=check;
body{
height: 200vh;
position: relative;
}
#element1{
border: 1px solid green;
width: 200px;
height: 50px;
}
#element2{
border: 1px solid red;
width: 200px;
height: 50px;
position: fixed;
display: none; /*initial display state*/
top: 50vh;
right: 0;
background-color: salmon;
}
<div id="element1"></div>
<div id="element2"></div>
Also, you can check for the Intersection Observer API which is used sometimes for lazy loading images.
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API

If you don't plan on supporting really old browsers (like IE11 and below), you can actually use the Intersection Observer API to achieve what you're doing. The advantage is that the API actually contains configurable logic that can further fine tune at what threshold you want to toggle display state of the target element.
In fact, almost 74% of global browser traffic actually supports Intersection Observer. With the notable exception of Safari. Fret not, there is a polyfill available if you need it.
Here is an example:
function callback(entries) {
entries.forEach(function(entry) {
var elementToToggle = document.getElementById('element2');
elementToToggle.style.display = entry.isIntersecting ? 'none' : 'block';
});
}
var observer = new IntersectionObserver(callback);
observer.observe(document.getElementById('element1'));
body {
min-height: 200vh;
position: relative;
}
.element {
width: 50%;
height: 50px;
border: 1px solid rgba(0,0,0,.25);
}
#element1 {
background-color: steelblue;
position: absolute;
top: 100px;
}
#element2 {
background-color: rebeccapurple;
position: fixed;
top: 25;
right: 0;
}
<div class="element" id="element1"></div>
<div class="element" id="element2"></div>

Related

Can I use requestAnimationFrame to smooth out scroll behaviour?

I have a small scroll effect which simulate that a logo will disappear if a lower div will scroll over it.
Currently I'm checking if two divs are intersecting. If this is true, then the height of the div of the logo will decrease with the scroll position of the div beneath.
Unfortunately, my demo is not foolproof and some fragments of the logo are still visible.
Is there a way to do this jank-free? Maybe with requestAnimationFrame?
function elementsOverlap(el1, el2) {
const domRect1 = el1.getBoundingClientRect();
const domRect2 = el2.getBoundingClientRect();
return !(
domRect1.top > domRect2.bottom ||
domRect1.right < domRect2.left ||
domRect1.bottom < domRect2.top ||
domRect1.left > domRect2.right
);
}
const el1 = document.querySelector(".logo");
const el2 = document.querySelector(".clickblocks");
let scrollPositionEl2;
let heightDifference;
const logoHeight = el1.offsetHeight;
document.addEventListener("DOMContentLoaded", () => {
var scrollDirectionDown;
scrollDirectionDown = true;
window.addEventListener("scroll", () => {
if (this.oldScroll > this.scrollY) {
scrollDirectionDown = false;
} else {
scrollDirectionDown = true;
}
this.oldScroll = this.scrollY;
// test
if (scrollDirectionDown) {
if (elementsOverlap(el1, el2) === true) {
scrollPositionEl2 = el2.getBoundingClientRect().top;
heightDifference = logoHeight - scrollPositionEl2 + 100;
//console.log(logoHeight - heightDifference);
el1.style.height = `${logoHeight - heightDifference}px`;
}
} else {
//scrolling up
scrollPositionEl2 = el2.getBoundingClientRect().top - 100;
el1.style.height = `${scrollPositionEl2}px`;
//console.log(logoHeight);
}
});
});
#import url("https://fonts.googleapis.com/css2?family=Inter:wght#900&display=swap");
.wrapper {
max-width: 100vw;
margin: 0 auto;
background-image: url("https://picsum.photos/1920/1080");
background-size: cover;
background-attachment: fixed;
height: 1200px;
position: relative;
&::after {
content: "";
position: absolute;
background: rgba(0, 0, 0, 0.3);
width: 100%;
height: 100%;
inset: 0;
}
}
body {
margin: 0;
}
main {
width: 100%;
height: 100vh;
position: relative;
z-index: 1;
}
.clickblocks {
width: 100%;
height: 200px;
display: grid;
grid-template-columns: repeat(12, (minmax(0, 1fr)));
}
.clickblock {
transition: all ease-in-out 0.2s;
backdrop-filter: blur(0px);
border: 1px solid #fff;
height: 100%;
grid-column: span 6 / span 6;
font-size: 54px;
font-weight: 700;
padding: 24px;
font-family: "Inter", sans-serif;
color: white;
text-transform: uppercase;
&:hover {
backdrop-filter: blur(10px);
}
}
.logo {
background: url("https://svgshare.com/i/ivR.svg");
width: 100%;
background-repeat: no-repeat;
background-position: top;
position: fixed;
top: 100px;
}
.logo-wrapper {
position: relative;
}
<div class="wrapper">
<main>
<div class="logo-wrapper" style="height: 390px">
<div class="logo" style="height: 300px">
</div>
</div>
<div class="clickblocks">
<div class="clickblock">
Some Content
</div>
</div>
</main>
</div>
Few things here to optimize your performance.
getBoundingClientRect() is a rather expensive calculation. If there are NO other options it's fine.
The Intersection Observer API is a lot more performant, and you can set the root element on the API. Then observe the element that is moving. This should be able to telly you if their are colliding.
Whenever you do scroll based logic, you should really try and throttle the logic so that the scroll any fires ever 16.6ms. That will reduce the number of times the calculations are made, and speed things up on the FE.
Learn how to use Google Chrome's performance tab. It can be overwhelming at first, but it gives you the ability to drill into the exact piece of code that's slowing your site down.
Learn about JS's event loop, and what's really going on under the hood. This video by Jake Archibald really help me understand it.
Hope this helped, sorry that I didn't give you an actual solution.

Prevent Mouseenter and Mouseleave Firing Within Element Without Using Pointer-Events

I'm using 'mouseenter' and 'mouseleave' to change the visibility of an image when I enter and leave an element. My issue is these events keep firing even when I'm within the element. Using 'pointer-events = none' works but it turns off another animation I have on the image. Is there a solution to this that either doesn't use pointer-events nor mousenter/leave and allows me to have animations on my image? DEMO
HTML:
<img id="image" src=""/>
<div id='box' class="box"></div>
CSS:
.box {
border: 2px solid red;
height: 400px;
width: 60%;
margin: 10px auto;
}
#image {
position:absolute;
width: 60px;
height: 60px;
display: none;
}
JS:
$(document).mousemove(function(e){
const height = $('#image').height() / 2;
const width = $('#image').width() / 2;
$("#image").css({
left:e.pageX-width,
top:e.pageY-height
});
});
$('.box').mouseenter(_=> {
$('#image').show();
});
$('.box').mouseleave(_=> {
$('#image').hide();
});
I'm not sure if this accomplishes what you're looking for - but you could change the z-index of the image and the background of the parent container, like:
$(document).mousemove(function(e){
const height = $('#image').height() / 2;
const width = $('#image').width() / 2;
$("#image").css({
left:e.pageX-width,
top:e.pageY-height
});
});
let entries = 0;
let exits = 0
$('.box').mouseenter(_=> {
$('#image').show();
entries += 1;
document.getElementById("entries").textContent=entries;
});
$('.box').mouseleave(_=> {
$('#image').hide();
exits += 1;
document.getElementById("exits").textContent=exits;
});
.box {
border: 2px solid red;
height: 400px;
width: 60%;
margin: 10px auto;
background: transparent;
}
#image {
position:absolute;
width: 60px;
height: 60px;
display: none;
z-index: -1;
}
#display {
position: absolute;
top:0;
left: 0;
border: 1px solid black;
width: 100px;
height: 100px;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="image" src="https://i5.walmartimages.ca/images/Large/580/6_r/875806_R.jpg"/>
<div id='box' class="box"></div>
<div id= 'display'>
<div id= 'entries'>00</div>
<div id= 'exits'>00</div>
</div>
Which will cause the .box to always be on top, even though the image is under your cursor.
Have you tried maybe setting a value to indicate the current state of the image?
Something like this:
var showImage = false;
$(document).mousemove(function(e){
const height = $('#image').height() / 2;
const width = $('#image').width() / 2;
$("#image").css({
left:e.pageX-width,
top:e.pageY-height
});
});
$('.box').mouseenter(_=> {
if (showImage)
return;
showImage = true;
$('#image').show();
});
$('.box').mouseleave(_=> {
showImage = false;
$('#image').hide();
});

Changing style of div after adding sibling div

When I add a sibling div to the #boundary div, I can no longer change the style of the #box child div. What am I doing wrong? The following is a simplified version of my code:
let box = document.getElementById("box");
let boundary = document.getElementById("boundary")
//Adding this line prevents my code from changing the #box style to blue
boundary.innerHTML += "<div>A</div>"
document.addEventListener("keydown", function(event) {
if (event.key == "ArrowDown") {
box.style.backgroundColor = "blue"
}
})
#box {
width: 75px;
height: 75px;
background-color: green;
border: solid black 1px;
position: absolute;
top: 100px;
left: 100px;
}
<div id="boundary">
<div id="box"></div>
</div>
When you append a new string to innerHTML it's like you create a new HTML content inside #boudary so the old element you selected is different from the new one created.
To verify this, select your element after the DOM change and you will get the new one created and you will be able to change its style:
let boundary = document.getElementById("boundary")
boundary.innerHTML += "<div>A</div>";
//Here you select the new one
let box = document.getElementById("box");
document.addEventListener("click", function(event) {
box.style.backgroundColor = "blue"
})
#box {
width: 75px;
height: 75px;
background-color: green;
border: solid black 1px;
position: absolute;
top: 100px;
left: 100px;
}
<div id="boundary">
<div id="box"></div>
</div>
Adding a string to innerHTML creates a new #box DOM element, and this breaks the box reference in your code. Use Element.insertAdjacentHTML() instead:
let box = document.getElementById("box");
let boundary = document.getElementById("boundary")
boundary.insertAdjacentHTML( 'beforeend', "<div>A</div>");
document.addEventListener("keydown", function(event) {
if (event.key == "ArrowDown") {
box.style.backgroundColor = "blue"
}
})
#box {
width: 75px;
height: 75px;
background-color: green;
border: solid black 1px;
position: absolute;
top: 100px;
left: 100px;
}
<div id="boundary">
<div id="box"></div>
</div>
Another option is to remove the let box = document.getElementById("box"); line. This will work because every element with id creates an automatic global variable, that references it and updates automatically.
let boundary = document.getElementById("boundary")
boundary.innerHTML += "<div>A</div>";
document.addEventListener("keydown", function(event) {
if (event.key == "ArrowDown") {
box.style.backgroundColor = "blue"
}
})
#box {
width: 75px;
height: 75px;
background-color: green;
border: solid black 1px;
position: absolute;
top: 100px;
left: 100px;
}
<div id="boundary">
<div id="box"></div>
</div>
You need to put a semicolon after it.
boundary.innerHTML += "<div>A</div>";
I hope this helps.

Child div elements not appearing in parent div element created by JavaScript function

I started learning JavaScript about a few weeks ago, and I have a problem. I have here two functions that are meant to bring up a menu when a button is clicked. In theory the menu that pops up should bring up a small div element from the left side, and 6 div elements within that div element. The main div element has the id "pokemonswitch" and when I click the button with the related function it only brings up "pokemonswitch" the other div elements don't seem to want to appear inside "pokemonswitch". I have tinkered with the code and have gotten various results.
1: Div elements appear in "pokemonswitch as programmed but after I click another button that removes "pokemonwitch" the div elements remain there despite the parent element not being there.
2: The div elements do not appear at all within "pokemonswitch".
3: The div elements appear in random places and the rest of the function doesn't work.
My goal is to have a function that calls up "pokemonswitch" with six div elements inside of it. Is there something I am missing about structure that is causing my child div elements to act so crazy? I hope this is clear enough to be answered, if not I will be more than happy to append more details to the problem.
//MAKE DIV ELEMENT pokemonswitch VISIBLE AND ASSOCIATIVE SLOTS AS WELL
function pkmnFunction() {
var element = document.getElementById('pokemonswitch');
var cancel = document.getElementById('optionsdiv');
element.style.visibility = "visible";
document.getElementById('slot1').style.visibility = "visible";
document.getElementById('slot2').style.visibility = "visible";
document.getElementById('slot3').style.visibility = "visible";
document.getElementById('slot4').style.visibility = "visible";
document.getElementById('slot5').style.visibility = "visible";
document.getElementById('slot6').style.visibility = "visible";
cancel.innerHTML = "<input id='cancelbutton' type='button' value='cancel' onclick='canFunction()' style='position:absolute; top:95px; left:35px;'></input>";
element.innerHTML = "<div id='slot1'></div><div id='slot2'></div><div id='slot3'></div><div id='slot4'></div><div id='slot5'></div><div id='slot6'></div>";
}
//MAKE DIV ELEMENT pokemonswitch HIDDEN AND ASSOCIATED slot ELEMENTS AS WELL
function canFunction() {
var element = document.getElementById('pokemonswitch');
var cancel = document.getElementById('optionsdiv');
document.getElementById('slot1').style.visibility = "hidden";
document.getElementById('slot2').style.visibility = "hidden";
document.getElementById('slot3').style.visibility = "hidden";
document.getElementById('slot4').style.visibility = "hidden";
document.getElementById('slot5').style.visibility = "hidden";
document.getElementById('slot6').style.visibility = "hidden";
element.style.visibility = "hidden"
cancel.innerHTML = "<input id='b5' type='button' onclick='setSlots()' value='Check Slot' ></input><input id='b1' type='button' value='Fight!'></input><input id='b2' type='button' onclick='pkmnFunction()' value='Pkmn'></input><input id='b3' type='button' value='Items' onclick='itemFunction()'></input><input id='b4' type='button' value='Run'></input>";
}
////////////ASSOCIATED CSS STYLE CODE//////////////////
#pokemonswitch {
position: absolute;
width: 180px;
margin - left: -15px;
height: 100 % ;
border: solid;
border - color: black;
border - width: 2px;
border - radius: 25px;
background - color: 0099CC;
z - index: 3;
visibility: hidden;
}
#slot1 {
position: absolute;
top: 0px;
left: -10px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
}
#slot2 {
position: absolute;
top: 65px;
left: -10px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
#slot3 {
position: absolute;
top: 130px;
left: -500px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
#slot4 {
position: absolute;
top: 195px;
left: -500px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
#slot5 {
position: absolute;
top: 260px;
left: -500px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
#slot6 {
position: absolute;
top: 325px;
left: -250px;
padding: 5px;
text - align: center;
border: solid;
border - width: 1px;
background - color: red;
width: 170px;
height: 65px;
z - index: 4;
visibility: hidden;
}
The issue is, you are trying to refer an element that isn't even created yet.
element.innerHTML = "<div id='slot1'></div><div id='slot2'></div><div id='slot3'></div><div id='slot4'></div><div id='slot5'></div><div id='slot6'></div>";//Place this first
document.getElementById('slot1').style.visibility = "visible";
document.getElementById('slot2').style.visibility = "visible";
document.getElementById('slot3').style.visibility = "visible";
document.getElementById('slot4').style.visibility = "visible";
document.getElementById('slot5').style.visibility = "visible";
document.getElementById('slot6').style.visibility = "visible";
cancel.innerHTML = "<input id='cancelbutton' type='button' value='cancel' onclick='canFunction()' style='position:absolute; top:95px; left:35px;'></input>";
Also few other things I noticed were:
Instead of using style.visibility use style.display. <input> isn't a container element, so remove </input> everywhere.
document.getElementById('slot1').style.visibility = "visible";
element.innerHTML = "<div id='slot1'></div>";
This is not right. The first line suggests that an element with id slot already exists. The second line adds a new div with that same id.
If the element should already exist, you can add the existing element
var slot1 = document.getElementById('slot1');
slot1.style.visibility = "visible";
element.appendChild(slot);
If not, you can create it first:
var slot1 = document.createElement('div');
slot1.id = 'slot1';
slot1.style.visibility = "visible";
element.appendChild(slot);
I do it this way! Create a div that contains the form you want and make this div display:none. Then on click make it visible where you want to
<div style="display:none">
<div id="mycontent">
content content
</div>
</div>
then use
document.getElementById('ID')..style.display="value"

css in textfield so text is deleted as a word

I am trying to figure out how facebook does the person-highlight tagging below.
I have a <textarea> and what I want is that ability when I press backspace the whole name gets deleted.
And I also wanted the name to be highlighted in blue (but this one is easy).
Can this be done easily through css? Or do I have to use some sort of javascript to have the deletion stuff working?
TLDR: I needed a jQuery function that deletes the name that is highlighted when I press back..that's all, no need for autocompletion and such
you can make it by adding an absolute div behind the required text, and make the background transparent for the textarea.
here is a snippet of code that I just wrote, it might help you.
I just faced some problems with adding the correct left position to the highlighted div.
html :
<div class='container'>
<div class='highlighted'></div>
<textarea class='text_area'>hi my name is Ayman</textarea>
</div>
css :
.custom_table{
position: relative;
width:600px;
}
.row{
position: relative;
height:40px;
background: #c80000;
border-top:1px solid #fff;
}
.row div{
color:#fff;
text-align: center;
line-height:40px;
}
.row:hover .first,
.row:hover .second,
.row:hover .third,
.row:hover .fourth{
background:#522D2D;;
cursor:pointer;
}
.first{
position: absolute;
left:0%;
right:80%;
height:40px;
background: #00c800;
}
.second{
position: absolute;
left:20%;
right:60%;
height:40px;
background: #0000c8;
}
.third{
position: absolute;
left: 40%;
right: 25%;
height: 40px;
background: #BEBECF;
}
.fourth{
position: absolute;
left: 75%;
right: 0%;
height: 40px;
background: #D6182F;
}
JavsScript :
$(document).ready(function(e){
$('.text_area').bind('keypress', function(e) {
var code = (e.keyCode ? e.keyCode : e.which);
if (code == 64){
$('.text_area').val($('.text_area').val()+" Ayman")
line = $('.text_area').val().substr(0, $('.text_area').selectionStart).split("\n").length;
var hl = $("<div class='highlighted'></div>");
$(hl).css({'left':$('.text_area').getCursorPosition()+"px", 'top': ((line*14)-12)+"px"})
$('.container').append($(hl))
}
});
});
(function ($, undefined) {
$.fn.getCursorPosition = function() {
var el = $(this).get(0);
var pos = 0;
if('selectionStart' in el) {
pos = el.selectionStart;
} else if('selection' in document) {
el.focus();
var Sel = document.selection.createRange();
var SelLength = document.selection.createRange().text.length;
Sel.moveStart('character', -el.value.length);
pos = Sel.text.length - SelLength;
}
return pos;
}
})(jQuery);
You can use Jquery Token input https://github.com/loopj/jquery-tokeninput
More comprehensive list is here:
Facebook style JQuery autocomplete plugin

Categories

Resources