CSS technique for a horizontal line with words in the middle

523,108

Solution 1

This is roughly how I'd do it: the line is created by setting a border-bottom on the containing h2 then giving the h2 a smaller line-height. The text is then put in a nested span with a non-transparent background.

h2 {
   width: 100%; 
   text-align: center; 
   border-bottom: 1px solid #000; 
   line-height: 0.1em;
   margin: 10px 0 20px; 
} 

h2 span { 
    background:#fff; 
    padding:0 10px; 
}
<h2><span>THIS IS A TEST</span></h2>
<p>this is some content other</p>

I tested in Chrome only, but there's no reason it shouldn't work in other browsers.

JSFiddle: http://jsfiddle.net/7jGHS/

Solution 2

After trying different solutions, I have come with one valid for different text widths, any possible background and without adding extra markup.

h1 {
  overflow: hidden;
  text-align: center;
}

h1:before,
h1:after {
  background-color: #000;
  content: "";
  display: inline-block;
  height: 1px;
  position: relative;
  vertical-align: middle;
  width: 50%;
}

h1:before {
  right: 0.5em;
  margin-left: -50%;
}

h1:after {
  left: 0.5em;
  margin-right: -50%;
}
<h1>Heading</h1>
<h1>This is a longer heading</h1>

I tested it in IE8, IE9, Firefox and Chrome. You can check it here http://jsfiddle.net/Puigcerber/vLwDf/1/

Solution 3

Here is Flex based solution.

A heading with a central horizontal line to its sides

h1 {
  display: flex;
  flex-direction: row;
}
h1:before, h1:after{
  content: "";
  flex: 1 1;
  border-bottom: 1px solid;
  margin: auto;
}
h1:before {
  margin-right: 10px
}
h1:after {
  margin-left: 10px
}
<h1>Today</h1>

JSFiddle: https://jsfiddle.net/j0y7uaqL/

Solution 4

Shortest and best method:

span:after,
span:before{
    content:"\00a0\00a0\00a0\00a0\00a0";
    text-decoration:line-through;
}
<span> your text </span>

Solution 5

Ok, this one is more complicated but it works in everything but IE<8

<div><span>text TEXT</span></div>

div {
    text-align: center;
    position: relative;
}
span {
    display: inline-block;    
}
span:before,
span:after {
    border-top: 1px solid black;
    display: block;
    height: 1px;
    content: " ";
    width: 40%;
    position: absolute;
    left: 0;
    top: 1.2em;
}
span:after {
   right: 0;  
   left: auto; 
}

The :before and :after elements are positioned absolutely so we can pull one to the left and one to the right. Also, the width (40% in this case) is very dependent of the width of the text inside.. have to think about a solution for that. At least the top: 1.2em makes sure the lines stay more or less in the center of the text even if you have different font size.

It does seem to work well though: http://jsfiddle.net/tUGrf/3/

Share:
523,108
Jason
Author by

Jason

I'm a web developer who works in PHP/MySQL/SQLite and Server side Javascript: http://bondijs.org

Updated on January 14, 2022

