pn206
pn206

Reputation: 43

Unable to get the CSS :not() selector working as required

I'm a bit stumped with trying to get the CSS :not() selector to work for me in a very specific way. I've spent a huge amount of time looking around and found some good resources like this page but in the end I had to admit defeat. I'm hoping a more enlightened soul here will be able to help.

Basically, I want to blur some text while leaving other bits of text untouched. Please see below for the HTML/CSS:

<div class="top-hide">
    <p class="reveal">Paragraph 1</p>
    <div class="reveal">Paragraph 2</div>
    <div class="reveal"><p>Paragraph 3</p></div>
    <div><p class="reveal">Paragraph 4</p></div>
    <div class="reveal"><p class="reveal">Paragraph 5</p></div>
    <p>Paragraph 6</p>
    <div>Paragraph 7</div>
    <div><p>Paragraph 8</p></div>
</div>

.top-hide :not(.reveal) {
    color: transparent;
    text-shadow: 0 0 10px black;
}

I would like to reveal paragraphs 1 to 5, while 6 to 8 should be blurred out. However, paragraphs 1, 2 and 5 are revealed with the others blurred out. Could you please tell me why my CSS doesn't work and construct the correct CSS to achieve my goal.

I've also constructed a JSFiddle to demonstrate the problem I'm facing.

Many thanks

Upvotes: 4

Views: 71

Answers (3)

Suthan Bala
Suthan Bala

Reputation: 3299

Hope this helps. Here you go:

HTML

<body>
    <div class="top-hide">
        <p class="reveal">Paragraph 1</p>
        <div class="reveal">Paragraph 2</div>
        <div class="reveal"><p>Paragraph 3</p></div>
        <!-- It doesn't work for the paragraph 3 is because, at first the 
        browser checks if `.top-hide :not(.reveal)` case is met when looking at 
        `div.top-hide > div.reveal`, It does not. Then again, it checks for 
        `.top-hide :not(.reveal)` when it looks at `div.top-hide p`, but this time
        the `.top-hide :not(.reveal)` is met. -->

        <div><p class="reveal">Paragraph 4</p></div>
        <!-- In this case, the case is met for `div.top-hide div` -->

        <div class="reveal"><p class="reveal">Paragraph 5</p></div>
        <p>Paragraph 6</p>
        <div>Paragraph 7</div>
        <div><p>Paragraph 8</p></div>
    </div>
</body>

CSS

.top-hide :not(.reveal) {
    color: transparent;
    text-shadow: 0 0 10px black;
}

.top-hide .reveal, .top-hide .reveal *{
    color: black;
    text-shadow: none;
}

Updated JSFIDDLE

Upvotes: 1

LcSalazar
LcSalazar

Reputation: 16821

The nested elements are messing up with the selector... Example:

<div class="reveal"><p>Paragraph 3</p></div>

The div makes it reveal, but the p invalidates it. A quick fix is to always set the class in the first level (direct children), and then use a direct child selector:

Updated JsFiddle

.top-hide > :not(.reveal) {
    color: transparent;
    text-shadow: 0 0 10px black;
}

Upvotes: 1

Quentin
Quentin

Reputation: 943108

<div><p class="reveal">Paragraph 4</p></div>

Despite the paragraph having class="reveal", the selector you wrote matches the div element (and then the paragraph inherits the transparent foreground colour and the shadow).

There is no parent selector in CSS, so you can't exclude divs that contain elements with class="reveal".

The simplest solution to this would be to:

  1. Move all the class="reveal"s to the child elements (i.e. <div class="reveal"><p>Paragraph 4</p></div> and
  2. Use a child combinator so you only hide the unrevealed children (and not the descendants): .top-hide > :not(.reveal)

Upvotes: 4

Related Questions