Make a div scroll with page only in a certain place? - javascript

How can it be made so that a div scrolls with the page but only in a certain area of the page?
I can't work out how to do this with CSS for only part of the page, I think javascript may be the only option.
For e.g. There's three sections of a page, Top, Middle and Bottom.
There's a right floated div which should scroll with the user in the middle section and stop scrolling to be 'left in place' at the top of the middle section as well as the bottom of the middle section.
#Top {
background-color: grey;
width: 100%;
height: 400px;
}
#Middle {
background-color: green;
width: 100%;
height: 800px;
}
#Bottom {
background-color: blue;
width: 100%;
height: 400px;
}
#scrolling-section {
background-color: yellow;
width: 30%;
height: 150px;
float: right;
}
<div id="Top">
</div>
<div id="Middle">
<div id="scrolling-section">
This box should scroll along the green section but 'cut-off' and stop scrolling at the top and bottom of the green section
</div>
</div>
<div id="Bottom">
</div>
JSFiddle: fiddle

So here you have solution using jquery:
Listen to the scroll event and calculate how much the scrolling-section goes outside the Middle section while scrolling up / down.
Added position: relative to the scrolling-section.
Adjust the position of the scrolling-section accordingly.
$(document).scroll(function() {
var wrapper = $('#Middle');
var box = $('#scrolling-section');
var offsetTop = - wrapper.offset().top + $(window).scrollTop();
var offsetBottom = wrapper.offset().top - $(window).scrollTop() + wrapper.outerHeight() - box.outerHeight();
if (offsetBottom > 0 && offsetTop < 0) {
box.css({
'top': 0
});
} else if (offsetBottom > 0 && offsetTop > 0) {
box.css({
'top': offsetTop + 'px'
});
} else {
box.offset({
'top': $(window).scrollTop() + offsetBottom
});
}
});
#Top {
background-color: grey;
width: 100%;
height: 400px;
}
#Middle {
background-color: green;
width: 100%;
height: 800px;
}
#Bottom {
background-color: blue;
width: 100%;
height: 400px;
}
#scrolling-section {
position: relative;
background-color: yellow;
width: 30%;
height: 150px;
float: right;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="Top">
</div>
<div id="Middle">
<div id="scrolling-section">
This box should scroll along the green section but 'cut-off' and stop scrolling at the top and bottom of the green section
</div>
</div>
<div id="Bottom">
</div>
Let me know your feedback on this. Thanks!

Some Javascript is needed in order to read the point where you want to change the state of the div you wish to address. You can do this with the getBoundingClientRect() method. I have worked out a fiddle that will show you.
What happens is that you read the position of #Middle. I have added an input field that shows you the value. The change will be when the position hits zero. You then change the CSS properties of the #scrolling-section.
You will see some added readings of the element to ensure that it can be positioned in place and will keep its original width;
var scrollposition = document.getElementById("Middle");
var scrollsection = document.getElementById("scrolling-section");
var scrollsection_offsetLeft = scrollsection.offsetLeft;
var scrollsection_width = scrollsection.offsetWidth;
var valy = document.getElementById("posy");
window.addEventListener("scroll", function(event) {
valy.value = scrollposition.getBoundingClientRect().y || scrollposition.getBoundingClientRect().top;
if (valy.value <= 0) {
scrollsection.style.position = "fixed";
scrollsection.style.top = "0px";
scrollsection.style.left = scrollsection_offsetLeft + "px";
scrollsection.style.width = scrollsection_width + "px";
} else {
scrollsection.style.position = "static";
scrollsection.style.top = "auto";
scrollsection.style.left = "auto";
}
}, false)
#posy {
position: fixed;
top: 0;
}
#Top {
background-color: grey;
width: 100%;
height: 400px;
}
#Middle {
background-color: green;
width: 100%;
height: 800px;
}
#Bottom {
background-color: blue;
width: 100%;
height: 400px;
}
#scrolling-section {
background-color: yellow;
width: 30%;
height: 150px;
float: right;
}
<input type="text" id="posy" />
<div id="Top">
</div>
<div id="Middle">
<div id="scrolling-section">
This box should scroll along the green section but 'cut-off' and stop scrolling at the top and bottom of the green section
</div>
</div>
<div id="Bottom">
</div>

I'm on my mobile but if you add
#scrolling-section {
position: fixed;
background-color: yellow;
width: 30%;
height: 150px;
right: 8px;
}
This will scroll with the page but really there will need to be an event listener that will trigger when #scrolling-section appears on the screen possibly adding the attribute position:fixed; then another event listener when the #bottom appears calculates the size of #middle set margin-top & position:absolute; hope this helps point in the right direction.

