CSS for Developers: Horizontal and Vertical Centring

First, an apology.  I will be using the British spelling for “centre”, because, well, I’m British.  But it gets really confusing because you have to use the American spelling in the code.  And doesn’t “Centring” just look wrong?

Part Five: Horizontal and Vertical Centring

One of the most common things you want to do with blocks of content is to centre it.  In particular, you would think that vertically centring content would be straightforward, but it turns out that in HTML/CSS it just isn’t.

5.1 Horizontal Centring
Centring a paragraph of text is clearly easy - all you need is text-align: center.  However, sometimes you want to centre a block, something like a div, without having all the text centred as well.  This is slightly trickier than you might expect, because the only CSS attributes you have are for centring text.

<html>
<head>
<title>Horizontal Centering</title>
<style type="text/css”>
#div1, #div13 {
background-color: #DDDDDD;
}

#div2, #div14 {
background-color: #BBBBBB;
}

#div3, #div15 {
background-color: #999999;
}

#container, #container5 {
border: 1px solid black;
margin: 5px;
}

#container5 {
text-align: center;
}

#to-center {
margin-left: auto;
margin-right: auto;
width: 200px;
border: 5px solid red;
}

#to-center2 {
margin-left: auto;
margin-right: auto;
width: 200px;
border: 5px solid red;
display: block;
position: relative;
text-align: left;
}

</style>
</head>

<body>
<div id="container”>
<div id="to-center”>
<div id="div1”>One</div>
<div id="div2”>Two</div>
<div id="div3”>Three</div>
</div>
</div>
<div id="container5”>
<div id="to-center2”>
<div id="div13”>One</div>
<div id="div14”>Two</div>
<div id="div15”>Three</div>
</div>
</div>
</body>
</html>

Using margin-left: auto and margin-right: auto on the block you want to centre is a neat trick for doing this.  And it works fine in Chrome and Firefox.  However, it’s not so great in IE 7:

The trick for getting it centred here (the second block) is to set text-align: centre on the div containing the block to centre (container5), then reset the text-align to left on the centred block (to-center2) so the text isn’t centred.  Yes, a total faff.

However, there is some good news.  You can get IE to behave the same way as the more sane browsers by setting it into Strict Mode:

Remember kids: Strict Mode Is Your Friend.  And all you need to do is add the following to the top of your HTML file:

<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01//EN” “http://www.w3.org/TR/html4/strict.dtd">

5.2 Vertical Centring

<html>
<head>
<title>Vertical Centering</title>
<style type="text/css”>
#div1, #div4, #div7 {
background-color: #DDDDDD;
}

#div3, #div6, #div9 {
background-color: #999999;
}

#div5 {
height: 40px;
line-height: 40px;
background-color: yellow;
}

#div2 {
height: 50px;
background-color: orange;
vertical-align: middle;
}

#div8 {
height: 40px;
line-height: 40px;
background-color: cyan;
font-weight: bolder;
}

#container1, #container2, #container3 {
border: 1px solid black;
margin: 5px;
}

</style>
</head>

<body>
<div id="container2”>
<div id="div4”>One</div>
<div id="div5”>Two</div>
<div id="div6”>Three</div>
</div>
<div id="container1”>
<div id="div1”>One</div>
<div id="div2”>Two</div>
<div id="div3”>Three</div>
</div>
<div id="container3”>
<div id="div7”>One</div>
<div id="div8”>Massive line of text that needs to wrap to show the centering totally doesn’t work when you have more than one line of text.</div>
<div id="div9”>Three</div>
</div>
</body>
</html>

Given some of the problems with horizontal alignment, it shouldn’t come as a surprise to find vertical alignment is not simple at all.

Us straightforward developer types would expect to be able to put vertical-align: middle on a div and expect all content inside that div to be, well, vertically aligned in the middle.  However this is not the case - see the orange block above.  A quick Google will tell you why this doesn’t work, and I don’t intend to duplicate the explanation here.

There is a nice hack which works for single lines of text though: if you set the height of the container and the line-height to the same value, the text will be vertically centred within that container (see the yellow panel, div5, above). This works really well for things like buttons or icons.

