<<< iconic

Home

Saturday, January 10, 2015 11:50 PM >>>


of nested CSS selectors

Friday,  01/09/15  11:04 PM

<rant nerdlevel="11">

Today I actually used this selector in a style sheet:

table:not([bordercolor="#C0C0C0"]) > tbody > tr[bgcolor="#ffff99"]
  { display: block; border-radius: 15px; box-shadow: 2px 2px 4px #a0a0a0 }

Figuring out I needed to do this took me deep into the arcana of CSS selectors.  As you know, with CSS you specify the object(s) you want to style, and then what you want to do with them.  The specification of objects(s) is accomplished via selectors.  I had used the three most simple selectors before: specification by tag type (<tag>), specification by class (.<class>), and specification by id (#<id>).  For this case I wanted to style specific <tr>s unless they were inside a specific <table>s.

The <tr>s to be styled could be identified via their background color, hence, tr[bgcolor="#ffff99"].  The <table>s to be excluded could be identified via their border color, hence table[bordercolor="#C0C0C0"], specified with the :not property.  So at first* I tried this:

table:not([bordercolor="#C0C0C0"]) tr[bgcolor="#ffff99"]
  { display: block; border-radius: 15px; box-shadow: 2px 2px 4px #a0a0a0 }

But no joy in Mudville, it didn't work.  Huh?

The tr[bgcolor="#ffff99"] selector selects the <tr>s I want (I experimented to verify), and the table:not([bordercolor="#C0C0C0"]) selector selects all tables except the ones I want to exclude (I experimented to verify).  But no workey.  The <tr>s inside the <table> s were *still* selected and styled.

After a lot of extended messing around, I figured it out.  Turns out the <tr>s in question were inside the <table>s in question, but those tables were themselves nested inside a table which was not excluded.  Separating two selectors by a space only requires nesting, not immediate nesting.  Aha!

So next I tried this: 

table:not([bordercolor="#C0C0C0"]) > tr[bgcolor="#ffff99"]
  { display: block; border-radius: 15px; box-shadow: 2px 2px 4px #a0a0a0 }

The ">" means immediate nesting, the first selector must be the direct parent of the second.  But that didn't work either.  One more insight later, I realized that all <table>s actually have a <tbody>, even if it isn't explicitly specified, and so the <tr>s are actually nested inside a <tbody>, which in turn is inside the <table>.  Hence the selector shown at top, which worked (yay!).

You can see the result here.  I'm quite proud of myself :)

</rant>

* The "at first" part of this is a lie; understanding attribute selectors and :not required a lot of Googling.