Maybe there’s a technical term that I’m not aware of for this type of centered line-splitting heading. Whatever it’s called, I’ve used it in a project’s footer in the past, where I’ve divided the footer into sections with headers that look something like this:
I wanted to create such headings but with certain rules and restrictions:
- No images
- No extra HTML
- Scalable (that is, you could add larger text and it automatically sizes to fit)
- Fluid
- No JavaScript
Unfortunately, I could not figure out a way to do this while meeting all those requirements. All solutions come close, but they all require an extra element that overlays the line.
Maybe there’s something I haven’t thought of, but below I’ll outline the four methods I’ve brainstormed, including the one I’m using on the headings in my footer.
Method 1: A Pseudo-Element
With this solution, I’m adding an absolutely positioned pseudo-element inside the heading element. The pseudo-element has a top border, and it’s positioned halfway down from the top. I also wrap the heading text inside a <span>
to overlap the center portion of the horizontal line. The pseudo-element is z-indexed to ensure it’s below the span.
As I’ve done with all examples, the <span>
has left and right padding, to give the text some room to breathe.
Here’s the code:
h1:before { content: ""; display: block; border-top: solid 1px black; width: 100%; height: 1px; position: absolute; top: 50%; z-index: 1; } h1 span { background: #fff; padding: 0 20px; position: relative; z-index: 5; }
Drawbacks?
The extra span and the fact that pseudo-elements don’t work in IE6/7. But because this is decorative, it degrades into nothing, so not a bad solution if you don’t mind the extra element.
<
p class=”codepen” data-height=”343″ data-theme-id=”461″ data-default-tab=”result” data-user=”impressivewebs” data-slug-hash=”RwbzJaK” style=”height: 343px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;” data-pen-title=”Centered Heading Over Horizontal Line with CSS”>
See the Pen
Centered Heading Over Horizontal Line with CSS by Louis Lazaris (@impressivewebs)
on CodePen.
Method 2: Adjacent Sibling Selector
With this method, I’m using the adjacent sibling combinator to target and apply the border to the first paragraph after the heading.
Once I’ve targeted the paragraph, I give it a top border, plus a negative margin and top padding equal to the amount of the negative top margin. Again, the <span>
is needed to cover the border where the text is. Because the paragraph appears after the heading/span combo, the paragraph will naturally appear under the span, so no need for z-index.
The code is minimal:
h1+p { border-top: solid 1px black; padding-top: 2.5em; margin-top: -2.5em; }
Drawbacks?
This selector doesn’t work in IE6 and you still need the extra <span>
. Also, the top padding and top margin on the sibling element are essentially magic numbers, so you’ll have to adjust those to suit your needs.
If you’re not sure what element is going to appear after the heading, then you could use the universal selector, like this:
h1+* { border-top: solid 1px black; padding-top: 2.5em; margin-top: -2.5em; }
I’m not entirely sure if that has any other drawbacks or quirky behaviour, but it did work in all browsers that support this selector.
<
p class=”codepen” data-height=”372″ data-theme-id=”461″ data-default-tab=”result” data-user=”impressivewebs” data-slug-hash=”zYOVaBV” style=”height: 372px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;” data-pen-title=”Centered Heading Over Horizontal Line with Adjacent Sibling Selector”>
See the Pen
Centered Heading Over Horizontal Line with Adjacent Sibling Selector by Louis Lazaris (@impressivewebs)
on CodePen.
Method 3: Linear Gradient
With this method, I’ve placed a linear gradient directly on the <h1>
element. The gradient has color stops set to make the gradient appear like a simple horizontal line. Again, the extra <span>
is needed, to ensure the area behind the text covers the gradient.
Here’s the code:
h1 { background: linear-gradient(#ffffff 0%, #ffffff 49%, #000000 50%, #000000 51%, #ffffff 52%, #ffffff 100%); }
This is the method I ended up using in my project.
Drawbacks?
Besides the extra <span>
and no support in IE6-9 (which isn’t a big deal today).
<
p class=”codepen” data-height=”379″ data-theme-id=”461″ data-default-tab=”result” data-user=”impressivewebs” data-slug-hash=”GRKbGvv” style=”height: 379px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;” data-pen-title=”Centered Heading Over Horizontal Line with Linear Gradient”>
See the Pen
Centered Heading Over Horizontal Line with Linear Gradient by Louis Lazaris (@impressivewebs)
on CodePen.
Method 4: One of the Above Methods + JavaScript
This method inserts the extra <span>
element using JavaScript, so it could be combined with any of the methods shown above. Here’s the code:
var myHeading = document.querySelector('.four'),
myHeadingText = myHeading.innerHTML,
myFullText = '' + myHeadingText + '';
myHeading.innerHTML = myFullText;
There might be a few different ways to insert the <span>
(remember, you need the <span>
to wrap your heading text, not just be inserted next to it), but this is the method I chose.
Drawbacks?
Requires JavaScript, and there’s still an extra element — it’s just not in the HTML. If you choose to do this with Method 2, then you’ll have support everywhere except IE6 (which doesn’t support the adjacent sibling selector).
<
p class=”codepen” data-height=”374″ data-theme-id=”461″ data-default-tab=”result” data-user=”impressivewebs” data-slug-hash=”xxKozPw” style=”height: 374px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;” data-pen-title=”Centered Heading Over Horizontal Line with JavaScript”>
See the Pen
Centered Heading Over Horizontal Line with JavaScript by Louis Lazaris (@impressivewebs)
on CodePen.
A Note About Responsiveness
None of the examples above are responsive out-of-the-box except the last one that uses JavaScript. But in all cases, you’ll just need to remove the styles that create the horizontal line on smaller screens using media queries. So something like this:
@media (max-width: 480px) { .four:before { content: ""; border: none; } .four span { background: inherit; position: static; padding: 0; } }
In this case, I’m resetting the pseudo-element version.
Can It Be Done Another Way?
As always, when I finish a post like this, I’m always thinking that someone’s going to point out something extremely obvious that I’ve missed. So I’d be glad to hear if anyone can think of another way to do this type of heading with pure CSS.
I’ve put all the examples in a single combined CodePen, so feel free to mess around with it or any of the ones embedded above:
How about:
It doesn’t use pseudo elements, so should work in IE too
I can see what you’re trying to do there, and it works great in Chrome, but I can’t get it to work in IE8. It doesn’t honor the top margin setting for the span. And if you absolutely position it, it pushes the text all the way to the left.
Here’s a JSBin with your code if anyone wants to fiddle with it: http://jsbin.com/uloneh/edit#html,live
Also, IE7 doesn’t support “inline-block”, so even if you got it to work in IE8, it wouldn’t work in IE7 anyhow, which is the same as pseudo-elements.
But nice thinking, thanks.
Well, I think a solution for the semantic-addict might be something like this:
However, this requires the parent of the h1 element to be text-aligned to the center (which will make us have to reset all the child elements to the left-alignment), and have a position: relative. It’s a bit of heavy drawback have to remember to left-align all the child elements, but for those who aren’t willing to give up on semantics, might be good.
Interesting. I’m not crazy about the drawback of having to reset the centering on child elements, but yeah, for semantic freaks, this certainly is an option. Thanks.
Here’s Bryan’s solution in a JSBin:
http://jsbin.com/ekexid/edit#html,live
EDIT (June 30, 2016): Looks like this technique doesn’t work anymore, at least not in Chrome. (Thanks to Daria for emailing me about this)
What about using adjacent selector via jQuery? This way we’ve got IE6 support too. http://api.jquery.com/next-adjacent-Selector/
here’s how i did it:
the negative value is the border width + half the font size.
you dont need to set it to inline-block, since side padding applies to inline elements.
works cross-browser, as far as i know.
I think we have a winner here… Here’s Jim’s solution:
http://jsbin.com/atupup/edit#html,live
From my testing, this works everywhere, including IE6-8. Thanks!
Two problems here:
– it relies on opaque background, meaning you only have to use (known) solid colors for the parent element
– it messes up with the vertical flow creating unwanted vertical space
You’re right about the colors. Good point. I might have to take back my “winner” declaration. :)
Yeah, after seeing that drawback, I think I like all of my solutions better, because they don’t mess with the positioning of the main header element. Thanks for the feedback.
Nonetheless, I still think this could be used in situations where color and vertical space are not an issue and where IE6+ support is needed.
I find the solution to be quite good too.
With the exception of seelts’ solution, every single solution on this page relies on an opaque background on the header (or the span inside it). In theory they should all work just as well with a noise background, or anything that tiles if you’re very careful and willing to play with the background positioning a bit.
I’m pretty sure it wouldn’t work.
Oh, but it really does.
http://jsbin.com/oheyiz/6/edit#html,live
No, it only *seems* to work, it relies on a very tight scenario.
I would recommend you to check it under different browsers. In doesn’t *really* work in none of the big 5.
I can provide you with some screenshots if you think it’s necessary.
I forgot two things:
– consider first that no user has the same dpi and no browser renders typography the same way
– use em not px
… and about that tight scenario: it would *occasionally* work only if your font stack has just one font family in it.
… and about different browsers: I also mean different platforms.
i’m not sure what the difference is between *seems* to work and *really* works.
if it looks right in your scenario, in all modern browsers/platforms, then it’s the right solution. to me anyway, it’s about optimizing your code for the situation, not about using one blanket code snippet that’s way more complex than needed.
OK. Let’s make it more clear.
It *seems* to work because he has created him self a controlled environment: one browser, one dpi, one font.
The moment you start testing for the natural variety of platforms and browsers out there, it’s the moment when everything falls apart.
More precisely, the line is no longer at the middle, the pattern of the h1 no longer aligns it self with the pattern on the ex# divs.
If you really want to see it as a screenshot, I can provide you with some, but I believe you already know how to test cross browser?
… and no, it doesn’t do that:
“if it looks right in your scenario, in all modern browsers/platforms, then it’s the right solution.”
That’s the whole point: the pattern test only works in one browser maybe, with one font, maybe, and one platform, maybe.
Okay, so that example was a bit rushed and easy to break. Try this more rugged version.
http://jsbin.com/oheyiz/12/edit
While I do appreciate your efforts, it’s still very easy to break since it still depends on a number of must have elements, like the 16px base font, among others.
Like I said before, it only *seems* to work, it relies on a very tight scenario. The problem is by no means new, just the application. It wasn’t a good solution a decade ago and it still isn’t.
Fortunately, these days we can consider this a progressive enhancement and make use of libraries like jQuery for this feat.
… and let’s not forget about backgrounds with various levels of transparency.
Neat! Works cross-browser according to my testing as well. Thanks for that snippet. Very simple markup and styling too, nothing obtrusive.
only css, use clearfix
h1{border-bottom:3px solid #9faf41;}
h1 span{float:left; padding:0 10px; background-color:#111; margin-left:10px; margin-top:-15px; display:block; font-size:24px}
tutorial:
http://www.fatihhayrioglu.com/resim-kullanmadan-alti-cizgili-basliklar-olusturmak/
demo:
http://fatihhayrioglu.com/dokumanlar/cizgili_baslik.html
but IE can’t center the text
Fieldset has to be include in a form : http://www.w3schools.com/tags/tag_fieldset.asp
Technically, that’s not really true. A page will still validate in HTML5 with a stray fieldset, because now you can associate a fieldset or a form field with a form element:
http://www.impressivewebs.com/html5-form-attribute/
See also:
http://www.w3.org/TR/html5/association-of-controls-and-forms.html#attr-fae-form
Yeah, it would be a bit of a hack, but when it comes to cross-browser techniques, what isn’t a hack? :)
That’s funny. I created a few years ago a site with the same design for headings (well, I styled it a bit extra with a 1px box-shadow). At that moment I used extra markup. A month ago a redesigned the same site and I wanted to keep that element. But now I used a pseudo element (like the first method). For IE7 I used a crappy fallback (easy with the Paul Irish method – giving the html an extra ie7 class); border-top. It’s not ideal, but I don’t care that much about IE7.
If even the extra span is too much, you could try giving the h1 a background, some side padding, a negative bottom margin, and then putting border-top and padding-top on the UL that’s following it. The z-index will probably need to be messed with a bit, and it depends on a structure similar to how your footer is built, but it meets all the requirements as long as the h1 doesn’t break onto two lines.
Alternatively, if you’ve got the h1 and everything following wrapped in a single container, you could use a negative margin-top on the h1, and give the container a border-top and enough extra margin-top to compensate for the header sticking out. Assuming, of course, that this doesn’t conflict with any of the other styles on the container.
I think I figured it out: JSbin
Pro: single element
Con: no horizontal padding padding in IE<=7, the only way to do that would be to use
in the HTML instead of using pseudo-elements.And… it’s already in the wild!
That’s a pretty neat way to do it, and definitely great that it doesn’t require the extra element.
But …. it’s not quite working the way you describe in IE7. Here’s how it looks in IE7 (on IETester) on that live site you linked:
http://twitpic.com/7amhcn
So I get the same result in IE7 on IETester; IE8 in Compatibility mode (which is basically the same as IE7), and the same in IE8 in IE7 standards mode.
If you’ve tested in a native IE7 install and gotten a different result, then maybe it does work. But I doubt that. It seems that IE7 does support the
:first-line
pseudo-element, but it’s buggy.Nonetheless, very creative thinking there, whoever came up with that.
excuse, can I translate your article to my blog (Taiwan?)
I’ll write your original blog address & author
this is a very useful article, I hope can give lots of people realize it .
thank, again.
Here’s my quick take: http://jsbin.com/emafos/8/edit
Only thing is now to position side lines to be on the middle. This can be also done by using a repetitive 1px background on side spans.
A stripped down version: http://jsbin.com/emafos/9/edit
… and side lines on the middle: http://jsbin.com/emafos/10/edit
… and w/o any extra vertical spacing: http://jsbin.com/emafos/11/edit
No CSS – you embed your header in a table. Works in MSIE 8 – Firefox – Google Chrome. Haven’t tested others.
Appreciate your tutorials. Regards. g.
Kinda, sorta works, but that’s a pretty awful way to do it. Here’s an example after I wrestled your code into submission:
http://jsbin.com/exazib/edit#html,live
Reply to Louis Lazaris
Your own code is beautiful in your eyes, but doesn’t work as well: as you shorten the text in your header, it leaves increasing white space to the left and to the right; the horizontal lines should eat up that white space. There is nothing automatic in your html or css, you have to declare the width of the text in your header. To make width handling automatic, you have to replace your
<td style='padding:10px 20px 0 10px; width:260px; text-align: center;' width='1'>
with<td style='padding:10px 20px 0 10px; width:0px; text-align: center;' width='1'>
When you do that correct your problem and you also need not worry about centering the header text: the browser takes care of that. The width clause in the style attribute sets the minimum width and it is best to set the minimum to 0. regards
gv
Your example doesn’t work when I do what you say here. You’re going to have to create an example so we can see your in action, otherwise I can’t see it working.
But anyhow, thanks for the feedback, it’s interesting to see this attempted in various ways, even a table. :)
We recently implemented our own solution for our company website ( http://alchemica.it/ )
It should work well on almost all popular browsers
Looks good! From my testing, works in IE6-8 too. Thanks.
This one worked perfectly..i just love the simplicity of it.
Thanks for sharing
Giulia ..Thanks for awesome, brief working code snippet across multiple browsers..It worked for me even in IE7…
Wow! that’s works on FF8 too!!! ;)
this is really cool stuff here…thanks for sharing such a wonderful tutorial
You kids and your new-fangled css layouts think too hard about this :)
With a little css help this is the best method I’ve used to achieve true transparency with my text.
Thank you i am using this one..
Out of all the options, this is the one I’m using too. This is because my background isn’t a solid colour.
Just a note to most people, you’ll need a non-breaking space ( ) rather than a regular space or else the words will fall on to two/three/more lines.
What really bugs me is that this should not rely on a white background or a solid color background. I suppose the only way to do it without that is to calculate the width of the heading with js.
h1{ background: left 49% url(1pxX1px.jpg) repeat-x;}
+span in h1
Just had to figure out a similar way to do this, however it was for e-mail template project, so the only CSS I could use was in-line styles (which I believe removes the possibility of using before).
I was able to get a pretty viable solution by floating HR tags alongside text (using divs when/if necessary). It came out looking pretty well using regular text, although you’d have to mess with some padding when using something huge like a h1 header. You also may need to tinker with the width % of the hr’s depending on the size of your text until you find what’s best for whatever sized font you’re using.
Just used method 1. Great help and perfect for responsive. Thanks!
It’s a little bit old topic… but I want to share another solution. It doesn’t require additional markup and doesn’t have the issue with background. Browser support is IE8+, so in case of IE7 it’s probably better to find another solution.
See demo and source code here: http://jsbin.com/eyisiz/edit#html,live
Only problem is it’s not centered. The lines should appear on both sides of the heading. :)
thanks alot guys, my problem is not use tag position ^^
this one is also very good http://faavorite.com/faave/154596612713353216
without background-color??????
Well, seems like the last one has got serious problems in Firefox.
Looks fine to me in the latest Firefox. The problem seems to be that in JS Bin, the body background colour doesn’t start pure white, and so you have to select the “output” window with your cursor in order to get the white that matches the background of the headings.
Greetings i encountered a problem just failed to arrange the titles within the horizonatl navigartion bar in equal space ?
Can you create an example that I can see, with JS Bin? I’m not entirely sure what you’re trying to do…?
After trying different solutions, I have found one that match all your requirements, plus allows any kind of background, unfortunately is not compatible with IE7.
You can check it here: http://jsfiddle.net/Puigcerber/vLwDf/
Nice!
Awesome. Thank you for sharing this. I’ve been looking for this solution, a background color on the heading to hide the line behind the heading was not an option for me because the client design had a horizontal body background gradient.
You are welcome! I’m glad it has been useful for you.
Wow! Just awesome, congratulations. Thank you for sharing it. I’ll probably be using your solution right away.
You are welcome, I hope it helps!
I also wrote a blog post explaining it a bit http://puigcerber.wordpress.com/2013/03/08/centered-heading-overlaying-a-horizontal-line-with-css/
Well done sir. Not to take away from your answer, but @Marek’s solution below is slightly better thanks to the centering even when the heading takes up multiple lines.
Cheers
This is awesome! Well done Pablo, this helped me a ton and works perfectly to let a background image show behind the heading and between the spaces (as opposed to being filled in with a solid color). Cheers!
Thanks! I’m glad it helped you ;)
Super easy solution to implement for CSS novices like myself. Thank you!
(and thanks Louis for the blog post)
You are welcome! Happy New Year!
Your solution worked, but I want my horizontal lines to not extend to the end of the page….I couldn’t get yours to work with shorter lines.
Thanks though!
Hi Andrew!
For that I can think just of wrapping the
<h1>
tag with a<div>
and give to this div element left and right padding.Cheers, Pablo.
This version doesn’t use a background color and works with wrapping (multiline) text. It won’t work in IE7 and below.
Check it: http://jsfiddle.net/gTSfy/
* Drops mic * ;)
This is where it’s at.
This is all kind of silly. Why not just use a fieldset and legend. 6 lines of CSS gives you the best solution possible.
Because we’re not styling a set of “fields”, we’re styling a heading (h1, h2, etc). You can’t just use a fieldset in place of a heading, this would cause serious accessibility issues.
Here’s a solution I came up with to do a similar thing, but left aligned. Not sure if it could be reworked for center alignment.
Advantages: no extra HTML whatsoever, no need to style parent or adjacent elements, no JS, not sure how you would make it centered
Disadvantages: only IE8 and up
Sorry, slight edit to my comment on the last line of code. That second
overflow: hidden
doesn’t chop the line, it hides the content.Easier to throw up a demo so we can see. I did it for you:
http://jsbin.com/isupes/1/edit
Yours doesn’t seem to need the second overflow:hidden, and I also had to add a margin and change the top value to a negative, to get it to center. Not bad, but would be nice to be able to do it on both sides like that with no extra element.
Yeah, I had to play around with the numbers a bit too. My original usage used ems and I tested it re-sizing text, etc and there were no problems with the center changing.
That’s strange it works without the second
overflow: hidden
. Didn’t for me, but it might depend on weather or not the dot is sticking out of the h2 or not.If I come up with a centered solution, I’ll let you know.
Great blog, by the way, just discovered it looking for a solution to this problem.
The second trick looks great. Thanks for sharing the tricks.
Using method 1 and it works absolutely brilliantly. Thanks a lot for this Louis.
Cheers :)
I don’t like full width lines.
a better solution without span, without js only one element and css:
http://puigcerber.wordpress.com/2013/03/08/centered-heading-overlaying-a-horizontal-line-with-css/
Yep, it’s been posted already here:
http://www.impressivewebs.com/centered-heading-horizontal-line/#comment-34913
Excellent!
Working method 1 example: http://jsbin.com/cocegujuwo/1/
The parent element requires “position:relative” for the absolute positioning to work.
Unfortunately, JSBin has broken a lot of old URLs so I had to correct those. It should be working fine now.
This is my modified version from:
http://jessica-eldredge.com/2014/01/26/headings-with-lines/
(6: Flexbox)
<h1>Title</h1>
What do you think?
Here is a super simple solution. https://stackoverflow.com/questions/2812770/add-centered-text-to-the-middle-of-a-hr-like-line