CSS transformed parent affect child position - html

Why are child positions affected when you transform the parent?
I want the blue box stay in the bottom right position of the yellow box. But when I translate the red box, the blue box will move to his (red) parent.
In real life box-red represents my ui-view in Angular. The views are sliding in and out. I can't change the HTML hierarchy.
See my codepen
https://codepen.io/benbesuijen/pen/GPOQjM
HTML
<div class="box-yellow">
<div class="box-red">
<div class="box-blue"></div>
</div>
</div>
CSS
.box-yellow {
background-color: yellow;
position: relative;
height: 200px;
width: 200px;
}
.box-red {
background-color: red;
height: 100px;
width: 100px;
}
.box-blue {
background-color: blue;
bottom: 0;
height: 50px;
position: absolute;
right: 0;
width: 50px;
}
.box-move {
transform: translateX(100%);
}

Take a look at the spec: The Transform Rendering Model
Specifying a value other than ‘none’ for the ‘transform’ property
establishes a new local coordinate system at the element that it is
applied to.
What that means here is that the blue element will become relative to the element with the transform (the red parent) - not relative to the viewport (like regular static elements)
However, we can solve this case by applying the transform to the yellow-box, and have the the blue one's position: fixed.
Below is an example:
var button = document.querySelector('button'),
boxRed = document.querySelector('.box-red');
button.addEventListener('click', function() {
boxRed.classList.toggle('box-move');
});
.box-yellow {
background-color: yellow;
transform: translate(0, 0);
float: left;
position: relative;
height: 200px;
width: 200px;
}
.box-red {
background-color: red;
height: 100px;
width: 100px;
}
.box-blue {
background-color: blue;
position: fixed;
bottom: 0;
right: 0;
height: 50px;
width: 50px;
}
.box-move {
margin-left: 50%;
}
button {
margin-left: 20px;
}
<div class="box-yellow">
<div class="box-red">
<div class="box-blue"></div>
</div>
</div>
<button>Translate red box</button>
Hope this helps :)

I think your only way is to use margin-left and calculate the size of the box. Something like:
button.addEventListener('click', function() {
var boxRedWidth = boxRed.getBoundingClientRect().width;
boxRed.style.marginLeft = boxRedWidth +"px";
});
It's due to the translateX essentially making it a relative position object, meaning the .box-blue jumps into that as its relative parent.
With margin-left the .box-red remains as static meaning it doesn't become a relative parent to box-blue.

Related

z-index not working with position relative

I write css coded is the following lines. but not working z-index.
I want to know how I can make the z-index work while keeping the value of position as relative.
#foo {
position: relative;
z-index: -1;
width: 100%;
height: 30%;
background-color: lightblue;
}
#bar {
width: 50%;
height: 30%;
background-color: lightpink;
}
As far as I know, if you set the value of position to a non-static value, the z-index should work. Are there any other factors that affect the z-index?
Also if I change the value of position to absolute it works fine.
When position is relative
When position is absolute
everything is working as you need you can see I have added margin-bottom:-20px; to .foo so that you can se that in effect that .foo is behind .bar.
Understand that position won't take item out of flow, which will keep it at it's position. To see this in effect there must be some overlapping between two elements, than you can see the z-index in efffect.
html,
body {
width: 100%;
height: 100%;
}
#foo {
position: relative;
z-index: -1;
width: 100%;
height: 30%;
background-color: lightblue;
margin-bottom: -20px;
}
#bar {
width: 50%;
height: 30%;
background-color: lightpink;
}
<div id="foo">Foo</div>
<div id="bar">Bar</div>

How to set the height of a div container having absolute positioned element

