This is the celebrated journal of Mr. Simon Collison A.K.A Colly

CSS Challenge: Come on, boffins!

28th October 2005

Today a colleague set me a CSS challenge that I just can’t meet. I can sort of achieve the desired effect with appalling markup and combined paragraph and unordered list styles, but that’s awful. Maybe one of you boffins out there can make it work, or maybe it’s just plain impossible. Here’s the skinny…

The challenge

The aim is to apply underlines to paragraph text that stretch the whole width of the column (without using justified text), regardless of the lengths of the paragraph text itself. Whilst this can be achieved with background images, this will be useless when the user resizes the text, as the text will break out of the lines and look a right mess.

What we don’t want is this

Here is the easy way, but not what we want. Applying a bottom border to the paragraph would only give us one border underneath the paragraph, so inside the paragraph, a span is used to apply the bottom border to the text. That’s fairly easy, but the lines do not stretch to the full width of the column:


So that is no good. We need to make the lines stretch, and also have them resize with the text.

How it should work

OK, here is how I want it to look. See that the horizontal lines stretch the full width of the container, regardless of the text:


Why can’t we use background images?

Yes, it’d be easy to create a background image of horizontal lines and combine that with line-height in the paragraph to achieve the effect, but if you resize the text with the browser, the background image is not gonna resize with it. Check out the dark blue area on The Big Noob. A lovely site, and they’ve carefully combined the background image with the text. However, if you resize the browser, the text breaks out of the lines and it looks a bit wrong.

What can we use?

I’m trying combinations of absolute and relative positioning, display: block and display: inline, differing line-heights, custom underlines - all sorts really. The only rules are that we shouldn’t need extra markup bloat (such as my unordered list) and the thing should validate. That’s it. Anything goes.

Can you help?

Make it happen first, and I’ll send you a little prize. Link to a working example on your server, with explanatory text if possible, or leave tips in the comments. Ensure the text resizes on all important browsers, and that the lines adjust accordingly. If you crack it, and your code is lean and valid, you’ll win something as yet undecided, and get bigged-up on these here pages. Alternatively, do you think it’s impossible?

I can’t keep banging my head against a brick wall here, so it’s TEAM time (Together Everybody Achieves More). Go web, go!


# Tobias Bergius responded on 28th October 2005 with...

It will work if you set display: block on the span elements. See

# Rob Lewis responded on 28th October 2005 with...

Tobias - that seems to break at certain text sizes (I’m using Firefox 1.0.7 on Win XP)


# Simon Collison responded on 28th October 2005 with...

Tobias I got excited then, but then I realised you have broken the paragraph into individual lines - each of which is contained inside a span.

I can’t do that - it defeats the point of paragraphs and their flexibility for any copy, and the lines wrap if you size the text too high. Good try though…

# Lachlan Hunt responded on 28th October 2005 with...

I believe it really is impossible; but then again, things that are impossible just take longer.  The problem is that the only way to make each line box the same width in order to apply underlines or borders of the same length is to use ‘text-align: justify;’, but you’ve already decided against justified text.

There is also no supported method of spacing out the background image and it looks like the proposed ‘background-spacing’ property has been removed from the latest CSS3 backgrounds draft.

# Stuart responded on 28th October 2005 with...

Here’s my effort. I use a span to get the width right across and a background image on the p to fill in the bottom line. It’s not perfect but I can’t see how this can be done with just the paragraph element.

Resize lines test

Firefox works, IE mainly works but there’s a bit of the line missing on the top right. Opera needs a 1px bottom-padding on the p which needs to be applied using a hack or some other method. I’m still working on it.

# Simon Collison responded on 28th October 2005 with...

Stuart: Again, I got excited, but you can’t use text-align: justify…

# Simon Clayson responded on 28th October 2005 with...

Leave it Colly, she’s not worth it!

I hope that there’s no tight deadlines on this. Whats more the prize on this is better be good Mr Colly, but if it’s something as great as a giant box of Mini Rolls I may reconsider and give it some time. The solution is going to have to involve some extreme geekery beyond my ‘thinking in pictures’ mindset.

I like Lachlans definition of impossible.

Another way of looking at this is ‘It’s Friday afternoon and I think I’ll have a cup of tea’.

# Stuart responded on 28th October 2005 with...

It’s a great challenge but without text-align: justify it just can’t be done. (I’ll be happy to be proved wrong though)

I had played around with this exact problem in the past but my example above is about as far as I got.

I’ll put the kettle on.

# siftee responded on 28th October 2005 with...

Yo colly! is javascript an option? if so i can whip you up something

# Simon Collison responded on 28th October 2005 with...

Siftee: Yeah, JS is fine. Ian’s example looks great, but found a couple of problems, so feel free to keep trying.

I think Ian Lloyd has come really close!

Ian’s example. It uses javaScript, but it’s unobtrusive. I’m checking it out…

Problems with Ian’s example: If I add a new paragraph, it gets placed on top of the other one, and links weren’t rendered when I added them. Still checking it out.

Hmm. Simon Willison pointed out that Ian’s example also adds a 2000 px bottom border to the paragraph. Not there yet…

# Simon Collison responded on 28th October 2005 with...

Simon Willison’s example only works in Firefox at the mo (he says) but looks good, although lots of spans needed in storage. The source will explain more:

Simon Willison’s example.

Simon: “The way mine works is that the div full of spans that generates the lines is absolutely positioned inside the container div, and has overflow: hidden to make sure only exactly the right number of lines is visible. The container div stretches with the paragraph.”

# Jonathan Snook responded on 28th October 2005 with...

In FF, with Simon’s example, I run onto the odd occurrence where the last line sometimes does not have an underline on it.

# Lachlan Hunt responded on 28th October 2005 with...

