Position by center point, rather than top-left point
Asked Answered
P

7

67

Is it possible to tell the code to position by the center point of an element, rather than by the top-left point? If my parent element has

width: 500px;

and my child element has

/*some width, for this example let's say it's 200px*/
position: absolute;
left: 50%;

one would assume that based on the 50% positioning, the child element will be in the middle of the parent, leaving 150px of free space on each side. However, it is not, since it is the top-left point of the child that goes to 50% of the parent's width, therefore the whole child's width of 200px goes to the right from there, leaving 250px of free space on the left and only 50px on the right.

So, my question is, how to achieve center positioning?

I found this solution:

position: absolute;
width: 200px;
left: 50%;
margin-left: -100px;

but I don't like it because you need to edit it manually for each element's width - I would like something that works globally.

(For example, when I work in Adobe After Effects, I can set a position for an object and then set specific anchor point of that object that will be put to that position. If the canvas is 1280px wide, you position an object to 640px and you choose the center of the object to be your anchor point, then the whole object will be centered within the 1280px wide canvas.)

I would imagine something like this in CSS:

position: absolute;
left: 50%;
horizontal-anchor: center;

Similarly, horizontal-anchor: right would position the element by its right side, so the whole content would be to the left from the point of its parent's 50% width.

And, the same would apply for vertical-anchor, you get it.

So, is something like this possible using only CSS (no scripting)?

Thanks!

Playground answered 10/3, 2013 at 22:23 Comment(0)
P
93

If the element must be absolutely positioned (so, margin: 0 auto; is of no use for centering), and scripting is out of the question, you could achieve this with CSS3 transforms.

.centered-block {
    width: 100px; 
    left: 50%; 
    transform: translate(-50%, 0); 
    position: absolute;
}

See this fiddle for some examples. The important parts: left: 50%; pushes block halfway across its parent (so its left side is on the 50% mark, as you mentioned). transform: translate(-50%, 0); pulls the block half it's own width back along the x-axis (ie. to the left), which will place it right in the center of the parent.

Parrnell answered 10/3, 2013 at 23:5 Comment(5)
@Playground user beware: browser specific commands should be thoroughly tested. The good news is that there are usually equivalent properties for each browser out there.Limonene
Good solution, but at least nowadays there is a certain amount of cross-browser compatibility; just add keys -ms-transform and transform with the same value.Tenacious
This works vertically as well: .middle-block { height: 100px; top: 50%; transform: translateY(-50%); position: absolute; } The top rule positions the top of the element according to it's nearest relatively positioned wrapper, while the transform moves the element in accordance with it's own length.Badman
Thank you for this solutionVisible
Thank You And also use transform: translate(50%,0) for RTL websitesAfro
P
5

Here's one way to center a text element in the middle of the container (using a header as an example

CSS:

.header {
     text-align: center;
     top: 50%;
     left: 50%;
     transform: translate(-50%, -50%);
     position: absolute;
}

It centers by a middle anchor point.

Puffin answered 24/7, 2018 at 14:40 Comment(0)
L
2

If adding another element is an option, consider the following:

/* CSS for all objects */

div.object {
  width: 100%;
  height: 100%;
  position: absolute;
  left: -50%;
  top: -50%; /* to anchor at the top center point (as opposed to true center) set this to 0 or remove it all together */
}

div.anchor {
  position: absolute; /* (or relative, never static) */
}


/* CSS for specific objects */

div#el1 {
  /* any positioning and dimensioning properties for element 1 should go here */
  left: 100px;
  top: 300px;
  width: 200px;
  height: 200px;
}

div#el2 {
  /* any positioning and dimensioning properties for element 2 should go here */
  left: 400px;
  top: 500px;
  width: 100px;
  height: 100px;
}

div#el1>div.object {
  /* all other properties for element 1 should go here */
  background-color: purple;
}

div#el2>div.object {
  /* all other properties for element 2 should go here */
  background-color: orange;
}
<div class="anchor" id="el1">
  <div class="object">
  </div>
</div>
<div class="anchor" id="el2">
  <div class="object">
  </div>
</div>

Essentially what we're doing is setting up one object to define the position, width and height of the element, and then placing another one inside of it that gets offset by 50%, and gets its parent dimensions (ie width: 100%).

Limonene answered 21/4, 2014 at 13:24 Comment(0)
M
2

