2

I have a lot of <p> tags on thousands of pages.

There are hundreds of <p> tags like below.

<p>Read: <a href="https://example.com" target="_blank" rel="noopener">Example</a></p>

Those start with Read:.

I want t to apply some CSS to <p> tag only if the paragraph starts with Read:. Is it possible?

Ranuka
  • 273
  • 3
  • 17
  • CSS doesn't have any selectors that target content. One line of JS can do it. – zer00ne Jun 13 '21 at 02:38
  • If you control the DOM set a data-attribute for each p tag that is for read. Then you could use CSS like `p[data-read="true"] { //some style }` set the p tag like `

    Read: //something

    `
    – dale landry Jun 13 '21 at 03:08

2 Answers2

4

This is not posible with CSS alone, you would need Javascript to achieve this.

This example shows you...

#1. How to use Javascript to search your documents p tags and find strings where the 1st index of the string is set to the target string Read: using indexOf().

#2. How to then set an attribute, el.setAttribute(), on that tag that identifies that element as a Read: element containing the string we want to affect in our CSS.

#3. How to use CSS + elements attribute to then style the target elements in the DOM as you want them styled.

  • const p = [...document.getElementsByTagName('p')] -> create an array of elements we can then loop over using tag.forEach()

  • tag.textContent.indexOf("Read:") === 0-> lets find elements that have target string at the very beginning of the tag.textContent.

  • tag.setAttribute("data-read", true) -> set the tags data-read attribute to true

  • p[data-read="true"] in CSS we style all elements that are p tags and have the attribute <p data-read="true">

Using this method we are able to use CSS to style the tags and JS to find them.

const p = [...document.getElementsByTagName('p')]

p.forEach(tag=>tag.textContent.indexOf("Read:") === 0 ?  tag.setAttribute("data-read", true) : false)
p[data-read="true"] {
  background-color: lightgreen;
  font-weight: bold;
  color: darkgreen;
}

p[data-read="true"]:after {
  content: ' *';
}
p[data-read="true"]:before {
  content: '* ';
}
<div>
  <p>Read: some info</p>
  <p>Read: some info</p>
  <p>p tag content</p>
  <p>more ptag info</p>  
  <p>Perhaps the p content has a sentence that starts with the string and we do not want to get that one. Read: Speak: Listen:</p>
  <p>Read: At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.</p>
</div>
dale landry
  • 7,831
  • 2
  • 16
  • 28
2

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <p>Read: More</p>
    <p>Read: More</p>
    <p>Hey</p>
    <p>Hello</p>
    <p>Lorem ipsum dolor sit amet, consectet Read: More</p>
    <script>
      let list = document.getElementsByTagName("p");
      for (let i = 0; i < list.length; i++) {
        if (list[i].textContent.startsWith("Read:")) {
          list[i].style.color = "red";
        }
      }
    </script>
  </body>
</html>

I don't know if CSS have such selectors but you can still achieve your goal with JavaScript

    let list = document.getElementsByTagName("p");
    for (let i = 0; i < list.length; i++) {
       if (list[i].textContent.startsWith("Read:")) {
           list[i].style.color = "red";
       }
    }
Uzair Saiyed
  • 575
  • 1
  • 6
  • 16