I'm trying to animate the margins of a div set by the window height and width.
Please see the fiddle.
http://jsfiddle.net/cf4zM/
The bottom and right margins animate fine on the first click, however left and top do not animate. After first click all margins animate.
Any help would be great.
$( document ).ready(function() {
$("#resizer").height(
$(window).innerHeight()
);
$("#resizer").width(
$(window).innerWidth()
);
});
var xminus = window.innerWidth/15;
var yminus = window.innerHeight/15;
function resizediv(){
var x = $("#resizer").width() - xminus;
var y = $("#resizer").height() - yminus;
var heightoffset = (window.innerHeight - $("#resizer").height())/2
var widthoffset = (window.innerWidth - $("#resizer").width())/2
$("#resizer").animate({
width : x,
height : y,
marginTop : heightoffset,
marginBottom : heightoffset,
marginLeft : widthoffset,
marginRight : widthoffset
}, 1000, function(){
});
}
Demo
It's because of the margin you are setting with jquery.
Check out margin of the div on each click through browser debugger you will find the error.
You can also set margin auto in the css assigning top, bottom, left, right position 0 in order to have absolute centering of the div and remove margin set from script.
CSS
#resizer{
background-color: white;
position: fixed;
top:0;
bottom:0;
right:0;
left:0;
margin:auto;
padding: 0;
border:1px solid #000;
}
jquery
$( document ).ready(function() {
$("#resizer").height(
$(window).innerHeight()
);
$("#resizer").width(
$(window).innerWidth()
);
});
var xminus = window.innerWidth/15;
var yminus = window.innerHeight/15;
function resizediv(){
var x = $("#resizer").width() - xminus;
var y = $("#resizer").height() - yminus;
var heightoffset = (window.innerHeight - $("#resizer").height())/2
var widthoffset = (window.innerWidth - $("#resizer").width())/2
$("#resizer").animate({
width : x,
height : y
}, 1000, function(){
});
}
You're setting the left margin to:
var widthoffset = (window.innerWidth - $("#resizer").width()) / 2
Originally, the resizer width is the same as the window's width, which means that at the first click, the offset will always be 0, which is causing the element to remain in its position.
On the other hand, width is set to:
$("#resizer").width() - xminus
which means that it will be reduced from the very first click.
Related
I am trying to animate an opacity value from 0 to 1, based on the scroll position within the viewport height. The code below sets variables for windowHeight and scrollTop, which can be combined to calculate percentageScrolled (0–100) of the viewport height. Based on this I am able to switch CSS values at set points, but instead I want to gradually change the opacity from 0–100 of percentageScrolled.
How can I adjust the code below to transition/animate the opacity?
Thanks.
$(window).on('scroll', function(){
// Vars
var windowHeight = $(window).height();
var scrollTop = $(this).scrollTop();
var percentageScrolled = (scrollTop*100)/windowHeight;
if( percentageScrolled < 100 ) {
$('.colour-overlay').css('opacity', '1');
} else {
$('.colour-overlay').css('opacity', '0');
}
});
You can remove the if and set the opacity to the percentage divided by 100
$(window).on('scroll', function() {
// Vars
var windowHeight = $(window).height();
var scrollTop = $(this).scrollTop();
$('.colour-overlay').css('opacity', scrollTop / windowHeight);
});
.colour-overlay {
display: block;
width: 20px;
height: 1200px;
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="colour-overlay"></div>
$(‘.colour-overlay’).css(opacity, percentageScrolled / 100);
Instead of if else statement.
Also as a general advice try to avoid using var, use const or let instead and if your project doesnt depend on jquery try to avoid it too.
const overlays = document.querySelectorAll(‘.colour-overlay’);
window.addEventListener('scroll', () => {
const windowHeight = window.offsetHeight;
const scrollTop = window.scrollTop;
const percentageScrolled = (scrollTop * 100) / windowHeight;
for (const overlay of overlays) {
overlay.style.opacity = percentageScrolled / 100;
}
});
This would be the pure js solution.
Dont know if i understood you right, but a wrote an example have a look.
$(document).on('scroll', function(){
// Vars
// use body instead of window, body will return the right height where window will return the view size
var windowHeight = $("body").height();
var scrollTop = $(this).scrollTop();
var percentageScrolled = Math.abs((((scrollTop / windowHeight) * 100) / 100 ));
$('.colour-overlay').css('opacity', percentageScrolled);
});
.colour-overlay{
background:red;
height:1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="colour-overlay"></div>
I'm using a JQuery plugin called SMINT to create sticky navigation that becomes fixed to the top of the viewport when scrolling. I'm trying to leave a space before and after the navigation at the top of the page and multiple full height divs below.
Using
* {margin: 0; padding: 0; outline: 0;
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
box-sizing:border-box;
}
makes the divs full height (minus the sticky nav) but botches the initial navigation. (after scrolling the navigation is fine). Removing the border-box screws up the full-height.
My attempt: https://jsfiddle.net/colintkelly/uxsg6mL8/
Live example: http://www.banditfish.com/black-fives/
You don't need any plugin for that - here is a quick and easy to understand/customize
Approach:
JSnippet demo - using your HTML without smint
var barSelector = ".subMenu",
offSetToTriggerFixed = 1,
offsettofix = $(barSelector).offset().top + offSetToTriggerFixed,
$fixedBar = $(barSelector).eq(0).clone();
//Set cloned style and append to body:
$fixedBar.css({ display:'none', position: 'fixed', top:0, 'z-index':1100});
$('body').append($fixedBar);
//Set heights:
var viewPortHeight = $('body').height(),
navHeight = $(barSelector).outerHeight(),
$anyOtherSec = $('.section').not('.sTop');
$anyOtherSec.css({ height: viewPortHeight - navHeight + 5});
//Trigger when needed:
$(window).scroll(function(){
var fromTop = $(this).scrollTop();
if (fromTop <= offsettofix) $($fixedBar).hide();
else $($fixedBar).show();
});
I need to retrieve the visible height of a div within a scrollable area. I consider myself pretty decent with jQuery, but this is completely throwing me off.
Let's say I've got a red div within a black wrapper:
In the graphic above, the jQuery function would return 248, the visible portion of the div.
Once the user scrolls past the top of the div, as in the above graphic, it would report 296.
Now, once the user has scrolled past the div, it would again report 248.
Obviously my numbers aren't going to be as consistent and clear as they are in this demo, or I'd just hard code for those numbers.
I have a bit of a theory:
Get the height of the window
Get the height of the div
Get the initial offset of the div from the top of the window
Get the offset as the user scrolls.
If the offset is positive, it means the top of the div is still visible.
if it's negative, the top of the div has been eclipsed by the window. At this point, the div could either be taking up the whole height of the window, or the bottom of the div could be showing
If the bottom of the div is showing, figure out the gap between it and the bottom of the window.
It seems pretty simple, but I just can't wrap my head around it. I'll take another crack tomorrow morning; I just figured some of you geniuses might be able to help.
Thanks!
UPDATE: I figured this out on my own, but looks like one of the answers below is more elegant, so I'll be using that instead. For the curious, here's what I came up with:
$(document).ready(function() {
var windowHeight = $(window).height();
var overviewHeight = $("#overview").height();
var overviewStaticTop = $("#overview").offset().top;
var overviewScrollTop = overviewStaticTop - $(window).scrollTop();
var overviewStaticBottom = overviewStaticTop + $("#overview").height();
var overviewScrollBottom = windowHeight - (overviewStaticBottom - $(window).scrollTop());
var visibleArea;
if ((overviewHeight + overviewScrollTop) < windowHeight) {
// alert("bottom is showing!");
visibleArea = windowHeight - overviewScrollBottom;
// alert(visibleArea);
} else {
if (overviewScrollTop < 0) {
// alert("is full height");
visibleArea = windowHeight;
// alert(visibleArea);
} else {
// alert("top is showing");
visibleArea = windowHeight - overviewScrollTop;
// alert(visibleArea);
}
}
});
Calculate the amount of px an element (height) is in viewport
Fiddle demo
This tiny function will return the amount of px an element is visible in the (vertical) Viewport:
function inViewport($el) {
var elH = $el.outerHeight(),
H = $(window).height(),
r = $el[0].getBoundingClientRect(), t=r.top, b=r.bottom;
return Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H));
}
Use like:
$(window).on("scroll resize", function(){
console.log( inViewport($('#elementID')) ); // n px in viewport
});
that's it.
jQuery .inViewport() Plugin
jsFiddle demo
from the above you can extract the logic and create a plugin like this one:
/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
*/
;(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i,el) {
function visPx(){
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
Use like:
$("selector").inViewport(function(px) {
console.log( px ); // `px` represents the amount of visible height
if(px > 0) {
// do this if element enters the viewport // px > 0
}else{
// do that if element exits the viewport // px = 0
}
}); // Here you can chain other jQuery methods to your selector
your selectors will dynamically listen to window scroll and resize but also return the initial value on DOM ready trough the first callback function argument px.
Here is a quick and dirty concept. It basically compares the offset().top of the element to the top of the window, and the offset().top + height() to the bottom of the window:
function getVisible() {
var $el = $('#foo'),
scrollTop = $(this).scrollTop(),
scrollBot = scrollTop + $(this).height(),
elTop = $el.offset().top,
elBottom = elTop + $el.outerHeight(),
visibleTop = elTop < scrollTop ? scrollTop : elTop,
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
$('#notification').text(`Visible height of div: ${visibleBottom - visibleTop}px`);
}
$(window).on('scroll resize', getVisible).trigger('scroll');
html,
body {
margin: 100px 0;
}
#foo {
height: 1000px;
background-color: #C00;
width: 200px;
margin: 0 auto;
}
#notification {
position: fixed;
top: 0;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="foo"></div>
<div id="notification"></div>
The logic can be made more succinct if necessary, I've just declared separate variables for this example to make the calculation as clear as I can.
Here is a version of Rory's approach above, except written to function as a jQuery plugin. It may have more general applicability in that format. Great answer, Rory - thanks!
$.fn.visibleHeight = function() {
var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop;
scrollTop = $(window).scrollTop();
scrollBot = scrollTop + $(window).height();
elTop = this.offset().top;
elBottom = elTop + this.outerHeight();
visibleTop = elTop < scrollTop ? scrollTop : elTop;
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
return visibleBottom - visibleTop
}
Can be called with the following:
$("#myDiv").visibleHeight();
jsFiddle
Here is the improved code for jquery function visibleHeight: $("#myDiv").visibleHeight();
$.fn.visibleHeight = function() {
var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop, height;
scrollTop = $(window).scrollTop();
scrollBot = scrollTop + $(window).height();
elTop = this.offset().top;
elBottom = elTop + this.outerHeight();
visibleTop = elTop < scrollTop ? scrollTop : elTop;
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
height = visibleBottom - visibleTop;
return height > 0 ? height : 0;
}
I am building my sister a website at SarahNWatson.com/new. I have it set up as a big photo/video album. For actual content pages, such as her Bio, I have it so that it opens a modal window.
Right now I have the modal window so that the height starts at 0px and then animates open, however this gives me a slide down effect. I want it to open outwards as if something were in the box pushing in both directions. How can I accomplish this?
Here's the code:
function createModal(filler) {
var $this = $(this);
var $body = $('body');
var winHeight = $(window).height();
var winWidth = $(window).width();
$body.prepend('<div id="blackout">');
$("#blackout").css({ height:winHeight }).fadeIn(1800);
$body.prepend('<div id="modal_window">');
$("#modal_window").html(filler).fadeIn(2000);
var modalHeight = $("#modal_window").height();
var modalWidth = $("#modal_window").width();
var offsetH = winHeight/2 - modalHeight;
var offsetW = winWidth/2 - modalWidth/2;
$("#modal_window").css({ top:offsetH, left:offsetW, height:'0px' }).animate({ height:modalHeight });
}
And the CSS:
#modal_window {
position: absolute;
z-index: 1000;
width: 600px;
background: rgba(0,0,0,.8);
padding: 15px;
}
Start with offsetH = winHeight/2 and offsetW = winWidth/2. Then, animate all of the top, left, and height CSS properties. The final top will be (winHeight - modalHeight)/2 and final left will be (winWidth - modalWidth)/2.
function createModal(filler) {
var $this = $(this);
var $body = $('body');
var winHeight = $(window).height();
var winWidth = $(window).width();
$body.prepend('<div id="blackout">');
$("#blackout").css({ height:winHeight }).fadeIn(1800);
$body.prepend('<div id="modal_window">');
$("#modal_window").html(filler).fadeIn(2000);
var modalHeight = $("#modal_window").height();
var modalWidth = $("#modal_window").width();
var offsetH1 = winHeight/2;
var offsetH2 = (winHeight-modalHeight)/2;
var offsetW = (winWidth-modalWidth)/2;
$("#modal_window")
.css({ top:offsetH1, left:offsetW, height:'0px' })
.animate({ top:offsetH2, height:modalHeight });
}
UPDATE: Code sample updated to only animate vertically.
Essentially, you're moving the box up as it grows taller. So instead of sliding down it gives the appearance of expanding from the middle.
You could give it a margin-top of half the ultimate height (modalHeight) and add marginTop:"toggle" to your animation:
.animate({ height:modalHeight, marginTop:"toggle"})
Try using the CSS setting Bottom instead of Top. You should then use the bottom of the element to position it thus having it animte upwards instead of downwards.
.animate() always animate away from the anchor.
I would like to create a div, that is situated beneath a block of content but that once the page has been scrolled enough to contact its top boundary, becomes fixed in place and scrolls with the page. I know I've seen at least one example of this online but I cannot remember it for the life of me.
Any thoughts?
[Working demo]
var el = $("#sticky");
var win = $(window);
var width = el.width();
var height = el.height();
var win_height = $(window).height();
window.onscroll = function() {
var offset = el.offset().top + height - win_height;
if ( win.scrollTop() > offset ) {
window.onscroll = function() {
el.css({
width: width,
position: "absolute",
top: win.scrollTop() + win_height - height
});
};
}
};
If you don't need to support IE based browsers you can use:
position: "fixed"
bottom: 0