Transformed body fixed-position div aligning to body, not window - html

I have created a <div> fixed, set the following styles on it:
#mydiv {
position: fixed;
left: -150px;
width: 150px;
top: 0;
bottom: 0;
border: 1px solid #f00;
}
This produces a <div> that is offscreen, and presumably the same height as the window.
Then I apply the following styles to the <body>:
body {
-webkit-transform: translate(150px, 0);
}
To my knowledge, this should move the body 150px to the right, thereby moving #mydiv into view. This works, but now #mydiv is the height of the body, not the height of the window.
Here's a JSFiddle example
Is this a Webkit bug? Or is this something I'm doing wrong?
EDIT:
This appears to happen on Firefox as well.

The solution to this problem, while perhaps not immediately intuitive, is pretty straightforward.
html, body {
height: 100%;
}
Normally position: fixed elements are aligned relative to the window (the parent of the html element). When css transforms are applied, however, position: fixed elements are aligned relative to the closest parent with a css transform applied.
The alternate approach Webkit and other browsers could have taken, would be to still align position: fixed elements to the window. But the problem with this would be the position: fixed div would not move at all when the body was transformed, and so the div would still be positioned offscreen.

Related

Fixed element positioning relative to its parent

I have an element that gets position: fixed while dragging. This element is inside a modal that is a direct child of the body element.
On the image below, the modal is gray, the rest of the body is black, and the button is blue. When I add the following styles to the button:
position: fixed;
top: xxxpx;
left: -100px;
It positions the button relative to the modal, not the viewport. Is that even possible that an element with position: fixed be positioned relative to something but the viewport? It acts like an absolutely positioned element instead.
'normally' position fixed fixes relative to the viewport.
But there are exceptions. See MDN
The element is removed from the normal document flow, and no space is created for the element in the page layout. It is positioned relative to the initial containing block established by the viewport, except when one of its ancestors has a transform, perspective, or filter property set to something other than none (see the CSS Transforms Spec), in which case that ancestor behaves as the containing block. (Note that there are browser inconsistencies with perspective and filter contributing to containing block formation.) Its final position is determined by the values of top, right, bottom, and left.
Here's a simple example:
body {}
.parent {
position: relative;
margin: 100px;
transform: scale(1);
width: 50vw;
height: 10vw;
background: black;
rfilter: blur(1);
}
.child {
position: fixed;
top: 0px;
left: 0px;
width: 100px;
height: 100px;
background-color: blue;
}
<body>
<div class="parent">
<div class="child"></div>
</div>
</body>
Notice that the blue child element is placed at the top left of its parent. Its parent has a transform - and as it's scale(1) we might assume it doesn't do much. But it does create the parent as the containing block.
I think your problem is the transform on the parent.

CSS - Mozilla absolute position full width issue

Fiddle -
We've got some divs displayed as table/table cell.
Single Cell is 50% wide, We've got absolute positioned element inside first cell-div. This element is 100% wide, but its parent is 50% wide.
On Chrome absolute positioned element is 100% wide of its parent, and on Mozilla Firefox its 100% of screen. Have you idea why is that?
My goal is to make it 100% wide of this parent, and also note that I need it to be absolute positioned.
redTry giving width:inherit for #main.
#main {
width: inherit;
height: 100%;
position: absolute;
top: 0;
opacity: 0.5;
bottom: 0;
z-index: 100;
background: pink;
}
//below is the hack for chrome.
#media screen and (-webkit-min-device-pixel-ratio:0)
{
.d-td div#main
{
width: 100%;
}
}
It happens because Mozilla doesn't support position: relative for any display: table-cell elements. Remove position: relative from table-cell element and create a <div> with position: relative inside it. All position: absolute elements inside this div will be positioned properly.

Lack of outermost margin with smaller viewport

