How do I centre absolutely positioned content of unknown width?
Asked Answered
M

5

32

Before someone asks me why the hell I would want to do this let me come straight out and tell you. That way one of you clever peeps out there can tell me a far better way...

I'm making a viewer for paintings which should stretch to fill the page, well 90% of the height of the screen to be precise. I want to fade the paintings in one over the other and want to center each of them in the middle of the screen.

To fade the paintings in over each other I need to position them 'absolute' to stop them from stacking. Here's where the trouble comes. Ever since I've set them to absolute, every method I use to center the containing div hasn't worked.

Part of the problem is that I'm not setting any width for the paintings as I want them to dynamically size themselves to fill 90% of the user's screen.

I've found a hundreds of methods for centering absolute content and believe I might need to shrink wrap the containing div. However I've not had any success as of yet.

HTML-

<div id="viewer_div">
    <img src="" id="first" />
    <img id="second" class="hidden"/>
</div>

Style Sheet

#viewer_div {
        width:1264px;
}


img {
    height:90%;
    display:block;
    margin-left: auto;
    margin-right:auto;
}

The above gives me the desired effect, but doesn't allow me to position the images absolute. Can anyone suggest a way of centering the images but also allows me to fade one over the other?

Mclin answered 20/2, 2012 at 20:18 Comment(5)
Well this is an ordeal. I'm sure you know how to do it with fixed width and absolute positioning, right?Globose
After some fiddling, I can guarantee that you cannot do this with pure CSS and (x)HTML. You need Javascript. Which is unfortunate, since this is purely about display and that's what CSS is for... You can fork my fiddle jsfiddle.net/dekket/58BjM if you want. It's as far as I got, so nowhere really :/Mammet
Thanks for your input. Greg has shown a cleaner approach below that solves my problem.Mclin
Take a look, answered here #17069935Mainsheet
@AntonIskandiarov That is for if you have a percentage-based width e.g. width: 90%;. This is for unknown / automatic width e.g. width: auto;, and unfortunately unless width is set to something (including a percentage) the linked answer treats it as width: 100%. You can of course add a wrapper div with width: 100%; using that trick, then put this content centred inside it the usual way...Aurel
A
50

Either use JavaScript to calculate the width and move it,

use a CSS hack to move the element right and left by 50%,

or don't absolutely position it.


This answer is incredibly short, but it is to the point. If you require something to be centralised (meaning you would like the browser to determine where the centre point is, and position it there), then you can't use absolute positioning - because that takes away control from the browser.


To fade the paintings in over each other I need to position them 'absolute' to stop them from stacking.

This is where your problem lies. You have assumed that you need absolute positioning for the wrong reason.

If you are experiencing problems placing elements on top of each other, wrap the images in an absolutely positioned container which is 100% width and has text-align: center


If you do feel that absolute positioning is necessary, the following hack can be used to achieve your desired results:

div {
    position: absolute;
    /* move the element half way across the screen */
    left: 50%;
    /* allow the width to be calculated dynamically */
    width: auto;
    /* then move the element back again using a transform */
    transform: translateX(-50%);
}

Obviously the above hack has a terrible code smell, but it works on some browsers. Be aware: this hack is not necessarily obvious to other developers, or other browsers (especially IE or mobile).

Apocarpous answered 20/2, 2012 at 20:25 Comment(6)
Thank you Greg, this worked a treat. I thought it had to be simpler than I was making it.Mclin
I put yes to 'was this post helpful' is that what you mean?Mclin
ah got it. Cheers again, you've no idea how much grief it was causing.Mclin
Really good answer, this worked brilliantly. In my code I also gave the child element (the images in the case of this question) "position: relative" and a z-index that was higher than element that it was covering. This allowed the child (rather than its full-width parent) to be in front of the element that it was positioned on.Interlunar
This answer is useful and helpful, but ultimately incorrect. The more recent answers have it right.Recension
@Recension agreed. A lot has changed on the web since 2012. Thanks to SO voting this shouldn't be a problem.Apocarpous
V
67

Pushing the element left by 50% of its width and then translating it horizontally by 50% has worked for me.

.element {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
} 

I found the concept in the following link, and then I translated to fit my horizontal align needs: https://gist.github.com/colintoh/62c78414443e758c9991#file-douchebag-vertical-align-css

