Check the demo here: https://jsfiddle.net/g2djbwm5/1/
Scroll the page untill the input is visible.
Type in something but keep the focus into it
Using the mouse scroll the page again until the input is no longer visible
Now type in something
Input will be scrolled into view to the very top like this
Is there any way to show this input not very top but some 20px from the top when user type in? something like
Code:
<div style="width: 100%; height: 800px;">..............</div>
<input type="text"/>
<div style="width: 100%; height: 800px;" />
In CSS you can use this to make the scroll stops some px above:
scroll-margin-top: 50px;
an example here
Create a function to locate the y position of the element -> input. Then an event listener for input and conditional to check the position of the element. If it is off the page when focused and the event is input, place it on top and change the position to sticky else position relative.
let input = document.getElementById('input');
let inputPos = -1;
if (input === document.activeElement) {
input.addEventListener("input", () => {
if (inputPos < 0) inputPos = findPosY(input);
if (pageYOffset > inputPos) {
input.style.cssText = 'position:sticky; top: 0px; bottom: 0px;';
} else {
input.style.position = 'relative;';
}
});
}
function findPosY(obj) {
let curtop = 0;
if (typeof(obj.offsetParent) != 'undefined' && obj.offsetParent) {
while (obj.offsetParent) {
curtop += obj.offsetTop;
obj = obj.offsetParent;
}
curtop += obj.offsetTop;
} else if (obj.y)
curtop += obj.y;
return curtop;
}
<div style="width: 100%; height: 800px;">..............</div>
<input id="input" type="text" />
<div class="input" style="width: 100%; height: 1800px;" />
This decision comes to my mind, but this solution is a "crutch" (hack).
The problem with this solution is that when scrolling, the input loses its sticky positioning and returns its default coordinates.
If my small solution is modified, taking into account the preservation of the position of the input when scrolling, then the solution will be good, as it seems to me.
let input_text = document.querySelector('input[type="text"]');
input_text.oninput = function() {
this.classList.add('top_for_input');
}
window.onscroll = function() {
input_text.classList.remove('top_for_input');
}
.top_for_input {
position: sticky;
top: 20px;
bottom: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="width: 100%; height: 800px;">..............</div>
<input type="text"/>
<div style="width: 100%; height: 800px;" />
Related
I am basing my code off of this SO thread.
I have a parent div that is half way down the page. Within that parent div I want to display a sticky footer div, but only when viewport is showing the parent div. I have tried 4 different tutorials so far with no luck.
The page structure is this:
HEADER
HERO
CONTENT RIGHT-SIDE(id="wrap-vs")
CONTENT-FULL-WIDTH
FOOTER
When RIGHT-SIDE is within view, I want to display a sticky div within it. You can't see RIGHT-SIDE when page loads, you need to scroll down to it. Also, when we are below it I want the sticky div to go away.
var targetdiv = document.querySelector('.tabs');
console.log(targetdiv);
targetdiv.style.display = "none";
function CheckIfVisible(elem, targetdiv) {
var ElemPos = elem.getBoundingClientRect().top;
targetdiv.style.display = (ElemPos > 0 && ElemPos < document.body.parentNode.offsetHeight) ? "block" : "none";
}
window.addEventListener("onscroll", function() {
var elem = document.querySelector('#wrap-vs');
CheckIfVisible(elem, targetdiv);
});
#wrap-vs {
height: 100%;
background-color: yellow;
}
.tabs {
position: fixed;
bottom: 0;
}
<div id="wrap-vs">
<div class="tabs">
right-side content sticky div
</div>
</div>
This is how I fixed it:
// Create a new observer
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
// Log if the element and if it's in the viewport
console.log(entry.isIntersecting);
if(entry.isIntersecting == true){
document.querySelector('.tabs').style.display = 'block';
} else {
document.querySelector('.tabs').style.display = 'none';
}
});
});
// The element to observe
var app = document.querySelector('#wrap-vs');
// Attach it to the observer
observer.observe(app);
#wrap-vs {
height: 100%;
background-color: yellow;
}
.tabs {
position: fixed;
bottom: 0;
}
<div id="wrap-vs">
<div class="tabs">
right-side content sticky div
</div>
</div>
On clicking a button my program will create a dynamic div with a class name dynamictextbox . There is a label with the class name mytxt and textbox with class name mytext inside this div which is also dynamically created.
When i create a new dynamic div it is overlapping with previously created div.
Below is the CSS i've used
.dynamictextbox{
width:50%;
position:relative;
padding:10;
}
.dynamictextbox .mytxt{
position:absolute;
left:0px;
right:50%;
}
.dynamictextbox .mytext{
position:absolute;
left:51%;
right:100%;
}
Below is the HTML code
<div id="Enter your name" class="dynamictextbox">
<label class="mytxt">Enter your name</label>
<input type="text" name="Enter your name_name" id="Enter your name_id" class="mytext">
</div>
<br />
<div id="bigData" class="dynamictextbox">
<label class="mytxt">Now this is a long text which will overlap the next div.Need solution for this. Please give me a solution for this</label>
<input type="text" name="bigData_name" id="bigDate_id" class="mytext">
</div>
<br />
<div id="div_temp" class="dynamictextbox">
<label id="txtlb" class="mytxt">Dynamic Label</label>
<input type="text" name="tb" id="tb" class="mytext">
</div>
<br />
What you need here, is to expand the element according to the content height. Unfortunately you cannot do this using CSS. So we'll have to move along with javascript.
Here goes the script
<script>
var max = 0;
function setHeight() {
var elements = document.getElementsByClassName('mytxt');
var height = 0;
for (var i = 0; i < elements.length; i++) {
height = elements[i].scrollHeight;
if (height > max) {
max = height;
}
}
elements = document.getElementsByClassName('dynamictextbox');
for (var i = 0; i < elements.length; i++) {
elements[i].style = "min-height: " + max + "px";
}
}
</script>
At the end of all the divs call the funtion setHeight().
<script>setHeight()</script>
So the output will look like this
P.S. I've added borders to the class dynamictextbox for testing purposes.
This may be helpful - JSFIDDLE
Just remove the .mytxt class from your CSS and increase the left attribute of .mytext class
.dynamictextbox .mytext{
position:absolute;
left:60%;
right:100%;
}
Update the code below. Is this what you where going after?
$("#add").on("click", function(){
// just a helper function for some random content
function dynamicText(){
var min = 1;
var max = 50;
var random = Math.floor(Math.random() * max) + min;
var text = "";
for(var i = 0; i < random; i++){
text += "text ";
}
return text;
}
// add to the container
var addMe = "\
<div class='dynamictextbox'>\
<label class='mytxt'>"+dynamicText()+"</label>\
<textarea class='mytext'>"+dynamicText()+"</textarea>\
</div>\
";
var container = $("#container");
container.append(addMe);
});
.dynamictextbox{
width:50%;
padding:10;
margin-top: 10px;
background: #CCC;
overflow: auto;
}
.dynamictextbox .mytxt{
position: relative;
float: left;
width: calc(50% - 10px);
}
.dynamictextbox .mytext{
float: right;
width: calc(50% - 10px);
height: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
On clicking a button my program will create a dynamic div with a class name dynamictextbox . There is a label with the class name mytxt and textbox with class name mytext inside this div which is also dynamically created.
<br><hr><br>
<button id="add">ADD</button><br><br>
<div id="container"></div>
In my webpage I have 4 "waypoints" that have their respective links in a menu. What I need is to also bind the scroll of the page to these waypoints. So when the page loads, the pointer is at the top and based on the scrolling direction, the page moves to the next/previous waypoint. Until now I have come up with this simplistic approach, which goes into a scroll loop due to the scrollTo() function triggering the whole method again.
$(function () {
var top = $(window).scrollTop();
var currentWaypoint = 0;
var previousWaypoint = 0;
$(window).scroll(function () {
console.log("Scroll triggered");
console.log("Current Waypoint: " + currentWaypoint);
var curTop = $(window).scrollTop();
if (top < curTop) {
if (currentWaypoint < 4) {
previousWaypoint = currentWaypoint;
currentWaypoint=currentWaypoint+1;
}
}
else {
if (currentWaypoint > 0) {
previousWaypoint = currentWaypoint;
currentWaypoint=currentWaypoint-1;
}
}
top = curTop;
if (previousWaypoint != currentWaypoint) {
switch (currentWaypoint) {
case 1:
$.scrollTo(document.getElementById("waypoint-collection"));
case 2:
$.scrollTo(document.getElementById("waypoint-report"));
case 3:
$.scrollTo(document.getElementById("waypoint-video"));
case 4:
$.scrollTo(document.getElementById("waypoint-mail"));
default:
}
}
console.log("New Waypoint: " + currentWaypoint);
});
});
I've seen this sort of behaviour implemented in some websites but cannot seem to find anything relevant with google. Any ideas?
EDIT:
The relevant HTML code:
<html>
<head>
<style>
body {
background-color: #FFFFFF;
}
.features-container-wh {
min-height: 12.5rem;
text-align: center;
height: 100%;
}
.features-container-bl {
background-color: #43bfcb;
text-align: center;
color: #FFFFFF;
height: 100%;
}
.features-container-bottom {
height: 100%;
}
</style>
</head>
<body>
<div class="features-container-wh">
Collection
Report
Video
Mail
</div>
<div class="features-container-bl" id="waypoint-collection">
<p>Stuff...</p>
</div>
<div class="features-container-wh" id="waypoint-report">
<p>Stuff...</p>
</div>
<div class="features-container-bl" id="waypoint-video">
<p>Stuff...</p>
</div>
<div class="features-container-bottom" id="waypoint-mail">
<p>Stuff...</p>
</div>
</body>
$('html, body').animate({scrollTop: $("#.wayPoint1").offset().top}, 2000);
I have a problem that I want to detect if an element is covered by another one in one page.
eg:
DOM elements
<div class="ele ele1"><p>A</p></div>
<div class="ele ele2"><p>B</p></div>
<div class="ele ele3"><p>C</p></div>
<div class="cover"><p>D</p></div>
CSS style
.ele{
display: inline-block;
width: 100px;
height: 100px;
position: relative;
}
p{
width: 100%;
text-align: center;
}
.ele1{
background-color: red;
}
.ele2{
background-color: blue;
}
.ele3{
background-color: green;
}
.cover{
position: absolute;
width: 100px;
height: 100px;
left: 300px;
top: 10px;
background: grey;
}
http://jsfiddle.net/veraWei/6v89b1fy/
How to detect element A is not been covered but element C is covered by ele D?
One more thing: the number of "D" is uncertain. Maybe there are E/F/G... in the page.
I appreciate all the thoughts or existing examples/jQuery plugins/CSS/etc.
Thanks all your guys' detailed answers. But I need more shortly explanation maybe one attribute that indicate that A is not covered by any elements and C is covered by rendering. Is there any plugin or attribute existing?
Why not try the following :
1) Find the element position relative to the viewport:
rect=elt.getBoundingClientRect();
x=rect.left;
y=rect.top;
(or may be consider the midpoints coordinates)
2) Find the top element at position x, y:
topElt=document.elementFromPoint(x,y);
3) Check if the top element is the same than the original element :
if(elt.isSameNode(topElt)) console.log('no overlapping');
Are you looking for something like this?
http://jsfiddle.net/6v89b1fy/4/
var coverElem = $(".cover");
var elemArray = [];
elemArray.push($(".ele1"), $(".ele2"), $(".ele3"));
for(i=0; i< elemArray.length; i++)
{
var currElemOffset = elemArray[i].offset();
var currElemWidth = elemArray[i].width();
var currElemStPoint = currElemOffset.left ;
var currElemEndPoint = currElemStPoint + currElemWidth;
if(currElemStPoint <= coverElem.offset().left && coverElem.offset().left <= currElemEndPoint)
{
elemArray[i].append("<span>Covered</span>");
}
else
{
elemArray[i].append("<span>Not covered</span>");
}
}
Here is a quick example of how you may go about doing it. This would check for both vertical and horizontal overlapping. This is kind of generic and not-so-generic as well since this is based off the HTML in your question. Adjust the top/left values of the .cover to see it work for all possible cases.
var $cover = $(".cover"),
cWidth = $cover.width(),
cHeight = $cover.height(),
cLeft = $cover.offset().left,
cRight = $(window).width() - (cLeft + cWidth),
cTop = $cover.offset().top,
cBtm = $(window).height() - (cTop + cHeight);
$("div:not(.cover)").each(function() {
var $this = $(this),
eleWidth = $this.width(),
eleHeight = $this.height(),
eleLeft = $this.offset().left,
eleTop = $this.offset().top,
eleRight = $(window).width() - (eleLeft + eleWidth),
eleBtm = $(window).height() - (eleTop + eleHeight);
if (
cLeft < (eleLeft + eleWidth) &&
cRight < (eleRight + eleWidth) &&
cTop < (eleTop + eleHeight) &&
cBtm < (eleBtm + eleHeight)
) {
alert($this.text() + " is covered by " + $cover.text());
}
});
.ele {
display: inline-block;
width: 100px;
height: 100px;
position: relative;
margin-top: 40px;
}
p {
width: 100%;
text-align: center;
}
.ele1 {
background-color: red;
}
.ele2 {
background-color: blue;
}
.ele3 {
background-color: green;
}
.cover {
position: absolute;
width: 100px;
height: 100px;
left: 60px;
top: 110px;
background: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="ele ele1">
<p>A</p>
</div>
<div class="ele ele2">
<p>B</p>
</div>
<div class="ele ele3">
<p>C</p>
</div>
<div class="ele ele3">
<p>D</p>
</div>
<div class="ele ele3">
<p>E</p>
</div>
<div class="ele ele3">
<p>F</p>
</div>
<div class="ele ele3">
<p>G</p>
</div>
<div class="cover">
<p>COVER</p>
</div>
OK. I've gone through all cases of overlapping and have created this fiddle. I've used getBoundintClientRect() and have used it to get top, left, bottom, right values of two divs on which overlapping is to be checked and then I've compared the offsets using various conditional statements and conditions too which you'll find below. In the fiddle all your four elements are having position: absolute, adjust their top and left values to make them overlap one another and to check whether two elements are overlapping or not? pass the two elements in the function -
checkElements(elA, elB); // pass two elements to check
which is in the very last.
You will see the long if else conditions in the fiddle, they are just for testing all possibilities of overlapping. Here is that all possible conditions used to check overlapping -
if((eleB.top >= eleA.top && eleB.top <= eleA.bottom) || (eleB.bottom >= eleA.top && eleB.bottom <= eleA.bottom)) {
if((eleB.left >= eleA.left && eleB.left <= eleA.right) || (eleB.right >= eleA.left && eleB.right <= eleA.right)) {
el1.innerHTML = '<p>covered</p>';
}
else {
el1.innerHTML = '<p>not covered</p>';
}
}
else {
el1.innerHTML = '<p>not covered</p>';
}
You will also see if B overlaps A then it will write A is covered because I've compared using x and y coordinates of A and B. In this case, I think an additional condition checking z-index will be used. I've not created for that.
Check the fiddle, and adjust top and left values of different elements and then pass two elements in the function checkElements() and see the result is correct or not.
You can also do all the checking simultaneously as -
checkElements(elA, elB); // check if A is overlapped by B
checkElements(elB, elC); // check if B is overlapped by C
checkElements(elC, elD); // check if C is overlapped by D
See this fiddle using the multiple checking.
EDIT: If looping is the problem, then you can combine all the loops of if else into a single if else like this -
if(((eleB.top >= eleA.top && eleB.top <= eleA.bottom) || (eleB.bottom >= eleA.top && eleB.bottom <= eleA.bottom)) && ((eleB.left >= eleA.left && eleB.left <= eleA.right) || (eleB.right >= eleA.left && eleB.right <= eleA.right))) {
el1.innerHTML = '<p>covered</p>'; // or your code of adding true to the attribute that tells about overlapping
}
else {
el1.innerHTML = '<p>not covered</p>';
}
Updated fiddle
<body>
<div id = "SiteContainer">
<div id = "NavigationButtons"></div>
<div id = "ShowReelContainer">
<div id= "NavigationBackward" name = "back" onclick="setPosition();">x</div>
<div id= "NavigationForward" name = "forward" onclick="setPosition();">y</div>
<div id = "VideoWrapper">
<div id = "SlideShowItem">
<img src="Images/A.png" alt="A"></img>
</div>
<div id = "SlideShowItem">
<img src="Images/B.png" alt="B"></img>
</div>
<div id = "SlideShowItem">
<img src="Images/C.png" alt="C" ></img>
</div>
</div>
</div>
</div>
<script>
var wrapper = document.querySelector("#VideoWrapper");
function setPosition(e)
{
if(e.target.name = "forward")
{
if!(wrapper.style.left = "-200%")
{
wrapper.style.left = wrapper.style.left - 100%;
}
}
else
{
if(e.target.name = "back")
{
if!(wrapper.style.left = "0%")
{
wrapper.style.left = wrapper.style.left + 100%;
}
}
}
}
</script>
</body>
Hi, I am very new to javascript. What I am trying to do, is change the x-position of a div when another div (NavigationForward or NavigationBackward) is clicked. However it does not appear to do anything at all. Basically if the div with name forward is clicked, I want to translate the VideoWrapper -100% from it's current position and +100% when "back". The css div itself VideoWrapper has a width of 300%. Inside this div as you can see is a SlideShowItem which is what will change. Perhaps I am adding and subtracting 100% the wrong way?
EDIT:
Thanks everyone for helping me out with this...I had just one more query, I am trying to hide the arrows based on whether the wrapper is at the first slide or the last slide. If its on the first slide, then I'd hide the left arrow div and if it's on the last, I'd hide the right arrow, otherwise display both of em. Ive tried several ways to achieve this, but none of em work, so Ive resorted to using copies of variables from the function that works. Even then it does not work. It appears that my if and else if statements always evaluate to false, so perhaps I am not retrieving the position properly?
function HideArrows()
{
var wrapper2 = document.getElementById("VideoWrapper");
var offset_x2 = wrapper2.style.left;
if(parseInt(offset_x2,10) == max_x)
{
document.getElementById("NavigationForward").display = 'none';
}
else if(parseInt(offset_x2,10) == min_x)
{
document.getElementById("NavigationBackward").display = 'none';
}
else
{
document.getElementById("NavigationForward").display = 'inline-block';
document.getElementById("NavigationBackward").display = 'inline-block';
}
}
//html is the same except that I added a mouseover = "HideArrows();"
<div id = "ShowReelContainer" onmouseover="HideArrows();">
To achieve this type o slider functionality your div VideoWrapper must have overflow:hidden style, and your SlideShowItemdivs must have a position:relative style.
Then to move the slides forward or backward you can use the style left which allows you to move the divs SlideShowItem relative to it's parent VideoWrapper.
I've tested this here on JSFiddle.
It seems to work as you described in your question, although you may need to do some adjustments, like defining the width of your slides, how many they are and so on.
For the sake of simplicity, I defined them as "constants" on the top of the code, but I think you can work from that point on.
CSS
#VideoWrapper{
position:relative; height:100px; white-space:nowrap;width:500px;
margin-left:0px; border:1px solid #000; overflow:hidden; }
.SlideShowItem{
width:500px; height:100px;display:inline-block;position:relative; }
#NavigationForward, #NavigationBackward{
cursor:pointer;float:left; background-color:silver;margin-right:5px;
margin-bottom:10px; text-align:center; padding:10px; }
HTML
<div id = "SiteContainer">
<div id = "NavigationButtons">
</div>
<div id = "ShowReelContainer">
<div id= "NavigationBackward" name = "back" onclick="setPosition('back');">prev</div>
<div id= "NavigationForward" name = "forward" onclick="setPosition('forward');">next</div>
<div style="clear:both;"></div>
<div id = "VideoWrapper">
<div class= "SlideShowItem" style="background-color:blue;">
Slide 1
</div>
<div class = "SlideShowItem" style="background-color:yellow;">
Slide 2
</div>
<div class = "SlideShowItem" style="background-color:pink;">
Slide 3
</div>
</div>
</div>
</div>
JavaScript
var unit = 'px'; var margin = 4; var itemSize = 500 + margin; var itemCount = 3; var min_x = 0; var max_x = -(itemCount-1) * itemSize;
function setPosition(e) {
var wrapper = document.getElementById("VideoWrapper");
var slides = wrapper.getElementsByTagName('div');
var offset_x = slides[0].style.left.replace(unit, '');
var curr_x = parseInt(offset_x.length == 0 ? 0 : offset_x);
if(e == "forward")
{
if(curr_x <= max_x)
return;
for(var i=0; i<slides.length; i++)
slides[i].style.left= (curr_x + -itemSize) + unit;
}
else if(e == "back")
{
if(curr_x >= min_x)
return;
for(var i=0; i<slides.length; i++)
slides[i].style.left= (curr_x + itemSize) + unit;
} }
After you analyze and test the code, I don't really know what's your purpose with this, I mean, you maybe just playing around or trying to develop something for a personal project, but if you are looking for something more professional avoid to create things like sliders on your own, as there are tons of plugins like this available and well tested out there on the web.
Consider using jQuery with NivoSlider, it works like a charm and is cross browser.
I would recommend using jQuery, this will reduce your coding by quite a bit. Can read more here: http://api.jquery.com/animate/
I've created a simple fiddle for you to take a look at. This example uses the .animate() method to reposition two div elements based on the CSS 'left' property.
CSS:
#container {
position: absolute;
left: 1em;
top: 1em;
right: 1em;
bottom: 1em;
overflow: hidden;
}
#one, #two {
position: absolute;
color: white;
}
#one {
background: pink;
width: 100%;
top:0;
bottom:0;
}
#two {
background: blue;
width: 100%;
left: 100%;
top:0;
bottom:0;
}
HTML:
<div id="container">
<div id="one">Div One</div>
<div id="two">Div Two</div>
</div>
JavaScript/jQuery:
var one, two, container;
function animateSlides(){
one.animate({
left : '-100%'
}, 1000, function(){
one.animate({
left : 0
}, 1000);
});
two.animate({
left : 0
}, 1000, function(){
two.animate({
left:'100%'
}, 1000);
});
};
$(function(){
one = $('#one');
two = $('#two');
container = $('#container');
setInterval(animateSlides, 2000);
});
JSFiddle Example: http://jsfiddle.net/adamfullen/vSSK8/3/