252

I have a problem when I try to center the div block "products" because I don't know in advance the div width. Anybody have a solution?

Update: The problem I have is I don't know how many products I'll display, I can have 1, 2 or 3 products, I can center them if it was a fixed number as I'd know the width of the parent div, I just don't know how to do it when the content is dynamic.

.product_container {
  text-align: center;
  height: 150px;
}

.products {
  height: 140px;
  text-align: center;
  margin: 0 auto;
  clear: ccc both; 
}
.price {
  margin: 6px 2px;
  width: 137px;
  color: #666;
  font-size: 14pt;
  font-style: normal;
  border: 1px solid #CCC;
  background-color: #EFEFEF;
}
<div class="product_container">
  <div class="products" id="products">
    <div id="product_15">
      <img src="/images/ecommerce/card_default.png">
      <div class="price">R$ 0,01</div>
    </div>

    <div id="product_15">
      <img src="/images/ecommerce/card_default.png">
      <div class="price">R$ 0,01</div>
    </div>   

    <div id="product_15">
      <img src="/images/ecommerce/card_default.png">
      <div class="price">R$ 0,01</div>
    </div>
  </div>
</div>
Nhan
  • 3,595
  • 6
  • 30
  • 38

22 Answers22

262

Update 27 Feb 2015: My original answer keeps getting voted up, but now I normally use @bobince's approach instead.

.child { /* This is the item to center... */
  display: inline-block;
}
.parent { /* ...and this is its parent container. */
  text-align: center;
}

My original post for historical purposes:

You might want to try this approach.

<div class="product_container">
    <div class="outer-center">
        <div class="product inner-center">
        </div>
    </div>
    <div class="clear"/>
</div>

Here's the matching style:

.outer-center {
    float: right;
    right: 50%;
    position: relative;
}
.inner-center {
    float: right;
    right: -50%;
    position: relative;
}
.clear {
    clear: both;
}

JSFiddle

The idea here is that you contain the content you want to center in two divs, an outer one and an inner one. You float both divs so that their widths automatically shrink to fit your content. Next, you relatively position the outer div with it's right edge in the center of the container. Lastly, you relatively position the inner div the opposite direction by half of its own width (actually the outer div's width, but they are the same). Ultimately that centers the content in whatever container it's in.

You may need that empty div at the end if you depend on your "product" content to size the height for the "product_container".

