64

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
  • 27,963
  • 30
  • 126
  • 237

3 Answers3

72

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
  • 43,592
  • 5
  • 83
  • 98
  • 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
  • 4
    @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,374
  • 1
  • 18
  • 38
0

enter image description here[left: 50% + transform: translateX(-50%)][2]

https://drive.google.com/file/d/1fi0Cl0ssIabVjWWGq8Oyozur2sq_g41n/view?usp=share_link

  • You seem unaware that you can [edit] your posts. That would have allowed you to improve https://stackoverflow.com/a/75050239/7733418 instead of creating this very similar post. Also, while you seem to be trying to improve your post, please have a look at [answer]. It is recommended to add textual explanations, even to good pictures. Even if the link text could be considered code, note that code-only answers are usually not perceived as very helpful. – Yunnosch Jan 08 '23 at 19:40
  • 1
    One of the previous versions of your post was slightly better, because of better formatting markdown... see https://stackoverflow.com/editing-help ). Also please understand that link-only answers are not considered real answers and risk being flagged as such and deleted. Many users are even in the habit of never clicking on links, just to be safe. So, if you provide a solution please do so directly here, ideally consisting of code with explanations on how it works and why it helps. – Yunnosch Jan 08 '23 at 19:41