Comments

  • Jason
    Jason over 2 years

    I'm trying to make a horizontal rule with some text in the middle. For example:

    ----------------------------------- my title here -----------------------------

    Is there a way to do that in CSS? Without all the "-" dashes obviously.

  • Marnix
    Marnix over 13 years
    Nice, only problem is that you have to set the background to white and can't set it to transparent.
  • Stephan Muller
    Stephan Muller over 13 years
    in that case you'll have to work with two lines, one on each side. That's going to be difficult to achieve in a clean way..
  • thirtydot
    thirtydot over 13 years
    These are clever, but I sure hope the OP doesn't want this for inside a form tag. If he does, as I'm sure you know, he could simply use fieldset and legend.
  • Stephan Muller
    Stephan Muller over 13 years
    Heh, you're right about that. Might as well go for that anyway if this doesn't work.. not semantically correct but it's better than having to resort to javascript for something like this imo.
  • DrLazer
    DrLazer almost 12 years
    This is my favourite solution. It works on OSX too and some of the others dont. If you use this solution remember to set the background of the span to the same color as the background of your page, it will be especially obvious what i mean if your background isn't white. ;)
  • Luke
    Luke about 11 years
    This really is a good solution; particularly as it works with any background and does not require a set width on the heading element.
  • BeetleTheNeato
    BeetleTheNeato over 10 years
    This is great. I adapted your code a bit to left-align the text and make the :after element the width of the block. I'm curious: what exactly is the role of margin-right: -50%? When I was fumbling around with code, missing that property would make the decoration break to another line. And even when :after is assigned 100% width, I still need the negative margin-right of 50% to make it fit. Why?
  • Puigcerber
    Puigcerber over 10 years
    As I understand it, adding negative margins in both sides pulls the element in both direction so that's why it gets centered.
  • Xavier John
    Xavier John over 10 years
    The best solution I found that works well when the screen is resided and without setting the background color of the text is jsfiddle.net/vLwDf/268
  • Chao
    Chao about 8 years
    This is not flexible, since you fix the background color of the text as white.
  • JoeMoe1984
    JoeMoe1984 over 7 years
    One of the things I love about this solution is that it works for situations where you don't know what color the background is. Easily the best solution so far for this problem.
  • Mikhail Vasin
    Mikhail Vasin almost 7 years
    In my case line appeared to be a bit to thick, so I hacked it by assigning a different font family: font-family: monospace; worked fine.
  • Jesse Buitenhuis
    Jesse Buitenhuis about 6 years
    I use another element: <h1><span>Today</span></h1> with a margin/padding on the span.
  • Christian Michael
    Christian Michael over 5 years
    I created a scss example with placeholder codepen.io/cmichael110/pen/KJLxBq. @Matt__C Your solution with the left alignment is also a good thing - maybe someone here can extend it with a fullwidth line.
  • maxi-code
    maxi-code over 5 years
    If you have small width and large text then the cross line is not working as expected.. wrap all the html in a div with width: 150px. How can you solve that? I'm looking a responsive solution as this part of my app will be shown in mobile devices
  • Nikita Fedyashev
    Nikita Fedyashev almost 5 years
    My favorite approach so far but unfortunately it doesn't work in email clients for some reason(Gmail mobile & web)
  • Emerson
    Emerson over 4 years
    How can I restrict this to a certain class, as I can't have this applied to all of the heading, just to some of them. I trie to use "h2.titulo:before{..." but it didn't work.
  • Puigcerber
    Puigcerber over 4 years
    Yeah, that should work @emerson, or even just the class .titulo:before.
  • S.Goswami
    S.Goswami almost 4 years
    While this is easy and clever, this just creates a strike-through on the word and hides it with a padding and a background colour to the span. So if you have a background colour that is defined by the user, you have to change the background colour of the span as well. In my case, I enable user to switch between dark and lite mode. I have to update the span colour every-time the user switches the colour. That's a painful situation. So it's good idea to make use of the pseudo elements here, as written by @Puigcerber. So I made line is grey, will work in both lite and dark mode.
  • fregante
    fregante over 3 years
    The padding is achieved via the existing margin left/right you see in the demo.
  • vikramvi
    vikramvi about 3 years
    Simple and sweet, works perfectly with tailwind css as well with this solution, thanks for sharing
  • Jed Lynch
    Jed Lynch over 2 years
    I think this is the more robust solution. This will work if you need to insert an icon between the lines.
  • Jed Lynch
    Jed Lynch over 2 years
    This will not work with media queries.
  • Sebi2020
    Sebi2020 over 2 years
    ::before not :before
  • mercury
    mercury over 2 years
    this is the simplest solution
  • mercury
    mercury over 2 years
    I create a small background .png image and put it as a background .
  • Nimble Stalker
    Nimble Stalker over 2 years
    It's good solution but if you use language like Russian you need to add padding because this language have a letters like Й and top of this letter is hidden
  • Rendy The Code
    Rendy The Code over 2 years
    It's only worked for specific background color. It's not working when using transparent background
  • John Magnolia
    John Magnolia about 2 years
    With latest version you can do it without adding extra HTML even more awesome. before:mr-2 before:block before:flex-1 before:border-b-2 before:border-gray-200 after:ml-2 after:block after:flex-1 after:border-b-2 after:border-gray-200 lg:before:mr-4 lf:after:ml-4
  • Mateusz Osuch
    Mateusz Osuch about 2 years
    If it's flex-based solution, I would add align-items: center; to the h1 definition so no margin: auto is needed