Pinned elements that are centered with CSS break when window resizes
alancolyer opened this issue · 11 comments
Hi there,
I've really been enjoying using this plugin so far, it has worked some serious magic with the project I'm working on.
However I ran up against an issue I haven't been able to work out, when resizing the browser window.
I have a div structure similar to:
<div class='wrapper'>
<div id='myPin' style='width:20px;height:20px;left:50%;margin-left:-10px;position:absolute'>My Pin!</div>
</div>
I hope that illustrates the kind of positioning I'm after.
Now before the element is pinned, it stays in the center of the screen regardless of resizes. However after the element gets pinned, it is given an absolute left value in Pixels, which must be calculated by the script. This is a problem because it breaks when you resize the window - pin stays where it is, the rest of the screen moves and it's no longer centered.
I've tried running checkAnim when the browser window resizes and even changing the css of the pinned element to left:50% and margin-left: -10px to re-center it - this works but when you scroll again the script changes the css back.
So what I need is either a way to directly edit the left PX value of the Tween on the fly, or a way to make superscrollorama recalculate the positions of all the animations for the pinned elements - anyone have any ideas?
I've written an extension to add support for re-centering pinned elements when the browser window resizes, if you're using the same kind of positioning that I am (left 50%, then negative left margin of half the element's width).
Just hook into window.resize and run controller.fixPins() when your window resizes and you need to update the pinned element coordinates.
superscrollorama.fixPins = function(){
var windowWidth = $(window).width();
var count = pinnedObjects.length;
for (var index = 0; index < count; index++)
{
var pinObj = pinnedObjects[index];
var el = pinObj.el;
var l = (windowWidth/2); //the new left position - i.e same as the pixel equivelant of left:50%
el.css('left', l+'px');
if (pinnedObjects[index].fixedPositioning && pinnedObjects[index].fixedPositioning.left)
{
pinnedObjects[index].fixedPositioning.left = l;
}
if (pinnedObjects[index].origPositioning && pinnedObjects[index].origPositioning.left)
{
pinnedObjects[index].origPositioning.left = l+'px';
}
if (pinnedObjects[index].spacer.length)
{
pinnedObjects[index].spacer.css('left', l+'px');
}
}
return superscrollorama;
};
Hi Alan,
this looks really interesting.
Can you supply a demo page so I will be able to avoid this issue for ScrollMagic (Superscrolloramas future Version).
regards,
Jan
Hi Jan,
I'll try to put something up and link to it, not sure if I'll get the time though so I might just end up linking to my project when it goes live lol.
Will update once I've sorted something out....
Well a simplified version, only reduced to the described penomenon would be far preferable.
So if you could do that it would be much appreciated.
Take your time though and launch your project first :)
I snuck some time and did a (very) simple example, you can find it here: http://alancolyer.com/superscrolloramatest/
I hope that makes enough sense to get an idea of the problem I was trying to solve - it's not a perfect solution but something like that built into the next version would definitely make it more flexible. It caters for a fairly common use when you want a responsive layout with something pinned in the center of the screen, which was mostly what we needed it for.
Hope that helps, if you have any questions or if it doesn't make sense I'll do my best to explain further.
Hi Alan,
this is a very cool demo!
I will definitely work this into SrollMagic using it.
If you have to take it offline, please zip and and email it to me.
thank you and kind regards,
Jan
Hi Jan,
no problem, I won't need to take it down :)
Hi Alan,
thanks to your demo I fixed this issue for ScrollMagic.
The Reason for it is simple. When pinning an Element I need to convert its position to fixed. to do this I use the jQuery.css() method to get top and left position etc.
The curious thing though is that this always returns pixel values (even though you defined percentage values in your css).
So I found there are three ways to address this:
1.) calculate the correct pixel values on resize (similar to what you did)
2.) parse the Stylesheet for information about percentage positioning
3.) Rely on inline styles (<div style="left: 50%">
) to achieve this effect.
You can read more on this issue and how to approach it here and here.
I ultimately decided against the first two options for the following reasons:
1.) this would make the need for an additional parameter to the pin method. i.e. "leftPosRelative". Then I'd need to find out in relation to which element the position would need to be calculated, which may vary, according to DOM. All in all I found this too cluttering and unrelyable.
2.) since there are virtually unlimited ways of applying CSS rules in a stylesheet there is absolutely no relyable way to make sure you have the correct definitions, if you set out to do it for all users...
3.) this is the way I ultimately went with. There are no calculations needed and best flexibility. So if a user wants to position the pinned element centered he has to use inline styling to set left to 50%. If nothing is set $.css() will be used like before.
I think think this is the best solution and I already put to work using your example.
Check this out:
http://www.janpaepke.de/tmp/ScrollMagic_relative_positioning/positionfix_SCROLLMAGIC.html
So... one down! :)
regards,
J
Awesome! I took a look at the demo, you've nailed it and I think your solution is a good "one size fits all" approach that won't limit or break compatibility - nice one :)
On a related note, our clients are very happy with the project we built using superscrollorama - thanks for writing such a great plugin :)
Well a lot of the credit goes to John, as he started it.
But thanks! :)
Be sure to send us a link once it's public.
regards,
J
HA! I got an even better solution!
I was scrolling further down the pages on stackoverflow I send you and there was this one guy that suggested to hide the parent, read the css value and then show the parent again.
This prevents jQuery vom calculating the pixels and returns the percentage instead.
This is awesome, now it works like a charm even with stylesheet definitions only!
I updated the demo, check it out! :)
regards,
J