How can I replace text with CSS?
Asked Answered
L

26

479

How can I replace text with CSS using a method like this:

.pvw-title img[src*="IKON.img"] { visibility:hidden; }

Instead of ( img[src*="IKON.img"] ), I need to use something that can replace text instead.

I have to use [ ] to get it to work.

<div class="pvw-title">Facts</div>

I need to replace "Facts".

Labe answered 25/10, 2011 at 21:58 Comment(2)
The question is how to do it with CSS. I am using a CMS that only allows me to change the CSS, which is why I arrived at this page while googling for the answer, and not a different one. That is why we answer the question that was asked instead of asking why the asker's situation isn't different.Evonevonne
If anybody else is as clueless as I am: FOUCCapsicum
G
421

Or maybe you could wrap 'Facts' round a <span> as follows:

.pvw-title span {
  display: none;
}
.pvw-title:after {
  content: 'whatever it is you want to add';
}
<div class="pvw-title"><span>Facts</span></div>
Guanabana answered 18/12, 2012 at 21:3 Comment(10)
Nice, but that's a change to HTML rather than just CSS.Honegger
Sometimes its your only optionAgonistic
How can I include a new line? Tried <br> and \n without success. ThanksSawbuck
span { display: none; } should also hide the pseudo element. You should use visibility: hidden insteadSolemnize
display: none; and visibility: hidden; both hide the pseudo elementVelodrome
@Mathew is hiding the span but adding the pseudo element to the div, so the pseudo element should not be hidden (either by using visibility or display property)Camphor
If you're changing the HTML then you should probably change the text in the HTML itself.Zenaidazenana
This is the only approach that works for my situation so far. I have control over the HTML and CSS, but I only want to replace some label text within a longer line of text for one particular customer and this is in fact the tidiest approach.Dona
This approach is also good if you want to include help text for a file upload input, as the wording on the button is different in Chrome to IE and Firefox. Rather than hacking the input file element you can simply target the help text this way.Lulalulea
I believe, there should be ::after instead of :afterGraver
H
332

Obligatory: This is a hack: CSS isn't the right place to do this, but in some situations - eg, you have a third party library in an iframe that can only be customized by CSS - this kind of hack is the only option.

You can replace text through CSS. Let's replace a green button that has the word 'hello' with a red button that has the word 'goodbye', using CSS.

Before

Here's our green button:

button {
  background-color: green;
  color: black;
  padding: 5px;
}
<button>Hello</button>

After

Now let's hide the original element, but add another block element afterwards:

button {
  background-color: green;
  color: black;
  padding: 5px;
}

/* Bonus CSS to do cool things */

button {
  visibility: hidden;
}
button:after {
  content:'goodbye'; 
  visibility: visible;
  display: block;
  position: absolute;
  background-color: red;
  padding: 5px;
  top: 2px;
}
<button>Hello</button>

Note:

  • We explicitly need to mark this as a block element, 'after' elements are inline by default
  • We need to compensate for the original element by adjusting the pseudo-element's position.
  • We must hide the original element and display the pseudo element using visibility. Note display: none on the original element doesn't work.
Honegger answered 10/1, 2013 at 15:55 Comment(9)
This doesn't work in ie 10, any idea how to modify it to do so?Elsworth
display: none; doesn’t work because ::after really means “inside this element, but at the end”, in case anyone was curious.Jumna
Unfortunately, the "modified" button does not work like a button anymore. It's a good example, just that it does not apply to a button.Solemnize
display: none; and visibility: hidden; both hide the pseudo elementVelodrome
How come when I do this it replaces the element but the text is all caps and can't be changed to lowercase?Migratory
@JpajiRajnish That's probably because you need to set it to text-transform: lowercase.Twirl
@JpajiRajnish What browser? Replaced text is 'goodbye' here, all lowercase.Honegger
so you can only use content: css on pseudo elements? is it possible to add a :focus box-shadow on a pseudo element?Oedipus
Indeed this hack is not universal. You have to take into account that the resulting element will retain the dimensions of the original element. So your replacement text should be the same width/height.Haydon
F
218

If you're willing to use pseudo elements and let them insert content, you can do the following. It doesn't assume knowledge of the original element and doesn't require additional markup.

.element {
  text-indent: -9999px;
  line-height: 0; /* Collapse the original line */
}

.element::after {
  content: "New text";
  text-indent: 0;
  display: block;
  line-height: initial; /* New content takes up original line height */
}

JSFiddle Example