Vise answered 19/3, 2015 at 16:10 Comment(4)
For browser support, it looks like this works in everything except IE8 and Opera Mini: caniuse.com/#feat=transforms2dAurel
Hmmm... it's giving me trouble on iOS.Gravity
its one of those satisfying things you discover thought out by another dev. thanks!Swot
As commented in the linked Gist: "just be aware that since css transforms are performed on layers on the GPU, the calculations it returns will not necessarily land on even pixels. When that happens you're going to get blurry text and edges."Terrenceterrene
A
50

Either use JavaScript to calculate the width and move it,

use a CSS hack to move the element right and left by 50%,

or don't absolutely position it.


This answer is incredibly short, but it is to the point. If you require something to be centralised (meaning you would like the browser to determine where the centre point is, and position it there), then you can't use absolute positioning - because that takes away control from the browser.


To fade the paintings in over each other I need to position them 'absolute' to stop them from stacking.

This is where your problem lies. You have assumed that you need absolute positioning for the wrong reason.

If you are experiencing problems placing elements on top of each other, wrap the images in an absolutely positioned container which is 100% width and has text-align: center


If you do feel that absolute positioning is necessary, the following hack can be used to achieve your desired results:

div {
    position: absolute;
    /* move the element half way across the screen */
    left: 50%;
    /* allow the width to be calculated dynamically */
    width: auto;
    /* then move the element back again using a transform */
    transform: translateX(-50%);
}

Obviously the above hack has a terrible code smell, but it works on some browsers. Be aware: this hack is not necessarily obvious to other developers, or other browsers (especially IE or mobile).

Apocarpous answered 20/2, 2012 at 20:25 Comment(6)
Thank you Greg, this worked a treat. I thought it had to be simpler than I was making it.Mclin
I put yes to 'was this post helpful' is that what you mean?Mclin
ah got it. Cheers again, you've no idea how much grief it was causing.Mclin
Really good answer, this worked brilliantly. In my code I also gave the child element (the images in the case of this question) "position: relative" and a z-index that was higher than element that it was covering. This allowed the child (rather than its full-width parent) to be in front of the element that it was positioned on.Interlunar
This answer is useful and helpful, but ultimately incorrect. The more recent answers have it right.Recension
@Recension agreed. A lot has changed on the web since 2012. Thanks to SO voting this shouldn't be a problem.Apocarpous
B
7

To go off of Samec's answer, you can also use this to center an absolute position element vertically and horizontally of unknown dimensions:

#viewer_div {
  position: relative;
}
#viewer_div img {
  position: absolute;
  left: 50%;
  top: 0%;
  transform: translate(-50%, 50%);
}
Banderillero answered 19/1, 2016 at 20:5 Comment(0)
M
1

Centering div with position: absolute and width: unknown:

HTML:

<div class="center">
  <span></span>

  <div>
    content...
  </div>

</div>

CSS:

.center{
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: grid;
  grid-template-columns: auto auto;

  /* if you need the overflow */
  overflow: auto;
}

You can use this solution even if the content is wider than the screen width, and don't need to transform: translate (which can blur elements)


How it works:

Grid will insert a span before the first auto, and insert a div right before the second auto, and you get:

span(0px) - auto - div(...px) - auto

auto will be equal to each other.


Same for vertical centering, but write grid-template-rows instead of a grid-template-columns

Markitamarkka answered 12/9, 2021 at 1:19 Comment(0)
K
1

2021

A modern approach to absolutely centered content with grid and inset

The inset CSS property is a shorthand that corresponds to the top, right, bottom, and/or left. MDN

#viewer_div {
  display: grid;
  place-items: center;
  position: absolute;
  inset: auto 0;
}

*,
::after,
::before {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

body {
  width: 100vw;
  height: 100vh;
  background-color: hsl(201, 27%, 10%);
  position: relative;
}

#viewer_div {
  display: grid;
  place-items: center;
  position: absolute;
  inset: auto 0;
  background-color: hsl(197, 7%, 21%);
  color: white;
}
<div id="viewer_div">
  <h1>Title 2021</h1>
  <img src="https://via.placeholder.com/180x100.png/09f/fff" id="first" />
</div>
Kosher answered 12/9, 2021 at 9:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.