I have a <div id="wrapper"></div>​ with
#wrapper {
height: 300px;
margin: 10px;
position: absolute;
top: 0;
left: 0;
width: 400px;
}​
When I resize the viewport so that horizontal scrollbars appear, the right margin disappears; I can only scroll as far right at the element's content, but I want the margin to be present on all sides. It also happens to the left margin if right: 0; is applied, and to the bottom margin if the viewport is made shorter. Giving wrapper a position: static; (default) makes no difference.
Why is this happening? It doesn't follow normal margin collapse rules. How can I get my margin back? I've tried giving the body padding/margin.. nada.
jsFiddle
Background Info
The default width of the body element is the html width which is also the window width (or iframe width in such a case). The default behavior of a block level element is that the scroll only accounts for the actual element (hence, it doesn't care about the right margin if there is nothing more to display on the right). This causes your right margin issue. (By the way, according to this article, the scroll bars are actually appearing on the html element, not the body.)
For Position: Absolute
By having #wrapper with position: absolute, the body element ends up with zero height. This causes your bottom margin issue in this case.
A solution is to account for the margins like so (see fiddle):
body {
min-height: 320px;
min-width: 420px;
}
This assigns a minimum dimension to the body equal to the width + margins and height + margins of the absolute element.
Now, I'm not sure what you expect to happen if you have right: 0 set, as forcing a left margin to "remain" just ends up causing, in my opinion, a premature scroll bar to activate. See this fiddle.
Regarding Position: Static
The default block level behavior can be changed by forcing a shrink-wrap like behavior on the body element using (see fiddle):
body { display: inline-block; }
Note: that body { float: left; } did not give me the same shrink-wrap behavior (see fiddle).
The inline-block element will account for the margin of its inner elements to determine its own width, which then allows the right margin to work.
The reason the display: inline-block; solution does not work on the #wrapper being position: absolute is because it makes the body have a zero width and height, since the absolute positioning takes that element out of flow and there is nothing left inside body to give it dimension.
The above was currently only tested on IE9.
I'm afraid there's only one simple and quick solution, and that is to create a new div inside the wrapper div.
http://jsfiddle.net/QHKmN/2/
CSS
#wrapper {
background: black;
height: 300px;
margin: 10px;
position: absolute;
top: 0;
left: 0;
width: 400px;
}
#inwrapper {
background: green;
height: 290px;
margin: 5px auto;
position: relative;
width: 390px;
}
​
HTML:
<div id="wrapper">
<div id="inwrapper">
</div>
</div>
​
And there's your margin.

Place a footer with Content positioned as absolute