Framework answered 26/2, 2014 at 22:14 Comment(10)
This answer works in places that a number of the other answers don't such as text nodes inside a <th> element.Barret
This works well. In my case, line-height: 0 and color: transparent on the main element and resetting those values on the pseudo do the job (no fiddling with text-indent)Colonialism
Shouldn't it be line-height: normal instead of initial?Maxim
the reason to use text-indent is that if the original text is longer, the element remains the size of the old text, not shrinking to the size of the new text (assuming that is what you want)Increase
The text-indent: -9999px; works on IE. Whereas the visibility: hidden; method doesn't work on IE.Equipoise
This works for me inside of a th element but not on a label element, Any ideas why?. In the last case I added visibility hidden/visibleExalt
This solution is best because it works in Internet explorer.Ploughshare
This is easily the best answer!Trellas
Out of curiosity, what is the effect on accessibility of this solution? Will screen-readers see both text elements squished together?Astonishment
It should be noted that the example assumes that the element is the block one. For example, it does not work for elements with display: inline.Jetta
F
89

Based on mikemaccana’s answer, this worked for me

button {
  position: absolute;
  visibility: hidden;
}

button:before {
  content: "goodbye";
  visibility: visible;
}
<button>original</button>

§ Absolute positioning

an element that is positioned absolutely is taken out of the flow and thus takes up no space when placing other elements.

Ferrigno answered 18/6, 2013 at 3:51 Comment(1)
For me this answer was superior to others because it works with a text replacement within the same line, that is, it does not force a line break in text (for my particular combination of HTML and CSS).Thorman
P
44

This is simple, short, and effective. No additional HTML is necessary.

.pvw-title { color: transparent; }

.pvw-title:after {
        content: "New Text To Replace Old";
        color: black; /* set color to original text color */
        margin-left: -30px;
        /* margin-left equals length of text we're replacing */
    }

I had to do this for replacing link text, other than home, for WooCommerce breadcrumbs

Sass/Less

body.woocommerce .woocommerce-breadcrumb > a[href$="/shop/"] {
    color: transparent;
    &:after {
        content: "Store";
        color: grey;
        margin-left: -30px;
    }
}

CSS

body.woocommerce .woocommerce-breadcrumb > a[href$="/shop/"] {
    color: transparent;
}

body.woocommerce .woocommerce-breadcrumb > a[href$="/shop/"]&:after {
    content: "Store";
    color: @child-color-grey;
    margin-left: -30px;
}
Protanopia answered 16/4, 2015 at 18:16 Comment(0)
L
36

In order to use after and hide the original content, you can use this hack:

.pvw-title {
  font-size: 0;
}
.pvw-title:after {
  font-size: 1rem;
  content: 'I am a totally different piece of text!';
}
<div class="pvw-title">Facts</div>

Setting font-size to 0 makes the text disappear without removing the actual element from the viewport. Therefore, the :after selector works and should show on all browsers.

Lucilius answered 29/6, 2021 at 22:42 Comment(0)
M
28

You can't, well, you can.

.pvw-title:after {
  content: "Test";
}

This will insert content after the current content of the element. It doesn't actually replace it, but you can choose for an empty div, and use CSS to add all the content.

But while you more or less can, you shouldn't. Actual content should be put in the document. The content property is mainly intended for small markup, like quotation marks around text that should appear quoted.