So basically I have a parent div element containing just one child div element.
Now I want to set the position of child div to absolute (for animation / page-transition effect). But on doing so, height of parent div element gets set to 0 which changes the whole layout which isn't desired.
How do I fix this to set height of parent div element to that of height of absolute positioned child div element
Here's how my that block of code looks
HTML
<div class='parent'>
<div class='child'></div>
</div>
CSS
.parent {
position: relative;
}
.child {
position: absolute;
top: 0;
}
Although stretching to elements with position: absolute is not possible, there are often solutions where you can avoid the absolute positioning while obtaining the same effect. Look at this fiddle that solves the problem in your particular case http://jsfiddle.net/gS9q7/
The trick is to reverse element order by floating both elements, the first to the right, the second to the left, so the second appears first.
.child1 {
width: calc(100% - 160px);
float: right;
}
.child2 {
width: 145px;
float: left;
}
Finally, add a clearfix to the parent and you're done (see the fiddle for the complete solution).
Generally, as long as the element with absolute position is positioned at the top of the parent element, chances are good that you find a workaround by floating the element.
One way you could do this is by setting a variable in CSS and using the variable on both the parent and child elements height and width.
html {
--height: 100px;
--width: 200px;
}
.parent {
position: relative;
border: 1px solid black;
height: var(--height);
width: var(--width);
}
.child {
position: absolute;
height: var(--height);
width: var(--width);
background: red;
top: 0;
}
<div class='parent'>
<div class='child'></div>
</div>
Another would be to use javascript to set the property of the parents width and height to that of the child elements.
const par = document.querySelector('.parent');
const child = document.querySelector('.child');
const getSetStyles = (p, c, arr) => {
const styleArr = {};
arr.map( a => styleArr[a] = getComputedStyle(c).getPropertyValue(a) );
Object.entries(styleArr).map( sArr => par.style.setProperty(sArr[0], `${sArr[1]}`) );
}
getSetStyles(par, child, ['width', 'height'])
html {
--height: 100px;
--width: 200px;
}
.parent {
position: relative;
border: 2px solid black;
}
.child {
position: absolute;
height: var(--height);
width: var(--width);
background: red;
top: 0;
}
<div class="parent">
<div class="child"></div>
</div>
I don't know if I have followed your question correctly, but please set a height for the parent then set the height of child to 100%
.parent {
position: relative;
height: 100px;
width: 100px;
}
.child {
position: absolute;
top: 0;
height: 100%;
width: 100%;
}

Keep child position the same after parent moved with CSS transform

Is it possible to take a child outside of the flow of its transformed parent? Simple example below:
HTML:
<div class="parent">
<div class="child"></div>
</div>
Move parent
CSS:
.parent {
background: red;
height: 200px;
position: relative;
transition: 0.5s ease-in-out;
width: 200px;
}
.child {
background: black;
height: 100px;
left: 0;
top: 0;
position: absolute;
width: 100px;
}
.moved {
transform: translateX(100px);
}
Javascript:
$('#button').on('click', function(e) {
e.preventDefault();
console.log('test');
$('.parent').toggleClass('moved');
});
JSFiddle: http://jsfiddle.net/ous3s873/1/
Very simple stuff. Basically, the parent (red box) is being moved 100px to the right using a CSS transform. My desired output is that the child (black box) would stay in the same place as the parent moves behind it.
One option is adding a negative translateX to the child element in order to make it stay at its place:
Updated Demo
.moved .child {
transform: translateX(-100px);
}

How to get overlay to fill scrollable parent using pure CSS?

Here's a simple example:
<div class = "has-scrollbar">
<div class = "long"></div>
<div class = "overlay"></div>
</div>
.has-scrollbar {
width: 200px;
height: 100px;
overflow-y: scroll;
position: relative;
}
.long {
height: 200px;
width: 50px;
background: blue;
}
.overlay {
width: 100%;
height: 100%;
background: red;
opacity: 0.5;
position: absolute;
top: 0;
}
JsFiddle
The red overlay should completely fill the parent container. The height of .long is not known in advance. The .has-scrollbar div should still be scrollable (and not covered).
Any solution using position: fixed on .overlay will not likely work. The real-world scenario is far more complex. Consider the position of .has-scrollbar within the body to also not be known in advance.
So you don't know about long, but seems like you do control has-scrollbar, so you can make overlay fixed and position it in the same place as has-scrollbar:
.overlay {
height: 100px;
margin-top: 8px; /* just to compensate for body margin in the example */
pointer-events: none; /* mouse events will pass through */
position: fixed;
width: 200px;
}
Updated JSFiddle.

