Why and when did Chromium change the behavior position relative?
Here is an example of the current behaviour. I would expect the offset of #box1 to also shift #box2 downwards, as it used to do so? Instead, it's now as if #box1 is positioned absolutely (in relation to its current position) in the sense that #box2 and the rest of the document completely ignore the offset of #box1.
div {
position: relative;
padding: 20px;
opacity: 0.75;
}
#box1 {
top: 20px;
background: green;
}
#box2 {
background: plum;
}
<div id='box1'></div>
<div id='box2'></div>
This has made it so incredibly difficult to achieve something that should be so simple. What I am trying to do is place a button dead smack in the center of the page. When the user clicks the button, additional boxes are added to the list, positioned relatively.
The list container's height probably should be the same height as the page, so that everything should move upwards towards the top of the page when I scroll through the list.
This use to be easy to do by giving the button a relative position, and then placing it halfway down the page. I remember position relative you used to reflow other elements, but not anymore? Now I am completely dumbfounded.
I guess I could use a pseudo element to offset the first child now that I think of it.
Anyways, two questions:
When and why did Chromium change the behavior position relative? (Or am I tripping and it was never changed?)
How can I go about achieving something like this when the dimensions of the document are unknown since the page is responsive?
Related
The Goal
I'm practicing writing my own simple JavaScript slideshow plugin, and the intended method is to have all of the images -- all of which are the same size -- in the same location on the screen (so all having the same x and y values), but alter their z-indexes to shuffle them in front of or behind each other as necessary, cycling through each of them. The JavaScript is working well so far, but I'm not able to get the images to all layer on top of each other on the page -- they just stack, from the top of their container downward, one per line.
What I've Got
This is a simplified version of the relevant portion of my HTML:
<section>
<div class="images">
<img src="1">
<img src="2">
<img src="3">
</div>
</section>
And the CSS
.images {
height: 15em;
margin: 0 auto;
overflow: hidden;
width: 20em;
}
As you can see, it's not too complex. I'm at a loss as to where to go from here, though. The only way I've been able to get the images to layer the way I want is to apply position: absolute; and top: 0; to the images, but that also throws them outside of their div, and then applying that to the div itself causes the whole layout to go into chaos. So if anyone has any advice, I'd greatly appreciate it! :)
Add position:relative to your .images class. Absolutely positioned elements are positioned with respect to their closest positioned ancestor element.
You need to apply position: relative to the div. That way the images use their parent div as a reference.
One option would be to use the JavaScript to modify the display and visibility CSS attributes to show and hide the images.
visibility: hidden means the element is not visible, but it still takes up space in the page flow.
display: none means the element takes up no space in the page flow.
I've seen browsers behave oddly when display is none but visibility is hidden. I've found it's best to switch both.
For the image you want to be visible, set display: block and visibility: visible
When working with position:fixed; this is the expected result one would get:
What I actually want to achive is:
as in this result when working with two position: relative; elements
Don't get me wrong, I know how position: fixed or position: absolute works and should behave, how I haven't come around how to get both properties for the same div...
One approach wich works, but isn't a satisfying solution is that I put a position: relative -div below my fixed element, not allowing the second element moving below the fixed element because it is already taken by the extra div.
So I have tried to get this second relative div working with :after or :before pseudo-elements. This doesn't quite seem to work
div:after, div:before { position: relative; }
it somehow get's mixed up because the element itself is
div { position: fixed }
and turning fixed and relative around obviously also doesn't work because fixed will be bound to the relative - element.
Any ideas?
And if somebody is wondering why I need to use fixed and don't just go with relative : it's for scrolling reasons.
why not use a margin left on the relative div?
http://jsfiddle.net/q3nQr/1/
html
<div id="fixed"></div>
<div id="relative"></div>
css
#fixed { position: fixed; width: 60px; height:100px; background: red; }
#relative { position: relative; width: 300px;height:1000px; background: green; margin-left:65px; }
UPDATE
Take a look at the w3 spec for static positioning (just read the first two paragraphs).
http://www.w3.org/wiki/CSS_absolute_and_fixed_positioning
Absolutely positioned elements are removed entirely from the document
flow. That means they have no effect at all on their parent element or
on the elements that occur after them in the source code. An
absolutely positioned element will therefore overlap other content
unless you take action to prevent it. Sometimes, of course, this
overlap is exactly what you desire, but you should be aware of it, to
make sure you are getting the layout you want!
Fixed positioning is really just a specialized form of absolute
positioning; elements with fixed positioning are fixed relative to the
viewport/browser window rather than the containing element; even if
the page is scrolled, they stay in exactly the same position inside
the browser window.
This means that elements with fixed or absolute positions do not associate with any other elements in the document, this means they cannot effect the width of another element. If the width of the static element is not known, I think you will need manipulate the DOM with javascript; something as simple as (jquery, not tested):
var staticwidth = $("#static").width();
$("#relative").css('margin-left', staticwidth + 'px');
Isolated test case (view in IE 7 or IE 8/9 in IE 7 mode)
Viewing this page in IE 7 is causing my width value to be ignored. If you remove the padding value, the width is properly applied, but when you add in the padding, it causes the entire page to grow, and it treats the padding almost as margin. The larger the width of the page, the larger the blank area to the right of the element. I've been unable to find which bug this is, and, more importantly, how to fix it. Has anyone seen this and does anyone know a solution?
Things I've tried so far:
zoom fix
display: inline-block (recommended for double vertical padding issue)
It isn't line-height (it's a width issue...)
Screenshot of the issue:
This div should span the entire width of the page, and no more, but you'll notice the scrollbar here:
And the result of scrolling to the right:
This should not be there.
Examining the element in the browser tools shows the width to be incorrectly the full width of the page, instead of the full width minus the padding.
Disclaimer: I'll ignore the functional requirement and your comments on the other answers and just concentrate on the concrete problem.
This IE7 specific problem is caused by using an offset (e.g. top, right, bottom or left) on a relatively positioned element. If you offsets a relatively positioned element, then it will basically still retain the whole space of its original position. Note that this doesn't happen when offsetting absolutely positioned element.
Before the left offset is been applied, the relatively positioned element is due to its width and and the right padding completely out of the viewport and hence a horizontal scollbar will be generated. After the left offset is applied on the relatively positioned element, you're basically leaving a space of the same size as the offset on the other side of the offset, still outside the viewport.
A bit sane webbrowser will during redrawing however discover that there's nothing visible outside the viewport and hence hide the scrollbar again. IE7, however, isn't that smart enough and retains the scrollbar.
After all, using left offset was technically been the wrong solution. You should in first place have used margin-left instead of left. Unlike the offset, the margin doesn't leave an empty space on the original position, but really pushes the whole element to the desired position.
So, here's how your script is been fixed:
$('#el').css({
'width': document.body.scrollWidth - 200,
'padding-right': 200,
'margin-left': (-1 * (document.body.scrollWidth - 322) / 2) - 1
});
By the way, I wonder how that float: left; makes sense in this construct wherein you apparently want to simulate a 100% width. It'll probably be for other purposes not visible in the concrete example.
You can solve this without using javascript for calculating width, and no padding, instead use position: absolute. Here's an updated fiddle. It will work in any browser
#el {
background-color: #FFFF00;
min-height: 45px;
width: 100%;
position: absolute;
left:0;
right: 0;
top: 0;
}
http://jsfiddle.net/LRpHq/7/
I was having this problem with a skeleton.css implementation. Specifically, my #header was taking the width of body, which took the width of html. The remaining content had a set-width of 978px. So when the window was smaller than 978, the background of the header would only render to the width of the viewport. i.e. - if you started the render at 500 wide, that's all the wider #header would get. Dragging a wider width of the viewport had no problems, but right scroll cut the header to the size of initial viewport.
My fix: html,body { min-width:978px } /* your width may vary */
Since you seem to be fine with using Javascript, adjust your resize() function:
function resize () {
$('#el').css({'width':$(window).width(),'position':'absolute','left':'0px'});
}
Fixed the original post as it was off by miles.
edit:
Tested in a sandboxed IE7 and it works. (what can i say, i go out of my way to get something perfect, also am new around here so that bounty would really help to be very honest) to also note that it works natively in IE7, IE8 and IE9, FF3.6, Opera 10 and should work in Safari with no problem, Chrome didn't get mentioned as it's my default browser and it works, no doubt about it.
Here is the JS:
function resize () {
$('#el').trigger('resize').width('100%');
}
resize();
and the CSS:
#container {
width: 320px;
border: 1px solid #000000;
min-height: 500px;
margin: 0px auto;
}
#el {
background-color: #FFFF00;
min-height: 45px;
width: 100%;
position: absolute;
left: 0;
}
i found solution for similar problem here. see if it can helps you too.
Please refer to my site Vault X
I have been trying to make the light switch next to the vault a clickable function.
However, I cannot get my div to stay fixed on this position (adjusting the window size causes it to move about).
What is the best way to achieve this?
Doing position:absolute (or more appropriately here position:fixed) specifies a elements position outside the normal flow of the document relative to the first parent that has a position other than static (in this case (and always with position:fixed) the browser window).
As such, since youve specified a top and a right position, these values are fixed. When you move the right border in, the distance from the browser viewport must stay the same, so the element moves.
You can try positioning from the left, but that will only guard against resizing from the right (if I drag the left corners in, the element will move)
Alternatively, you should position this element statically within the document, within your #wrapper div so that resizing the window has no effect on document flow.
Because your graphic is anchored to the horizontal center of your page, you can use the same center, then offset.
#switch {
height:50px;
width:50px;
background: #F00; /* Just so we can see it */
position: absolute;
top: 150px;
left: 50%; /* Put the left edge on the horizontal center */
margin-left: 148px; /* Move it 148px to the right of the horizontal center, placing it over the lightswitch */
}
What you need to do is, think about where you want the element to be (fixed will stick it in a coordinate location X/Y, absolute, will move with the document, relative is quite clearly relative to where it is).
So with that said, I would recommend creating an 'anchor point' using
<div style="position: relative;" class="anchor-point">
<div style="position: absolute; top: 100px; right: 50px;">
<img href="" />
</div>
</div>
The anchor-point means you can stick this element in an area of your page, the inner part, with position:absolute; lets you move FROM your anchor to anywhere you want (top/right/left/bottom), combine this with z-index to layer your elements just how you want it.
This will guarantee that your element (that is pos:abs) will stay where you want it.
Here's a question that's been haunting me for a year now. The root question is how do I set the size of an element relative to its parent so that it is inset by N pixels from every edge? Setting the width would be nice, but you don't know the width of the parent, and you want the elements to resize with the window. (You don't want to use percents because you need a specific number of pixels.)
Edit
I also need to prevent the content (or lack of content) from stretching or shrinking both elements. First answer I got was to use padding on the parent, which would work great. I want the parent to be exactly 25% wide, and exactly the same height as the browser client area, without the child being able to push it and get a scroll bar.
/Edit
I tried solving this problem using {top:Npx;left:Npx;bottom:Npx;right:Npx;} but it only works in certain browsers.
I could potentially write some javascript with jquery to fix all elements with every page resize, but I'm not real happy with that solution. (What if I want the top offset by 10px but the bottom only 5px? It gets complicated.)
What I'd like to know is either how to solve this in a cross-browser way, or some list of browsers which allow the easy CSS solution. Maybe someone out there has a trick that makes this easy.
The The CSS Box model might provide insight for you, but my guess is that you're not going to achieve pixel-perfect layout with CSS alone.
If I understand correctly, you want the parent to be 25% wide and exactly the height of the browser display area. Then you want the child to be 25% - 2n pixels wide and 100%-2n pixels in height with n pixels surrounding the child. No current CSS specification includes support these types of calculations (although IE5, IE6, and IE7 have non-standard support for CSS expressions and IE8 is dropping support for CSS expressions in IE8-standards mode).
You can force the parent to 100% of the browser area and 25% wide, but you cannot stretch the child's height to pixel perfection with this...
<style type="text/css">
html { height: 100%; }
body { font: normal 11px verdana; height: 100%; }
#one { background-color:gray; float:left; height:100%; padding:5px; width:25%; }
#two { height: 100%; background-color:pink;}
</style>
</head>
<body>
<div id="one">
<div id="two">
<p>content ... content ... content</p>
</div>
</div>
...but a horizontal scrollbar will appear. Also, if the content is squeezed, the parent background will not extend past 100%. This is perhaps the padding example you presented in the question itself.
You can achieve the illusion that you're seeking through images and additional divs, but CSS alone, I don't believe, can achieve pixel perfection with that height requirement in place.
If you are only concerned with horizontal spacing, then you can make all child block elements within a parent block element "inset" by a certain amount by giving the parent element padding. You can make a single child block element within a parent block element "inset" by giving the element margins. If you use the latter approach, you may need to set a border or slight padding on the parent element to prevent margin collapsing.
If you are concerned with vertical spacing as well, then you need to use positioning. The parent element needs to be positioned; if you don't want to move it anywhere, then use position: relative and don't bother setting top or left; it will remain where it is. Then you use absolute positioning on the child element, and set top, right, bottom and left relative to the edges of the parent element.
For example:
#outer {
width: 10em;
height: 10em;
background: red;
position: relative;
}
#inner {
background: white;
position: absolute;
top: 1em;
left: 1em;
right: 1em;
bottom: 1em;
}
If you want to avoid content from expanding the width of an element, then you should use the overflow property, for example, overflow: auto.
Simply apply some padding to the parent element, and no width on the child element. Assuming they're both display:block, that should work fine.
Or go the other way around: set the margin of the child-element.
Floatutorial is a great resource for stuff like this.
Try this:
.parent {padding:Npx; display:block;}
.child {width:100%; display:block;}
It should have an Npx space on all sides, stretching to fill the parent element.
EDIT:
Of course, on the parent, you could also use
{padding-top:Mpx; padding-bottom:Npx; padding-right:Xpx; padding-left:Ypx;}