Pual
Pual

Reputation: 105

Highlighting paragraphs based on a class

I’m trying to change the style of paragraph based on selected class. For example, I have a text that contain as a list of p elements. Based on some rules, I change the style of a single p element with a class 'alert'. In such a case, I want all paragraphs coming after it to have a unique style. The same applies for another class 'danger'. Alert comes first, and danger comes second. Both are optional. Both can be proceeded by other paragraphs that are not danger nor alert. Here is an example

<div class='text'>

<p>Some paragraph0</p>

<p class="alert">Alert</p>
<p>Some paragraph1</p>
<p>Some paragraph2</p>

<p class="danger">Danger</p>
<p>Some paragraph3</p>
<p>Some paragraph4</p>

</div>

The problem that I want the style changes to elements that come after p with either class alert or danger. So, I would have the options to say apply after or before p with class danger or alert.

.alert{
   background: #FFFF00;
    font-weight: bold;
}

.danger{
    background: #F00;
    font-weight: bold;
}

Upvotes: 0

Views: 176

Answers (4)

Ivan86
Ivan86

Reputation: 5708

You can use javascript to get it done. This will work in all situations.

Works for elements of class="text" that contain one element with class alert or class danger, or both.

If there are no elements with class alert or class danger nothing will happen.

Here is the code: (run the snippet)

Note: I am giving the targeted elements an example class specialClass, and there are two buttons at the bottom to simulate adding styles before and after alert or danger.

function applyStyles(whenToStyle)
{
  // get all elements with class 'text'
  var elements = document.querySelectorAll('.text');
  
  // go through all elements with class 'text'
  for(var i=0; i< elements.length; i++)
  {
    // set all to false for new container of class 'text'
    var alertSeen = false;
    var dangerSeen = false;
    var hasAlert = false;
    var hasDanger = false;
    
    // get the children in order as they appear on the page
    var children = elements[i].children;
    
    // check if elements with class 'alert' or 'danger' exist
    if(elements[i].getElementsByClassName('alert').length > 0) hasAlert = true;
    if(elements[i].getElementsByClassName('danger').length > 0) hasDanger = true;
    
    // go through all children elements of the selected element
    for(var j=0; j< children.length; j++)
    {
      // if the classList doesn't contain 'alert' or 'danger'
      if(!children[j].classList.contains('alert') && !children[j].classList.contains('danger'))
      {
          if(whenToStyle == 'before')
          {
            if((!alertSeen && hasAlert) || (!dangerSeen && hasDanger))
            {
              children[j].classList.add('specialClass');
            }
          }
          else if(whenToStyle == 'after')
          {
            if((alertSeen && hasAlert) || (dangerSeen && hasDanger))
            {
              children[j].classList.add('specialClass');
            }
          }
      }
      else
      {
        // mark if we are on an element with class 'alert' or 'danger'
        if(children[j].classList.contains('alert')) alertSeen = true;
        else if(children[j].classList.contains('danger')) dangerSeen = true;
      }
    }
  }
}
.alert{
   background: #FFFF00;
    font-weight: bold;
}

.danger{
    background: #F00;
    font-weight: bold;
}

.specialClass
{
  background-color:#09f;
  color:#FFF;
  font-size:1.3em;
}
<div class='text'>

  <p>Some paragraph0</p>

  <p class="alert">Alert</p>
  <p>Some paragraph1</p>
  <p>Some paragraph2</p>

  <p class="danger">Danger</p>
  <p>Some paragraph3</p>
  <p>Some paragraph4</p>

</div>

<input type="button" value="click to apply before" onclick="applyStyles('before')" />
<input type="button" value="click to apply after" onclick="applyStyles('after')" />

Upvotes: 0

user4723924
user4723924

Reputation: 142

You can target them like this...

.alert p:not(:first-child) {color:orange;}

.danger p:not(:first-child) {color:purple;}

Upvotes: 1

orabis
orabis

Reputation: 2809

You can use the ~ selector, which can select elements preceded by danger or alert. I am following the assumption you are having in your case. The problem with this logic that it will not work properly with multiple warnings or dangers.

div.text p.alert ~ p:not(.danger), div.text p.alert {
    background: #FFFF00;
}

div.text p.danger ~ p:not(.alert), div.text p.danger {
    background: #F00;
}

div.text p.alert{
    font-weight: bold;
}

div.text p.danger{
    font-weight: bold;
}

Upvotes: 1

EKW
EKW

Reputation: 2113

This is a job for the general sibling selector!

.danger ~ p, .alert ~ p { // selects all paragraphs after a danger or alert tag
    // css rules go here.
}

Upvotes: 0

Related Questions