Why does display:table-cell not center content without display:table?

15,677

Solution 1

Actually, the browser is inserting an anonymous table element as you expected. However, this element only exists to make the table semantics work. There isn't any way in CSS to target this anonymous block to give it 100% width and height, which your layout requires.

You'll need an actual element in your HTML to act as the "table" object if you want to alter its presentation.

Solution 2

How Does display property Work?

The display property allows you to specify a range of table-related values in order to make elements display as though they were table elements. The available display values are:

  • table makes the element behave like a table element
  • table-row makes the element behave like a table row (tr) element
  • table-cell makes the element behave like a table cell (td) element
  • table-row-group makes the element behave like a table body row group (tbody) element
  • table-header-group makes the element behave like a table header row group (thead) element
  • table-footer-group makes the element behave like a table footer row group (tfoot) element
  • table-caption makes the element behave like a table caption element
  • table-column makes the element behave like a table column (col) element
  • table-column-group makes the element behave like a table column group (colgroup) element

check complete list here... http://www.digital-web.com/articles/everything_you_know_about_CSS_Is_wrong/

but your issue can be solved like this

Check working fiddle http://jsfiddle.net/jZJXf/1/

Css should be like this.

body, html {
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
}
body {
    display: table;
}


#header {
    width: 100%;
    height: 2em;
    background: gray;
}

#vertical {
    display: table;
    width: 100%;
    height: 100%;
}

#horizontal {
    display:table;
    height: 500px;
    width: 500px;
    margin: 10% auto 0% auto;
    background: gray;
}

#footer {
    height: 2em;
    width: 100%;
    background: gray;
    bottom: 0px;
    display: table;

}
Share:
15,677
Admin
Author by

Admin

Updated on June 29, 2022

