Fixed placed element within certain area - javascript

I have a page where I display a long list of results from a DB query.. and I also show a Google Map to the RIGHT of this long list.
Map is roughly 240px wide and maybe 600px long/height.
This MAP is inside a container DIV (#mapContainer).. that contains the map, and a dropdown box above the map canvas.
Currently, the mapContainer scrolls along with the page itself.. what I would like to do is have it be static/fixed element. So it starts/displays/is placed where I have it currently on the page.... if I scroll the page.. the map should stay fixed.. until the end (bottom) of the results are scrolled to..
(I dont want the mapContainer to scroll and cover the footer element/div)
Following this tutorial:
http://www.webgeekly.com/tutorials/jquery/a-simple-guide-to-making-a-div-static-as-you-scroll-past-it/
It doesnt stay fixed..
//sticky map placement
$(function () {
var msie6 = $.browser == 'msie' && $.browser.version < 7;
if (!msie6) {
console.log("NOT IE 6");
var top = $('#mapContainer').offset().top;
$(window).scroll(function (event) {
console.log("scrolling.......");
var y = $(this).scrollTop();
if (y >= top) {
$('#mapContainer').addClass('fixed');
console.log("class added");
}else {
$('#mapContainer').removeClass('fixed');
console.log("class removed");
}
});
}
});
The first console.log() outputs fine.. but nothign in the window.scroll() portion fires ever.
Rest of code used:
#mapContainer{
display:table;
width:240px;
float:right;
/* sticky map */
position: absolute;
top: 458px;
left: 50%;
/* width: 100px; */
margin-left: 339px;
}
#<span class="skimlinks-unlinked">mapContainer.fixed</span> {
position: fixed;
}
On the tutorials page itself.. he has a toolbar on the left side..
that stops 'being fixed' when you scroll all the way to the top.. (it will start to move with the rest of the page scroll at a certain point).. and it doesnt go all the way down to cover the footer either.
I'm not clear why the jQuery portion isnt firing.. and I'm not clear what that last style is for? (seems odd looking)
All this absolute, fixed, relative, to parent, to viewport..etc.. is confusing.
Any easy to read/follow/understand tutorials that will get me to where I want to be? Or suggestions on what I am doing wrong with the correct approach?

I looked at your Fiddle and noticed a couple things:
Your "fixed" class was not represented in the CSS. When I looked into the CSS I saw a span element wrapping a ".fixed" reference with a position property set.
You are styling the mapContainer div using the ID. This is a very rigid selector as the order of CSS selectors goes. The hierarchy of CSS selectors is specifid and IDs will override types and classes. See: http://htmlhelp.com/reference/css/structure.html
The when scrolling, I am seeing the console logging in my dev tools. Also, when inspecting the element, I am seeing it add and remove the class name.
Based on my observations, modifying the CSS selector for your container should do the trick. Adding the ID to the class will keep the CSS rule specific enough:
#mapContainer.fixed { position: fixed; }
Refer to this updated Fiddle for an example with these changes in place:
http://jsfiddle.net/pmurst8e/4/
Update: For demonstration purposes of what I was referring to with the resize I modified your example a bit. It isn't the prettiest, but it conveys the point: http://jsfiddle.net/pmurst8e/6/
Update: There are a couple issues with the latest Fiddle (v12):
The sidebar will always go fixed the moment you scroll because "top" is never calculated. It's being set to zero, and the offset calculation is commented out.
Absolute positioning is relative to the closest positioned parent. If no parent is positioned, it's relative to the window. To constrain an absolute positioned element, set the constraining parent to "position:relative;".
Instead of using a percentage and left position rule, consider positioning the sidebar to the right, relative to the "contentContainer", by a set number of pixels.
When the fixed position takes effect, we also need to set the sidebar fixed left position. Otherwise, it will use the positioning in the CSS. In contrast to absolute positioning, Fixed positioning is relative to the window, meaning an absolute element "right: 10px" will be 10px from the right of the positioned parent, but will appear 10px from the right of the window when fixed.
You don't need a float when you have absolute positioning. Absolute position removes an element from the normal flow of the document, and because of this float does not apply.
I updated the Fiddle to show how to make these adjustments. I cleaned out the float and margin from the mapContainer and left the absolute positioning. With that I set the contentContainer to relative to constrain mapContainer to it. You will also see, on the script side, I added a line to set the offset of mapContainer. Without this, when it becomes fixed it will be 10px off the right border of the window.
Updated Fiddle: http://jsfiddle.net/pmurst8e/14/
Also, you want to leave your top offset line in tact. Without that, it goes fixed the moment the scroll moves and never goes back. When that becomes the case, you're better off just setting fixed permanently.
var top = $('#mapContainer').offset().top; // you want this
Regarding the bottom boundary, you can do a couple things:
Resize the sidebar so that it shrinks to the window size. This is demoed in my example from my first post in this and the downside is it forces the sidebar to become a scrollable div so the child content is all visible.
Use a check for the bottom so that when you hit the limit, the container goes back to an absolute position, but one set at the bottom: 0 of the parent.
Something like:
var limit = $('footer').offset().top;
var $mc = $('#mapContainer');
var pos = $mc.offset().top + $mc.outerHeight();
if (pos >= limit) {
$mc.removeClass('fixed')
.addClass('bottom-set').css('left',''); // define this in CSS for bottom absoluteness
}
#mapContainer.bottomFixed {
bottom: 0;
top: auto;
}
And to be fully honest, you might save yourself some time working this all out if you take a look at the ScrollToFixed plug-in (https://github.com/bigspotteddog/ScrollToFixed). I seem to be mentioning it quite a bit lately, but this issue seems to be a popular one right now.
Incidentally, go to your OP and click the Edit button. Shrink the height of your browser and scroll down. You should see SO has a fixed sidebar that passed the footer. ;)

