Forums user McAsh wondered how they might code up a design in which there was a large header and a smaller subheader beneath it which featured double horizontal lines jutting out after the text to both the left and right of the centered text. An easy thing to mock up as image, but a much more difficult thing to pull off in CSS because of the variable nature of text (length, size, etc).
The post mockup was this:

I coded up one way to do it which works, but isn’t quite perfect. I figured I’d post it here and you all could chime in with better ways if you can think of them.
If the background was a solid color, this would be fairly easy. Apply the lined background to the subhead and center a span in the middle with a bit of padding and a background color to match the solid background. We don’t have a solid background color here. Perhaps some trickery using the same background image but fixing the background position would work, but I didn’t go there.
Instead, I used the ::before and ::after pseudo elements to create the left and right set of lines. The text is still in a span, which is relatively positioned. The right set is a pseudo element on that span which starts 100% from the left with a bit of margin to push it away, and vice versa for the left set. Both are of a fixed height and use border-top and border-bottom to create the lines. Thus no backgrounds are used and the insides of everything is transparent.
The length of the lines is long enough to always break out of the parent container, and they are cut off by hidden overflow on that parent.
.fancy {
line-height: 0.5;
text-align: center;
}
.fancy span {
display: inline-block;
position: relative;
}
.fancy span:before,
.fancy span:after {
content: "";
position: absolute;
height: 5px;
border-bottom: 1px solid white;
border-top: 1px solid white;
top: 0;
width: 600px;
}
.fancy span:before {
right: 100%;
margin-right: 15px;
}
.fancy span:after {
left: 100%;
margin-left: 15px;
}
Example:
Check out this Pen!
There are two things I don’t love about this.
- The line-height: 0.5 thing in there to center the lines around the text feels like a “magic number” to me which might not be right depending on the font.
- The width of the pseudo elements lines isn’t exactly what they need to be, but way longer than they need to be and cut off.
Neither are that huge of a big deal but little things that probably could be cleverly fixed.
Awsome! Will be using on my next project!
One clean way would be to use CSS gradients. Either with no fallbacks or a dataURL.
Change the color.
“fancy span” haha cleaver!
I just finished pulling one of these off using a span to center the text and add the solid background color to act as the transparency with some padding.
I never really gave much thought to if I wanted to have it on a background that doesn’t have a solid color.
Thanks for this Chris.
Chris, to address your “magic number” concern, instead of doing
line-height: 0.5
, you can use percentage-based positioning (top: 50%
) on the pseudo-element. This also lets you putoverflow: hidden
on a.fancy
element instead of the<article>
, which is nice, in case you need to have other pseudo-elements escape the<article>
.Here’s the code
Since you always know the height of the double-line flourish, you can set a negative
margin-top
equal to half that height. Sass isn’t required, but I used it to show how this method doesn’t require guesstimate numbers.I attempted to test the code you provided. I tried it off of Codepen… without using a custom font. My result was one solid line. Whereas the original method worked. I didn’t change the “magic number” when I was testing; so I don’t know if that will change.
This method is especially helpful when offsetting the lines to either the left or right
I faced the same problem with a website I was building & I coded it like this
The site has two variations of this one that spans the full width of the container & another one which doesn’t fill 100%
The only thing I don’t like here is that whenever I want to use it on different background I have to change the span background color.
thx for your code, refactored it for our usecase and works like a charm. …
Nice solution , but i have a question, how can I apply this to an image (like a logo), instead of a text?
You may want to check out this:
http://pepsized.com/demo/?id=614
This is how she handled it:
h1:after {
content: “”;
height: 2px;
display: block;
position: absolute;
left: 0;
right: 0;
top: .5em;
z-index: -1;
border-top: 1px solid #504331;
border-bottom: 1px solid #504331;
}
Nice use of “embiggen” as a class name! It is a perfectly cromulent word. :)
Can you use flexbox on pseudo-elements? That seems like it would make it easier to do this kind of thing.
Actually,
display: table(-cell)
might do the trick: http://codepen.io/aaronjamesyoung/pen/nFiDqnice and simple technique
I tackled a similar topic a while back, which uses a single horizontal line on both sides of the heading:
http://www.impressivewebs.com/centered-heading-horizontal-line/
In addition to my four methods, all of which use an extra span, there are a bunch of other suggestions in the comments, including this one:
http://www.impressivewebs.com/centered-heading-horizontal-line/#comment-34913
by Pablo Villoslada Puigcerber, which doesn’t need a span, and I believe will work with various backgrounds too. And I’m actually using the linear gradient method (which Hugo mentions above) on my website’s footer, which I think is fairly easy to do and clean, if you don’t care about the extra span. And in this day and age, you shouldn’t care about the extra span, because removing it makes absolutely no difference to anything in the universe. :)
Here’s a quick fork that makes it two lines like in Chris’ example. It’s font size independent.
http://jsfiddle.net/F3UqW/
Here’s another fork ported over to Chris’ original Pen
@Colin – your method works like a charm – the negative margin does the trick and simply needs to match the width of the pseudo elements. Brilliant.
Here’s how to do it with flexbox (Chrome only), as suggested by Aaron: http://codepen.io/anon/pen/IKbFx
And here’s another way to do it without flexbox, which removes the line-height “magic number” issue: http://codepen.io/anon/pen/crEJa
The second solution sets the width of p.fancy to 200%, then shifts the text back using text-indent of -50% (50% of 200% = 100%). That allows for using inline-block pseudo elements, instead of absolutely positioned ones.
Here’s how to do it with flexbox (Chrome only), as suggested by Aaron: http://codepen.io/anon/pen/IKbFx
And here’s another way to do it without flexbox, which removes the line-height “magic number” issue: http://codepen.io/anon/pen/crEJa
The second solution sets the width of p.fancy to 200%, then shifts the text back using text-indent of -50% (50% of 200% = 100%). That allows for using inline-block pseudo elements, instead of absolutely positioned ones.
Using the table display technique means you can do it without any other elements. Aaron Young is on the right track, but you don’t need to use a span. Here is one of my StackOverflow answers from a while ago that shows how: http://stackoverflow.com/questions/13714432/create-css-header-with-centered-logo-and-lines-that-extend-out-from-the-right-l/13714634#13714634
I quite like the table cell technique. I think it’s the best possible way. No overly sized elements. Easy centering both horizontally and vertically.
how about this?
is there anyway it would be safe with resizing and zooming?
Changing the size doesn’t seem to do anything, but I guess it can’t be just that simple.
What’s the flaw in it?
The only problem is that you can’t change the distance between two lines other than using different font, that is.
I made a quick demo on this, let me know your thoughts: http://codepen.io/catalinred/pen/bwqta
I decided to use the pseudo table-cell trick. I combined it with transforms to bring the top and bottom borders closer together. This means I don’t have
overflow: hidden;
, there are no “magic numbers” and the lines are exactly the width they need to be.Because this trick does not rely on multiple backgrounds or linear-gradient it also works in a wider range of browsers. Even IE8 is acceptable :)
Excellent! This is a great solution – way to think outside the box with your transform idea.
The only issue is that this won’t work for responsive sites in which headings might have to wrap (
white-space: nowrap
, and it breaks if this rule is removed).I’d love to find the solution that works for wrapping as well.
PS – caniuse.com also indicates that transforms aren’t supported in IE8. That won’t be a problem for too much longer, but I just wanted to add that tidbit.
Excellent – Thanks for posting.
Smart. How is the support for Internet Explorer?
Hey Chris, I found that if I give the .fancy :after and :before pseudo lines a width of 100% the lines will be the same with of the fancy heading, or if a smaller percentage such as 80% is used it would be that percentage of the total width of the heading.
If the heading were to gain or be added more character the lines will adjust accordingly, which is where the overflow hidden could be an interesting solution to hide any excess lines that would extend beyond or outside the content container, or at that point it might be better to just use a smaller fixed pixel width value.
Awesome example!
Also I find that if you use 100pts or point values instead of pixels or percentages could be a better solution than the one I just posted above.
Hey Chris, I read the top part of the article and decided to try it out on my own first before seeing your solution.
This is what I came up with: http://codepen.io/rzea/pen/ecrfL
Some notes on this solution:
1.- It doesn’t use extra markup
2.- CSS is a bit shorter
3.- The width of the side lines are not “container” dependent, meaning they are the same width regardless the element is applied to.
4.- Depending on how something like this would get implemented, I may/may-not be using “magic numbers”, but hey, I had to assign values to this thing, eh? lol.
Let me know what you think.
Looks good to me. Just slightly different requirements with the lines-on-sides being a static width not the “remaining” width (which you make clear in your demo).
I recently had to the exact same thing. Firstly I did a brief search on how to do it but could not find anything (mostly because I didn’t know how this thing is called technically). So I started thinking. Initially I did with good old table with three td and the center one with white-space: nowrap and width: 1px. This worked fine but then I wanted to remove the tables and came up with this solution http://cdpn.io/BcnaE Hope it helps.
:)
A nice approach to this seemingly simple, and of course very nice, design feature.
The discrepancy here between the ease that designers’ enjoy and the complications that front-end folks deal with is quite significant!
Center the pseudo-elements vertically:
top: 0;
bottom: 0;
margin: auto;
http://codepen.io/anon/pen/vaGoe
Thanks Chris, I used something similar in one of my projects… ;)
Thanks Chris!!! I used that in my project that I’m working on right now. You saved me a lot of time : ) I used the @Денис method to center the pseudo-elements vertically and it all worked perfectly.
The additional markup (span element inside h1) is kinda nasty. So I tried to get rid off the span, but unlike Ricardo’s solution fill the whole width with the lines-on-sides.
I went through some iterations that relied on a background color, i.e. they didn’t work with background images. Cf. this
forum thread (in German, but you’ll find links to samples).
Finally, I came up with this solution.
It works with just
<h1>Heading</h1>
markup. The basic idea is to usedisplay: table-cell
like Marush did, but for pseudoelements.Oops. I swear I hadn’t seen Joshua’s comment before.
The
Fieldset
and<legend>
html tags is the easiest way to accomplish this and it’s not even a hack though you have to change your markup.Simple use:
Demo here: http://jsfiddle.net/F3UqW/
Found on StackOverflow
Yes, but that’s a completely non-semantic way of accomplishing it. Let’s try to respect the markup we all love :)
From the MDN:
Better ways of doing it with
:before
and:after
.I was the one asking for this solution and I have to thank you again for this one, Chris. If you’re interested in seeing the outcome you can check it out here:
http://malenemailand.dk
I’m trying to achieve a similar effect but with a single underline which extends out from the end of the heading and fills the remaining space available on the line…
However, I’m having problems containing the ‘underline’ inside the parent container.
Any thoughts?