Marieann answered 25/10, 2011 at 22:2 Comment(3)
I'm very sure about that I used a code to replace text with kind of that method.. '<div class="pvw-title">Facts</div> <div class="pvw-title">Facts</div>' I can't use :after, cause i got more than one div class with the same name :(Labe
How widely compatible is that for browsers? And i suspect javascript is going to be a better choice long term for this kind of flexibility.Fetishist
Modern browsers support it. I'm not sure about older IE versions, but I guess that can be looked up on quirksmode.com. -edit- It can: quirksmode.org/css/user-interface/content.htmlMarieann
B
15

Try using :before and :after. One inserts text after HTML is rendered, and the other inserts before HTML is rendered. If you want to replace text, leave button content empty.

This example sets the button text according to the size of the screen width.

button:before {
  content: 'small screen';
}

@media screen and (min-width: 480px) {
  button:before {
    content: 'big screen';
  }
}
<meta name="viewport" content="width=device-width, initial-scale=1">

<button type="button">xxx</button>
<button type="button"></button>

Button text:

  1. With :before

    big screenxxx

    big screen

  2. With :after

    xxxbig screen

    big screen

Boren answered 12/9, 2016 at 17:14 Comment(0)
S
13

The simplest way I found is by making the element font-size: 0px, then overwrite it with any font size when creating :after pseudo. Example below:

.pvw-title { 
    font-size:0px;
}

.pvw-title:after {
        content: "Hello";
        font-size:15px !important;
}
Stefansson answered 26/2, 2021 at 19:44 Comment(0)
S
12

If you just want to show different texts or images, keep the tag empty and write your content in multiple data attributes like that <span data-text1="Hello" data-text2="Bye"></span>. Display them with one of the pseudo classes :before {content: attr(data-text1)}

Now you have a bunch of different ways to switch between them. I used them in combination with media queries for a responsive design approach to change the names of my navigation to icons.

jsfiddle demonstration and examples

It may not perfectly answer the question, but it satisfied my needs and maybe others too.

Sinuosity answered 7/8, 2016 at 10:26 Comment(0)
T
12

I had better luck setting the font-size: 0 of the outer element, and the font-size of the :after selector to whatever I needed.

Townsville answered 3/3, 2017 at 16:34 Comment(2)
This works well. Here is a demo.Christian
Smart use of font-size:0 - first time for me. Kudos!Migration
P
12

Text replacement with pseudo-elements and CSS visibility

HTML

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

CSS

.replaced {
    visibility: hidden;
    position: relative;
}

.replaced:after {
    visibility: visible;
    position: absolute;
    top: 0;
    left: 0;
    content: "This text replaces the original.";
}
Precambrian answered 16/8, 2018 at 0:25 Comment(0)
C
12

Try this way:

IDENTIFIER {
    visibility: hidden;
    position: relative;
}
IDENTIFIER::after {
    visibility: visible;
    position: absolute;
    top: 0;
    left: 0;
    content: "NEW_CONTENT";
}
Continuum answered 31/8, 2021 at 1:45 Comment(1)
This doesn't work if the element is center aligned or not at the start of its bounding boxPromenade
B
10

This worked for me with inline text. It was tested in Firefox, Safari, Chrome, and Opera.

<p>Lorem ipsum dolor sit amet, consectetur <span>Some Text</span> adipiscing elit.</p>

span {
    visibility: hidden;
    word-spacing: -999px;
    letter-spacing: -999px;
}

span:after {
    content: "goodbye";
    visibility: visible;
    word-spacing: normal;
    letter-spacing: normal;
}
Bringingup answered 2/8, 2013 at 22:39 Comment(1)
Doesn't work for me in at least IE 9 through 11 due to it ignoring the "visibility:visible" on the :after element: #17531447Sawfly
A
9

I use this trick:

.pvw-title {
    text-indent: -999px;
}
.pvw-title:after {
    text-indent: 0px;
    float: left;
    content: 'My New Content';
}

I've even used this to handle internationalization of pages by just changing a base class...

.translate-es .welcome {
    text-indent: -999px;
}
.translate-es .welcome:after {
    text-indent: 0px;
    float: left;
    content: '¡Bienvenidos!';
}
Accouplement answered 5/7, 2015 at 12:16 Comment(1)
This is problematic for users with screen readers. If you don't change the disaply/visibility of the element and don't provide any aria hints, your "invisible" text may still be read by a screen reader.Counsellor
N
3

Using a pseudo element, this method doesn't require knowledge of the original element and doesn't require any additional markup.

#someElement{
    color: transparent; /* You may need to change this color */
    position: relative;
}
#someElement:after { /* Or use :before if that tickles your fancy */
    content: "New text";
    color: initial;
    position: absolute;
    top: 0;
    left: 0;
}
Nert answered 16/5, 2015 at 17:8 Comment(0)
D
3

This implements a checkbox as a button which shows either Yes or No depending on its 'checked' state. So it demonstrates one way of replacing text using CSS without having to write any code.

It will still behave like a checkbox as far as returning (or not returning) a POST value, but from a display point of view it looks like a toggle button.

The colours may not be to your liking, they're only there to illustrate a point.

The HTML is:

<input type="checkbox" class="yesno" id="testcb" /><label for="testcb"><span></span></label>

...and the CSS is:

/* --------------------------------- */
/* Make the checkbox non-displayable */
/* --------------------------------- */
input[type="checkbox"].yesno {
    display:none;
}
/* --------------------------------- */
/* Set the associated label <span>   */
/* the way you want it to look.      */
/* --------------------------------- */
input[type="checkbox"].yesno+label span {
    display:inline-block;
    width:80px;
    height:30px;
    text-align:center;
    vertical-align:middle;
    color:#800000;
    background-color:white;
    border-style:solid;
    border-width:1px;
    border-color:black;
    cursor:pointer;
}
/* --------------------------------- */
/* By default the content after the  */
/* the label <span> is "No"          */
/* --------------------------------- */
input[type="checkbox"].yesno+label span:after {
    content:"No";
}
/* --------------------------------- */
/* When the box is checked the       */
/* content after the label <span>    */
/* is "Yes" (which replaces any      */
/* existing content).                */
/* When the box becomes unchecked the*/
/* content reverts to the way it was.*/
/* --------------------------------- */
input[type="checkbox"].yesno:checked+label span:after {
    content:"Yes";
}
/* --------------------------------- */
/* When the box is checked the       */
/* label <span> looks like this      */
/* (which replaces any existing)     */
/* When the box becomes unchecked the*/
/* layout reverts to the way it was. */
/* --------------------------------- */
input[type="checkbox"].yesno:checked+label span {
    color:green;
    background-color:#C8C8C8;
}

I've only tried it on Firefox, but it's standard CSS so it ought to work elsewhere.

Dreddy answered 12/11, 2015 at 15:5 Comment(0)
D
2

I found a solution like this where a word, "Dark", would be shortened to just "D" on a smaller screen width. Basically you just make the font size of the original content 0 and have the shortened form as a pseudo element.

In this example the change happens on hover instead:

span {
  font-size: 12px;
}

span:after {
  display: none;
  font-size: 12px;
  content: 'D';
  color: red;
}

span:hover {
  font-size: 0px;
}

span:hover:after {
  display: inline;
}
<span>Dark</span>
Dittmer answered 28/12, 2019 at 21:11 Comment(1)
FINALLY. I had to work around the :hover business you had going on, and also had to add line-height: 0px alongside the font-size: 0px on the original element, but this is the ONLY answer that doesn't mess up padding/spacing/surrouding elements/the container element for me. Credited you in my derivative answer: https://mcmap.net/q/79899/-how-can-i-replace-text-with-cssMonarchism
M
2

Setting the original element's line-height and font-size to 0px (then setting the :after pseudo element's font-size) is the only thing that worked for me without messing up spacing/formatting/padding of the element's container and surrounding elements.

#test {
  font-size: 0px;
  line-height: 0px;
}

#test:after {
  font-size: 12px;
  content: 'Good Bye';
}
<span id="test">Hello</span>

Built off StefanBob's answer.

Monarchism answered 13/5, 2023 at 15:24 Comment(0)
B
1

I had an issue where I had to replace the text of link, but I couldn't use JavaScript nor could I directly change the text of a hyperlink as it was compiled down from XML. Also, I couldn't use pseudo elements, or they didn't seem to work when I had tried them.

Basically, I put the text I wanted into a span and put the anchor tag underneath it and wrapped both in a div. I basically moved the anchor tag up via CSS and then made the font transparent. Now when you hover over the span, it "acts" like a link. A really hacky way of doing this, but this is how you can have a link with different text...

This is a fiddle of how I got around this issue

My HTML

<div class="field">
    <span>This is your link text</span><br/>
    <a href="//www.google.com" target="_blank">This is your actual link</a>
</div>

My CSS

 div.field a {
     color: transparent;
     position: absolute;
     top:1%;
 }
 div.field span {
     display: inline-block;
 }

The CSS will need to change based off your requirements, but this is a general way of doing what you are asking.

Brandebrandea answered 21/3, 2015 at 20:48 Comment(1)
@AlmightWhy I suspect this was downvoted because this solution requires modifying the markup and I suspect if the OP could modify the markup, he/she would just change the text directly. In other words, the OP required a CSS only solutionDillingham
P
1

Unlike what I see in every single other answer, you don't need to use pseudo elements in order to replace the content of a tag with an image

<div class="pvw-title">Facts</div>

    div.pvw-title { /* No :after or :before required */
        content: url("your URL here");
    }
Placia answered 21/7, 2017 at 23:43 Comment(2)
As of CSS2, content only applies to :before and :after. CSS3 extends it to everything, but the Generated Content module is still in draft status, so any use is highly likely to be browser-dependent.Pea
What is a "balise"? Not "1. (European Train Control System) An electronic beacon or transponder placed between the rails of a railw", I presume. (Please respond by editing your question, not here in comments).)Megaron
L
1

After eight years, I faced the same challenge when trying to use the Stylish browser extension to change something on a website (not mine). And this time I made it work by looking at the source code using "inspect element" and created the CSS code based on that.

This it what it looked like before:

