Anne van Kesteren

:lang() is different from [lang]

Note: it is also different from *[*|lang], which might be obvious, but should be mentioned.

Two days ago I learned something new about CSS selectors. Specifically, the :lang pseudo-class. I always thought it was a useless addition, since one could already use attribute selectors to match the language of a specific element, but it appears that :lang does more. I have set up a few test cases (the files prefixed with 'lang') to test browser behavior and it seems that only Mozilla is really good with this stuff (except for 007, but I'm not sure if that is accurate).

Opera fails every most of the test cases. The first three test case were written a bit Mozilla specific, since they relied on other CSS selectors that Opera has not implemented yet. However, Opera doesn't support the combination of :lang and content-language, which is part of the specification. I didn't take the time to test in Internet Explorer. Safari doesn't support :lang at all.

Some pages are using PHP so I could easily add the necessary HTTP headers; if you view the source of those files you can see the code that was used. You should read comment 3 of this post if you are interested in an explanation on the difference, since I forgot that. I was excited about the test cases...


  1. Yeah, I use :lang(x) to style language specific quotation marks (and a couple of other things, like setting Roman text in capitals).

    With [lang='x'] the style would only apply to element with a lang attribute (which is none, on my sites that are served as XHTML1.1). With :lang(x) the style is applied to all elements that... well... are written in language x, even if this is set by a parent element, and even when the language is set via xml:lang.

    Gotta love :lang.

    Posted by ACJ at

  2. ACJ: Thanks for the clear explanation of the differences.

    Posted by Jeroen at

  3. Well, it is a bit more "complicated". :lang(x) matches any element that is "written" in language x. This can be set using the HTTP content-language header for the entire document, and more specifically by using recognized attributes (perhaps there will be elements as well in the future) for changing the language of that particular section element and it's descendents.

    We currently have LANG for HTML documents and LANG (within the special preserved, non-declared XML namespace) for XML documents (also known as xml:lang). Both can be matched in CSS using a rule like [lang] in your CSS file. Note that although xml:lang has a namespace prefix, that doesn't mean it won't be matched. To be sure, you could use *[*|lang], which would match any element with the attribute LANG which is in any namespace. You can't assume [xml|lang] to work by the way, you will have to read an intro to CSS namespaces for more information about that and why it won't work (think of @namespace, they didn't invent that for no purpose).

    Posted by Anne at

  4. Ben je teruggekomen op het gebruik -weigeren- van x-css, en consorten? Indien ja: hoe dat zo?

    Posted by Robbert Broersma at

  5. No, not the use case you are talking about. I used x-css here specifically for the test case, but since it seems to cause confusion, I will make it x-example.

    Posted by Anne at

  6. It is misleading what you say about Opera failing every test case for :lang. If you use :root and :not selectors which it doesn't support, and then append :lang, to then claim that it doesn't support the latter, it wrong of you.

    But I could do the same easily. Wrap any CSS1 selector in the CSS3 media query, and then claim Mozilla doesn't support CSS1. Come on, Anne. Why don't you construct a minimal testcase for the language selector that doesn't rely on support for other mechanisms? Hypotheses testing 101, my friend.


    Posted by Moose at

  7. Testcase.

    Posted by Moose at

  8. Thank you Moose. Anne, you are the person I would have expected better off.

    even if this is set by a parent element

    I think <parent-element lang="something"><child-element>, the child-element should also be styled if you use the selectors correctly. Of course this doesn't include elements with xml:lang or lang via http-header, but that's not the point here.

    Posted by Frenzie at

  9. Test case without :root (004.htm) and Opera still doesn't support it. Another test case (005.htm), which Opera doesn't support either. It seems that Opera only supports it (006.htm) the use case that isn't really interesting, inheriting.

    Frenzie, if you expect things you will always be disappointed.

    Posted by Anne at

  10. First of all, I disproved you claim that it does not support this selector, so you were obviously wrong, and yet this claim is still in your post. Next, if claims prefixed with "probably" are hard to take on faith for anyone, and if you had checked the documentation, you would not need such prefix.

    Next, you use content-language php headers, and if Opera does not apply the selector, it is because it applies it only if there is a language attribute. So it is time to correct your false claim about lack of support with information on where and in what conditions it does support it. Otherwise, what you have written is plain false and wrong.

    Finally, what is uninteresting to you actually is most interesting to everyone else, since people use language attributes locally on the page, and rarely who needs to use it for the entire document, since then again you can rely on root attributes, and not headers.

    You have proven nothing beyond that you were wrong yourself, and that your interests diverge from the entire population, measure zero sets excepted.


    Posted by Moose at

  11. Frenzie, if you expect things you will always be disappointed.

    That depends on what you expect.

    However, like Moose said, you still claim incorrect things. That it fails to apply it when you use content-headers does not change that. You could of course say that Opera only supports it if there's a lang attribute present and therefore doesn't give that much of a pro to attribute selectors (but it does give it, definitely), but which probably means that they don't support the selector is just... well, what Moose says.

    Posted by Frenzie at

  12. If Opera doesn't support that part of HTTP or doesn't do anything with it to match :lang it just doesn't support that selector (completely, if you like).

    For people who are still reading, someone told me Safari didn't support this, I will update some parts of the post accordingly.

    Posted by Anne at

  13. Thank you for posting a correction. It still remains true that within partial support, the most important aspect to web authors is supported.

    Thank you, also, for allowing us to skin your site.


    Posted by Moose at

  14. I cannot leave it unanswered, after all. Eh. You seem to be under impression that partial support is equivalent to no support. A few examples are due.

    A very useful, all-or-nothing, is your approach. You didn't address the issue of when and where the :lang selector is used. I leave it for the posterity to judge.


    Posted by Moose at

  15. Moose, I wonder, doesn't it bore you if the entire web looks the same? I like the diversity on the sites I visit. That's also party the reason there's a new default skin on Watchzine now (which is also fluid which should be to your liking btw).

    Also, isn't it true then that no single browser even supports CSS1 completely then? But to me it looks like Anne already adjusted his comment. :)

    Btw, Anne, do you know the #number values for the Dutch quotes? (you know, the ,,quote'' style)

    Posted by Frenzie at

  16. I didn't adjust any comment, only the post. I'm also not sure what Moose is referring too but if he assumes I think that, let it be that way. I don't really care.

    Frenzie, perhaps you can find something useful here, but remember that you use the quotation marks of the general document language, not the quotation marks of the language specified in the Q element. See also the specification.

    Posted by Anne at

  17. If Opera doesn't support that part of HTTP or doesn't do anything with it to match :lang it just doesn't support that selector (completely, if you like).

    I assumed that you added the (completely, if you like) later.

    Thanks for the link, that was exactly what I was looking for.

    Posted by Frenzie at

  18. Frenzie - either Anne doesn;t pay attention to what he writes, or he believes what he writes. Only he knows. As written, his approach is an all-or-nothing one.

    As for being bored — look at it this way: you are the user, and that's what user stylesheets are for — to adjust the frequently visited sites to your liking. I have my own preferences, and I'm quite happy with them. By the revealed preference theorem, had I not preferred my own styles, I wouldn't have used them. So I skin every site I can from amongst those I frequently visit. There, I just confessed that I am a frequent visitor here :) To each his own, and I am grateful as hell for the invention of user stylesheets. It makes me so much more powerful as a user than I would otherwise have been. I love user stylesheets.

    Posted by Moose at

  19. It depends on the site, if it's a site like this one, user stylesheets rule. If it's a site like Google, your only solution is Proxomitron. ;)

    Posted by Frenzie at

  20. I was able to skin it because Anne was so kind as to provide an ID for the root element, on my request :)

    Anne, why not add a domain blog ID to index.php matrix of Blog Software That Shall Not Be Named? This way, you could mass popularize CSS signatures, user stylesheets, etc. Awareness work. Whaddayasay?

    Frenzie again: the power of user stylesheets lies in subtraction, not addition. I have a bad habit of deaily visiting a heavily overdesigned, heavy-loaded, and ugly site. So what do I do? Remove everything but the posts themselves, and whatever remains is made plain-text with my colors. The site loads in an instant now. Do I benefit or wot? :]

    display: none; — a gods' gift.

    Posted by Moose at

  21. For me the power of user stylesheets lies in change. This can includes both addition and substraction, but substraction is obviously the most useful one. Btw, the HREF weblog is pretty interesting.

    Posted by Frenzie at