However, it doesn’t work so well for paragraphs of text or sentences that might wrap, line-height is for a single line of text only.  See the cyan panel above for what happens if your text wraps.

I’d love to give you an answer on how to get this to work for text that wraps, but I haven’t found a satisfactory solution yet.  What I usually do is set a fixed height on the container and then set the margin on the text so that it sits in a way that looks vaguely centred.  Not a solution I’m happy with, because a) it can sometimes render slightly differently on different browsers b) it’s a very fragile solution if you’re going to internationalise your page as some languages will have longer or shorter paragraphs and c) it feels like a massive hack.

If anyone has a nice solution for vertically centring paragraphs of text I’d love to hear it.

CSS for Developers: Cross Browser Table Border Behaviour

One of the aims of this series is to highlight some stupid gotchas in support for CSS in the different browsers.

Today’s gotcha is table borders.

Yes, yes, I said don’t use tables.  What I means is, don’t use tables for layout. But you can use tables for, you know, tabular data.  Like, for examples, lists of instruments and their bid and ask prices.

But you should know that even when you use strict mode, Internet Explorer has slightly… eccentric… rendering behaviour for tables.  Actually to be specific, it’s IE7 only.

<html>
<head>
<title>Table Borders</title>
<style type="text/css”>
table, td {
border: 1px solid black;
}
td {
height: 20px;
min-width: 5px;
}
</style>
</head>

<body>
<table cellpadding="0” cellspacing="0”>
<tr>
<td>first cell</td>
<td>second</td>
</tr>
<tr>
<td>
<div></div>
</td>
<td>
<div></div>
</td>
</tr>
</table>
</body>
</html>

The HTML here is a simple table with a border round all the cells (using CSS border, not the deprecated border attribute on the table) - a fairly common situation.

This is how it renders in IE7:

Note the distinct lack of a border around the lower two cells.  If a table cell is empty, or contains a div which is empty, IE doesn’t render the cell at all.

The cheat to get around this is to add &nbsp; into every empty cell - either inside the div, if there’s a div in there, or inside the td if there’s nothing else in there.  Then IE wakes up and remembers to render the borders.

CSS for Developers: Column Layout Using CSS

This is a continuation of my series of CSS hints / tips / cheats for developers (and other technical-but-not-UI people).

The screenshots are in Chrome on a Mac.  The originals were on Firefox on Ubuntu so I can tell you the behaviour is identical.

Part Three: Column Layout Using CSS (or: still no excuse to use tables)

Today’s example is a simple one, but worth knowing all the same.  The aim is, once again, not to use HTML tables to provide any sort of layout.  In most cases not only does using a div reduce the size of your DOM (and potentially help improve the performance of your page), it’s actually a lot less complicated to organise your layout this way.

3.1 Display Elements or Text in Columns

<html>
<head>
<title>Column layout</title>
<style type="text/css”>
#col1 {
background-color: yellow;
/**have to know the width **/
width: 30%;
float: left;
}
#col2 {
background-color: lightBlue;
width: 30%;
float: left;
}
</style>
</head>

<body>
<div id="col1”>
<div>1</div>
<div>2</div>
</div>
<div id="col2”>
<div>3</div>
<div>4</div>
</div>
</body>
</html>
Again you can see we’re using float on the divs to get them to appear side-by side.

The code is much more intuitive organised this way - everything from a single column is grouped together in a single div.  If this was done using tables, you’d have the content for a single column scattered in different cells on different rows of the table.  Re-arranging the order of the columns in the case of tables is much more of a pain in the neck.  With a div, it’s a simple move.

CSS for Developers: The Joy of Floats

As promised, the Long Awaited Follow-Up to CSS for Developers Part One! Well, long-awaited if you’re as afflicted with NADD as I am.

Quick recap - the aim of this series is to provide a quick and easy how-to around the magic that is CSS.  It’s primarily aimed at developers, although I would hope it’s comprehensible to a range of tech-savvy people.

(Note: unless otherwise stated, the screenshots are in Chrome on a Mac - given an earlier version of this guide I can tell you the behaviour is identical to Firefox on Ubuntu).

