I'm attempting to create a parallax effect (which works great) however there is a small problem. Instead of the parallax being relative from the element's current position, it jumps to 0. How would I be able to have the parallax affect it's position relative to it's current position?
Here is my javascript:
$("#caveConfron").mousemove(function(e){
var x = e.pageX - this.offsetLeft;
var alreadyY = $("#caveConfron").css("backgroundPositionY");
$("#caveConfron").css({"backgroundPosition":-(x/85)+"% 0%"});
});
And my CSS for the element:
#caveConfron{
width:242px;
height:344px;
border:5px solid black;
background:url('../img/caveConfrontBg.jpg') no-repeat center top;
position:relative;
}
Here is an example of what happens: http://jsfiddle.net/gNCjS/
After much experimentation, I figured out the problem.
First and foremost, when the mouse hits the center of the div, the value of the mouse position of x should be "0". So this is what I did without tweaking the CSS:
$("#caveConfron").mousemove(function(e){
var x = e.pageX - this.offsetLeft;
var reduce = $(this).width()/2;
$("#caveConfron").css({"backgroundPosition":(((-x+reduce)/55)+50)+"% 0%"});
});
The variable reduce gets half of the width of the div. Then, I get the negative of the variable x while adding it to the the value of reduce so if the mouse position of x surpasses half of the div, it will go positive, so the middle will perpetually be "0." I then divide 55 so it wont jump sporadically when moving around on the x axis, it will be a small change (feel free to tweak this value if you want the jump to be much more substantial; for my purposes it was great). On top of that, I add 50, because in my original CSS the background's position is centered which coincidentally puts the value (in number terms) at 50%.
Hope my explanation was good!
Related
I have a div that is position: absolute. Sometimes on smaller screen resolutions it goes off the screen. Is it possible to calculate in px how much of it is off the screen?
As has been already mentioned, this really isn't the way for solving this problem, however the code you need is:
const offsetRight = document.querySelector('.your-element').getBoundingClientRect().right - window.innerWidth
This code gets the px value of the right edge of your element and calculates the difference between that and the edge of the window.
For the left side:
const offsetLeft = 0 - document.querySelector('.your-element').getBoundingClientRect().left;
I'm attempting to take elements that are statically or relatively positioned and absolutely position them relative their parent container without changing their physical location on the screen.
Here is my approach:
function changePosition(element){
var instance = {};
instance.element = element;
instance.parent = instance.element.parentElement;
instance.dim = instance.element.getBoundingClientRect();
instance.parent.dim = instance.parent.getBoundingClientRect();
instance.element.style.left = instance.dim.left - instance.parent.dim.left + "px";
instance.element.style.top = instance.dim.top - instance.parent.dim.top + "px";
instance.element.style.position = "absolute";
}
changePosition(document.getElementById("thing1"));
changePosition(document.getElementById("thing2"));
The HTML:
<div>
<input id="thing1" />
<input id="thing2" />
</div>
On JSFiddle: http://jsfiddle.net/oumt0nkv/2/
Without the position = "absolute", it calculates and applies left and top as expected. However, when I add that line back in both the left and top get set to 0px.
If I explicitly use 100px instead of variables for the left and top values, it works as expected.
I don't know why this is happening. If the position = "absolute" line was before the lines setting left and top I might understand it. This way, it appears some of these lines of code are happening asynchronously?
This is occurring in both Chrome and Firefox. Thank you!
If #thing1 is statically positioned, it will appear at top-left.
And if #thing2 is statically positioned too, it will be pushed to the right or to the next line by #thing1.
If #thing1 is absolutely positioned with the box offset properties set to auto, it will appear at its static position, i.e. at the place it would be if it wasn't absolutely positioned. That is, at top-left.
But since it's absolutely positioned, it's taken out of flow. So it has no impact on later siblings. Therefore, #thing2 will also appear at top-left, because it won't be pushed by #thing1.
What you can do is iterate backwards. This way, when you get the bounding rectangle, previous siblings won't be absolutely positioned yet, so they will push the current element.
function changePosition(element){
var dim = element.getBoundingClientRect(),
pdim = element.parentElement.getBoundingClientRect();
element.style.left = dim.left - pdim.left + "px";
element.style.top = dim.top - pdim.top + "px";
element.style.position = "absolute";
}
changePosition(document.getElementById("thing2")); // First 2
changePosition(document.getElementById("thing1")); // Then 1
<div>
<input id="thing1" />
<input id="thing2" />
</div>
You are doing it wrong. left and top are set to 0 because you subtract the element's left from the parent element's left, which happen to be the same, so you end up with 0.
What actually happens in the example is that first, the first input is made absolute, which causes the second input to end up in the top left corner of the div, because the first no longer takes up space. Then the second one gets the first treatment as the first.
Solution: calculate the current positions first, then apply position to both of them.
The other answers explain the issue pretty well - by making #thing1 absolute you take it out of the flow, thereby making #thing2 jump to the left, so when you do its recalculation, it's over on the left as well.
One other solution is to defer the updates to the position property until after your code completes. You can do this with setTimeout with a delay of 0
setTimeout(function(){
instance.element.style.position = "absolute";
},0);
http://jsfiddle.net/oumt0nkv/10/
I have a series of pictures that I would like to slideDown() from left to right (creating a waterfall effect). I create the waterfall effect using setInterval():
var i = 1;
var numberCount = 5;
var counter = window.setInterval(function(){
$("#instagram-pictures .instagram-picture:nth-child(" + i + ")").slideDown(1200);
if(i === numberCount){
window.clearInterval(counter);
}
else{
i = i + 1;
}
}, 400);
This works without a hitch except the slideDown part. For some reason, my pictures are not sliding down from the width of the entire top line, rather they are "expanding out" from the top left hand corner.
jsFiddle here
How do I fix this?
.slideDown() animates the height of an element, not it's position. You're allowing the width of each picture to be automatically determined based on the height. So as the height changes, it's determining new widths as well, and animating a diagonal stretch.
If you give the images a fixed width you'll get the downward animation you're after.
Source: http://api.jquery.com/slidedown/
Try ths:
Give each image a fixed width
.instagram-picture{
display: none;
width:100px;
height: 160px;
}
The width is determined based on the height and since the height is changing when the image slides down, the width changes with it. Therefore, setting a fixed width will fix your problem!
JSFiddle Demo
I'm trying to implement an effect where an image (it can be of varying sizes) zooms on hover with a border appears around it. The non-zoomed image is limited to a maximum size of 250px and the zoomed to 550px.
I do this by applying a class to the div on mouseenter and remove it on mouseleave. This works well enough, but the problem is that I want to detect if the div goes partly off-screen. To do this I need the offset of the transformed div:
$(document).ready(function () {
$('.image-container').on('mouseenter', function () {
var y = $(this).offset().top,
x = $(this).offset().left;
console.log('old', x, y);
$(this).addClass('image-hover');
y = $(this).offset().top;
x = $(this).offset().left;
console.log('new', x, y);
});
$('.image-container').on('mouseleave', function () {
$(this).removeClass('image-hover');
});
});
If you look at the jsfiddle below, I get the old offsets after adding the class.
http://jsfiddle.net/6JZCW/14/
So, how to get the updated offsets? Is there a better way of doing what I want to achieve?
you are trying to get offset of your $('.image-container'), but its padding never change, you change only the padding of '.image-block' so when you console.log do this
$('.image-block').offset().top;
$('.image-block').offset().top;
I have been looking into parallax effects for vertical scrolling on my web page, and after some research, I'm not sure that what I want to do is technically a parallax effect.
From what I've seen, most parallax effects assume you want to be able to scroll indefinitely with many background images rolling by, or with huge images that repeat.
What I want to do is have the background of two DIVs be filled with a background image as the scroll bar reaches the bottom of the page. Note that I do not want the background images to stretch. I'm assuming to get the effect I want that these images would have a vertical height bigger than most people's viewport, and then their vertical position would change. When the user's scrollbar is at the top, a certain amount of the background is visible, and then it moves vertically to fill the background space as the user scrolls down.
Please see the image below for a visual explanation of the effect I hope to acheive:
The height of the veiwport will vary depending on the length of content inside the inner DIV.
My trouble is that if what I am trying to do is not exactly a parallax effect, then I don't know what else to call it, and my attempts to search by describing it keep landing me back at pages offering tutorials on parallax effects. So I've been stumped by a lack of terminology.
If someone could direct me to how I can control the vertical position of the background depending on the scrollbar position, that would be much appreciated. If this can be done with just CSS that would be great, but I'm assuming some Javascript would be required. A jQuery solution would also work for me.
Update:
After searching using the terms provided in comments, I've got the background image in the outer DIV to almost do what I want with the following code:
$(window).scroll(function () {
var yPos = $("#outerDiv").height() - ($("#outerDIV").height() * ($(window).scrollTop() / $(window).height()));
document.getElementById('outerDIV').style.backgroundPosition="0px " + yPos + "px";
});
It moves the background image in the right direction relative to the scrolling, but what it lacks is constraining that motion to within the viewport. Getting the right proportions based on the viewport and DIV sizes is proving to be just a little beyond my mathematical abilities.
For your requirement, you have to use a jquery parallax plugin to guide this activity, my best suggest it to use a Superscollorama and play with the elements as your wish...
As far as your question, Try this example,
controller.addTween(
'#examples-background',
(new TimelineLite())
.append([
TweenMax.fromTo($('#parallax-it-left'), 1,
{css:{backgroundPosition:"(0 -54px)"}, immediateRender:true},
{css:{backgroundPosition:"(0 -54px)"}}),
TweenMax.fromTo($('#parallax-it-right'), 1,
{css:{backgroundPosition:"(0 -54px)"}, immediateRender:true},
{css:{backgroundPosition:"(0 54px)"}})
]),
1000 // scroll duration of tween
);
You serial vice change as far as your wish...
Try practice this plugin, hope that works for you...
http://johnpolacek.github.io/superscrollorama/
Thanks...
Turns out what I want to acheive is possible with no special plugins, just some carefully thought out math. I did use a little jQuery syntax, but I don't think it's strictly necessary.
The code below has copious notes, so hopefully it's largely explanatory. In summary, you just need to find the position of the background image when the scroll would be at the top, and the position it would be if the scroll bar was at the bottom, and then you can use the percentage of the scrollbar's movement to work out where you are between those two points. It's a little tricker than just that, of course, in that you have to account for the difference between the total height of the scroll bar and where your DIV appears on the page and a few other adjustments, but the details of what I did are below.
What I've done here is just for the "outer DIV" that I described in my question. To get a background to move like the "inner DIV" I described, you'd have to modify the code, presumeably by reversing a few parameters. I haven't done that yet, but it seems like a straightforward task.
Hope others find this code useful. If anyone has suggestions on how it can be made more efficient or better, please let me know.
function moveBG(){
// imageHeight is not the total height of the image,
// it's the vertical amount you want to ensure remains visible no matter what.
var imageHeight = 300;
// Get the maximum amount within the DIV that the BG can move vertically.
var maxYPos = $("#outerDIV").height() - imageHeight;
// Get the amount of vertical distance from the top of the document to
// to the top of the DIV.
var headerHeight = document.getElementById("outerDIV").offsetTop;
// Calculate the BG Y position for when the scrollbar is at the very top.
var bgTopPos = $(window).height() - headerHeight - imageHeight;
// I don't want the image to wander outside of the DIV, so ensure it never
// goes below zero.
if (bgTopPos < 0)
{
bgTopPos = 0;
}
// Calculate the BG Y position when the scrollbar is at the very top.
var bgBottomPos = $(document).height() - $(window).height() - headerHeight;
// To prevent the BG image from getting cut off at the top, make sure
// its position never exceeds the maximum distance from the top of the DIV.
if (bgBottomPos > maxYPos)
{
bgBottomPos = maxYPos;
}
// Subtract the top position from the bottom, and you have the spread
// the BG will travel.
var totalYSpan = bgBottomPos - bgTopPos;
// Get the scrollbar position as a "percentage". Note I simply left it as a
// value between 0 and 1 instead of converting to a "true" percentage between
// 0 and 100, 'cause we don't need that in this situation.
var scrollPercent = ($(window).scrollTop() / ( $(document).height() - $(window).height()));
// The percentage of spread is added to the top position, and voila!
// You have your Y position for the BG image.
var bgYPos = bgTopPos + (Math.round(totalYSpan * scrollPercent));
// Apply it to the DIV.
document.getElementById('outerDIV').style.backgroundPosition="0px " + bgYPos + "px";
}
// Place the BG image correctly when opening the page.
$(document).ready(function() {
moveBG();
});
// Make it update when the scrollbar moves.
$(window).scroll(function () {
moveBG();
});