59

I recently refactored some of my CSS and was pleasantly surprised to find an easier way to horizontally align my absolutely positioned element:

.prompt-panel {
    left: 50%;
    transform: translateX(-50%);
}

This works great! Even if my element's width is auto. However, I do not understand what's going on to make this actually work. My assumption was that translateX was just a modern, more performant means of moving an element around, but that does not appear to be the case.

Shouldn't these two values cancel each other out? Furthermore, why does

.prompt-panel {
    left: -50%;
    transform: translateX(50%);
}

not show the same result as the first code snippet?

Sean Anderson
  • 26,361
  • 27
  • 120
  • 228

2 Answers2

69

The CSS left property is based on the size of the parent element. The transform property is based on the size of the target element.

Name: transform

Percentages: refer to the size of bounding box [of the element to which the style is applied]

http://www.w3.org/TR/css3-transforms/#transform-property

'top'

Percentages: refer to height of containing block

http://www.w3.org/TR/CSS2/visuren.html#position-props

If the parent is 1000px wide and the child is 100px, The browser would interpret the rules in your question as:

Example 1:

.prompt-panel {
    left: 500px;
    transform: translateX(-50px);
}

Example 2:

.prompt-panel {
    left: -500px;
    transform: translateX(50px);
}
Dark Falcon
  • 42,395
  • 5
  • 80
  • 94
  • 4
    I would expand on this by adding that the default origin for the transform is the center of the element. http://www.w3.org/TR/css3-transforms/#transform-origin-property – Moby Disk Sep 22 '14 at 20:02
  • 3
    @MobyDisk: Which is useful to know, but has no bearing. Origin doesn't matter for a translate, only for a rotate or scale (or other operation like these). – Dark Falcon Sep 22 '14 at 20:04
  • So `translateX` has the same function as `margin-left: -px` had in earlier css-hacks, doesn't it? – ArchLinuxTux Nov 28 '17 at 11:08
  • No, because `margin-left` is based on the parent element's size when using percentages. `translateX` is based on the child's size when using percentages. This whole question was about percentages or `width: auto` elements, not fixed pixel values. – Dark Falcon Nov 28 '17 at 12:06
21

left 50% will move the element exactly at the center of the main container where this element belongs! BUT translateX(50%) will move the element right exactly to 50% of its width,and NOT at the center of the whole Container element!

Thats the main difference between them and thats why this example has differences!

A general example to clear this out: (fiddle here):

#pos
{
    border:1px solid black;
    position:absolute;
    width:200px;
    height:150px;
}
#pos-2
{
    border:1px solid black;
    position:absolute;
    width:auto;
    height:150px;
}
.prompt-panel {
 position:absolute;
}

.prompt-panel1 {
    position:absolute;
    left: 50%;
}
.prompt-panel2 {
    position:absolute;
    left: -50%;   
}
.prompt-panel3 {  
     position:absolute;
     transform: translateX(-50%);
}

.prompt-panel4 {  
     position:absolute;
     transform: translateX(50%);
}
.prompt-panel5 {  
     position:absolute;
     left: 50%;
     transform: translateX(-50%);
}
.prompt-panel6 {  
     left: -50%;
      transform: translateX(50%);
}
#pos-auto
{
    position:absolute;
}
<div><b> With fixed width 200px</b></div>
<br/>
<div id="pos">
<div class="prompt-panel">panel</div>
<br/>
<div class="prompt-panel1">panel1</div>
<br/>
<div class="prompt-panel2">panel2</div>
<br/>
<div class="prompt-panel3">panel3</div>
<br/>
<div class="prompt-panel4">panel4</div>
<br/>
<div class="prompt-panel5">panel5</div>
<br/>
<div class="prompt-panel6">panel6</div>
</div>
<br/><br/><br/> <br/><br/><br/><br/><br/><br/>
<div><b> With fixed width auto</b></div>
<br/>
<div id="pos-2">
<div class="prompt-panel">panel</div>
<br/>
<div class="prompt-panel1">panel1</div>
<br/>
<div class="prompt-panel2">panel2</div>
<br/>
<div class="prompt-panel3">panel3</div>
<br/>
<div class="prompt-panel4">panel4</div>
<br/>
<div class="prompt-panel5">panel5</div>
<br/>
<div class="prompt-panel6">panel6</div>
</div>
Giannis Grivas
  • 3,284
  • 1
  • 15
  • 37