Part Two: The Joy of Floats (or: why they don’t do what you think they should)

Last time I stated that using float is a great way to position elements contained in a div.  Well, it has its downsides too.  Quite a few actually.

So this post documents the ones I ran into and what we did on the LMAX Trader UI to get it to look the way we wanted.

Disclaimer: There might be better ways to do a lot of this stuff - if you locate them via Google or work them out for yourself then well done!

2.1 Starting a New Line Using Floats

<html>
<head>
<title>Horizontal flow</title>
<style type="text/css”>
#left {
background-color: cyan;
width: 50%;
float: left;
}
#center {
background-color: yellow;
width: 50%;
float: left;
}
#right {
background-color: red;
width: 50%;
float: left;
}
#next-line {
background-color: green;
width: 200px;
clear: left;
float: left;
}
</style>
</head>

<body>
<div id="container”>
<div id="left”>Left</div>
<div id="center”>Center</div>
<div id="right”>Right</div>
<div id="next-line”>Next Line</div>
</div>
</body>
</html>
  • clear: left will reset any left float from before the div it is applied to. This will cause the div to be shown on a new line, although it can still have a float property as well
  • clear: right will put the div below any divs with a right float applied 
  • clear: both will do both. 

I usually do clear: both if I need to ensure the div will be on a new line.

2.2 Right Aligning Floated Divs

<html>
<head>
<title>Float Right</title>
<style type="text/css”>
#left {
float: right;
border: 1px solid gray;
}
#center {
float: right;
border: 1px solid gray;
}
#right {
float: right;
border: 1px solid gray;
}
#container {
background-color: yellow;
height: 26px;
}
#left2 {
float: left;
border: 1px solid gray;
}
#center2 {
float: left;
border: 1px solid gray;
}
#right2 {
float: left;
border: 1px solid gray;
}
#container2 {
clear: both;
float: right;
background-color: #90ee90;
height: 26px;
}
</style>
</head>

<body>
<div id="container”>
<div id="left”>Left</div>
<div id="center”>Center</div>
<div id="right”>Right</div>
</div>
<div id="container2”>
<div id="left2”>Left</div>
<div id="center2”>Center</div>
<div id="right2”>Right</div>
</div>
</body>
</html>

If you want to right-align a number of elements (for example, buttons at the bottom of a dialog), there are two approaches. One is to set float: right on each individual item (see the yellow panel above) - you’ll notice that this means the divs are displayed in reverse order, because they’re set to float to the right of each other. A better approach is to put the divs you want right-aligned into a container div and float that to the right (see the green panel). This ensures the correct ordering of the items.

2.3 Floating Behaviour to be Aware Of: float left next to float right (cross browser)

<html>
<head>
<title>Float right next to float left</title>
<style type="text/css”>
#left {
background-color: blue;
width: 50%;
float: left;
}
#center {
background-color: yellow;
width: 50%;
float: left;
}
#right {
background-color: red;
width: 50%;
float: left;
}
#next-line {
background-color: green;
width: 50%;
clear: left;
float: left;
}
#float-left {
clear: left;
background-color: purple;
float: left;
}
#float-right {
background-color: cyan;
float: right;
}
</style>
</head>

<body>
<div id="container”>
<div id="left”>Left</div>
<div id="center”>Center</div>
<div id="right”>Right</div>

<div id="next-line”>Next Line</div>

<div id="float-left”>Floating Left</div>
<div id="float-right”>Floating Right</div>
</div>
</body>
</html>

In Firefox and Chrome (tested under Ubuntu and OS X), if you clear the float on a single div element, that div and all the ones after it will appear underneath all the previous ones.  For example, see the “Floating left” (purple) and “Floating right” (cyan) divs above.  The two divs appear on the same line, floating side-by-side.

This may even be the same behaviour in IE in strict mode (I don’t remember if I tested it).  But by default, Internet Explorer renders this quite differently.

(Apologies for some of the inconsistency in screenshots - given my choices of operating systems, getting the cursed screenshots in IE was… challenging).

The point is that in IE the float: right is quite literal - it floats to the right directly underneath the last floated element, regardless of any prior clear commands.

