Fixed element positioning relative to its parent - html

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.

Related

Display child elements constrained to parent element

Say I have a button positioned inside a div:
.parentDiv {
width: 100px;
height: 50px;
background-color: #B9DEED;
}
.childButton {
position: absolute;
left: 90px;
opacity: .5;
}
<div class="parentDiv">
<button class="childButton">Childbutton</button>
</div>
This gets rendered like so:
Is there a way to display the button so that it is constrained to the div, i.e. it gets cut off after the "C"?
That's not a button positioned inside a div, that's a button (that happens to be child of a div) positioned within the page. For the button to positioned within the div, the div needs to be positioned itself.
Once the parent has position, the overflow: hidden will start to work.
div {
outline: 1px solid blue;
width: 100px;
height: 50px;
position: relative;
overflow: hidden;
}
button {
position: absolute;
left: 90px;
}
<h3>Sample</h3>
<div>
<button>Childbutton</button>
</div>
Core take-away: position is always related to the closest ancestor (it does not have to be the direct parent) that has position. If there is none, it is related to the page. Setting position: relative on a parent establishes a frame of reference without taking the parent out of the document flow.
You can see the difference if you set top: 10px on the button. Try with and without position: relative on the div to verify the frame of reference.
You can use the style overflow: hidden to hide everything outside the parent-element.
This does, however, not apply to position: absolute elements. You would need to use position. relative for that.

position: absolute not doing what I expect

I am having problems getting the grasp of position: absolute
I understand that it positions itself according to the position of its relative parent. So what is wrong with my example? when clicking on the first ".col-lg-6", why is the faded blue line not centered on the right col?
Please could you rework the code and explain why this is happening?
.formWrapper
{
background: blue;
height: 100vh;
position: relative;
margin: 0;
}
.formWrapper .contactForm
{
width: 750px;
height: 400px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: yellow;
}
<div class="formWrapper">
<div class="contactForm row">
<div class="col-lg-6"><h1>HI</h1></div>
<div class="col-lg-6"><h1>HI</h1></div>
</div>
</div>
I can't rework the code and give you what you want exactly, because I don't see the faded blue line you're talking about. But, I will explain what is going on with your code, as I see it.
HTML Markup
<div class="formWrapper">
<div class="contactForm row">
<div class="col-lg-6"><h1>HI</h1></div>
<div class="col-lg-6"><h1>HI</h1></div>
</div>
</div>
.formWrapper
{
background: blue;
height: 100vh;
position: relative;
margin: 0;
}
You have a .formWrapper div colored blue. It takes up the full screen, and you've positioned it relative. Positioning it relative provides an anchor for its child element to use when defining its own position as absolute (necessary).
.formWrapper .contactForm
{
width: 750px;
height: 400px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: yellow;
}
You've defined the a fixed width and height of the yellow .contactForm div and colored it yellow.
By defining position: absolute, with top:50% and left:50%, the top left position of the .contactForm div would appear in the very middle of the .formWrapper div. However, you've also added the transform: translate(-50%, -50%) style, which moves the .contactForm div to the left 50% of its own width and up 50% of its own height.
Important
The position: absolute style that you've set in the parent of the div.col-lg-6 elements does not affect the children's positioning within that element. Position absolute only directly affects the actual element to which you've applied this style, changing its position in reference to its own parent, or the closest parent that has a position style defined.
Position Fixed
If your goal is to have a pop up that sits in the center of the screen, then you might want to use position: fixed, which positions the element relative to the window. This way you don't have to worry about the effects of other elements.
You could position the popup in the middle of the view the same way you positioned the .contactForm div in the middle of the its parent div.
Bootstrap
If you are using bootstrap or any other css framework, you may want to consult their documentation on how to accomplish your goals. Frequently, when using a css framework, adding your own custom styles that affect the sizes and positioning of elements can have consequences that are difficult to manage.
By setting a position of absolute or fixed, you might break the expected flow of the rest of the css. So, only do it when there is no standard way of doing what you need and you know the consequences.

CSS relative vs absolute position

I'm trying to understand the difference between relative and absolute positions in CSS. I've read the explanations and definitions of both absolute and relative, yet I still find a particular example rather strange. Can someone explain why in the following example :
Here's the HTML file :
body {
display: block;
}
.d1 {
margin-top: 100px;
position: relative;
width: 100px;
height: 100px;
background: #815BFF;
}
.d2 {
position: absolute;
margin-left: 100px;
width: 100px;
height: 100px;
background: #815BFF;
}
.d3 {
position: absolute;
margin-top: 100px;
margin-left: 200px;
width: 100px;
height: 100px;
background: #815BFF;
}
<body>
<div class="d1">div 1</div>
<div class="d2">div 2</div>
<div class="d3">div 3</div>
</body>
I've posted the example on http://codepen.io/l7uci/pen/JWNrRj.
If I change the position of any div from absolute to relative, why does the div itself not change, but all the divs that come after it take it as a reference and change according to it ? I was expecting the other divs to still be placed relative to the body, as in Difference between relative and absolute .
If you use position:absolute but don't set top, left, bottom or right, the element takes the position it would have had in normal flow, even though it is not itself in normal flow, so doesn't affect the position of subsequent elements.
So if you change an element without top, left, bottom or right from absolute to relative it doesn't move, this is it still takes it's place in normal flow, but it is now in normal flow, so subsequent elements will move to take account of its size.
-An element with position: relative; is positioned relative to its normal position.
Setting the top, right, bottom, and left properties of a relatively-positioned element will cause it to be adjusted away from its normal position. Other content will not be adjusted to fit into any gap left by the element.
-An element with position: absolute; is positioned relative to the nearest positioned ancestor (instead of positioned relative to the viewport, like fixed).
However; if an absolute positioned element has no positioned ancestors, it uses the document body, and moves along with page scrolling.

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

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.

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.