-3

Is there a way to add CSS styles for text without tags? Maybe it could be done just with CSS, or maybe I need to use JS?

<html>
<body>

    <p>Foo</p>

    Bar

    Bar

    Bar

    <p>Foo</p>

    <div>

        <p>Foo</p>

        Bar

        Bar

        Bar

        <p>Foo</p>

    </div>

</body>
</html>

In other words, I want to make all "Bar"s red color. Is there a way to do it?


EDIT

My question was ambiguously formulated. T.J. Crowder answered very good, but I must note that the actual task was to match arbitrary text. So, in the example below, it should be matched all text about animals:

<html>
<body>

    <p>Foo</p>

    Cat

    Cat and elephant are going through the jungle

    Elephant

    <p>Foo</p>

    <div>

        <p>Foo</p>

        Green parrot

        Red parrot

        Yellow parrot

        <p>Foo</p>

    </div>

</body>
</html>
john c. j.
  • 725
  • 5
  • 28
  • 81

2 Answers2

3

Your example is a bit ambiguous, because the Bar instances are the only things that are directly contained by body. If I assume you may have other things than Bar in that section, no, you can't apply CSS just to the Bar parts and not to the other parts.

In JavaScript, you could wrap the Bar text in an element (say, a span) and then style that element. The simple naive way is to use replace:

// Simple, but naive, and probably not what you want
document.body.innerHTML = document.body.innerHTML.replace(/\bBar\b/g, '<span class="wrapper">Bar</span>');

Here's an example, but keep reading:

document.body.innerHTML = document.body.innerHTML.replace(/\bBar\b/g, '<span class="wrapper">Bar</span>');
.wrapper {
  font-weight: bold;
  color: green;
}
<p>Foo</p>

Bar

Glarb

Bar

Glarb

Bar

<p>Foo</p>

<div>

  <p>Foo</p>

  Bar
  
  Glarb

  Bar
  
  Glarb

  Bar

  <p>Foo</p>

</div>

The problems with doing that are:

  • Bar will be matched everywhere, even in attributes and such
  • It will blow away the page entirely, and replace all of the elements on the page with new elements. That will disconnect event handlers, for instance.

So instead, you can do something more refined, find the text within text nodes and only wrap it when you find it, which A) Doesn't find it in the wrong place, and B) Doesn't affect event handlers on existing elements.

My answer here demonstrates how to wrap a portion of the text in a text node in another element. Here it is applied to your specific situation:

walk(document.body, "Bar");

function walk(node, targetString) {
  var child;

  switch (node.nodeType) {
    case 1: // Element
      for (child = node.firstChild; child; child = child.nextSibling) {
        walk(child, targetString);
      }
      break;

    case 3: // Text node
      handleText(node, targetString);
      break;
  }
}

function handleText(node, targetString) {
  var start, targetNode, followingNode, wrapper;

  // Does the text contain our target string?
  // (This would be a regex test in your http://... case)
  start = node.nodeValue.indexOf(targetString);
  if (start >= 0) {
    // Split at the beginning of the match
    targetNode = node.splitText(start);

    // Split at the end of the match
    followingNode = targetNode.splitText(targetString.length);

    // Wrap the target in an element; in this case, we'll
    // use a `span` with a class, but you'd use an `a`.
    // First we create the wrapper and insert it in front
    // of the target text.
    wrapper = document.createElement('span');
    wrapper.className = "wrapper";
    targetNode.parentNode.insertBefore(wrapper, targetNode);

    // Now we move the target text inside it
    wrapper.appendChild(targetNode);

    // Clean up any empty nodes (in case the target text
    // was at the beginning or end of a text ndoe)
    if (node.nodeValue.length == 0) {
      node.parentNode.removeChild(node);
    }
    if (followingNode.nodeValue.length == 0) {
      followingNode.parentNode.removeChild(followingNode);
    }
  }
}
.wrapper {
  font-weight: bold;
  color: green;
}
<p>Foo</p>

Bar

Glarb

Bar

Glarb

Bar

<p>Foo</p>

<div>

  <p>Foo</p>

  Bar
  
  Glarb

  Bar
  
  Glarb

  Bar

  <p>Foo</p>

</div>
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thank you very much. Yes, it really works, but my question was ambiguously formulated. I was trying to find a way to apply CSS to *any* non-tagged text. So, it could be bar, it could be abcefg - any text with no tags. As I understand, your script with regex (posted at the link) do this work? – john c. j. May 11 '16 at 13:27
  • @johnc.j.: The above would let you do it to any *specific* text, if that's what you mean; just change what you search for. If that's not what you mean, I don't understand "any text with no tags." There is **no** text in an HTML page that isn't contained within an element (e.g, in a tag). In your question, you have four instances of "Foo" contained in four `p` elements, three instances of "Bar" contained in the one `body` element, and three instances of "Bar" contained in a `div` element. – T.J. Crowder May 11 '16 at 13:33
  • Here is jsfiddle with edited example: https://jsfiddle.net/0ovcu4u4/1/ . So, in this example, all the text about animals should be matched. That's was I looked for. Hope, now it's not ambiguously – john c. j. May 11 '16 at 13:44
  • @johnc.j.: Edit that into your question, using Stack Snippets (the `<>` toolbar button) if a runnable example is desired (e.g., like jsFiddle). Content for questions must be fully contained on-site, not just linked. – T.J. Crowder May 11 '16 at 13:47
  • @johnc.j.: All of the text related to animals in that example **is** "within tags:" Some of it is in the `body` element, some of it is in a `div` element. The only difference between that text and "Foo" is that "Foo" is in a `p` element instead. – T.J. Crowder May 11 '16 at 13:49
  • Done. So, it could be achived from the link you posted, with regex? – john c. j. May 11 '16 at 13:55
  • 1
    @johnc.j.: See [my question above](http://stackoverflow.com/questions/37162665/add-css-styles-for-non-tagged-text/37162807?noredirect=1#comment61863909_37162807): What "it"? – T.J. Crowder May 11 '16 at 14:11
1

If you only want the text that is directly in body, you can set a different style for body than for all elements:

body {
    color: red;
} 

body * {
    color: green;
}

This also works within any other given element, just replace body with your parent element.


After your edit, this answer doesn't really fit the question any more. Keep in mind that the "Bar"s are not "text outside of tags", they're text inside tags, it's just that they're directly inside their parent tag, rather than stacked inside another additional tag.
So the type of node you're trying to select with CSS does not exist.

The good news is that my code will still work for your new example, if you set these rules both for body and for your new div.

KWeiss
  • 2,954
  • 3
  • 21
  • 37