If you want to get the same behaviour across all browsers, you need to be stricter with adding containers for different content areas:


<html>
<head>
<title>Float right next to float left - correct</title>
<style type="text/css”>
#left {
background-color: blue;
width: 50%;
float: left;
}
#center {
background-color: yellow;
width: 50%;
float: left;
}
#right {
background-color: red;
width: 50%;
float: left;
}
#next-line {
background-color: green;
width: 50%;
clear: left;
float: left;
}
#float-left {
background-color: purple;
float: left;
}
#float-right {
background-color: cyan;
float: right;
}
</style>
</head>

<body>
<div id="container”>
<div id="left”>Left</div>
<div id="center”>Center</div>
<div id="right”>Right</div>
<div id="next-line”>Next Line</div>
</div>

<div style="clear: both”>
<div id="float-left”>Floating Left</div>
<div id="float-right”>Floating Right</div>
</div>
</body>
</html>

2.4 Floating Behaviour to be Aware Of: parent divs of floated elements do not resize to child


<html>
<head>
<title>Floats in containers</title>
<style type="text/css”>
#left {
border: 1px solid blue;
float: left;
}
#right {
border: 1px solid red;
float: right;
}
#container {
border: 1px solid black;
}
</style>
</head>

<body>
<div id="container”>
<div id="left”>Left</div>
<div id="right”>Right</div>
</div>
</body>
</html>

In the code above, we have a “parent” div, container, with two children, left and right.  Both of these children are floating, it doesn’t actually matter that one’s left and one’s right.  What you might not be able to see clearly is that the parent, container, has zero height.  It’s got a black border, you should be able to see that the top and bottom of the border are actually next to each other, showing the div has no height of its own.

However the children have a height, the height shrinks to fit the content, the text.

What I’m trying to get at is that if you want to place something underneath the left and right divs, you can’t rely on the browser working out where the bottom is and placing other divs underneath them:


<html>
<head>
<title>Floats in containers</title>
<style type="text/css”>
#left {
border: 1px solid blue;
float: left;
}
#right {
border: 1px solid red;
float: right;
}
#container {
border: 1px solid black;
}
#container2 {
border: 1px solid yellow;
}
#left2 {
background-color: green;
float: left;
}
#right2 {
background-color: purple;
float: right;
}
</style>
</head>

<body>
<div id="container”>
<div id="left”>Left</div>
<div id="right”>Right</div>
</div>
<div id="container2”>
<div id="left2”>Left</div>
<div id="right2”>Right</div>
</div>
</body>
</html>

(You’ll note this is not an article about design! I’m trying to use a combination of colours, outlines etc to make the point clear, not to make it look good)

Basically the floated divs are effectively absolutely positioned, and therefore take up no space on the document (more on this in a later post).

The way I’ve got round this in the past is to set a specific height on the parent div to force any following elements to appear underneath it. This works, but it can be fragile. In particular, it doesn’t allow for wrapping text (more on this later too).

Still to come:

  • Position and Display: relative, absolute, block, inline… what does it really mean?
  • Horizontal and Vertical Centring
  • Strict Mode Is Your Friend
  • Column layout using CSS
  • Why “width: 100%” might go off the edge of the page
  • Cross-browser table border behaviour
