Why does the :lang selector directly select all it

2019-09-21 07:45发布

问题:

The :lang selector is very different from all other selectors (AFAIK).

Other selectors only (directly) effect the actual matched elements themselves, whereas the :lang pseudo class is very different in that all elements within an element targeted by :lang selector are also directly targeted.

So let's say I place a border around an ul element - only the ul itself gets the border - not all of the list items (demo). Not so with :lang if I target that same ul which has an attribute of lang="en" - all of the list items will also get the border - to the extent that in order to override that rule (on the child !!) I have to use a selector with greater specficity (DEMO !!!).

:lang(en) {
  border: 5px solid red;
}
<ul lang="en">
  <li>item
    <li>item
      <li>item
        <li>item
          <li>item
</ul>

So I would like to know why the :lang selector was implemented in this very strange way. (apart from the fact that that's what it says in the spec) for the following reasons:

1) Counter-intuitive:

If we use the logic that all the descendants of the element with a lang attribute should be matched - because they share the same language - then conceptually the [lang] attribute selector should match in exactly the same way!

2) Not necessary:

a) Typically when dealing with different languages in a document you need to adjust text-related properties like font-family, font-size, color, quotes etc to suit the other language. The thing is that these properties anyway inherit such that by matching just the parent element element - all subsequent descendants get these changes. (demo)

b) If this functionality was necessary for some reason it could be achieved with the universal selector like so .parent,.parent * {} (demo)

回答1:

So I would like to know why the :lang selector was implemented in this very strange way.

It works that way because that's how we want it to work, most of the time. This way we can specify a language for the entire document, or for parts of the document, by putting the lang attribute just once at the top level.

For example, let's say I give a quoting rule for German (see this question):

q:before { content: open-quote; }
q:after  { content: close-quote; }

:lang(de) { quotes: "«" "»"; }

To make this work, I certainly do not want to have to apply the lang attribute to every single element throughout my HTML to which I might want to apply quotes. Instead, I need only apply it to the <html> element.

A semi-related example (see this question). Here we want the text-transform property to work properly with Greek. For that to happen requires the language to be known. Again, we can make this work properly by specifying the language for our entire page by putting lang='el' on the html element.

So let's say I place a border around an ul element - only the ul itself gets the border - not all of the list items (demo). Not so with :lang. If I target that same ul which has an attribute of lang="en" - all of the list items will also get the border (DEMO !!!).

Right, which is why you would not do things that way. If you want to target the ul, target it some other way, or if you must, you could use an attribute selector [lang='en'].

On the other hand, perhaps you wanted to make all Japanese text on a page red. If you've deployed the lang attribute correctly, that is a case where you would want to target using the :lang selector:

:lang(ja) { color: red; }


回答2:

You're targetting every element with a lang set to en, and the lang value does inherit. But you want to only select the ul. So, simply add the ul selector, as you're supposed to, and would do with every other normal pseudo-selector.

ul:lang(en) {
  border: 5px solid red;
}
<ul lang="en">
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>

If you, for some reason, don't want to use the ul selector, use the attribute lang itself, since it does not inherit, like this:

[lang="en"] {
  border: 5px solid red;
}
<ul lang="en">
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>



回答3:

There's nothing counter-intuitive with the :lang pseudo-class. All pseudo classes work this way in that they represent element states - so all elements in that particular state are targeted.

The [lang] attribute selector on the other hand will only select the elements themselves which have the attributes - because attribute selectors check for attributes not state.

Whether the :lang attribute is absolutely necessary or if its functionality could be achieved using other selectors might be debatable, but there's certainly nothing strange with the way :lang works.