Stumbled upon this question, and I'd like to add another way to center content within a div.

By using the CSS3 display mode 'flexible box', as in setting the following CSS properties to the parent div

display: flex;
position: relative;
align-items: center;
justify-content:center;

And 'at least' setting the following properties to the child div

position:relative;

The browser will automatically center the contents within the parent div, unaffected by their width or height, this particularly comes in handy when you're developing something like an image grid or just want to remove the hassle of calculating a divs position, then having to recalculate it when you change your mind about the set-up of said div.

In my own work, I tend to set-up a class named

.center-center

With the properties I described for the parent div, then just add it to whatever element of which I need its contents centered.

I've created a JSFiddle to support this explanation, feel free to click on the red squares to see the positioning in action.

https://jsfiddle.net/f1Lfqrfs/

For multi-line support, you can add (or uncomment in the JSF) the following CSS property to the parent DIV

flex-wrap: wrap;
M answered 26/4, 2017 at 7:52 Comment(0)
S
0

left:50% doesn't center the center of gravity of this div 50% to the left, it is the distance between the left border and the left border of the parent element, so basically you need to do some calculations.

left = Width(parent div) - [ Width(child div) + Width(left border) + Width(right border) ]

left = left / 2

So you can do a Javascript function...

function Position(var parentWidth, var childWith, var borderWidth)
{
      //Example parentWidth = 400, childWidth = 200, borderWidth = 1
      var left = (parentWidth - ( childWidth + borderWidth));
      left = left/2;
      document.getElementById("myDiv").style.left= left+"px";
}
Soares answered 10/3, 2013 at 22:45 Comment(1)
Thanks, I know this would work, but you just denied the only two things I asked for - no need to manually accomodate it for each element's width and no scripting, just CSS.Playground
L
0

I got it working by using transform: translateX with calc for horizonally positioning by element center instead of top-left. Same trick can be used for vertical using transform: transformY. This will work with width of any type (try resizing)

Snippet: transform: translateX(calc(-50% + 223px));

Browser support: https://caniuse.com/#feat=transforms2d, https://caniuse.com/#feat=calc

Codepen for more examples: https://codepen.io/manikantag/pen/KJpxmN

Note on offsetLeft/offsetTop etc: el.offsetLeft will not given proper value for CSS transformed elements. You would require something like el.getBoundingClientRect().left - el.offsetLeft - el.parentNode.offsetLeft (as mentioned here)

Note about flow effect: as detailed in CSS Things That Don’t Occupy Space, transform doesn't effect the following element without considering the offset caused by transform. Sometimes this may not be the intended behavior. This can be fixed using negative margins if width/height are fixed (doesn't work if width/height are using %)

.left-positioned {
  margin-left: 223px;
  background-color: lightcoral;
}

.center-positioned {
  transform: translateX(calc(-50% + 223px)); /*=====> actual solution */
  background-color: cyan;
}

.with-width {
  width: 343px;
  background-color: lightgreen;
}


/* styles not related to actual solution */

div {
  resize: both;
  overflow: auto;
}

.container {
  background-color: lightgray;
}

.ele {
  display: inline-block;
  height: 70px;
  text-align: center;
}
<div class="container">
  <div class="ele left-positioned">Reference element (left at 223px)</div> <br/>
  <div class="ele center-positioned">^<br/>Center positioned element (center at 223px)</div> <br/>
  <div class="ele center-positioned with-width">^<br/>Center positioned element with width (center at 223px)</div>
</div>
Linsang answered 24/1, 2019 at 9:54 Comment(0)
D
0

You can move an element so that it's centre is in the same position as it's pointer using the transform property and translate function like so:

transform: translate(-50%, -50%);

which is the equivalent of:

transform: translateX(-50%) translateY(-50%);

This will move the element back half its length across the X and Y axis so its centre will be over the pointer where you place it.

Centre Example

So for example, if you wanted to place an element in the centre of its parent you would first put the pointer in the centre like so:

left: 50%
top: 50%

and then add the transformation to move the centre of the element over the pointer, like so:

left: 50%
top: 50%
transform: translate(-50%, -50%);

Thanks to Joe Rhoney, 2019 for suggesting the use of transform in a previous answer's comment.

Dopester answered 24/6, 2021 at 13:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.