Previously:

    CSS for Developers: Horizontal Layout Using CSS

    I’m a Java Developer.  But I’m also a Web Developer.  Web Developers have been so badly maligned over the last decade or so that I always feel wary (and sometimes slightly ashamed) admitting this.  There’s some sort of assumption that Web Developers (and Front End Developers) aren’t real programmers. Similarly, “real” developers don’t like to be tainted by coming into contact with that nasty “front end stuff” in case someone mistakes them for a designer.

    Trust me, no-one is going to mistake a Java Developer for a designer.  For a start, when designers wear geeky glasses it’s ironic.  Or chic.  Or something.
    But developers will be forced to do something around the front end at some point in their lives.  Even if it’s because they’re sick of manually kicking off some process and want to give the users a big red button to press instead.
    So, as much to compensate for my own goldfish-like brain as anything else, I’m going to make a note of some of the CSS stuff I’ve used or found helpful during my mad scramblings to get the LMAX Trader user interface to a) look the way we wanted b) perform fast enough so our awesome back end performance wasn’t totally invisible to the retail user and c) Not Suck Too Badly in Internet Explorer.

    Part One: Horizontal Layout (or: There’s No Excuse For Tables Any More)

    You may (or may not) have heard that using tables for layout is a Bad Thing.  But to be fair, most of us don’t care.  I’ve done it myself, it’s usually the quickest way to lay stuff out on the page, especially if you’re new to HTML / CSS and/or short on time.  There are loads of arguments all over the web as to why this is a bad thing, but the reasons I didn’t want tables on the LMAX UI was a) we saw the performance improve by a really simple replacement of tables with divs and b) given the amount the UI was mutating, divs positioned with CSS was going to allow us a much quicker turnaround for the umpteenth re-design of the UI (ideally the upshot of this would be letting the designers mess with the CSS when they changed their minds and leave us developers out of it).
    Anyway let’s assume Tables Are Bad.  Tables are only for tabular data, not for layout.  In my world.

    1.1 Simple Horizontal Layout Using Inline

    The most common use of tables for layout is where you put elements side by side - the default behaviour of divs is that they lay out underneath each other.
    However it’s pretty easy to get divs to behave this way too, and using divs has some advantages over using tables.
    <html>
    <head>
    <title>Horizontal flow</title>
    <style type="text/css”>
    #left {
    background-color: cyan;
    display: inline;
    }
    #center {
    background-color: yellow;
    display: inline;
    }
    #right {
    background-color: red;
    display: inline;
    }
    </style>
    </head>

    <body>
    <div id="container”>
    <div id="left”>Left</div>
    <div id="center”>Center</div>
    <div id="right”>Right</div>
    </div>
    </body>
    </html>

    The first option is to use display: inline.  This will lay div elements next to each other, similar to a span.  This is the simplest way to get divs to appear side-by-side.

    The disadvantage of this technique, however, is that inline elements can’t be sized the same way as standard divs.  By default they contract to fit the content.
    The screenshot above is from Chrome on the mac - you’ll notice by default the elements have some spacing between them.  Reducing the margin/borders on the elements doesn’t seem to eliminate this, so that’s something else you might need to consider if you use this mechanism to display elements side-by-side.

    1.2 Simple Horizontal Layout Using Floats


    <html>
    <head>
    <title>Horizontal flow</title>
    <style type="text/css”>
    #left {
    background-color: cyan;
    float: left;
    }
    #center {
    background-color: yellow;
    float: left;
    }
    #right {
    background-color: red;
    float: left;
    }
    </style>
    </head>

    <body>
    <div id="container”>
    <div id="left”>Left</div>
    <div id="center”>Center</div>
    <div id="right”>Right</div>
    </div>
    </body>
    </html>
    Similar to using inline, floating a div will do the following:

    1. Make it shrink to fit the content
    2. Lay it out side-by-side with any sibling floating divs.

    You’ll want to apply padding, margins, height, width and whatever else to make it appear less rubbish.


    1.3 Wrapping Horizontal Layout


    <html>
    <head>
    <title>Horizontal flow</title>
    <style type="text/css”>
    #left {
    background-color: cyan;
    width: 50%;
    float: left;
    }
    #center {
    background-color: yellow;
    width: 50%;
    float: left;
    }
    #right {
    background-color: red;
    width: 50%;
    float: left;
    }
    </style>
    </head>

    <body>
    <div id="container”>
    <div id="left”>Left</div>
    <div id="center”>Center</div>
    <div id="right”>Right</div>
    </div>
    </body>
    </html>

    The advantage you have using divs over tables is that you can get the browser to work out how the elements should flow.  Tables require you to determine exactly how many cells appear on each row, but with divs you can determine a width for each element and have the browser work out whether to show it on a new line or not.  This will work with both percentage and pixel widths.

    • If you want a more table-like structure where you know exactly how many elements should appear on each line, use a percentage of the screen with.  
    • If you know the width of each element, you should set a pixel width on the elements and have the browser work out how many to show per line.

    The next CSS post will go over floating behaviour in a little more detail.