Related

Image resizes when position is changed to fixed on scroll

I would like an image to become fixed where it is once it appears on screen during a scroll, but become unfixed if the user scrolls back up.
However, when I use a JS on scroll function to change the image position to fixed, it suddenly "jumps"/resizes, and I'm not sure why. My fix was to create variables that alter the width and left values of the image after it becomes fixed, but I want to do this will multiple images on a page and each one seems to require a different width and left adjustment. I'm not sure what is conceptually causing this issue. Simply resetting the width and left to their original values does not work. Does a fixed position resize and image.
Here is a jsfiddle of the issue. And here is the code. JS:
var sitckyImageWidth = "38.4%";
var normalImageWidth = "48%";
document.addEventListener("scroll", function(){
var windowTop = $(window).scrollTop();
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
//loop through each div and grab top/bottom/midpoint info and find id
$('.articles').each(function(i){
var top = $(this).offset().top;
var bottom = top+ $(this).height();
var midPoint = (bottom+top)/2;
var thisId = this.id;
var newId;
//use container div info to find media info
var newId = thisId+"Media";
var sectionImage=document.getElementById(newId);
var sectionImageTop = $(sectionImage).offset().top;
//if article is on the page, change position to fixed and set top position
if (top<=windowTop&&bottom>windowTop){
$(sectionImage).css("top","10px")
$(sectionImage).css("position","fixed")
//$(sectionImage).css("width",sitckyImageWidth)
}
//if container is not at top of the page, return to relative
if (bottom<=windowTop||(bottom>windowTop&&top>windowTop)){
$(sectionImage).css("position","relative")
}
})
}); //end scroll
Position fixed means that an element will have relative sizes and positioning in relation to the viewport, not their parent elements.
Specifically what is happening here is that your div with ID article1Media is set to have a width of 48%. When it has the CSS property of position: relative then that resolves as 48% of the width of it's containing element (the div with id article1) however when it is position fixed that resolves as 48% of the width of the viewport. Since there is an implicit 8px margin on the <body> element then these are different.
There are a few different solutions to this, and how you tackle it depends on how you want to build your site.
Example fix 1
A simple fix for your immediate example is to simply add the following CSS.
body{
margin:0px;
}
.image{
margin:8px;
}
https://jsfiddle.net/Chipmo/k56qkk5b/13/
This moves the implicit margin onto the image element. Of course you can set it to whatever you like, or omit it entirely.
Look into CSS resets for more information about overriding implicit default styles, though be warned that it is possible to cause problems with overzealous reset codes.
( Edit: To be clear the above code is definitely not a drop in code for this problem everywhere. It will only work on quite simple HTML pages like your jsFiddle. )
Example fix 2
Another technique you could consider is locking the width and height to it's initial values using jQuery .width() and .height() functions. This would be inflexible, and you would have to do extra work to make it responsive (for mobile etc), but could be appropriate in some circumstances.
Example fix 3
A more portable solution might be to eschew relative sizing in favour of fixed widths and then use CSS media queries for reponsivity. Something like this:
.image{
width:500px;
}
#media(min-width:800px){
width:300px;
}
Example fix 4
If you wish to preserve the 'fluid' nature of using percentages I would suggest looking into using calc along with an offset that gets applied when the position is fixed (so, you add a class when you make the image fixed) that adjusts the sizing appropriately.
.media.image-fixed{
position:fixed;
width:calc(48% - 8px);
}
See this example https://jsfiddle.net/Chipmo/6mu2Lt9g/2/
Above behavior is observed since because of applying the position property not because of the scroll.Please take a look at the following link Position Properties
Position Fixed : Fixed position elements relative to document not on
any parent container.Hence occupies the complete width available.
Position Relative: Relative positioned elements behaves relative to hosted
containers.And inner elements consumes the hosted parent width.

