Keep child position the same after parent moved with CSS transform - html

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);
}

Related

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%;
}

CSS transformed parent affect child position

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.

CSS Transition and Auto position

I have a div .box with which has absolute position set at the bottom of the parent div. It does not have the top position set because the height differs for different .box divs. On hover over the parent div, I want to change its top position to 0 with the transition effect.
In the following code transition does not work if I do not define the top position by default. I have tried using top: auto and it still does not work. How can I use transition without defining the top position.
Here's my code:
HTML:
<div class="wrap">
<div class="box">
Box
</div>
</div>
CSS:
.wrap{
position: relative;
height: 200px;
width: 200px;
background: green;
}
.box{
background: yellow;
position: absolute;
bottom: 0;
left: 0;
transition: all 0.9s ease 0s;
top: 50%; /*== does not work without it ==*/
}
.wrap:hover .box{
top: 0;
bottom: 0;
}
Fiddle: http://jsfiddle.net/5hs09apn/
A slight different approach than using top: http://jsfiddle.net/5hs09apn/2/
set the height for the box, and on hover set it to 100%; let the bottom be zero, so you don't even need to use top
.box{
background: yellow;
position: absolute;
bottom: 0;
left: 0;
height:20px;
transition: all 1s ease 0s;
}
.wrap:hover .box{
height:100%;
bottom: 0;
}
.wrap {
position: relative;
height: 200px;
width: 200px;
background: green;
}
.box {
background: yellow;
position: absolute;
bottom: 0;
left: 0;
height: 20px;
transition: all 1s ease 0s;
}
.wrap:hover .box {
height: 100%;
bottom: 0;
}
<div class="wrap">
<div class="box">
Box
</div>
</div>
Add Top property in JQuery getting the current value of the Top of the .box using position().
This will be dynamic allocation of Top and will not effect your condition of varying .box height.
While doing this, you will have to add the hover effect in the JQuery part too, since the Top will be defined here and CSS wont know what to do with the hover.
Check the Fiddle here
This is the JQuery function added:
$(document).ready(function(){
var x = $('.box').position();
var myTop = x.top;
$('.box').css("top",myTop+"px");
$('.box').css("transition","all 0.9s ease 0s");
$('.wrap').bind('mouseover',function(){
$('.box').css("top","0px");
$('.box').css("bottom","0px");
});
$('.wrap').bind('mouseout',function(){
$('.box').css("top",myTop+"px");
$('.box').css("bottom","0px");
});
});
Hope this gives you what you need.
You can use:
.wrap:hover .box{
margin-bottom: 100%;
}
And try with different percentages until you get one you like. It's crude but I think it can work.

Animate absolute div

Got an absolute div inside relative, and i need that absolute div to dive out on container hover.
Basic html would be
<div class="container">
<div class="animated t50">See more</div>
</div>
css
.container {
position: relative;
width: 200px;
height: 200px;
overflow: hidden;
}
.animated {
position: absolute;
bottom: -5%;
}
.t50 {
transition :0.5s;
/*and further on with all the prefixes*/
}
.container:hover > .animated {
bottom: 5%;
}
so, apparently there is something i don't know...
You must set overflow: visible on the parent container.
Here's an example on JS Bin: http://jsbin.com/luhekatale/1/

CSS3 Transition reverse not taking effect

I have a create two divs that overlap using z-index and the top one will shrink width ways but I can't get it to shrink from right to left even though I've added animation-direction:reverse;
EXAMPLE
How do I change the direction of the shrink?
animation-direction is irrelevant here. That property relates to css animations. You are using transitions. Two different things entirely.
Give .grow a right position value and wrap your current divs in a container with relative positioning:
WORKING DEMO
<div class="pos_rel">
<div class="holder"></div>
<div class="grow"></div>
</div>
.grow {
right:0;
}
Also, you probably should have the :hover on the parent element to prevent your mouse moving out of .grow as it transitions:
DEMO
.pos_rel:hover .grow {
width: 50px;
}
http://jsfiddle.net/venkat7668/a4DUv/2/
I have modified your code little bit to get your expected animation.
<div class="main">
<div class="grow"></div>
<div class="holder"></div>
<div>
.main {
position: relative;
width: 300px;
height: 300px;
}
.holder {
position:absolute;
width: 300px;
height: 300px;
background:#cccccc;
z-index:1;
}
.grow {
width: 300px;
height: 300px;
background: green;
-webkit-transition: width 5s;
transition: width 5s;
float:right;
position:relative;
z-index:2;
}
.grow:hover {
width: 50px;
}