Targeting List Items by their Value Attribute
Asked Answered
B

3

17

As I recently learned, in HTML5 you can use the value attribute with list items, as long as they are inside of an ordered list. http://dev.w3.org/html5/markup/li.html

I have been trying to style the list items by their value. Preferably I would like to style them like:

li[value >= "10"] { background: orange; }
li[value >= "20"] { background: green; }

However, this is currently not possible with just CSS.


Here is a fiddle I've been playing around with, trying different things. http://jsfiddle.net/Hf57v/2/

HTML:

<ol>
    <li value="33"></li>
    <li value="4"></li>
    <li value="12"></li>
    <li value="88"></li>
    <li value="jadfk"></li>
</ol>

CSS:

li { width: 20px; height: 20px; margin: 20px; background: gray; }

li[value~="3"] { background: orange; }  /* #1  */
li[value="4"] { background: red; }      /* #2  */
li[value="12"] { background: blue; }    /* #3  */
li[value^="1"] { background: green; }   /* #4  */
li[value^="8"] { background: yellow; }  /* #5  */
li[value="NaN"] { background: pink; }   /* #6  */

1) This does not work at making the background orange for the <li value="33"></li>.
I thought it would since it contains a 3.

2) This works at changing the <li value="4"></li> to red.

3) This works at changing the <li value="12"></li> to blue.

4) This overrides the <li value="12"></li> background of blue, and changes the background to green. I thought it might not since ="12 is more specific than ^="1" (begins with 1).

5) This works at changing the <li value="88"></li> to yellow.

6) This does not work at making the background pink for <li value="jadfk"></li>. I tried it since the value must be a number, so if it's just a string/text, it returns NaN (not a number).

Also, the way the ol works, is if there is no value for a li, or the value is NaN, then that li takes on a value from the previous li. In the fiddle, the <li value="jadfk"></li> renders as 89. But even though it renders as 89. It does not obey the li[value^="8"] { background: yellow; } like the 88. does. I wonder why that is.


Main Question : Is there any way to target the li value's by > or < operators in CSS?

Follow Up Question : If the answer is no, then is there any hacks or selectors that I didn't include that do help target more list items by their value attribute's value at the same time?


Bounty Info :

The bounty jsfiddle link http://jsfiddle.net/tuDBL/

In the fiddle, I created an ordered list (ol), which contains 130 list items (li) whose values are from 0 to 129. The li's with values from 0-9 need to have a unique background color. The li's with values from 10-19 need to have a unique background color. Etc, etc, all the way through 129. So in the end, there will be 12 unique background colors, and each of them representing 10 consecutive li values. The bounty winner will most likely be the person that is able to do this with the least amount of valid CSS.

Busoni answered 18/1, 2014 at 3:37 Comment(1)
Regarding point 1: It doesn't work because ~ represents an attr "whose value is a whitespace-separated list of words, one of which is an exact value" (ref) .. this would have worked for something like value="3 3"> Did you mean * ([value*="3"])? jsfiddle.net/Lr5nJSewer
D
8

I assume no explanation needed for the ones that are working as you expected. Here are the thoughts about the others.

