How to Replace Text with CSS

Replacing text with CSS is not something I use often, but there are some specific cases where it comes in handy. If you have the ability to change text on the server-side, I always recommend that first. CSS text replacement should be a last resort, as that is not what CSS is intended for.

If you’re working within the limitations of a CMS, or you don’t have the ability to change your markup, CSS text replacement might be your only option.

There are a few ways to handle it. Let’s walk through the options, and explain how they work, and why other methods fail.

NOTE: In all of the following examples, you could use either pseudo-element, :before or :after. For these CSS text replacement methods, they are interchangeable.

Text Replacement with Pseudo-elements & CSS Visibility

A good argument can be made that this is the best method. It requires the smallest amount of markup, and works well for those who have little-to-no control over their HTML markup.

Here’s some HTML:

<p class="replaced">Original Text</p>

You want to replace “Original Text” with different content. Here’s how you can replace that text using only CSS.

.replaced {
	visibility: hidden;
	position: relative;

.replaced:after {
	visibility: visible;
	position: absolute;
	top: 0;
	left: 0;
	content: "This text replaces the original.";

Giving visibility a value of hidden hides an element, but leaves space where it would have been. In other words, it does not change the layout of the page. (This is different from display: none;, which we’ll cover below.) This is why we need to use positioning. Without absolutely positioning the pseudo-element, the new text would appear after the spot where the original text was supposed to be. By using absolute positioning, we can place the new text in exactly the same spot as the original text was supposed to appear.

Text Replacement with Pseudo-elements & CSS Display

This method requires a little extra markup in your HTML, but uses less CSS. Like the example above, it also utilizes a CSS pseudo-element to insert content onto the page.

The HTML (note the extra <span> tag that was not in our example above):

<p class="replaced"><span>Original Text</span></p>

Using the CSS display property, you can hide the content inside the <span> tag, and then attach a pseudo-element with your new content to the <p> tag. You do not need to use absolute positioning here because display: none; completely removes the element from the page, and it does affect the layout. It’s as if the text inside the <span> element never existed.

Here’s the CSS:

.replaced span {
	display: none;

.replaced:after {
	content: "This text replaces the original.";

display: none; will not work without the extra markup

If you didn’t have that extra element (in this case, the <span> tag) inside of your <p> tag, you cannot use display: none;. Any time you have a parent element with display: none;, all of its child elements, as well as its pseudo-elements, will not be displayed. Even if you set the pseudo-element to display: block;.

So, if this is your HTML:

<p class="replaced">Original Text</p>

…then this CSS will not work:

.replaced {
	display: none;

.replaced:after {
	display: block;
	content: "This text replaces the original.";

Using Special Characters & Symbols in Replaced Text

You might want to replace text with special characters or symbols, like an ampersand, tilde, emdash or non-breaking space. To do so, you must using the proper character encoding for that symbol. You cannot just place the symbol inside your content: ""; declaration, nor can you use the HTML code (e.g. &amp; or &mdash;).

This entity conversion chart will convert your special character, and give you the appropriate code to use with the CSS content property.

If you wanted to insert this: 29.9 = ~30

…it would look like this:

content: "29.9 \003D \0020 \007E 30";
  • \003D is the code for an equals sign (=)
  • \0020 is the code for a non-breaking space (&nbsp;)
  • \007E is the code for a tilde (~)

You need to include spaces in-between each special character code, otherwise the codes run together & CSS doesn’t know where the beginning & end of each code is located.

Other Helpful Tips

If you have any other ways to replace text with CSS, please let us know in the comments.

Dave Warfel

Dave is the co-founder of Escape Creative, a web company focused on teaching WordPress. He creates new content over at WP Smackdown.

18 thoughts to “How to Replace Text with CSS”

  1. This works with Firefox but does not seem to work with IE9. Can it be made to or is there a setting that needs to be enabled/disabled in IE?

  2. Hi Susan,

    This should work in IE9. CSS generated content on pseudo-elements is fully supported in IE9 and higher (source), and that’s really all we’re using here.

    If you send me an example of your site (or the code), I’ll try to take a look.

  3. Thank you for this – helped with a problem I had

    FYI, instead of

    I used

    which got around the position problem.

  4. Hi,

    At the sidebar on the right, i want to remove the ” , “ of

    6961 CM, Eerbeek ( in to: 6961 CM Eerbeek)

    I use a wordpress widget, but theres no possibility tho remove the ,

    Can anyone help me about this?


  5. My implementation of the technique “Text Replacement with Pseudo-elements & CSS Visibility” works on FF, Chrome and Safari.
    But I cannot get this work in IE9. The visibility: hidden; style is causing everything in the tag to be hidden, including the text added in the :after element. If I disable the visibility: hidden style, then both the old text and the new text are visible.

  6. Chris, looks like you figured it out.

    Logirush, IE9 might have an issue with the visibility property when it’s used with pseudo elements. It’s likely an issue isolated to older versions of IE9. Have you tried doing it with the display property instead?

  7. Great tip –exactly what I needed for overriding the post title on the home page of a WordPress blog. I found however, that I couldn’t use positioning as in my case, with a long replacement string, it would break on smaller devices. The solution I found to this was to use the line-height instead:

    /* Replace the title on the Home page */
    #post-2 .entry-title {
    visibility: hidden;
    line-height: 0;
    #post-2 .entry-title:before {
    visibility: visible;
    content: 'Welcome to Our Site!';
    line-height: 1.2em;

  8. Although this thread is fairly old, I thought I would add my input on the IE issue with visibility. Basically it seems IE just sucks, I am using the most recent version and my only solution was to make the original text the same color as the background..

  9. I’m so glad I came across this article! It may be two years old now, but the very first method worked for me. I was wanting to change the wording on my “continue reading” link, but since I’m using instead of “org”, I only have access to my css.

    It worked like a charm on Chrome. Thanks for sharing – you should update this article as the content is still relevant.

    Cheers 🙂

  10. So happy to hear you were able to put it to use. Thanks for sharing, Ann Marie. I’m sure you’re not the only one on trying to change the text of the ‘continue reading’ link. Way to think outside the box 😉

  11. Hi, thank you for your article.
    Is it possible to add the hover effect on changed text background?
    I try with
    .replaced:after:hover {
    background-color: red;
    but of course it is not working

  12. is it possible to replace the same targeted element (text) based on 2 conditions:
    if value = “A”, replace with text “AAA”
    else if value = “B”, replace with ‘BBB”


  13. Thanks a lot for this! That’s very smart! 😉
    But I still have a problem: how can I change the text, if the text is a link?

  14. Hi,
    Great post.
    My issue is that there is text in a after a .

    / 200 Goals

    So I want to replace the text “Goals” to “Points” but it’s outside a that I want to keep.
    I can only edit with custom CSS, so how do i get around this?
    Thank you in advance.

Leave a Reply

Your email address will not be published. Required fields are marked *