Fixed side menu inside wrapper

So I have a site that is contained in a wrapper that has a max width. This site also has a fixed side menu that is toggled with a button.
My issue is having the fixed side menu to stay inside the page wrapper as fixed elements are relative to the window not the parent element.
Here is an example using position: fixed: https://jsfiddle.net/okavp4p1/
As you can see the menu is coming out from the side of the viewport, not the wrapper (grey area).
I have found away around this using position: absolute: https://jsfiddle.net/5q3hn1fq/
Here you can see the menu is coming out of the wrapper. (correct)
But I had to write some extra jQuery to spoof fixed positioning on scroll.
// Fix menu
$(window).on('load scroll resize', function() {
navigation.find('ul').css('top', $(window).scrollTop());
});
But doing it this way causes glitches/lag on most web browsers. Though the example isn't to bad when scrolling but when implementing this on an actual site with tons more elements/code it becomes very obvious.
Here is what it looks like in use when scrolling down the page:
I have thought of disabling scrolling when the menu is open but I was just wondering if anyone can help?
there is a work-around for this. you need to create a bar at the top with position:fixed. This bar should have height: 1px and no background-color so you can't see it.
then you can add your navigation inside of there, and float:right. when you float right, it will show up, but will be pinned to the invisible fixed bar at the top. also, you have to give the nav a width of 0 so its invisible. then you can transition its width to 100px or whatever you want on button click.
finally, use jQuery to set its height to the height of the window on resizing of the window, and when you show it.
here's the fiddle: https://jsfiddle.net/ahmadabdul3/pptggn6v/1/
since the bar is inside a position:relative bar, it shouldn't jump around as much (or at all)
do NOT add right or left padding to the navigation though, this will break the effect. instead, you can put a container around the nav, and make the nav width: 90% or something so it appears to have some padding.
here's an updated fiddle with how the padding should be: https://jsfiddle.net/ahmadabdul3/pptggn6v/2/
If performance accross all browsers is the issue, you could re-write your function using plain .js instead of jquery.
I couldn't replicate the jittery movement in chrome, but the below should be put less strain on the browser.
$(window).on('load scroll resize', function() {
document.getElementById('nav-list').style.top = window.scrollY + 'px';
});
https://jsfiddle.net/hb4zsL6g/

Make Divs Absolute Only To Each Other