Ian’s example looks good, but instead of inserting “.” into each list item, you should use an no-break space.

var newText = document.createTextNode(”\uA0”);

Otherwise screenreaders will likely start reading out “DOT” for all 30 list items.  At least no-break space will not be heard.

# Jonathan Snook responded on 28th October 2005 with...

Also, I think the other problem with Simon’s is if there’s a link on any of the text… I don’t think it’ll be clickable because the positioned elements sit on top of it.

# Mike Stenhouse responded on 28th October 2005 with...

This is a bit shonky but it combines Ian and Simon’s solutions in a quick 3 minute fix:

Needs plenty of tidying but it works. Roughly. In FF and IE6/PC. Don’t have time for a proper test myself…

# Jonathan Snook responded on 28th October 2005 with...

Okay, now I’m just spamming these comments but here’s my entry. Downfall: I duplicate the node and make the text the same colour as the background. So, if you have a patterned background then it wouldn’t really work. And IE isn’t redrawing the border on the last line.

# Simon Collison responded on 28th October 2005 with...

Jonathan: Superb! Really lean, and cross-browser. Degrades with JS off well (though all do). This is really close.

Have you based your tweaks on the work the others did? It’s gonna be hard to give just one prize here.

Any more for any more? I say Jonathan’s is the one to beat at the moment…

# Mike Stenhouse responded on 29th October 2005 with...

I like Jonathan’s too - lean mean and, er, works!

# Jonathan Snook responded on 29th October 2005 with...

I took the idea of absolutely positioning an element from Simon and using Javascript from Ian. Using color to hide the text was all mine. :)

Mine could certainly be cleaned up and made more unobtrusive. I just did it quick and dirty to see what could be done.

# Blair responded on 29th October 2005 with...

Nowhere near as elegant as Jonathan’s, and someone would need to work out the JS (no time right now) but the following will work in Safari (untested, otherwise).

Blair’s example put online by Colly.

# Simon Collison responded on 29th October 2005 with...

Jonathan: Still love it, but noticed that if you go way high on text size, any lines with just one word have shortened underlines, and in all cases the last line is short no matter how many words there are on it.

Otherwise bloody brilliant.

# Blair responded on 29th October 2005 with...

Sorry about the bloody mess I’d made earlier, Colly. Thanks for putting it into an actual HTML file and posting it. Considering how much better Jon’s is, though, I’ll no bother trying to complete the JS for it…

# Ian Lloyd responded on 29th October 2005 with...

Ah well, I know that there were neater versions offered, but I managed to get the multiple paragraph thing sorted, and as for the big fat white border, that was contained in the outer div to some extent. I’m bailing out now with this version which needs tidying on a whole heap of areas - I think Jonathan’s version wins out on simplicity alone!

Gotta say, though, this was an excellent head-scratcher of a challenge that forced me to try out some unobtrusive Dom stuff (which I really need to get some practice in!)

# Lachlan Hunt responded on 29th October 2005 with...

Ian Lloyd, I see you tried to output the no-break space, as I sugested in a previous comment.  However, you also copied my mistake.  You should use “\u00A0”, not just “\uA0”.

# David responded on 29th October 2005 with...

Here is my try - it doesnt work but there may be something I’m missing or I may just be missing a few brain cells.

My idea was to use a background image of an underline that is the same width of the paragraph and has some white space built into it. (above the underline)
Then in the paragraph’s background image have the underline repeat-x and position it using ems - 0 1.8em.
1.8 em being 180%, the same line height I made for my image.
The part I thought might work was, because ems are relative units, an image sized with ems sizes relatively with the font size adjustment.
So positioning the background image at 1.8ems should resize the image with text resize.

But, it doesnt work. Was just a thought.

# David responded on 29th October 2005 with...

Sorry, here’s the url:

# Simon Collison responded on 31st October 2005 with...

Snook wins!

Give me a day or two, and time to iron out tiny issues with Snook’s example, and I’ll document the final winning technique, name it after him and the others whose code he added to, and try and add a few examples also.

Nice one, Snook - you win a prize. Email me your postal address when you can.

# Joram Oudenaarde responded on 4th November 2005 with...

I’m a complete noob in css and xhtml, so please bare with me here;

If you decrease the line-height, and place styled

< hr >

in between them, you wouldn’t need any Javascript right? And you can make the hr’s look like anything you want, including seteting the width to 100% ;)

Wouldn’t that be a solution?

# Ian Lloyd responded on 4th November 2005 with...

Well Joram, the thing is that when you resize text, it wraps onto the the next line, but with <hr /> you can’t be sure where the line will wrap and the horizontal line will not re-flow with the text. Besides, the hr element is presentational - almost as bad as using reams of font tags - if you wanted to remove underlines later you’d have to remove many instances in that page (and any others that used it). CSS is the preferred option every time, but it will not achieve the exact effect Simon was after, hence the challenge.

# waz responded on 5th November 2005 with...

Lachlan Hunt, thank you.

I’ve been looking for an hour for a way to create a blank cell using createTextNode and you led me to it:

var textNode;
var cellLeft = row.insertCell(0);

textNode = document.createTextNode(”\u00A0”);

Many blessings Lachlan.  May you never be hunted.

Responses are now disabled Your ability to respond is disabled automatically some 30 days after articles are published, or manually much sooner if spamming guttersnipes target a particular article.

Prev 524 Next

Superfluous Aside

Archived in HTML & CSS, Design & Web

There are 30 responses

External References

Copyright © Mr. Simon Collison 2003-2017. Protected and licensed under a Creative Commons License. Grab the RSS feed

Engineered in Nottingham, scaffolded by ExpressionEngine, steam-pumped by United & kept alive with tea and hugs.