I have a wrapper class that contains all the content on the web page. the problem is if the content is absolutely placed, it eats my footer. I have to place the content as absolute positioned.
It seems like the footer doesnot recognize that the content is absolute. Heres my code
<style>
* {
margin: 0;
}
html, body {
height: 100%;
}
.wrapper {
min-height: 100%;
height: auto !important;
height: 100%;
margin: 0 auto -4em;
}
.footer, .push {
height: 4em;
}
</style>
</head>
<body>
<div class="wrapper">
<img src="activity/Chrysanthemum.jpg" style="z-index: 1; position:absolute; width: 420px; height: 400px; left: 100px;top:260px; ">
<div class="push">
</div>
</div>
<div class="footer" >copyrights</div>
</body>
If I change the image style by removing the position:absolute property , everything looks normal. so my question is how can we place the footer at the bottom with absolute positioned contents?
Updated answer, regarding comment.
As I mentioned at my previous answer, this effect cannot be achieved using pure CSS. So, I will show the JavaScript approach. Add relevant IDs (see Fiddle), and add the following code at the end of your body. This code snippet will resize your wrapper when necessary.Note: When the page is smaller than the window's height, the page wrapper will still take the full height, because it's not possible to distinguish a height change by an absolutely positioned element.
<script>
(function(){
var wrapper = document.getElementById("wrapper");
var height = document.documentElement.scrollHeight;
wrapper.style.height = height + "px";
})();
</script>
Previous answer:
The issue is caused by the fact that absolutely-positioned elements do not affect the height/width of their parent.
To fix your code, apply the following CSS (only showing relevant CSS, updated postfixed by descriptive comments). Fiddle: http://jsfiddle.net/4ja2V/
html, body {
height: 100%;
width: 100%;
padding: 0; /* Get rid off the padding */
}
.wrapper {
position: relative; /* Necessary to properly deal with absolutely positioned
child elements. */
height: 100%;
margin: 0 auto 4em; /* So that the content is visible when scrolled down*/
}
.footer {
height: 4em;
position: fixed; /* Positions your footer at a fixed position in the window*/
bottom: 0; /* At the bottom of the window*/
}
You were using a negative bottom-margin for .wrapper, which caused the element to "eat" the footer. When you're using absolutely poisitioned inner elements, there's no reliable pure-CSS method to get the real width/height of the .wrapper element. Hence the appearance of position:fixed.
The footer is defined to have a height of 4em. Because the footer is positioned at a fixed position (ie, the element won't move when scrolling down), it's necessary to apply an additional margin at the bottom of the wrapper element.
give your footer a fixed hight and then in your absolute class, do
bottom: heightOfYourFooter + 5px;

Div on top of Div using z-index

I have the following divs in my HTML:
<div class="main">
<div class="bgimage"></div>
<div class="content">Text</div>
which is directly inside my body.
With the following CSS:
body {
margin: 0;
padding: 20px 0;
}
.content {
filter: alpha(opacity=50);
-moz-opacity: 0.5;
opacity: 0.5;
}
.content {
position: relative;
z-index: 1;
border: #000 thin solid;
width: 960px;
margin-left: auto;
margin-right: auto;
background-color: #000;
}
.bgimage {
position: absolute;
z-index: -1;
width: 1024px;
height: 768px;
margin-left: auto;
margin-right: auto;
background-image: url(bg1.jpg);
}
Basically, I have a Div that with a display of a background image, and I will have another Div on top of this with transparency. This current code works, but my problem is when I am trying to take the content div down from the top.
When I add margin-top:100px, for example, is also brings the image down. I thought it would not touch it if it is not on the same z-index? Why does adding a margin also force the bgimage div down?
I have also tried making the div with class of content a position of absolute and a zindex, but then this won't centre. How should I solve this?
your CSS should be
.bgimage { position: relative; }
.content { position: absolute; }
so the .content will be positioned relative to the .bgimage
your current CSS makes the .bgimage position relative to the document.
see this link on CSS positioning
z-index has no relation to positioning: it only affects the rendering order of your elements. Position: relative tells the browser to render the element at the place it should be, and offset it by eventual left, right, top or bottom coordinates. Therefore, margins, paddings, etc. still affect it.
Only position: absolute guarantees position independance.
I see no need for "z-index"es or "position: absolute" in your code at all -- unless you have other complications that you have not revealed to us.
To center the background on the DIV class="main":
body{margin:0;padding:20px 0;}
.main{background:transparent url(bg1.jpg) no-repeat center top;}
.content{border:#000 thin solid;width:960px;margin-left:auto;margin-right:auto;background-color:#000;opacity: 0.5;filter:alpha(opacity=50);-moz-opacity: 0.5;}
The "center top" places the center-top of the background image on the center-top of the element it's applied to. You may want to apply a
min-width:1024px;_width:1024px;
to the same element -- to prevent a narrower window from hiding the edges (this will change how the element is rendered if the "viewport" is narrower than the background's dimensions).
The only thing your pre-modified code it can do that my modified code can't:
Crop the background image (if it is not natively 1024px x 768px) by using the css "width" and "height" properties
If the class="main" element already has a background image set, most browsers don't support the CSS3 required to stack multiple backgrounds on the same element
Some of what was stated about "z-indexing" and the "position" property above was correct but failed to mention:
you've taken your class="content" element out of "the flow". The ancestor elements won't grow when the content of class="content" element grows. This is an important and fundamental difference between "z-index"ed elements and elements that remain "in the flow".
Other side notes:
elements with the same z-index are stacked according to their order in the HTML (later in the HTML means they are drawn above on the screen)
"z-index"ing requires "position: (absolute|relative)", "z-index: (valid value)", and IIRC "(top|left|bottom|right): (valid value)" to take the element "out of the flow"
CSS absolute positioning is always done "relative" to the most recent ancestor that has a "position: relative", otherwise it uses the body tag by default. If the CSS you included is all that affects those divs, then your .content div will be positioned relative to the .main div, but your .bgImage will be positioned based on the tag.
If you want both .content and .bgImage to move in lockstep, then you'll need to add a "position: relative" to div.main.