Related

On horizontal scroll of overflown div, fill in progress bar

I have a div which contains an image. The container of this image has overflow:scroll, so that the user can scroll left or right to see the rest of the image.
I've also implemented a progress bar, which should indicate how much of the image remains to scroll. I.e. if the user has scrolled 5% to the right, it'll fill up 5% of the progress bar (and vice versa).
I can get the function working based on scrollHeight, but can't get it working based on scrollWidth.
Where am I going wrong?
window.onscroll = function() {myFunction()};
function myFunction() {
var winScroll = document.body.scrollTop || document.documentElement.scrollTop;
var width = document.documentElement.scrollLeft - document.documentElement.clientWidth;
var scrolled = (winScroll / width) * 100;
document.getElementById("myBar").style.width = scrolled + "%";
}
.imgCont {
background: black;
overflow: scroll;
position: relative;
}
.imgCont img {
width: auto;
max-width: none;
}
.progress-container {
width: 100%;
height: 8px;
background: blue;
}
.progress-bar {
height: 8px;
background: red;
width: 0%;
}
<div class="imgCont">
<img src="https://i.imgur.com/KhWo66L.png">
</div>
<div class="progress-container">
<div class="progress-bar" id="myBar"></div>
</div>
You need to add listeners on the .imgCont element and use it's scrollLeft, scrollWidth and clientWidth properties
let scrEl = document.getElementById("scr-el")
scrEl.addEventListener('scroll', event => {
let scrolled = (scrEl.scrollLeft / (scrEl.scrollWidth - scrEl.clientWidth) ) * 100
document.getElementById("myBar").style.width = scrolled + "%"
});
.imgCont {
background: black;
overflow-x: scroll;
position: relative;
}
.imgCont img {
width: auto;
max-width: none;
}
.progress-container {
width: 100%;
height: 8px;
background: blue;
}
.progress-bar {
height: 8px;
background: red;
width: 0%;
}
<div id="scr-el" class="imgCont">
<img src="https://i.imgur.com/KhWo66L.png">
</div>
<div class="progress-container">
<div class="progress-bar" id="myBar"></div>
</div>
windows.onscroll won't emit any events while you scroll horizontally because scroll is happening in the element with class imgCont.
put an id imgCont
<div class="imgCont" id="imgCont">
<img src="https://i.imgur.com/KhWo66L.png">
</div>
and call the on scroll event as
document.getElementById("imgCont").onscroll
Jquery solution setps:
subtract the visible width of the image and the real image width
var winScroll = $(".imgCont img").width() - $(".imgCont").width();
get the left scroll position
var width = $(".imgCont").scrollLeft();
get the percentage from the width and position
var scrolled = ((width / winScroll) * 100);
Check the snippet:
$(function(){
$(".imgCont").scroll(function(){
var winScroll = $(".imgCont img").width() - $(".imgCont").width();
var width = $(".imgCont").scrollLeft();
var scrolled = ((width / winScroll) * 100);
$("#myBar").width(scrolled + "%");
});
});
.imgCont {
background: black;
overflow: scroll;
position: relative;
height:200px;
}
.imgCont img {
width: auto;
max-width: none;
}
.progress-container {
width: 100%;
height: 8px;
background: blue;
}
.progress-bar {
height: 8px;
background: red;
width: 0%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="imgCont">
<img src="https://static.toiimg.com/photo/msid-67868104/67868104.jpg?1368689">
</div>
<div class="progress-container">
<div class="progress-bar" id="myBar"></div>
</div>
Another solution.
let div = document.getElementById("theDiv")
div.addEventListener('scroll', function(e) {
let inner = window.innerWidth
let left = div.scrollLeft
let sWidth = div.scrollWidth
let total = sWidth - inner
let width = 1 * left / total * 100
if (width >= 100) {
return document.getElementById("myBar").style.width = "100%";
}
document.getElementById("myBar").style.width = `${width}%`;
});
body {
margin: 0;
}
.imgCont {
background: black;
overflow: auto;
position: relative;
}
.imgCont img {
width: auto;
max-width: none;
}
.progress-container {
width: 100%;
height: 8px;
background: blue;
}
.progress-bar {
height: 8px;
background: red;
width: 0%;
}
<div class="imgCont" id="theDiv">
<img src="https://i.imgur.com/KhWo66L.png">
</div>
<div class="progress-container">
<div class="progress-bar" id="myBar"></div>
</div>

Increase two divs height on mouse move

I horizontally split a page of the browser with two divs, and I want to increase the height of a div and reduce it in the other using the mouse position on the y axis. It would enlarge the first div when I'm in the upper part of the page and enlarge the second one when I'm at the bottom, but keeping both divs sum height equal to the height of the page.
This is my code
<html><head>
<meta charset="UTF-8">
<style>
*{
margin: 0 auto;
}
#container{
height: 100vh
}
#alto{
width: 100vw;
height: 50vh;
background-color: mediumpurple;
}
#basso{
width: 100vw;
height: 50vh;
background-color: royalblue;
}
</style>
</head>
<body>
<div id="alto" onMousemove="myFunction()" ></div>
<div id="basso" ></div>
<script>
function myFunction() {
var y = event.clientY + "px";
document.getElementById("basso").style.height = y ;
}
</script>
</body>
</html>
Take a look at this.
var section1 = document.getElementById("section1");
var section2 = document.getElementById("section2");
document.onmousemove = function(event) {
section1.style.height = event.clientY + 'px';
section2.style.height = "calc(100% - "+ event.clientY + 'px';
}
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container{
background: gray;
height: 100vh;
}
#section1, #section2{
height: 50%;
transition: all 0.1s;
}
#section1{
background: hotpink;
}
#section2{
background: pink;
}
<div class="container">
<div id="section1"></div>
<div id="section2"></div>
</div>
You can achieve a simpler version of this effect (ie. without constantly changing heights relative to the mouse position) with CSS alone.
Working Example:
body {
margin: 0;
padding: 0;
}
div {
width: 100vw;
height: 50vh;
margin: 0 auto;
transition: height 0.3s linear;
}
div:hover {
height: 80vh;
}
body:not(:hover) div {
height: 50vh;
}
div:not(:hover) {
height: 20vh;
}
.alto {
background-color: mediumpurple;
}
.basso {
background-color: royalblue;
}
<div class="alto"></div>
<div class="basso" ></div>