I have <div> elements as pages, and "next" and "back" buttons to switch between them. When the "next" button is clicked, the current page fades out and the next page fades in, using jQuery. As I've been doing it so far, the only way to ensure that the divs sit on top of each other instead of sitting next to each other is to style them position:absolute. However, this forces the divs to also overlay anything else on the page that they would otherwise push out of the way.
Is there any way to make divs basically positioned absolute only relative to each other, and still act as though they are positioned relative to the rest of the page? I've tried putting them inside a container that is positioned relatively, but the divs overflow their container, making it more or less useless.
Edit:
Basic fiddle: http://jsfiddle.net/9AXS4/4/
Yes, I mix up $ and jQuery. I've been using jQuery a lot after calling jQuery.noConflict()
If your pages, as you call them, are of fixed width and height, then you can set their container to be position:relative and also have the width and height of the pages..
.container{
position:relative;
width:500px; /*the total width of a page, including padding and borders*/
height:400px; /*the total height of a page, including padding and borders*/
}
This way the container element will handle the pushing around of the other elements
Here is your corrected fiddle: http://jsfiddle.net/gaby/9AXS4/2/
(the width/height of the container must account for paddings and border on the page elements)
Also you were targeting the container with .pagecontainer instead of #pagecontainer (since you used an id)
Update (after comment about arbitrary heights..)
Since your pages height is not fixed, you will need to resort to jQuery to resize the container..
Here is a full demo : http://jsfiddle.net/gaby/9AXS4/7/
The divs can't be positioned absolute in relation to each other, but they can be positioned absolutely in relation to an outer div. The container that holds the page divs should have position: relative in order to contain the inner page divs that are absolutely positioned.
If there is unwanted overlap, you can use overflow: hidden or overflow: auto on the outer div to hide it, depending on whether or not you want to allow for scrolling. If you are going to use the overflow property, be sure to include a height and width so the browser knows where the overflow should be.
http://jsfiddle.net/vkTXs/
$(".page").each(function(){
jQuery(this).hide();
});
$(".page").first().show();
$(".next").click(function() {
jQuery(this)
.parent().fadeOut()
.next().fadeIn();
var page = $(this).parent().next();
resizeContainer(page);
});
$(".back").click(function() {
jQuery(this)
.parent().fadeOut()
.prev().fadeIn();
var page = $(this).parent().next();
resizeContainer(page);
});
function resizeContainer(page){
// get height of next page
var newPageHeight = $(page).height();
// add padding and border
newPageHeight = newPageHeight + 14;
$('#pagecontainer').height(newPageHeight);
}

positioning the popup menu with jquery based on element position in window

I am sure this question may have been asked, but I couldn't find the right solution..
I need to show a menu on mouse over of an icon which can be placed anywhere on the page. Example code is here: ( http://jsfiddle.net/Qfjdk/2/ )
This shows the popup, however if I change the code from
#nav {
margin:0;
padding:0;
list-style:none;
float: left;
}
to
#nav {
margin:0;
padding:300px;
list-style:none;
float: right;
}
As can be seen, the position of the menu is always centered below. I want to change the position of the menu based on where the icon is displayed.
If the icon element is aligned right, I want to position the menu to start on right edge of icon. If the icon element is towards bottom left of displayed page, I want the menu bottom left to align with element top left etc..
I am not looking for the algorithm, am looking for the right way of setting parameters..
Appreciate your help
I would first define how many alternatives you want to support (for example, 4: button on right-top, right-bottom, left-top or left-bottom), and create a set of classes with these different options (.pos1, .pos2, .pos3, .pos4).
Then I'd use JS or jQuery to calculate the offset of the icon relative to the window. Depending on that result, I would give the popup the correct class from the ones you previously created. You can do this on load as well as on window resize. For example, calculating a distance to the right and applying css changes (you could apply a class instead, but this is just to show how it'd work):
var callback = function () {
// when hover on an element, calculate offset to right
$('.yourElement').mouseover(function(){
var currentElement = $(this);
var distanceRight = $(window).width() - ($(currentElement).offset().left + $(currentElement).width());
// If the distance is less than 50, then do...
if (distanceRight < 50) {
$('.yourPopup').css("left","-200px");
}
else {}
});
};
$(document).ready(callback);
$(window).resize(callback);

Issue when scrolltofixed plugin switches to position: absolute

i'm having a problem using the scrolltofixed jquery plugin
https://github.com/bigspotteddog/ScrollToFixed
i use:
$('#tostick').scrollToFixed({ limit: $('#app-footer').offset().top - $('#tostick').height() - 20});
my #tostick is inside a
margin:0 auto
div container and as soon it hits the fixed footer and the script switches from fixed to absolute positioning it jumps out of the container because
left: 1107px
is applied, which is the distance to the left border of the browser window, instead of the left border of the centered div container. it tried to add:
offsetLeft: -$('#container').offset().left
which is completely ignored.
thanks in advance for any tip!
You need to give more info we don't know what #tostick is. Obviously we need the whole JS, and related html and css. Have you tried moving the entire container div it its only purpose is to have a style of margin:0 auto?
Also you can do:
$('#tostick').bind('unfixed', function() { $(this).css('left', ''); });//or what it needs to look right
$('#tostick').bind('fixed', function() { $(this).css('left', '1107px'); });//switch back to what it was

Categories

Resources