<table>
  <tbody>
    <tr>
      <td role="gridcell">
        <span title="In progress" style="background-color: #e2047a;color:White;margin:2px;border-radius:2px;padding-left: 2px; padding-right: 2px;text-align: center;width: 45px; display: block;overflow: hidden;text-overflow: ellipsis;">In progress</span>
      </td>
    </tr>
  </tbody>
</table>

This is the same piece of the HTML and the CSS I used to modify the style:

td span[style="background-color: #e2047a;color:White;margin:2px;border-radius:2px;padding-left: 2px; padding-right: 2px;text-align: center;width: 45px; display: block;overflow: hidden;text-overflow: ellipsis;"] {
  width: 100px!important;
}
<table>
  <tbody>
    <tr>
      <td role="gridcell">
        <span title="In progress" style="background-color: #e2047a;color:White;margin:2px;border-radius:2px;padding-left: 2px; padding-right: 2px;text-align: center;width: 45px; display: block;overflow: hidden;text-overflow: ellipsis;">In progress</span>
      </td>
    </tr>
  </tbody>
</table>

You can run the code above and you will see that it works (tested in Chrome).


This is simply what I wanted back in the days when I asked this question.

I was using some sort of community blog/Myspace similar stuff and the only thing you had when styling your profile was their CSS editor, and that's why I wanted to select it based on the style.

I found the answer here:

Labe answered 2/1, 2020 at 11:26 Comment(0)
F
1

Well, as many said this is a hack. However, I'd like to add more up-to-date hack, which takes an advantage of flexbox and rem, i.e.

  • You don't want to manually position this text to be changed, that's why you'd like to take an advantage of flexbox
  • You don't want to use padding and/or margin to the text explicitly using px, which for different screen sizes on different devices and browsers might give different output

Here's the solution, in short flexbox makes sure that it's automatically positioned perfectly and rem is more standardized (and automated) alternative for pixels.

CodeSandbox with code below and output in a form of a screenshot, do please read a note below the code!

h1 {
  background-color: green;
  color: black;
  text-align: center;
  visibility: hidden;
}
h1:after {
  background-color: silver;
  color: yellow;
  content: "This is my great text AFTER";
  display: flex;
  justify-content: center;
  margin-top: -2.3rem;
  visibility: visible;
}
h1:before {
  color: blue;
  content: "However, this is a longer text to show this example BEFORE";
  display: flex;
  justify-content: center;
  margin-bottom: -2.3rem;
  visibility: visible;
}

Note: for different tags you might need different values of rem, this one has been justified for h1 and only on large screens. However with @media you could easily extend this to mobile devices.

A hack how to replace HTML text using CSS

Flawed answered 12/6, 2020 at 20:38 Comment(0)
H
1

Example

<!DOCTYPE html>
<html> 
<head> 
   <title>Devnote</title>
    <style>
        .replacedValue { 
            visibility: hidden; 
            position: relative; 
        } 
        .replacedValue:after { 
            visibility: visible; 
            position: absolute; 
            top: 0; 
            left: 0; 
            content: "Devnote is developer answer solve. devnote.in"; 
        } 
    </style> 
</head>
<body> 
    <p class="replacedValue">Old Text Here</p>
</body> 
</html>

Output

Devnote is developer answer solve. devnote.in
Hoashis answered 9/12, 2020 at 11:7 Comment(0)
D
0

This isn't really possible without tricks. Here is a way that works by replacing the text with an image of text.

.pvw-title{
    text-indent: -9999px;
    background-image: url(text_image.png)
}

This type of thing is typically done with JavaScript. Here is how it can be done with jQuery:

$('.pvw-title').text('new text');
Discommode answered 25/10, 2011 at 22:6 Comment(4)
I can't use Javascript either :/Labe
This is the only way I think it could work: .pvw-title span[style*="color:#000, font-size:14px;"]{ visibility:hidden; } .pvw-title span[style*="color:#000; font-size:14px;"]: after{ visibility:visible; color:#000; font-size:14px; content: "Test"; } but, since they both using the same style, I can't do it.. :/Labe
why would you select it based on the color/font?Discommode
I would you select it based on the whole style, so I can edit that specific title and not both, since the both have the same "div" name.Labe
L
0

The way to make this work is to add line-height to the CSS content. This will make the block to be seen above the hidden, thus this will not hide the changed text.

Example with use before:

.pvw-title span {
  display: none;
}

.pvw-title:before {
  content: 'Whatever it is you want to add';
  line-height: 1.5em
}
Launder answered 2/1, 2019 at 10:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.