CSS for frontend engineers

If you are working on a webapp, it is likely that sooner or later you will find yourself tasked with generating some web UI. While the esteemed colleague from the web design department excels at that (disclosure: I’m not a web designer), when asked for advice on how to get something “simple” done you’ll find that – left for a surplus of his or her empathy, skill and patience – you most likely will get an answer you can’t work with, either because it involves some fixed layout that does not scale, requires complicated markup or simply is counter-intuitive to your engineering instinct which asserts inner beauty and consistency to everything human made.

A note about this post:  As this article is evolving and I’ll be patching it from time to time and in order to reduce clutter, I will not denote changes with the usual [updated] tag.

In this post I will outline some of the recipes for getting standard things done easily and hassle free that makes sense to an engineer and, hopefully, is logically consistent 🙂 But I will also talk about things that would be nice to have, yet cannot be done with just HTML and CSS2 because they require Javascript.

Layout vs Microlayout

For the remainder of this post, I’ll distinguish between layouts and microlayouts. While a layout is applied to the page as a whole, a microlayout affects a block of elements such as some text and images in a container or nested containers. This is important for modularization which allows us to create and style resuable HTML components (think of taglibraries or tagfiles in JSP).

Tables: when to use

To make it short: tables have severe drawbacks even though at first they might seem the most obvious solution to get a layout right. The pros: the content scales to the extent of the screen, there are no line breaks with narrow screens, cells are placed exactly where you want them and colspan/rowpan allow for some pretty neat layout effects. Which is also the downside of designing with tables: they don’t fit equally well on big and small screens and do not allow to put more content in a line for bigger screens than originally designed for. When the screen is smaller than you designed for, scrollbars appear and when it is larger, content seems lost with wide gaps spread in between. Also the available width is equally/proportionally distributed across columns, which is something you probably do not want – one usually would like the extra space to go to some of the columns while others stay at a fixed width.

Use tables when:

– all columns of a layout stay on the same line regardless of page width
– rowpans or colspans are necessary
– the data displayed is tabular by nature

Don’t use tables when:

– depending on the screen width more or less content should fit on a line
– line breaking should occur and content should overflow to the next line
– a fluid layout is required
– Internet Explorer (IE forthon) renders rows containing cells with rowspan or colspan always at an automatically calculated height, overriding any manual settings

Intelligent layouts: layouts and microlayouts with DIVs

When handled properly, nested DIVs exhibit marvelous properties: they align nicely, content scales to small and big screens and your design makes best use of screen real estate.

Elements in a fixed container

A simple form of layouting is just inlining elements in a container. The container has a width equal to half the page width, thus you can observe how the (micro)layouting behaves when resizing the browser window.

Content
Content
Content
Content
Content
Content
Content

  

Content

  

Content

The key elements here are the float property and the (implied) display:block property. They make sure that one is aligned next to the other. The total available space is determined by the container, causing the Content elements to break every time the width is filled up.
A note on the “implied” display block property: DIVs have their display setting by default set to block. While it looks odd at first that a layout with inlined elements should use a display:block setting, this is not only ok but also neccessary: the float setting overrides the block behaviour, but on the other hand elements can assume concrete dimensions (when specified via width and hight) only when their display setting is block – it will not work with an inline value.

Container size determined by its content

This case is similar to the previous one, only that now we’ll remove the fixed size definition from the Container. 

Content
Content
Content
Content
Content
Content
Content
Wait, what happened here? This doesn’t look right… the container seems somehow to have collapsed into a single line. The reason for this is the behavior of the overflow css property. In order for us to get the Container to engulf its content, we need to specify a – rather surprising – overflow:hidden property. While this instructs the browser to hide every content that transcends the Container’s borders, it also causes the Container to inflate to a sufficient extent to contain all Content elements.
Content
Content
Content
Content
Content
Content
Content
That is somewhat better. But why does the container’s width extend further than the contents? Here it is that finally float and display coallesce: While floating alone would allow elements to line up next to each other, the display:block setting still would imply that an element takes up all horizontal space anyway. Now float:left overrides that behavior, getting HTML elements to horizontally adjust to their contents.

Content
Content
Content
Content
Content
Content
Content

And this is the HTML:

Content

Content

Aligning multiple Containers

Now lets try this with nested containers: I want a container which contains another container of a fixed size and gives the rest to a wildcard container:

Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content


Content




Content

Content


Sections: Forcing linebreaks


A break in the layout is best achieved with the clear property:

Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
New content

And here is the corresponding HTML:

Content


Content

Content

<div style="background-color: skyblue; border: 2px solid black; clear: both; overflow: hidden;”>
New content