5

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%);
}
Ben Besuijen
  • 624
  • 9
  • 23
  • Do you have to use `translateX`? You may need to explain your goal as I think you're going to run into more issues down the line if you don't give a bit more explanation as to what's going into those boxes? – dan richardson Aug 05 '15 at 09:05
  • 2
    This is an issue i believe caused by the stacking context of elements when transformed. Read more here: https://stackoverflow.com/questions/16148007/which-css-properties-create-a-stacking-context – Stewartside Aug 05 '15 at 09:13
  • @Dan, I updated my description. Stewartside, thanks, I will read it and hope I can found a solution. – Ben Besuijen Aug 05 '15 at 09:20

2 Answers2

5

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 :)

Nemanja Milosavljevic
  • 1,251
  • 18
  • 33
0

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.

dan richardson
  • 3,871
  • 4
  • 31
  • 38
  • The whole transform property is making te object relative (happend also with scale, rotate etc.) I cant figure out why this is normal CSS behavior. Your answer can fix the problem, but I cant use it because margin has poor performance with transitions. – Ben Besuijen Aug 05 '15 at 10:11
  • I think you have to forego the performance gain because I don't think there is another way. Unless @Nemanja answer works for you – dan richardson Aug 05 '15 at 10:37