Comments

  • Admin
    Admin almost 2 years

    I'm looking for the most efficient (or elegant) way to vertically and horizontally center content of variable height. I've come up with this: http://cssdeck.com/t/2veysdkg/16, which uses css tables to vertically center the main content.

    My demands for writing this particular piece of code were:

    • Must be able to center variable and fixed width content vertically and horizontally
    • Centered content must be inside the normal document flow (so no overlapping)
    • Sticky footer and normal header, both of 100% width
    • As few hacks, ugly code or non-semantic html as possible
    • I didn't care about support for IE6, IE7 (I'll use a different stylesheet for them)

    The weird thing is that the demands above are only met when the header and footer are set to display:table-row, and the body-tag to display:table. Which is weird because as I understand it the css will generate anonymous table elements when parent table elements are missing. So display:table-cell should work without all the surrounding elements, but yet I've not been able to make it work.

    If it were up to me I would prefer to not mess with the display mode for the body tag, and leave the header and footer on display:block. But I've not been able to make it work. Does anyone understand why this doesn't work, and how to meet the above demands without the use of display:table and display:table-row?

    For those who would rather not visit cssdeck to view my sourcecode I'll post it here:

    HTML

    <!doctype html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>Vertical Centering</title>
        </head>
        <body>
            <div id="header">header</div>
            <div id="vertical">
                <div id="horizontal">content</div>
            </div>
            <div id="footer">footer</div>
        </body>
    </html>
    

    CSS

    body, html {
        height: 100%;
        width: 100%;
        margin: 0;
        padding: 0;
    }
    
    body {
        display: table;
    }
    
    #header {
        display: table-row;
        height: 2em;
        background: gray;
    }
    
    #vertical {
        display: table-cell;
        vertical-align: middle;
        width: 100%;
        height: 100%;
    }
    
    #horizontal {
        height: 500px;
        width: 500px;
        margin: auto;
        background: gray;
    }
    
    #footer {
        height: 2em;
        display: table-row;
        width: 100%;
        background: gray;
    }
    
  • Admin
    Admin almost 12 years
    I've tried it, but it doesn't work for me: this way you lose the sticky footer, and the horizontal centering is off (too far to the left).
  • Admin
    Admin almost 12 years
    But that actually uses more html for layout purposes. My goal is to lessen the amount of unnecessary html and css. In my example everything works as I intended, and it uses less html than your example.
  • Admin
    Admin almost 12 years
    Also, it shouldn't be necessary to create the table and table-row elements for embedding the table-cell, unlike with html tables, with css-tables the browser should render an anonymous table automatically if any table elements are missing in the hierarchy (see: digital-web.com/articles/everything_you_know_about_CSS_Is_wr‌​ong).
  • Tony318
    Tony318 almost 12 years
    @Samuel How does this look? Took as much out as i could without drastically changing the layout. cssdeck.com/t/2veysdkg/20 EDIT Im not sure if you needed to keep the vertical div or not. If so you can add it back in with some slight adjustments to it. If it is necessary let me know and i'll try playing around again with it. EDIT2 It seems if you need vertical you can add the div back in and for the css just take out the display: table-row; line and it will still format properly
  • Admin
    Admin almost 12 years
    It looks ok, but my problem with absolute positioning the header and footer is that it takes them out of the document flow, allowing them to overlap other content. Also relative positioning of the centered element by % means that it isn't always perfectly centered (only at specific screenwidths/heights). What I'm looking for is a solution that retains the original properties of my design, but without the table and table-cell display properties.
  • Tony318
    Tony318 almost 12 years
    @Samuel one final change. Realized that the footer was taking the bottom of the browser window, not the bottom of the page, meaning that if you needed to scroll then the footer would be in the middle of the page. This fixes that problem cssdeck.com/t/2veysdkg/27
  • Admin
    Admin almost 12 years
    For me the footer renders a bit underneath the bottom of the browser window.. (I'm using FF12)
  • Tony318
    Tony318 almost 12 years
    I'm using IE with a pretty crappy screen resolution. I had changed it so that the footer would be at the bottom of the page when scrolling down instead of the bottom of the browser window which essentially could be the middle of the page depending on how long it is.
  • Admin
    Admin almost 12 years
    Well that's why you want a sticky footer. A sticky footer either sits at the bottom of the content, or the bottom of the browser window, dependant on which is further down. And coding in IE isn't really good for most designs. I'd suggest using chrome or FF.
  • Tony318
    Tony318 almost 12 years
    @Samuel after some playing and researching, it doesn't seem like you can get away from using both display and relative positioning. Vertical alignment is very buggy and usually relies on knowing the exact heights that you are working with. That in mind, not knowing the height leaves you with the relative positioning or display: table as the options. If there is another way i do not know it and google isn't helping either. Sorry i can't help more.
  • Tony318
    Tony318 almost 12 years
  • Admin
    Admin almost 12 years
    So how would you simplify (or improve) the code, keeping in mind the demands as stated in the question? Is it possible to obtain this layout more elegantly?
  • Admin
    Admin almost 12 years
    I'll ask you the same as Gareth: how would you simplify (or improve) the code, keeping in mind the demands as stated in the question? Is it possible to obtain this layout more elegantly?
  • MikeCruz13
    MikeCruz13 almost 12 years
    I personally wouldn't let the body act as the table. I think you could get away with it as is if you used pixels instead of percent, but otherwise, I would put a div around vertical to act as the parent and put the % height / width on that and take it off of vertical.
  • Admin
    Admin almost 12 years
    But that would mean I couldn't set the height to 100%, as that would push the footer out of the browser viewport. How would you solve that?
  • MikeCruz13
    MikeCruz13 almost 12 years
    That's already a problem with the way it is now. You can't have 100% of a 100% + 2em + 2em. If you want it to be liquid, I would go all % and use a min-height, min-width declaration. Your other option might be to put footer and header in vertical as siblings to horizontal. You can still position them at top / bottom.
  • Admin
    Admin almost 12 years
    I've put footer and header in a wrapper as siblings to the main content area: cssdeck.com/t/2veysdkg/46, as per your suggestion. Where would you put display:table-cell to vertically align the main content area, and how would you stretch the total height to 100%?
  • MikeCruz13
    MikeCruz13 almost 12 years
    you need to put display: table on the #wrapper and put the height / width on that. I also positioned it relative, which allows me to position the header / footer absolutely within the bounds of that box and stick them to the top / bottom. Also, keep in mind, i just put the 300px on the body b/c jsfiddle doesn't allow 100% on the body.
  • Admin
    Admin almost 12 years
    That is a good solution, but I have one problem with this kind of layout: the absolute positioning of the header/footer. Would it be possible to do this without positioning them absolutely (i.e. without taking them out of the document flow)? (I've put your jsfiddle in cssdeck here cssdeck.com/t/2veysdkg/47, they allow 100%)
  • MikeCruz13
    MikeCruz13 almost 12 years
    That first one gives you more control of the elements. Also, they are only positioned absolute-relative to the parent (table-cell), so they aren't gonna break out of that box. Here is the only other way I can think to achieve what you want: jsfiddle.net/mikecruz/gxK5T (make it fully liquid)
  • Admin
    Admin almost 12 years
    Hmm.. Yeah that's what I was afraid of. This way I'll not be able to fully control the height of the header and footer.. Seems to be a choice between my table based layout, absolute positioning or a percentage based height for the header/footer.. Which sucks, because none of them is ideal.
  • MikeCruz13
    MikeCruz13 almost 12 years
    Well, I don't got anything else for ya. I don't really see anything wrong with these options though. My preference would be to use the relative-absolute positioning in the css table. 2nd choice would be the liquid layout with utilization of min-height to set some minimum parameters. Good luck!
  • Gareth
    Gareth almost 12 years
    I wouldn't. If you want the whole page to use the table layout algorithm then there's no problem giving display:table; to the body element. If you don't want to treat the body specially then I would add a container element, and give that the table layout. Remember the issue here is that you want to apply extra styling to an otherwise anonymous element so you have to give it something to be referred to by. Although you don't want to add elements, this is acceptable here because your elements' layouts need to be related to each other, they aren't standalone.
  • Admin
    Admin almost 12 years
    I understand. I had hoped that there would be a way to make the design work (with a css/html combination I had overlooked). Thanks for helping anyway!
  • Admin
    Admin almost 12 years
    Thanks for the info, but with your solution the footer ends up underneath the browser viewport. Any idea how to fix that?
  • Admin
    Admin almost 12 years
    It looks all right in jsfiddle, but check it out here: cssdeck.com/t/2veysdkg/48, the footer is almost in the middle of the screen. Your margins on #horizontal sort of center the element, but this won't work for every resolution (in fact, it doesn't for mine).
  • Admin
    Admin almost 12 years
    Remove the top and bottom margins, and the layout collapses. So at the moment, this still doesn't solve my layout problem, as the original code will perform the vertical centering better, have a sticky footer and use less display:table tags. To rephrase my original question, what I'm looking for is: can you improve on my code without affecting its functionality or adding extra complexity?
  • Admin
    Admin almost 12 years
    Thank you, this is the first clear, articulate answer that relates to what I asked.
  • CSS Guy
    CSS Guy almost 12 years
    on this id #horizontal adjust margin. is there any else issue...?
  • Admin
    Admin almost 12 years
    By the way, I've made a design with an extra container with table layout, as you specified. Given this design (that uses an extra unsemantic div for the table layout), and the original (which applies the table layout to the body), which would you prefer? (you can find the designs here: cssdeck.com/t/2veysdkg/16 (original) and cssdeck.com/t/2veysdkg/51 (extra container with table layout)