Hide Sticky Div Once Scrolling Past Next Parent Div

I'm trying to hide a "sticky" div once it scrolls past the next parent div. I've currently successfully have it so it appears after scrolling "y > 100" but I'm having a lot of trouble getting the "Sticky Note" to disappear after scrolling past #break.
Example below.
http://codepen.io/anon/pen/BojKBx
$(document).scroll(function() {
var y = $(this).scrollTop();
if (y > 100) {
$('.bottomMenu').fadeIn();
} else {
$('.bottomMenu').fadeOut();
}
});
.bottomMenu {
display: none;
position: fixed;
bottom: 0;
width: 50%;
height: 60px;
border-bottom: 1px solid #000;
z-index: 1;
margin: 0 auto;
left: 50%;
margin-left: -500px;
text-align: center;
}
#header {
font-size: 50px;
text-align: center;
height: 60px;
width: 100%;
background-color: red;
}
#container {
height: 2500px;
}
#break {
text-align: center;
font-size: 30px;
margin-bottom: 300px;
width: 100%;
background-color: yellow;
}
#footer {
height: 60px;
background-color: red;
width: 100%;
bottom: 0;
}
<div id="header">Home</div>
<div class="bottomMenu">
<h2>Sticky Note</h2>
</div>
<div id="container"></div>
<div id="break">Should Not Be Seen After This Point</div>
<div id="footer"></div>
You can get Y position of a div (its vertical offset starting from the top of the page), and then add condition to show sticky note only when you're below the required "Y" coordinate, and above the required div. Example:
http://codepen.io/anon/pen/EVPKyP
Javascript code:
$(document).scroll(function () {
var bodyRect = document.body.getBoundingClientRect(),
elemRect = document.getElementById("break").getBoundingClientRect(),
offset = elemRect.top - bodyRect.top - window.innerHeight;
var y = $(this).scrollTop();
if (y > 100 && y < offset) {
$('.bottomMenu').fadeIn();
} else {
$('.bottomMenu').fadeOut();
}
});
Sources:
Retrieve the position (X,Y) of an HTML element
screen width vs visible portion

Hide container div below menu bar div using jquery and css

