7

I don't even know if this is possible using CSS only, but I have to ask.

PLEASE, read the specs before you provide an answer, accordingly. Thank you!

My markup:

<div class="wrapper">
    <img src="http://placehold.it/350x150">
    <p>Some text random size</p>
</div>

Obviously, .wrapper will have the height of my img element, if that's a block. Then, I need the p element to be centered horizontally and vertically inside the wrapper. I don't have a fixed width or height for the p element.

So, regardless paragraph size or even image size, it should be vertically and horizontally aligned, as is shown here https://i.stack.imgur.com/9qIiY.png or here https://i.stack.imgur.com/X3sBb.png.

If I set absolute position on the paragraph, it will not vertically align, because I cannot set negative margin if I don't know paragraph height. I was thinking about table and table-cell (vertical-align: middle;), but I only have 1 cell. Any thoughts?

Added fiddle: http://jsfiddle.net/f3x7977z/

It's important that the provided solution have backwards compatibility, in special in IE8+.

Any suggestions on extra wrappers, for the sake of the final result, are welcome!

designarti
  • 609
  • 1
  • 8
  • 18

5 Answers5

14

Explanation

Change the CSS property position of the wrapper to relative and of element you want centered to absolute.

Then position the element in the middle of the wrapper using top: 50% and left: 50%.

After this you will notice that the element is not exactly centered, because it's own height and width are off the calculation.

So we fix with the property transform: translate(-50%, -50%), which brings the element half of it's height up, and half it's width left. The result will be a vertically and horizontally centered element.

Since we are taking IE8 into consideration, we will use a filter to achieve the same effect as the transform: translate.

In order to generate the filter attribute, the following resource was used: IE's CSS3 Transforms Translator

Example

.box {
  margin: 10px;
  display: inline-block;
  position: relative;
}
.box span {
  position: absolute;
  top: 50%;
  left: 50%;
  background: #fff;
  box-shadow: 0 0 3px rgba(0, 0, 0, 1);
  padding: 5px;
}
.box.translate > span {
  transform: translate(-50%, -50%);
  -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=1, M12=0, M21=0, M22=1, SizingMethod='auto expand')";
}
<div class="box translate">
  <img src="http://placehold.it/500x200" />
  <span>centered text</span>
</div>
Romulo
  • 4,896
  • 2
  • 19
  • 28
  • Flex is not IE8. And your .google class has a width and a height. NOT an answer, but thanks for your effort. – designarti Oct 10 '15 at 12:45
  • you are right! flex is only for modern browers! i´m gonna update the answer to take IE8 into consideration. Can you check if its working now? My ietester under win10 is not working properly. – Romulo Oct 10 '15 at 13:06
  • Thanks! Might be correct. Just a sec. – designarti Oct 10 '15 at 13:37
  • I'm gonna have this as a right answer. Thought I was going crazy over this, because it was supposed to be simpler! Edited a fiddle of your answer and it is working properly - http://jsfiddle.net/z7cpwrgs/1/. Thanks again! – designarti Oct 10 '15 at 13:44
7

How to Center Vertically and Horizontally Multiple Absolutely Positioned Child Elements

Other answers posted here already address the IE8 requirement. This answer offers an clean and efficient solution for people who don't care about IE8.

HTML (no changes)

<div class="wrapper">
    <img src="http://placehold.it/350x150"/>
    <p>My text, size unknowkn</p>
</div>

CSS

html, body { height: 100%; } /* necessary when using percentage heights within body
                                on non-absolutely positioned children (such as .wrapper)
                                http://stackoverflow.com/a/31728799/3597276 */ 
.wrapper { 
    height: 100%;
    width: 100%;
    position: relative; /* establish nearest positioned ancestor for abs. positioning */
}

img {
  position: absolute;
  left: 50%; /* positions img relative to container */
  top: 50%;  /* positions img relative to container */
  transform: translate(-50%, -50%); /* positions img relative to its height and width */
}

p {
  position: absolute;
  left: 50%;  /* positions p relative to container */
  top: 50%; /* positions p relative to container */
  transform: translate(-50%, -50%);  /* positions p relative to its height and width */
  margin: 0;
}

DEMO: http://jsfiddle.net/f3x7977z/7/

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
1

There is a much more lightweight solution.

  1. Take 50% of the outer element down from the top
  2. margin up 50% of these 50% to the inside element to get on the center of bottomline of the outer element (see fiddle below)

.wrapper {
 position: absolute;
 top: 50%; left: 50%;
}
img { /* or a container with img and p */
 margin-top: -25%; margin-left: -50%;
}
<div class="wrapper">
    <img src="http://placehold.it/350x150">
    <p>Some text random size</p>
</div>
Michael P
  • 603
  • 1
  • 5
  • 22
1

Check this solution

HTML

<div class="wrapper">
    <img src="http://placehold.it/350x150"/>
    <span></span>
    <p>My text, size unknowkn</p>
</div>

CSS

.wrapper
{
    position: relative;
}

p
{
     position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 50%;
    height: 30%;
    margin: auto;
}
Alex
  • 8,461
  • 6
  • 37
  • 49
-1

In stead of the solution you should use this one

.wrapper {
    position: absolute;
    top: 50%; left: 50%;
}
img { 
    margin-top: -25%; margin-left: -25%;
}
Moin Shirazi
  • 4,372
  • 2
  • 26
  • 38
  • Yes, but you are using width and height of the body as a reference (absolute relative to the body). That's not a general context. – designarti Oct 10 '15 at 12:51