Grouping CSS Selectors & ::selection - css

Why we can't grouping CSS like..
p::selection , p::-moz-selection
{background:transparent;}
Demo : http://jsfiddle.net/l2aelba/MRyVC/1/
Why we have to select one by one like
p::selection {background:transparent;}
p::-moz-selection {background:transparent;}
Demo : http://jsfiddle.net/l2aelba/MRyVC/
Someone can expand this issue ?

Browsers are expected to drop the entire rule if any part of the selector is invalid:
The selector (see also the section on selectors) consists of everything up to (but not including) the first left curly brace ({). A selector always goes together with a declaration block. When a user agent cannot parse the selector (i.e., it is not valid CSS 2.1), it must ignore the selector and the following declaration block (if any) as well.
CSS 2.1 gives a special meaning to the comma (,) in selectors. However, since it is not known if the comma may acquire other meanings in future updates of CSS, the whole statement should be ignored if there is an error anywhere in the selector, even though the rest of the selector may look reasonable in CSS 2.1.
(Note that as far as a browser is concerned, "valid CSS 2.1" really means "a selector that is understood and supported by the browser".)
Since non-Mozilla browsers don't understand ::-moz-selection, they have to drop the rule. Since Mozilla browsers don't understand ::selection, they have to drop the rule as well. It's a lose-lose situation (and another reason why prefixes are unwieldy, especially in selectors).
For the record, I'm surprised this no longer works in Chrome (at least in version 25 on Windows as I just tested anyway). It used to stubbornly parse the selector p::selection, p::-moz-selection as simply p::selection and apply the rule instead of following the spec, and the developers had reasons for making it so. I wonder what changed...

Related

How does the _:-ms-lang(x) fix for Edge and IE work?

I had a situation where I had to apply a specific CSS style in Edge and IE browsers only. I found online that you can prepend your CSS selector with _:-ms-lang(x) and the style will only be applied in IE and Edge.
But I wonder, how exactly is this fix working? As far as I know, the comma will just separate different selectors, meaning that other browsers should also interpret and use this style.
Here is an example:
Let's say we want to apply a width of 94px to .selector element only in Edge and IE.
_:-ms-lang(x), .selector {
width: 94px;
}
The Edge browser will apply this style, and others won't. But why not?
The comma in the selector should apply the style to _:-ms-lang(x) element AND to .selector element.
Here is a source for this IE hack.
And one more.
In CSS, when a browser does not recognize part of a selector (or thinks there is an error in a selector), it completely ignores the entire rule.
Here's the section in the CSS3 spec outlining this behavior
The prelude of the qualified rule is parsed as a selector list. If this results in an invalid selector list, the entire style rule is invalid.
Here CSS2.1 talks about the special case of comma
CSS 2.1 gives a special meaning to the comma (,) in selectors. However, since it is not known if the comma may acquire other meanings in future updates of CSS, the whole statement should be ignored if there is an error anywhere in the selector, even though the rest of the selector may look reasonable in CSS 2.1.
Therefore when the other browsers try to parse the selectors, they find the _:-ms-lang(x) selector to be invalid and so ignore the entire rule (including .selector)
Also here is an excellent answer on why this behavior is desirable

Invalid CSS selector causes rule to be dropped: What is the rationale?

I'm looking more for links to mailing list discussions, etc. rather than speculation.
Can anyone help me find out the rationale behind the quoted error handling rules from the CSS Selectors Level 3 spec.
User agents must observe the rules for handling parsing errors:
a simple selector containing an undeclared namespace prefix is invalid
a selector containing an invalid simple selector, an invalid combinator or an invalid token is invalid.
a group of selectors containing an invalid selector is invalid.
Specifications reusing Selectors must define how to handle parsing errors. (In the case of CSS, the entire rule in which the selector is used is dropped.)
I had the following rule:
#menu li.last, #menu li:last-child {
...
}
To compensate for IE8's lack of last-child support, I used a class and a JavaScript shim. However, this didn't work because IE8 complies with the CSS spec on error handling, and discards the entire rule because it doesn't recognise one selector. This can be fixed by separating the two selectors in to individual rules.
Why is this desirable? Why doesn't the spec suggest simply discarding the unrecognised selector, but keeping the rest of the rule?
I'd like to know the rationale, as the rules currently seem counter-intuitive.
Why is this desirable? Why doesn't the spec suggest simply discarding the unrecognised selector, but keeping the rest of the rule?
The short answer is because it'd be too difficult for implementations to figure out what exactly constitutes "the rest of the rule" (or "the rest of the selector list" for that matter) without getting it wrong and inadvertently messing up layouts, as well as for consistency in error handling, and forward compatibility with future specifications.
I'll preface my long answer with a link to another answer of mine, on handling of invalid selectors. A comment on that answer points directly to section 4.1.7 of the CSS2.1 spec on dealing with errors in selectors within rule sets, which mentions commas in selectors as an example. I think it sums it up pretty nicely:
CSS 2.1 gives a special meaning to the comma (,) in selectors. However, since it is not known if the comma may acquire other meanings in future updates of CSS, the whole statement should be ignored if there is an error anywhere in the selector, even though the rest of the selector may look reasonable in CSS 2.1.
While the comma itself still means grouping two or more selectors as far as selectors are concerned, it turns out that Selectors 4 introduces new functional pseudo-classes that accept selector groups (or selector lists) as arguments, such as :matches() (it even changes :not() so it accepts a list, making it similar to :matches(), whereas in level 3 it only accepts a single simple selector).
This means that not only will you find comma-separated groups of selectors associated with rules, but you'll start finding them within functional pseudo-classes as well (note that this is within a stylesheet only; outside of CSS, selectors can appear in JavaScript code, used by selector libraries and the native Selectors API).
Although not the only reason by far, this alone is enough to potentially over-complicate a parser's error handling rules with a huge risk of breaking the selector, the rule set, or even the layout. In the event of a parsing error with a comma, the parser will have trouble determining whether this selector group corresponds to an entire rule set, or part of another selector group, and how to handle the rest of the selector and its associated rule set accordingly. Instead of trying to guess, risk guessing wrongly and breaking the rule in some way (e.g. by matching and styling all the wrong elements), the safest bet is to discard the rule and move on.
As an example, consider the following rule, whose selector is valid in level 4 but not in level 3, taken from this question of mine:
#sectors > div:not(.alpha, .beta, .gamma) {
color: #808080;
background-color: #e9e9e9;
opacity: 0.5;
}
A naïve parser that doesn't understand Selectors 4 may try to split this into three distinct selectors that share the same declaration block, instead of a single selector with a pseudo-class that accepts a list, based on the commas alone:
#sectors > div:not(.alpha
.beta
.gamma)
If it simply discards the first and last selectors which are obviously invalid, leaving the second selector which is valid, should it then try to apply the rule to any elements with class beta? It's clearly not what the author intends to do, so if a browser does that, it's going to do something unexpected to this layout. By discarding the rule with the invalid selector, the layout looks just a little saner, but that's an over-simplified example; rules with layout-altering styles can cause even bigger problems if applied wrongly.
Of course, other ambiguities in selector parsing can occur too, which can lead to the following situations:
Not knowing where the complex selector ends
Not knowing where the selector list ends
Not knowing where the declaration block begins
A combination of the above
All of which, again, are most easily resolved by discarding the rule set instead of playing the guessing game.
In the case of seemingly well-formed selectors that are unrecognized, such as :last-child as a pseudo-class in your example, the spec makes no distinction between unrecognized selectors and selectors that are just plain malformed. Both result in a parsing error. From the same section that you link to:
Invalidity is caused by a parsing error, e.g. an unrecognized token or a token which is not allowed at the current parsing point.
And by making that statement about :last-child I'm assuming the browser is able to parse a single colon followed by an arbitrary ident as a pseudo-class in the first place; in reality you can't assume that an implementation will know to parse :last-child as a pseudo-class correctly, or something like :lang() or :not() with a functional notation since functional pseudo-classes didn't appear until CSS2.
Selectors defines a specific set of known pseudo-classes and pseudo-elements, the names of which are most likely hardcoded in every implementation. The most naïve of parsers have the entire notation for each pseudo-class and pseudo-element, including the single/double colon(s), hardcoded (I wouldn't be surprised if the major browsers actually do this with :before, :after, :first-letter and :first-line as a special case). So what may seem like a pseudo-class to one implementation might very well be gobbledygook to another.
Since there are so many ways for implementations to fail, the spec makes no distinction, making error handling much more predictable. If a selector is unrecognized, no matter whether it's because it's unsupported or malformed, the rule is discarded. Simple, straightforward, and easy enough to get your head around.
All that said, there is at least one discussion in the www-style public mailing list suggesting that the specification be changed because it may not be so difficult to implement error handling by splitting selectors after all.
I should also mention that some layout engines behave differently, such as WebKit ignoring non-WebKit-prefixed selectors in a rule, applying its own prefixes, while other browsers ignore the rule completely (you can find more examples on Stack Overflow; here's a slightly different one). In a way you could say WebKit is skirting the rule as it is, although it does try to parse comma-separated selector groups smartly in spite of those prefixed selectors.
I don't think the working group has a compelling reason to change this behavior yet. In fact, if anything, they have a compelling reason not to change it, and that's because sites have been relying on this behavior for many years. In the past, we had selector hacks for filtering older versions of IE; today, we have prefixed selectors for filtering other browsers. These hacks all rely on the same behavior of certain browsers discarding rules they don't recognize, with other browsers applying them if they think they're correct, e.g. by recognizing prefixes (or throwing only the unrecognized ones out, as WebKit does). Sites could break in newer versions of those browsers if this rule were to change, which absolutely cannot happen in such a diversified (read: fragmented) Web as ours.
As of April 2013, it was decided in a telecon that this behavior remain unchanged for the reason I've postulated above:
- RESOLVED: Do not adopt MQ-style invalidation for Selectors
due to Web-compat concerns.
Media query-style invalidation refers to invalid media queries in a comma-separated list not breaking the entire #media rule.

Chained pseudo-selectors in IE8

Chained pseudo-selectors do not seem to work in IE8 on Windows XP. Is there any documentation about this?
I'm developing a website using Selectivizr in order to use CSS3 selectors, but a style such as this doesn't work in IE8, whereas it works everywhere else (unsurprisingly):
span:last-child:after {content: "foobar";}
This is not a bug, it's due to the fact the the selector doesn't match natively.
A simple selector is either a type selector or universal selector followed immediately by zero or more attribute selectors, ID selectors, or pseudo-classes, in any order. The simple selector matches if all of its components match.
The simple selector in this case is either span:first-child, which matches natively in IE8, or span:last-child, which does not.
One pseudo-element may be appended to the last simple selector in a chain, in which case the style information applies to a subpart of each subject.
Appending :after to span:first-child is a match, while appending it to span:last-child is not, and since Selectivizr is a post-processor, it comes too late to save the day. Perhaps a pre-processor would have better luck.

When declaring two of the same CSS properties in one rule set, does the browser render both?

When using the same CSS property in one rule set, in the case of needing to provide a fallback for browsers that don't support a property you may be using, like so:
body{
background: rgb(255, 255, 255);
background: rgba(255, 255 ,255, 0.5);
}
Do browsers that understand both of these declarations render the first, then overwrite it with the second? Or does a browser save itself the hassle and only render the latter?
Edit: I am aware that if a browser understands both declarations it will render the latter, but I want to know if the browser renders/draws the first into the viewport and then overwrites it with the second or does a browser work in a way that means it only renders the one declaration that is required, potentially saving itself resources?
I would expect modern (and probably old) browsers to parse the CSS rules supplied to it before rendering anything. Here's a screenshot from the Chrome profiler for both rules:
And here's another, for only the first rule:
As you can see, there are no extra steps involved when two different rules are present. If the browser was to render it twice, you would see another "Paint". (The slight reduction in paint time for the single rule is likely to be because I removed the rgba rule, so the browser did not have to take transparency into account).
the last of the 2 will be applied
To be more precise: the first will be applied, then the second.
It would be the same as having 2 identical selectors setting the background property.
The one most descriptive will be applied. If they are the same, the last declared will be the one applied.
The "C" in CSS stands for Cascading which means styles can add to or supercede preceding CSS rules. So the second declaration will override the first.
Browser handle this correctly. You can use that kind of rules.
For example, chrome will apply rgba, and IE8 will apply rgb.
Browsers in general apply the following algorithm:
for each element in the DOM tree
for each CSS rule
if rule's selector matches element
apply all declarations in rule
render
This is not how it works:
for each CSS rule
for each element in DOM tree
if rule's selector matches element
for each declaration in rule
apply declaration
render
That would be a huge performance problem.
It follows from the basic UA conformance requirements that browsers must first parse all CSS rules, then decide, by the principles set in the specifications, what values shall be used for each property of each element. There is no allowance for “incremental rendering” in the sense of applying part of the CSS code before reading the rest. And it would be very odd for a browser to deviate from this, as it would mean more work to implementors, more complaints from authors and end users, and no benefits.

Why doesn't the selector h3:nth-child(1):contains('a') work?

I check this selector:
h3:nth-child(1):contains('a')
selector doesn't work?
I check this in firefinder and does return nothing (not info that there is zero elements)
Then check this:
h3:nth-child(1)
and it returns h3, so selector is almost good, but something with this(h3 has text 'a') text goes wrong.
:contains() is not was going to be a CSS3 selector (thanks T.J. Crowder for the link), but it didn't make it, most likely because the way it works tends to lead to severe performance and over-selection issues. For example, if an element E matches :contains() for a given string argument, then all of its ancestors would also match; using it with a universal selector would lead to unexpected results with certain style properties, on top of being slow for the browser.
There is no other CSS selector that serves a purpose like :contains(). So you'll have to find some other way, either by modifying your HTML or even by using jQuery's :contains(), to achieve the effect you want:
Select an h3 element
if it is the first child of its parent
and its text contains the letter 'a'.
For jQuery and Selenium RC users: :contains() is implemented in the Sizzle selector engine used by jQuery, which is also used in Selenium RC (but not Selenium WebDriver). It works as described in this decade-old revision of the CSS3 spec, but again, due to how the spec describes it, you need to use it with care or it may lead to unexpected selections.
On a final note, h3:nth-child(1) can be replaced with h3:first-child, which as a CSS2 selector has better browser support.
If you're trying to use :contains(a) to find an anchor tag (rather than the letter A), you could use:
h3:nth-child(1) a
or
h3:first-child a
The :contains() pseudo-class isn't in the CSS Spec and is not supported by either Firefox or Chrome.
You can find a couple of detailed discussion in:
selenium.common.exceptions.InvalidSelectorException with "span:contains('string')"
Finding link using text in CSS Selector is not working
Solution
As a solution you have to drop the contains() part and your effective locator will be:
h3:nth-child(1)
Further as #BoltClock mentioned within his answer, you can also use:
h3:first-child
As an alternative, you can also use:
h3:first-of-type
tl; dr
selenium.common.exceptions.InvalidSelectorException with "span:contains('string')"
Finding link using text in CSS Selector is not working

Resources