Mike M. Lin
  • 9,992
  • 12
  • 53
  • 62
  • 1
    If you dont provide `overflow:hidden` for `.product_container` the `outer-center` div will overlap other nearby contents to the right of it. Any links or buttons to the right of `outer-center` wont work. Try background color for `outer-center` to understand the need for `overflow :hidden`. *This was a suggested edit by [Cicil Thomas](http://stackoverflow.com/users/1574023/cicil-thomas)* – Benjol Aug 10 '12 at 09:59
  • This approach is perfect for desktop websites... on mobile ones inner-divs seem to attach to the right, though. Is there a solution? – Mich Dart Dec 30 '12 at 17:52
  • 3
    Tell me about it! Sometimes we simply need a solution and don't have the luxury of having a good one to choose. A single-cell table is another option, although a table with one cell isn't really a table, is it? – Mike M. Lin Jan 09 '13 at 18:03
  • @fgysin Agreed, it's a counter-intuitive hack. And designers wonder why people *still* considering falling back to table-based layouts. – Yuck Jan 10 '14 at 13:57
  • 1
    This question is five years old. This answer is out of date but was never very elegant to begin with. What you *should do* is use display:inline-block – Wray Bowling Jul 30 '14 at 21:00
144

An element with ‘display: block’ (as div is by default) has a width determined by the width of its container. You can't make a block's width dependent on the width of its contents (shrink-to-fit).

(Except for blocks that are ‘float: left/right’ in CSS 2.1, but that's no use for centering.)

You could set the ‘display’ property to ‘inline-block’ to turn a block into a shrink-to-fit object that can be controlled by its parent's text-align property, but browser support is spotty. You can mostly get away with it by using hacks (eg. see -moz-inline-stack) if you want to go that way.

The other way to go is tables. This can be necessary when you have columns whose width really can't be known in advance. I can't really tell what you're trying to do from the example code — there's nothing obvious in there that would need a shrink-to-fit block — but a list of products could possibly be considered tabular.

[PS. never use ‘pt’ for font sizes on the web. ‘px’ is more reliable if you really need fixed size text, otherwise relative units like ‘%’ are better. And “clear: ccc both” — a typo?]

.center{
   text-align:center; 
}

.center > div{ /* N.B. child combinators don't work in IE6 or less */
   display:inline-block;
}

JSFiddle

anoopelias
  • 9,240
  • 7
  • 26
  • 39
bobince
  • 528,062
  • 107
  • 651
  • 834
  • 55
    parent -> text-align:center | child-> display:inline-block – mdskinner Jul 05 '11 at 03:17
  • 5
    `display: inline-block` is not supported in IE7 and older versions of Firefox – Jake Wilson Dec 06 '11 at 17:58
  • @Jakobud Actually it works, but only if you apply it to an element that has `display:inline` by default. – easwee Oct 09 '12 at 15:19
  • 1
    @Jakobud, for IE7 use "display: inline; zoom: 1;" instead of "display: inline-block;". It works for block elements. – Mihail H. May 01 '13 at 13:27
  • 1
    check out this link for more information on how to use this method cross browser - http://blog.mozilla.org/webdev/2009/02/20/cross-browser-inline-block/ – keyoke Jan 28 '14 at 15:56
  • 1
    I used this scss to implement it, which will work as long as your html structure exists to support it: .center { text-align: center; &:first-child { display: inline-block; } } – Dovev Hefetz Oct 15 '15 at 06:48
  • In my case, I wanted to center a `
    ` that was styled using [purecss.io](http://purecss.io/forms/), but unfortunately, this solution breaks the style of the inner element. @MaximeRossini's solution did the trick for me.
    – jorgeh Jan 05 '16 at 07:54
  • 1
    I favor `display:table ➝ display:block` over text-align ‘abuse’ ➝ stackoverflow.com/a/35460077/444255 – Frank N Feb 19 '16 at 09:31
  • This has the unwanted side effect of centring everything else in the container, too, forcing you to add extra, non-semantic markup. – Walf Mar 13 '20 at 00:47
101

Most browsers support the display: table; CSS rule. This is a good trick to center a div in a container without adding extra HTML nor applying constraining styles to the container (like text-align: center; which would center all other inline content in the container), while keeping dynamic width for the contained div:

HTML:

<div class="container">
  <div class="centered">This content is centered</div>
</div>

CSS:

.centered { display: table; margin: 0 auto; }

.container {
  background-color: green;
}
.centered {
  display: table;
  margin: 0 auto;
  background-color: red;
}
<div class="container">
  <div class="centered">This content is centered</div>
</div>

Update (2015-03-09):

The proper way to do this today is actually to use flexbox rules. Browser support is a little bit more restricted (CSS table support vs flexbox support) but this method also allows many other things, and is a dedicated CSS rule for this type of behavior:

HTML:

<div class="container">
  <div class="centered">This content is centered</div>
</div>

CSS:

.container {
  display: flex;
  flex-direction: column; /* put this if you want to stack elements vertically */
}
.centered { margin: 0 auto; }

.container {
  display: flex;
  flex-direction: column; /* put this if you want to stack elements vertically */
  background-color: green;
}
.centered {
  margin: 0 auto;
  background-color: red;
}
<div class="container">
  <div class="centered">This content is centered</div>
</div>
Maxime Rossini
  • 3,612
  • 4
  • 31
  • 47
  • 11
    I think this is definitely the best solution. Doesn't involve any strange hacks with floating nested divs, or anything like that. I think the only reason it's not rated higher is because people have gone too far against tables. This isn't a table, so I think it's a perfectly legitimate method. – Dan Jones May 23 '14 at 15:29
  • 1
    Agreed, this seems to be the best solution. While @bobince's solution is simple as well, it has the side effect of altering styles in the inner element. – jorgeh Jan 05 '16 at 07:55
  • The `display: table;` variant is ideal for pseudo-elements (`::before`, `::after`) where you can't add extra markup, and you want to avoid disruption to adjacent element styles. – Walf Mar 13 '20 at 00:53
24

six ways to skin that cat:

Button one: anything of type display: block will assume the full parents width. (unless combined with float or a display: flex parent). True. Bad example.

Button 2: going for display: inline-block will lead to automatic (rather than full) width. You can then center using text-align: center on the wrapping block. Probably the easiest, and most widely compatible, even with ‘vintage’ browsers...

.wrapTwo
  text-align: center;
.two
  display: inline-block; // instantly shrinks width

Button 3: No need to put anything on the wrap. So perhaps this is the most elegant solution. Also works vertically. (Browser support for transtlate is good enough (≥IE9) these days...).

position: relative;
display: inline-block; // instantly shrinks width
left: 50%;
transform: translateX(-50%);

Btw: Also a great way for vertically centering blocks of unknown height (in connection with absolute positioning).

Button 4: Absolute positioning. Just make sure to reserve enough height in the wrapper, since noone else will (neither clearfix nor implicit...)

.four
  position absolute
  top 0
  left 50%
  transform translateX(-50%)
.wrapFour
  position relative // otherwise, absolute positioning will be relative to page!
  height 50px // ensure height
  background lightgreen // just a marker

Button 5: float (which brings also block-level elements to dynamic width) and a relative shift. Although I've never seen this in the wild. Perhaps there are disadvantages...

.wrapFive
  &:after // aka 'clearfix'
    content ''
    display table
    clear both

.five  
  float left
  position relative
  left 50%
  transform translateX(-50%)

Update: Button 6: And nowadays, you could also use flex-box. Note, that styles apply to the wrapper of the centered object.

.wrapSix
  display: flex
  justify-content: center

→ full source code (stylus syntax)

Frank N
  • 9,625
  • 4
  • 80
  • 110
17

I found a more elegant solution, combining "inline-block" to avoid using float and the hacky clear:both. It still requires nested divs tho, which isnt very semantic but it just works...

div.outer{
    display:inline-block;
    position:relative;
    left:50%;
}

div.inner{
    position:relative;
    left:-50%;
}

Hope it helps!

JavierIEH
  • 743
  • 8
  • 19
5
<div class="outer">
   <div class="target">
      <div class="filler">
      </div>
   </div>
</div>

.outer{
   width:100%;
   height: 100px;
}

.target{
   position: absolute;
   width: auto;
   height: 100px;
   left: 50%;
   transform: translateX(-50%);
}

.filler{
   position:relative;
   width:150px;
   height:20px;
}

If the target element is absolutely positioned, you can center it by moving it 50% in one direction (left: 50%) and then transforming it 50% in the opposition direction (transform:translateX(-50%)). This works without defining the target element's width (or with width:auto). The parent element's position can be static, absolute, relative, or fixed.

West1
  • 1,430
  • 16
  • 27
  • 1
    This will be off center by half the width of the thing you are centering. – 4imble Jul 05 '16 at 07:56
  • @4imble No it won't. The "left" property moves it 50% (50% of its parent's width), and translateX(-50%) moves it 50% the other way (50% of the target element's width). – West1 Jul 05 '16 at 22:07
  • Ahh yes, i missed the translateX. Not sure this is reliable in any IE before IE 11. But you are right. – 4imble Jul 06 '16 at 08:33
3

This will center an element such as an Ordered List, or Unordered List, or any element. Just wrap it with a Div with the class of outerElement and give the inner element the class of innerElement.

The outerelement class accounts for IE, old Mozilla, and most newer browsers.

 .outerElement {
        display: -moz-inline-stack;
        display: inline-block;
        vertical-align: middle;
        zoom: 1;
        position: relative;
        left: 50%;
    }

.innerElement {
    position: relative;
    left: -50%;
} 
Community
  • 1
  • 1
Greg Benner
  • 668
  • 7
  • 15
  • Please add a description with your code. Posting code on it's own won't mean much to future visitors of SO. – Ren Nov 16 '12 at 09:13
3

By default, div elements are displayed as block elements, so they have 100% width, making centering them meaningless. As suggested by Arief, you must specify a width and you can then use auto when specifying margin in order to center a div.

Alternatively, you could also force display: inline, but then you'd have something that pretty much behaves like a span instead of a div, so that doesn't make a lot of sense.

Adam Bellaire
  • 108,003
  • 19
  • 148
  • 163
3

use css3 flexbox with justify-content:center;

    <div class="row">
         <div class="col" style="background:red;">content1</div>
          <div class="col" style="">content2</div>
    </div>


.row {
    display: flex; /* equal height of the children */
    height:100px;
    border:1px solid red;
    width: 400px;
    justify-content:center;
}
zloctb
  • 10,592
  • 8
  • 70
  • 89
1

Try this new css and markup

Here is modified HTML:

<div class="product_container">
<div class="products" id="products">
   <div id="product_15" class="products_box">
       <img src="/images/ecommerce/card_default.png">
       <div class="price">R$ 0,01</div>
   </div>
   <div id="product_15" class="products_box">
       <img src="/images/ecommerce/card_default.png">
       <div class="price">R$ 0,01</div>
   </div>   
   <div id="product_15" class="products_box">
       <img src="/images/ecommerce/card_default.png">
       <div class="price">R$ 0,01</div>
   </div>
</div>

And here is modified CSS:

<pre>
.product_container 
 {
 text-align:    center;
 height:        150px;
 }

.products {
    left: 50%;
height:35px;
float:left;
position: relative;
margin: 0 auto;
width:auto;
}
.products .products_box
{
width:auto;
height:auto;
float:left;
  right: 50%;
  position: relative;
}
.price {
    margin:        6px 2px;
    width:         137px;
    color:         #666;
    font-size:     14pt;
    font-style:    normal;
    border:        1px solid #CCC;
    background-color:   #EFEFEF;
}

Shinov T
  • 862
  • 5
  • 9
1
<div class="product_container">
<div class="outer-center">
<div class="product inner-center">
    </div>
</div>
<div class="clear"></div>
</div>

.outer-center
{
float: right;
right: 50%;
position: relative;
}
.inner-center 
{
float: right;
right: -50%;
position: relative;
}
.clear 
{
clear: both;
}

.product_container
{
overflow:hidden;
}

If you dont provide "overflow:hidden" for ".product_container" the "outer-center" div will overlap other nearby contents to the right of it. Any links or buttons to the right of "outer-center" wont work. Try background color for "outer-center" to understand the need of "overflow :hidden"

johndoe
  • 4,387
  • 2
  • 25
  • 40
1

I found interesting solution, I was making slider and had to center slide controls and I did this and works fine. You can also add relative position to parent and move child position vertical. Take a look http://jsfiddle.net/bergb/6DvJz/

CSS:

#parent{
        width:600px;
        height:400px;
        background:#ffcc00;
        text-align:center;
    }

#child{
        display:inline-block;
        margin:0 auto;
        background:#fff;
    }  

HTML:

<div id="parent">
    <div id="child">voila</div>
</div>
Nikola
  • 339
  • 4
  • 8
1

Do display:table; and set margin to auto

Important bit of code:

.relatedProducts {
    display: table;
    margin-left: auto;
    margin-right: auto;
}

No matter how many elements you got now it will auto align in center

Example in code snippet:

.relatedProducts {
    display: table;
    margin-left: auto;
    margin-right: auto;
}
a {
  text-decoration:none;
}
<div class="row relatedProducts">
<div class="homeContentTitle" style="margin: 100px auto 35px; width: 250px">Similar Products</div>
     
<a href="#">test1 </a>
<a href="#">test2 </a>
<a href="#">test3 </a>
</div>
hahaha
  • 1,001
  • 1
  • 16
  • 32
1

Slight variation on Mike M. Lin's answer

If you add overflow: auto; ( or hidden ) to div.product_container, then you don't need div.clear.

This is derived from this article -> http://www.quirksmode.org/css/clearing.html

Here is modified HTML:

<div class="product_container">
    <div class="outer-center">
        <div class="product inner-center">
        </div>
    </div>
</div>

And here is modified CSS:

.product_container {
  overflow: auto;
  /* width property only required if you want to support IE6 */
  width: 100%;
}

.outer-center {
  float: right;
  right: 50%;
  position: relative;
}

.inner-center {
  float: right;
  right: -50%;
  position: relative;
}

The reason, why it's better without div.clear (apart that it feels wrong to have an empty element) is Firefox'es overzealous margin assignment.

If, for example, you have this html:

<div class="product_container">
    <div class="outer-center">
        <div class="product inner-center">
        </div>
    </div>
    <div style="clear: both;"></div>
</div>
<p style="margin-top: 11px;">Some text</p>

then, in Firefox (8.0 at the point of writing), you will see 11px margin before product_container. What's worse, is that you will get a vertical scroll bar for the whole page, even if the content fits nicely into the screen dimensions.

Community
  • 1
  • 1
Alexander Pogrebnyak
  • 44,836
  • 10
  • 105
  • 121
0

Simple fix that works in old browsers (but does use tables, and requires a height to be set):

<div style="width:100%;height:40px;position:absolute;top:50%;margin-top:-20px;">
  <table style="width:100%"><tr><td align="center">
    In the middle
  </td></tr></table>
</div>
Craigo
  • 3,384
  • 30
  • 22
0
<style type="text/css">
.container_box{
    text-align:center
}
.content{
    padding:10px;
    background:#ff0000;
    color:#ffffff;

}

use span istead of the inner divs

<div class="container_box">
   <span class="content">Hello</span>
</div>
0

I know this question is old, but I'm taking a crack at it. Very similar to bobince's answer but with working code example.

Make each product an inline-block. Center the contents of the container. Done.

http://jsfiddle.net/rgbk/6Z2Re/

<style>
.products{
    text-align:center;
}

.product{
    display:inline-block;
    text-align:left;

    background-image: url('http://www.color.co.uk/wp-content/uploads/2013/11/New_Product.jpg');
    background-size:25px;
    padding-left:25px;
    background-position:0 50%;
    background-repeat:no-repeat;
}

.price {
    margin:        6px 2px;
    width:         137px;
    color:         #666;
    font-size:     14pt;
    font-style:    normal;
    border:        1px solid #CCC;
    background-color:   #EFEFEF;
}
</style>


<div class="products">
    <div class="product">
        <div class="price">R$ 0,01</div>
    </div>
    <div class="product">
        <div class="price">R$ 0,01</div>
    </div>
    <div class="product">
        <div class="price">R$ 0,01</div>
    </div>
    <div class="product">
        <div class="price">R$ 0,01</div>
    </div>
    <div class="product">
        <div class="price">R$ 0,01</div>
    </div>
    <div class="product">
        <div class="price">R$ 0,01</div>
    </div>
</div>

See also: Center inline-blocks with dynamic width in CSS

Community
  • 1
  • 1
Wray Bowling
  • 2,346
  • 2
  • 16
  • 19
  • Doesn't this answer already provide the same solution? http://stackoverflow.com/a/284064/547733 – Maxime Rossini Jul 31 '14 at 08:59
  • 1
    you're right, madmox! It's not as robust though. Also I'm realizing that setting text-align to left or right means this will never work on a site with translations that include switching left-to-right reading order to right-to-left. text-align is for aligning text, not elements. Ideally in the near future we will depend on display:flex for this sort of thing. – Wray Bowling Aug 04 '14 at 19:00
0

Crappy fix, but it does work...

CSS:

#mainContent {
    position:absolute;
    width:600px;
    background:#FFFF99;
}

#sidebar {
    float:left;
    margin-left:610px;
    max-width:300;
    background:#FFCCCC;
}
#sidebar{


    text-align:center;
}

HTML:

<center>
<table border="0" cellspacing="0">
  <tr>
    <td>
<div id="mainContent">
1<br/>
<br/>
123<br/>
123<br/>
123<br/>
</div><div id="sidebar"><br/>
</div></td>
</tr>
</table>
</center>
Lionel
  • 1
0

I'm afraid the only way to do this without explicitly specifying the width is to use (gasp) tables.

Kon
  • 27,113
  • 11
  • 60
  • 86
0

This is one way to center anything within a div not know the inner width of the elements.

#product_15{
    position: relative;
    margin: 0 auto;
    display: table;
}
.price, img{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}
Shirley Ashby
  • 347
  • 4
  • 5
-1

my solution was:

.parent {
    display: flex;
    flex-wrap: wrap;
}

.product {
    width: 240px;
    margin-left: auto;
    height: 127px;
    margin-right: auto;
}
Byron
  • 9
  • 2
-8

add this css to your product_container class

    margin: 0px auto;
    padding: 0px;
    border:0;
    width: 700px;
Arief
  • 6,055
  • 7
  • 37
  • 41