27

Suppose I have a container:

 <div id="container"> This is a red apple </div>

How to color a word "red" with red color? Something like (pseudocode)

#container:[word="red"]{
   color:red;
}

Is it possible to do this in pure CSS without introducing JavaScript or modifying the existing HTML?

James Donnelly
  • 126,410
  • 34
  • 208
  • 218
nicael
  • 18,550
  • 13
  • 57
  • 90
  • 6
    you must use javascript to look it and, break the sentence and have the word you want inside it's own tag. see - http://stackoverflow.com/q/119441/104380 – vsync May 19 '14 at 12:31
  • All DV because so far, all answers don't change css only...they all suggest markup changes. – Phlume May 19 '14 at 12:36
  • @Daniele94 I didn't down vote you. But seems like you don't understand me – nicael May 19 '14 at 12:36
  • 2
    @Daniele94 It was actually me, since not a single one of the questions actually addresses the OP's problem. He is wanting some sort of search-and-replace function to replace words with a coloured replacement. While this isn't possible with CSS alone, it's very easy with javascript. The first comment by vsync should help the OP. – Ben Fortune May 19 '14 at 12:36
  • 6
    with just CSS it's not possible. – shyammakwana.me May 19 '14 at 12:37
  • by css you can have a match on an element, attribute name and value of a named attribute. You should chose to go either with js or html structure as suggested. – alou May 19 '14 at 12:37
  • This is a duplicate of this: http://stackoverflow.com/q/119441/104380 – Phlume May 19 '14 at 12:39
  • Do you want to color every "red" word with red color? If so, I believe that is only possible with JavaScript. – Matjaž May 19 '14 at 12:39
  • @Daniele94 Then the answer should've been simply **no**. With alternatives using Javascript after explaining why it can't be done. – Ben Fortune May 19 '14 at 12:40
  • @Ben Fortune: i know that it cant be done without Javascript. So nicael why you dont want to use Js? – Daniele94 May 19 '14 at 12:41
  • 1
    @Daniele94 because I know how to do it with js. I am searching for better and simpler solution – nicael May 19 '14 at 12:43
  • ok @nicael but for me you cant do that without js if you dont want to change your html/css. But next time please explain better your problem or what you want – Daniele94 May 19 '14 at 12:44
  • maybe this is not what you need, but it might helped you [link](http://css-tricks.com/a-call-for-nth-everything/) – Matjaž May 19 '14 at 12:55
  • @dystroy Please Read question carefully before posting such comments and down voting. My question Is Not duplicate. – nicael May 27 '14 at 14:16
  • @nicael There are many similar questions. I really don't get what was the blocking problem. But anyway, you have answers here. Is there a reason you accepted none of them ? – Denys Séguret May 27 '14 at 14:18
  • Making it bold doesn't explain why the other QA which also don't need you to change the HTML aren't good for you... – Denys Séguret May 27 '14 at 14:20
  • @dystroy Maybe I didn't find. Please show. – nicael May 27 '14 at 14:20
  • Well, there's [this one](http://stackoverflow.com/questions/18590527/javascript-replace-specific-word-index-in-html-string) and the other one given by Phlume. They're easy to adapt. But as you have answers here and you already gave away the bounty, I think you should explain why no answer given here is good enough to be accepted. If you really don't want JS (which would be strange), then abir's answer looks correct. – Denys Séguret May 27 '14 at 14:22
  • "This one" uses javascript. And, by now, solution provided by Anders G suits me most. Yes, it is tricky, but it works for single word "red". Also I like mfirdaus's solution, because it both functional and uses something like "pseudocode" I showed (however, it uses javascript). – nicael May 27 '14 at 14:30
  • @nicael Place the red word inside span tag then with css target the span tag, :) – Waqas Khan Apr 02 '15 at 09:25
  • 3
    A solution for this with pure CSS is only limited possible. Have a look at the article [10 jQuery text highlighter plugins](https://www.sitepoint.com/10-jquery-text-highlighter-plugins/) for a few jQuery plugins which can handle this task better, e.g. [mark.js](https://markjs.io/). – dude May 24 '16 at 06:41

14 Answers14

29

Background

This is a Vanilla JavaScript solution because it ain't possible with CSS. Not joking, read the specification. You can match on an element, the name of an attribute in the element, and the value of a named attribute in an element. I don't see anything for matching content within an element though.

Introduction

Here's my shot at it. I am sure there is a sleeker way, but this is the gist of how it would start off as. Also, since there are a finite number of colors that you will want to colorify, it's nice to use a bunch of if statements like I have.

A better technique of course would be to do it more programmatically by building a color dictionary and hence make the code organized. But this works, and it's Vanilla JS. Apparently, I didn't have expertise in Regex, so I am sure a few lines are unnecessary.

Features

  • Works for multiple color occurrences
  • Works for multiple colors as visible

http://jsfiddle.net/TB62H/5/

var text = document.getElementById("content");
var str = text.innerHTML,
    reg = /red|blue|green|orange/ig; //g is to replace all occurances

//fixing a bit
var toStr = String(reg);
var color = (toStr.replace('\/g', '|')).substring(1);

//split it baby
var colors = color.split("|");

if (colors.indexOf("red") > -1) {
    str = str.replace(/red/g, '<span style="color:red;">red</span>');
}

if (colors.indexOf("blue") > -1) {
    str = str.replace(/blue/g, '<span style="color:blue;">blue</span>');
}

if (colors.indexOf("green") > -1) {
    str = str.replace(/green/g, '<span style="color:green;">green</span>');
}

if (colors.indexOf("orange") > -1) {
    str = str.replace(/orange/g, '<span style="color:orange;">orange</span>');
}


document.getElementById("updated").innerHTML = str;

Results

enter image description here

Ali Gajani
  • 14,762
  • 12
  • 59
  • 100
  • 3
    A suggestion: To make it scalable I'd go for storing the values using an array and then do a loop perhaps. Something like http://jsfiddle.net/mfirdaus/TB62H/7/ – mfirdaus May 26 '14 at 00:51
  • Sorry, but using `innerHTML` (VanillaJS) or `.html()` (jQuery) is evil! It will destroy all events of the element and trigger generation of the DOM again and again. If definitely advise against this solution! Instead, have a look at [mark.js](https://markjs.io/), which was built exactly for this task with dozens of cross-browser unit tests. – dude May 24 '16 at 06:39
  • 1
    @julmot nice library there. Saved. – Ali Gajani May 24 '16 at 12:16
17

Not to prove a point, but to answer your question - this is possible in CSS without JS: Example

In short: we set a black background color for text color and a red background image for the specific red string. We remove the original text fill using -webkit-text-fill-color. The background is clipped to the text outline using -webkit-background-clip: text; and the red image is sized and positioned over whatever text string we want to color.

Please note: I would never recommend using this for any live website. This works in webkit only as it's based on non-standard wekbit-specific CSS rules. And the color is not really bound to the colored text string - it's completely static.

Edit: Here's the CSS:

#container {
    -webkit-text-fill-color: transparent;
    -webkit-background-clip: text;
    background-size: 1.5em 1em;
    background-repeat: no-repeat;
    background-position: 3.4em 0;
    background-color: #000;
    background-image: url(data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5rooor8DP9oD/2Q==);
}
agrm
  • 3,735
  • 4
  • 26
  • 36
  • 4
    As I mentioned the color is not bound to the text - it have to be positioned manually. You can move it around by adjusting the `background-position`. This is one of the reasons I wouldn't use this for any live projects. I just felt compelled to answer as I love experimental CSS. – agrm May 24 '14 at 19:41
  • I already understood. But it can be done, so it is wonderful. Nobody else mentioned it. – nicael May 24 '14 at 19:42
  • @nicael Yeah, I see you updated your comment. Glad you figured it out! – agrm May 24 '14 at 19:42
  • 1
    Isn't it too moved to the left? change `background-position: 3.2em 0;` to `background-position: 3.4em 0;`? – nicael May 24 '14 at 19:46
  • What if the sentence is: This is a red and red apple ? – Ali Gajani May 24 '14 at 20:40
  • 1
    @AliGajani You can chain/comma-separate CSS background values to set more backgrounds and color more words. – agrm May 24 '14 at 20:53
  • @AliGajani *I already understood.* My question was "How to color specific word in a container using CSS". He answered. "Yes". It doesn't color all "red" words, but done in CSS. I can say that your solution is more functional, but you didn't notice that I want to use CSS only. – nicael May 24 '14 at 20:54
  • My solution seems to be more efficient and lightweight :) Use it at will – Ali Gajani May 24 '14 at 20:56
  • @AliGajani No doubt. Although I clearly stated the weaknesses of my technique to begin with, it *is* JS independent. – agrm May 24 '14 at 21:23
  • 2
    Yes, I enjoyed reading your solution. A very clever hack Anders – Ali Gajani May 24 '14 at 21:25
  • 1
    As you correctly stated, I can agree with "I would never recommend using this for any live website.". This answer is not useful. Just change the text and you will see: http://jsfiddle.net/5qDLs/1/ – Tomas May 27 '14 at 09:35
  • 1
    @TMS OP asked if this was possible using CSS only. No word on whether this is for a live website or for experimentation only. Do I recommend the technique for live sites? No. Is it possible using CSS only, as OP asks? Yes. – agrm May 27 '14 at 19:16
  • 1
    -1; while this answer is certainly clever, and meets all the criteria set forth by the question *as a robotic lawyer would interpret them*, it's pretty clear that it's never going to be useful to anybody. Heck, if you're going to slyly evade the spirit of the question in this way, you don't even need to be as clever about it as you've been here - you might as well set the text colour to transparent and use a larger background image containing the entire text, [like this](http://jsfiddle.net/5qDLs/2/). Now we have cross-browser support, and it doesn't break when you zoom out. Hooray!... maybe? – Mark Amery Jun 26 '14 at 20:27
  • @Mark - I generally agree with your position, but... your proposed method has many drawbacks that `agrm`'s solution does not - namely that, should the text need to change, his/hers can be adjusted with a few changes to numbers with a text editor - or even in a pinch from some console/command-line interface, whereas yours would require a re-rendering in an image manipulation program... neither is significantly better than the other over all, IMO – Code Jockey Aug 15 '14 at 14:43