Point 1: (as noted in JoshC's comment) you have the wrong selector. li[value*="3"] is what you were looking for if you want it to change because it "contains" a 3.

Point 4: Selector specificity has nothing to do with anything inside the attribute selector, but rather the presence of the attribute selector itself. So li[value="12"] and li[value^="1"] have the exact same specificity because both have the type selector li and the attribute selector [value] tied to them. Therefore, the css cascade order wins out; therefore in your example li[value^="1"] is the last matching selector in the cascade and it wins (if you reversed the order the other would win).

Point 6: The css is only reading the html. It does not see what the ol itself is doing with the text that is not a number. In fact, in Firebug, it shows the value as being 0 on my system, but [value="0"] still does not work. The only two selectors that will work for non-numerical values are the actual value itself li[value="jadfk"] or the unqualified attribute value of li[value], which if you made that the default, then it would need to be first in the order of your calls, otherwise it would make all of them pink (again, because of cascade order and equal specificity).

I am not aware of any current way to directly do an evaluation of > or < for an attribute as you desire without javascript. As to a hack to do something like that, a previous answer of mine may be helpful, assuming the number range is limited. That answer is using essentially the same technique as what Lior's later answer to this question has put in his answer (whether he got the idea from my link I provided or not I do not know, nor does it really matter), so I will not repeat the coding and concepts here.

Update (Adding a Solution IE7/8 Compatible)

Since Lior had an answer similar to my linked answer, I came up with this option. It does not use the :not() selector (so if IE7 compatibility is an issue, this may be preferable). Rather, it utilizes the general sibling selector which is IE7 compatible. It uses 12-13 selectors (depending on whether you want the first 10 to have the default background or not), and utilizes the cascade order to override the previous color values (so the order of these selectors in the css is important).

Fiddle Example

li[value] {background: yellow;} /* if other than default bkg. wanted on 1st 10 */
li[value="9"] ~ li[value] {background-color: red;}
li[value="19"] ~ li[value] {background-color: blue;}
li[value="29"] ~ li[value] {background-color: gray;}
li[value="39"] ~ li[value] {background-color: dimgray;}
li[value="49"] ~ li[value] {background-color: brown;}
li[value="59"] ~ li[value] {background-color: purple;}
li[value="69"] ~ li[value] {background-color: Chartreuse;}
li[value="79"] ~ li[value] {background-color: black;}
li[value="89"] ~ li[value] {background-color: DarkSlateBlue;}
li[value="99"] ~ li[value] {background-color: Bisque;}
li[value="109"] ~ li[value] {background-color: Indigo;}
li[value="119"] ~ li[value] {background-color: Lavender;}

(Thanks to Lior's code for the color values used here -- yes, I swiped those.)

This also only works because we are dealing with an ordered list. The previous answer I linked to, we were not (the numbers were arbitrary and in no relation).

Technically, some of the selectors above are redundant

Assuming the value attribute is only on the ordered list, then the selectors could be reduced to this:

Fiddle Example

[value] {background: yellow;} /* if other than default bkg. wanted on 1st 10 */
[value="9"] ~ li {background-color: red;}
[value="19"] ~ li {background-color: blue;}
[value="29"] ~ li {background-color: gray;}
[value="39"] ~ li {background-color: dimgray;}
[value="49"] ~ li {background-color: brown;}
[value="59"] ~ li {background-color: purple;}
[value="69"] ~ li {background-color: Chartreuse;}
[value="79"] ~ li {background-color: black;}
[value="89"] ~ li {background-color: DarkSlateBlue;}
[value="99"] ~ li {background-color: Bisque;}
[value="109"] ~ li {background-color: Indigo;}
[value="119"] ~ li {background-color: Lavender;}
Disproportionate answered 18/1, 2014 at 20:47 Comment(4)
I have to say I haven't visited your link (actually I think I haven't read that part of your answer) before I noticed my name...which is a shame as it might have saved me some time, although your example is with classes.Rincon
@Lior: like I said, it didn't really matter. Its not like I have a corner market on the concept. I just found it interesting that the link I gave essentially had the same solution you proposed. That was also a good reason to not reproduce the code here in my answer for the OP, as I would then have ended up mirroring your answer.Disproportionate
Ok, I just wanted to make sure there are no hard feelings. As the fact that we both thought of using the :not selector (which is pretty obvious I would hope) isn't that big of a coincidence and doesn't automatically mean they were taken one off another, but like you said it doesn't matter.Rincon
@Lior: none at all. I added my own twist to the solution for an answer to give something different as an option. It uses less code while maintaining IE7 compatibility.Disproportionate
R
7

Option 1:

Using the CSS3 :not selector we can keep the CSS rules to a minimum. Take a look at this:

Give a background color for all li (this will affect only values 0-9), and then use negation :not for all other rules in addition to the value selector.

Example:

li[value^="1"]:not([value="1"]) {background-color: red;}
li[value^="2"]:not([value="2"]) {background-color: blue;}
li[value^="3"]:not([value="3"]) {background-color: gray;}
li[value^="4"]:not([value="4"]) {background-color: dimgray;}
li[value^="5"]:not([value="5"]) {background-color: brown;}
li[value^="6"]:not([value="6"]) {background-color: purple;}
li[value^="7"]:not([value="7"]) {background-color: Chartreuse;}
li[value^="8"]:not([value="8"]) {background-color: black;}
li[value^="9"]:not([value="9"]) {background-color: DarkSlateBlue;}
li[value^="10"]:not([value="10"]) {background-color: Bisque;}
li[value^="11"]:not([value="11"]) {background-color: Indigo;}
li[value^="12"]:not([value="12"]) {background-color: Lavender;}

Just 12 lines. Here's the fiddle - http://jsfiddle.net/eF74N/5/

Option 2:

Applying the style to all the sets of ten li (10-19, 20-29 etc...), with only the ones that will also apply to 10,11,12,13 having a :not selector as well.

Then overwriting the ones with 0-9 values with their own styles.

http://jsfiddle.net/eF74N/2/

Note: The :not selector is supported from IE9 and up (and of course real browsers), it's pretty useful, MDN docs: https://developer.mozilla.org/en/docs/Web/CSS/:not

Option 3

A take on option 1, a bit longer, but backwards compatible with IE7. Overriding the 10,11,12,13 elements with another values based rule instead of the :not selector. The additional rule is:

li[value="10"],li[value="11"],li[value="12"],li[value="13"] {background-color: red;}

http://jsfiddle.net/eF74N/8/

Rincon answered 20/1, 2014 at 10:20 Comment(2)
+1 because it works, even if the values are mixed. I would probably override the previous colors with li[value="10"]{}, li[value="11"]{} etc. instead of using :not. It makes your css longer, but also backwards compatible with IE7+ FiddleTurner
Cool Thanks @chrona, It's a clean and simple solution (though not the shorts as you pointed out), I'll update my answer and add this option.Rincon
T
3

CSS3-way (should work everywhere except IE8 and lower): http://jsfiddle.net/u95Kd/

Here some information where :nth-child() works: http://caniuse.com/#feat=css-sel3

Turner answered 20/1, 2014 at 10:39 Comment(2)
I like the colors chosen, but I think the li's value should be part of the solution. Otherwise, like Salman wrote, it makes it fragile as it's order based.Rincon
@Rincon Using the values as solution, I'd stick with your idea.Turner

© 2022 - 2024 — McMap. All rights reserved.