CSS I want a div to be on top of everything

How do I make an html div tag to be on top of everything? I tried adding z-index: 1000, but it remains the same.
In order for z-index to work, you'll need to give the element a position:absolute or a position:relative property. Once you do that, your links will function properly, though you may have to tweak your CSS a bit afterwards.
Yes, in order for the z-index to work, you'll need to give the element a position: absolute or a position: relative property... fine.
But... pay attention to parents!
The element's z-index may be limited by its parent's z-index value.
You have to go down the nodes of the elements to check if at the level of the common parent the first descendants have a defined z-index.
All other descendants can never be in the foreground if at the base there is a lower definite z-index.
In this snippet example, div1-2-1 has a z-index of 1000 but is nevertheless under the div1-1-1 which has a z-index of 3.
This is because div1-1 has a z-index greater than div1-2.
.div {
}
#div1 {
z-index: 1;
position: absolute;
width: 500px;
height: 300px;
border: 1px solid black;
}
#div1-1 {
z-index: 2;
position: absolute;
left: 230px;
width: 200px;
height: 200px;
top: 31px;
background-color: indianred;
}
#div1-1-1 {
z-index: 3;
position: absolute;
top: 50px;
width: 100px;
height: 100px;
background-color: burlywood;
}
#div1-2 {
z-index: 1;
position: absolute;
width: 200px;
height: 200px;
left: 80px;
top: 5px;
background-color: red;
}
#div1-2-1 {
z-index: 1000;
position: absolute;
left: 70px;
width: 120px;
height: 100px;
top: 10px;
color: red;
background-color: lightyellow;
}
.blink {
animation: blinker 1s linear infinite;
}
#keyframes blinker {
50% {
opacity: 0;
}
}
.rotate {
writing-mode: vertical-rl;
padding-left: 50px;
font-weight: bold;
font-size: 20px;
}
<div class="div" id="div1">div1</br>z-index: 1
<div class="div" id="div1-1">div1-1</br>z-index: 2
<div class="div" id="div1-1-1">div1-1-1</br>z-index: 3</div>
</div>
<div class="div" id="div1-2">div1-2</br>z-index: 1</br><span class='rotate blink'><=</span>
<div class="div" id="div1-2-1"><span class='blink'>z-index: 1000!!</span></br>div1-2-1</br><span class='blink'> because =></br>(same</br> parent)</span></div>
</div>
</div>
More simply :
For z-index:1000 to have an effect you need a non-static positioning scheme.
Add position:relative; to a rule selecting the element you want to be on top
You need to add position:relative; to the menu. Z-index only works when you have a non static positioning scheme.
z-index property enables you to take your control at front. the bigger number you set the upper your element you get.
position property should be relative because position of html-element should be position relatively against other controls in all dimensions.
element.style {
position:relative;
z-index:1000; //change your number as per elements lies on your page.
}
I gonna assumed you making a popup with code from WW3 school, correct?
check it css. the .modal one, there're already word z-index there. just change from 1 to 100.
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
It seems like nesting an element inside a <dialog> element puts it on top of everything. It is placed both horizontally and vertically centered to the screen if you use showModal() but you lose the interactivity with other elements in the page.
document.querySelector("dialog").showModal();
<dialog>
<div class="element">I am on top of everything else</div>
</dialog>
<div class="backdrop">Backdrop element</div>
If you still want interactivity with the background elements, you can use the show() method. It is placed only horizontally centered to the screen.
document.querySelector("dialog").show();
<dialog>
<div class="element">I am on top of everything else</div>
</dialog>
<div class="backdrop">Backdrop element to check if I am underneath or not.</div>