6

Sadly CSS does not have any selector right now to achieve what you need. You have to use JavaScript or Server Side Scripting to achieve what you want.

abir_maiti
  • 490
  • 3
  • 9
  • @TMS: No, we clearly say it isn't possible with CSS, but we do give JS based solutions, so the other answers should NOT be down-voted. – Ali Gajani May 27 '14 at 08:01
4

Now if you allow me to use just a bit of javascript, and perhaps the caveat that I have no idea how well this will scale, might break a lot of CSS, and the implementation is a bit shoddy. That said, I think we can simply give css a bit of a hand by rewriting the HTML.

As you know we can add spans around the words and we can select that. But instead of just selecting the chosen one and attaching the style information, we span all the words. And attach the word as an value to the attribute "word". With the help of a way to get all the textNodes, it might look something like

//adapted from https://stackoverflow.com/a/10730777/1480215
function makeHighlightable(){
  var n, a=[], walk=document.createTreeWalker(document.body,NodeFilter.SHOW_TEXT,null,false);
  while(n=walk.nextNode()) a.push(n);
    for(var i=0;i<a.length;i++){
      var newSpan=document.createElement("span")
      var words=a[i].nodeValue.replace(/[\r\n]/g,"").split(' ');
        for(var j=0;j<words.length;j++){
            var escapedWord=words[j].replace(/[^a-zA-Z0-9-']/g,'').toLowerCase()
            words[j]='<span word="'+escapedWord+'">'+words[j]+'</span>'
        }
        words=words.join(" ")
        newSpan.innerHTML=words
        a[i].parentNode.replaceChild(newSpan,a[i])
    }
}

makeHighlightable()

With that in place, you can now do

#container [word=red]{ /* space instead of : */
    color:#F00;
}

Demo

and it might possibly work.

Community
  • 1
  • 1
mfirdaus
  • 4,574
  • 1
  • 25
  • 26
3

Simple but anyway RIGHT answer: NO.

Please, don't be rude with others in your comments, they took time to read your question, think about how they would solve such a problem, write an answer (or a comment) and... help YOU... they don't deserve be treated in a rude way.

Best regards and good look.

Miguel.

BTW: check Wrap certain word with <span> using jquery and http://forum.jquery.com/topic/wrapping-specific-words-inside-span-elements

Community
  • 1
  • 1
miguel-svq
  • 2,136
  • 9
  • 11
1

Use <span> for this.

<div id="container"> This is a <span class="red">red</span> apple </div>

CSS:

.red {
color: red;
}

Edit
It isn't possible without any additional Javascript or HTML. According to the CSS3 specification there is no such selector (There were thoughts about a :contains() selector for CSS3). Also see this and this Question.

Kimmax
  • 1,658
  • 21
  • 34
1

If you don't want to add html/javascript the simpel answer is NO you can't

Take a look at the following specification http://www.w3.org/TR/css3-selectors/#selectors

That are all available selectors for CSS3 and therefor it's simply impossible, and that's your answer.

You have 2 options left without changing the content one is all ready described here:

  • javascript
  • server-side parsing so everything gets wrapped with the span tag
Sander Visser
  • 4,144
  • 1
  • 31
  • 42
0

Use pseudo elements to add the coloured word and some careful positioning to cover the initial black instance. It's dirty, but it works.

#container
{
    position: relative;
    font-family: monospace;
    margin: 0;
    padding: 0;
    font-size: 15px;
}

#container:after
{
    content: "red";
    color: red;
    position: absolute;
    left: 90px
}

Demo


EDIT: Also, a variation that works with proportional fonts (but doesn't render quite so cleanly, at least for me, in Chrome):

#container
{
    position: relative;
    margin: 0;
    padding: 0;
}

#container:before
{
    content: "This is a ";
    position: absolute;
    z-index: 2
}

#container:after
{
    content: "This is a red";
    color: red;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 1
}

Demo 2

graphicdivine
  • 10,937
  • 7
  • 33
  • 59
-1
  1. It cannot be done using only css selectors at present checkout documentation for CSS selectors

It can be easily Done with Jquery with a single line statements

Check Out the Demo

Highlighting and remove highlight on button click

The Simplest Solution when You Select a specific word with mouse that word would be highlighted throughout the Container

Jquery

var text = $('div').text().replace(/Ipsum/g,"<span class='red'>Ipsum</span>");
$('div').html(text);

EDIT:

$('#id1').click(
    function(){
    var text = $('div').text().replace(/Ipsum/g,"<span class='red'>Ipsum</span>");
$('div').html(text);
    }
);

$('#id2').click(
  function(){
      $( "span.red" ).each(function() {
  $( this ).contents().unwrap();

});

    }
);

CSS

.red {
color: red;
}

HTML

<div>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
 </div>

EDIT:

<input type="button" value="Click to highlight" id="id1" />
<input type="button" value="Click to remove highlight" id="id2" />

codefreaK
  • 3,584
  • 5
  • 34
  • 65
  • 3
    oh my god, reading from `text()` and writing to `html()`. don't let the web security people see this – guest May 29 '14 at 22:31
-1

So I have the same task, and the solution is pretty simple, but tricky You need to add :after pseudo-element and then:

#container:after {
  content: "";
  position: absolute;
  width: 200px;
  height: 50px;
  background-color: red;
  top: 10px;
  left: 100px;
  z-index: -1;
}

Adjust top, left, height, width for your case.

Alex Faster
  • 199
  • 10
-2

I don't understand why people say it's impossible to do it without JavaScript. I remember doing that kind of stuff with <span> like so:

<div id="container"> This is a <span style="color:red">red</span> apple </div>
Lambientan
  • 17
  • 1
  • 4
-2

I was dealing with this same issue. I had my base content wrapped in a

tag and all I did was surround each word I wanted highlighted in a tag and used CSS to change the colour of tags to red. Easy and simple.

e.g

<p>Base text, and then I want <p1>THIS</p1> word highlighted
</p>

p1 {
color: red;
}

Worked so well and did not mess up formatting at all.

A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
Roman
  • 1
-3

Here's some code that uses jQuery to wrap a class around the word red, which can be colored.

 <div id="container">This is a red apple</div>
 $("#container:contains('red')").each(function(){
     $(this).html($(this).html().replace("red", "<span class='red'>red</span>"));
 });
Robbie JW
  • 729
  • 1
  • 9
  • 22
Kisspa
  • 584
  • 4
  • 11
-4

You should use the span tag to surround the word "red"

<div id="container"> This is a <span>red</span> apple </div>    

Then select this span using

#container span {
    color: red;
}
soarjay
  • 641
  • 4
  • 17