Sam Croft

Full-stack developer

Quick CSS tip: creating percentage width borders without using superfluous markup


Filed in: css

Note: This article is about the physical width of a border based on its element’s size. This article is not about the border-width css property.

Lately I’ve been working on a lot of designs that require a percentage, or fixed, border width that is different to the width of the box model for the element it is being applied to. More often than not this is a centre aligned small border-bottom to visually separate one section from another.

The ‘width’ problem with CSS borders

Mockup of a percentage width border between two elements

The desired effect—creating a percentage width border with CSS is not as simple as it should be

The CSS border property does have a width property but it relates to the width (er stroke/thickness?) of the actual border, rather than the width the border covers on the box model. There is no way (that I am aware of) of controlling the actual width that the border spans across the box model, it’s always 100%.

The before and after pseudo selectors coming to the rescue, again

When I first discovered the :before and :after pseudo selectors it was awesome, I could do all sorts. But at the time, support was so limited I couldn’t really use them. I think this was around the time of IE 7 just having been released and pre-Chrome. It’s not until the last year or so that I’ve started using them more freely in my CSS.

Creating a percentage width border

As I mentioned above; I use this method to visually separate two, or more, sections. Consider the markup of two quotes:

		Here's to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square holes. The ones who see things differently. They're not fond of rules. And they have no respect for the status quo. You can quote them, disagree with them, glorify or vilify them. About the only thing you can't do is ignore them. Because they change things. They push the human race forward. And while some may see them as the crazy ones, we see genius. Because the people who are crazy enough to think they can change the world, are the ones who do.
		<cite><a href="" title="Think Different, an advertising slogan for Apple Inc.">Apple Inc.</a></cite>

		I made so many mistakes in running the company so far, basically any mistake you can think of I probably made. I think, if anything, the Facebook story is a great example of how if you're building a product that people love you can make a lot of mistakes
		<cite><a href="" title="Mark Zuckerberg: I've made so many mistakes">Mark Zuckerberg, Facebook Inc.</a></cite>

A couple of random quotes from some unknown SME‘s. Going with the requirement discussed above, I’m going to add a percentage width border in-between the two quotes to visually separate them. I can do this with a few lines of CSS and without adding any extra markup.

blockquote {
	position: relative;
	margin-bottom: 40px;
	blockquote:after {
		content: '';
		position: absolute;
		width: 50%;
		left: 25%;
		bottom: -20px;
		border-bottom: 1px solid #666;

Ok, so what’s going on here?

Lines 1-4 – firstly I am giving the position property for each blockquote element a value of relative. This will allow me to position the border so that it is relative to the quote position. I’m also going to apply some margin to the bottom of the quote.

Line 5 – now I am creating a new element by using the :after pseudo selector for each blockquote element that I can add the border to.

Lines 6-9 – here I am specifying that the content of this element will be an empty string. To position it correctly I give the position property a value of absolute. Following this I can apply left and bottom position values. For the purpose of this example the border will be 50% in width, see below, and thus require a left position of 25%. I’m also going to halve the value of the margin that I applied to the blockquote element. This will position the border exactly halfway in between each quote.

Line 10 – I set the width of the border – in this example; 50% of the width of the quote.

Line 11 – finally I set the border style. Nothing fancy here, just a simple border.

Of course, you will be left with a border after the last blockquote. Let’s get rid of that by combining the :last-child pseudo class and the :after pseudo selector:

blockquote:last-child:after {
	border-bottom: none;

This completes the effect.

The benefits of using this technique to create CSS percentage width borders

It’s a bit of a no-brainer really. No superfluous markup is required to create this effect and you can apply this technique just about anywhere in a design. While some might see the requirement of using advanced and pseudo selectors as a bad thing, I see it as an entirely positive thing. It’s basic progressive enhancement. Nothing is broken if the effect is not visible, but for the vast majority nowadays it will be visible anyway.



About the author

I'm Sam Croft a full-stack developer with over 15 years experience in web and app development. For the last six years I have been a partner of Running in the Halls, an app and game design studio based in Huddersfield, UK. During this time I have developed many web and applications. Highlights include a node.js/ app to create the worlds largest crowd-based game on the first series of Channel 4's Gadget Man with Stephen Fry and Librarygame, a Library gamification platform for Universities. Librarygame is being played by over 6,000 students at The Open University, The University of Manchester, The University of Glasgow and The University of Huddersfield.

In my spare time I enjoy long distance running, watching all sports (especially F1) and playing video games. I live in the Holme Valley in West Yorkshire with my wife, Alex.

Sometimes I tweet.

  • airtonix

    came here expecting a description on how to get around the fact that border-width does not accept percentage values :<

  • M.F.

    Bad article naming

  • Well, personally this is *exactly* what I was looking for. Thanks, Sam!

  • rickibarnes

    I came here hoping I *wasn’t* going to find a description on how to get around border-width not accepting percentage values :D This article is what I meant with my search terms.

  • Chris Catalano

    If you can’t apply positioning to the main element because it breaks your design you can simplify it as so:

    yourelementname:after {
    width: 60%;
    margin:0 auto;
    border-bottom: 1px solid #666;

    yourelementname:last-child:after {
    border-bottom: none;