I have a fixed header and menu bar and there is a container div when i scroll down the container div does not hide itself below the menu bar as shown in image below is the jquery code i am using. Please help to solve my issue.
var header= $('.header');
var start_div = $(header).offset().top;
var menu_div = $('.menu');
var menu = $(menu_div ).offset().top;
$.event.add(window, "scroll", function() {
var p = $(window).scrollTop();
$(header).css('position',((p)>start_div ) ? 'fixed' : 'static');
$(header).css('top',((p)>start_div ) ? '0px' : '');
$(header).css('width','840px');
$(header).css('min-height','108px');
});
$.event.add(window, "scroll", function() {
var p = $(window).scrollTop()+100;
$(menu_div).css('position',((p)>menu) ? 'fixed' : 'static');
$(menu_div).css('top',((p)>menu) ? '110px' : '');
$(menu_div).css('width','575px');
$(menu_div).css('height','57px');
});
Unless I'm missing something you don't need jQuery or even JS to do that.
Check the snippet (codePen here)
html,
body {
width: 100%;
height: 100%;
background-color: white;
}
.header-wrapper {
top: 0;
right: 0;
left: 0;
position: fixed;
height: 160px;
background-color: white;
}
.header {
background-color: cyan;
height: 100px;
width: 100%;
}
.menu {
width: 100%;
height: 50px;
background-color: green;
margin-top: 10px;
}
.content {
color: #fff;
background-color: black;
margin-top: 170px; /* same as height of header + nav + margins + 10px for coolness*/
}
<body>
<div class="header-wrapper">
<div class="header">Blue Header</div>
<div class="menu">Green Menu</div>
</div>
<div class="content">
My content<br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br>
blabla
<br><br><br><br><br><br><br><br><br><br><br><br><br><br>
blabla
<br><br><br><br><br><br><br><br><br><br><br><br><br><br>
</div>
</body>
Use the css z-index property.
.header, .menu {
z-index: 2
}
.container {
z-index: 1
}
http://www.w3schools.com/cssref/pr_pos_z-index.asp

How do I check whether the right/left edge of an element is overlapping the side of it's container?

I'm trying to display a right / left navigation arrow within a container (the arrows replace the existence of a scrollbar) when the corresponding edge of the content overlaps the container's sides.
Also, when the content is scrolled all the way to the end and can't scroll any further, the arrow should disappear.
My problem is, I'm confused as to how I write the function to check whether the element's contents are overlapping one edge or the other to hide one arrow or the other.
I started writing logic like this:
function setArrows(elem){
if (elem.scrollLeft() > 0) { //scroll position is greater than zero
// show left arrow
}
if () { //scroll position is less than zero
//show right arrow
}
}
but that doesn't seem to be the right logic. It sounded simpler in my head before I went to actually write the function.
How do I check whether the right/left edge of an element is overlapping the side of it's container?
Here's a Stack Snippet:
$('#wrapper').scroll(function(){
//check edges
});
div {
padding: 0px;
margin: 0px;
}
#wrapper {
width: 500px;
height: 100px;
background-color: blue;
overflow-x: scroll;
overflow-y:hidden;
}
#content {
width: 1000px;
height: 100px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="wrapper">
<div id="content">
</div>
</div>
You need to check if the content width minus the scrollLeft is greater than the wrapper width. If it is show the right scroller..
Something like this
$(function() {
var content = $('#content'),
arrows = $('.arrow'),
wrapper = $('#wrapper').scroll(function() {
//check edges
// handle left arrow
if (this.scrollLeft > 0) {
arrows.filter('.left').addClass('visible');
} else {
arrows.filter('.left').removeClass('visible');
};
// handle right arrow
if (content.outerWidth() - this.scrollLeft > wrapper.width()) {
arrows.filter('.right').addClass('visible');
} else {
arrows.filter('.right').removeClass('visible');
};
});
arrows.on('click', function() {
if ($(this).is('.left')) {
wrapper[0].scrollLeft -= 100;
} else {
wrapper[0].scrollLeft += 100;
}
return false;
});
// initialize
wrapper.trigger('scroll');
});
div {
padding: 0px;
margin: 0px;
}
#wrapper {
width: 500px;
height: 100px;
background-color: blue;
overflow-x: hidden;
overflow-y: hidden;
position: relative;
}
#content {
width: 1000px;
height: 100px;
background: url('http://lorempixel.com/1000/100/abstract/2') 0 0 no-repeat;
}
#full-container {
position: relative;
display: inline-block;
}
.arrow {
position: absolute;
top: 0;
bottom: 0;
width: 40px;
background-color: black;
display: none;
z-index: 100;
cursor: pointer;
color: #fff;
text-align: center;
line-height: 100px;
}
.arrow.visible {
display: block;
}
.arrow.left {
left: 0
}
.arrow.right {
right: 0
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="full-container">
<div class="arrow left"><</div>
<div id="wrapper">
<div id="content"></div>
</div>
<div class="arrow right">></div>
</div>

Categories

Resources