What I'm particularly wondering is how expensive *:after would be, resource-wise.
Would the pseudo element become the key selector in this case? Or would the client grab all the elements anyway?
In other words, what's the difference between the *:after and * performance-wise?
[edited. stupid example. my bad.]
For clarification, I'm trying my hand at drawing sth using only css and found myself using a lot of pseudo elements. Just wandering if I can save myself some time by writing
*:after,
*:before {
content:'';
}
and its resource cost.
Thanks.
Would the pseudo element become the key selector in this case?
Technically, the subject of the selector is *, meaning whichever element is matched by * will be the one generating the pseudo-element.
The term "key selector" isn't well-defined when it comes to pseudo-elements, plus unlike the concept of subject selectors it's actually an implementation detail. If "key selector" means "selector representing the box that is rendered", then I suppose you could say that the pseudo-element is the key selector. I'm not familiar with implementation details, though, since I'm not an implementer.
Either way, it's safe to assume that the client walks through the DOM and, for every element that it picks out:
Attempt to match the element against the selector, ignoring the pseudo-element for now (in this case, *).
If the element matches the selector, attempt to create a pseudo-element box as a child of this element's box (in the case of generated pseudo-elements like :before and :after) if it is applicable (some elements cannot generate pseudo-elements).
Apply styles to the pseudo-element box and render it as with any other box.
The difference between your two selectors is that the former contains a pseudo-element while the latter does not. Since they do fundamentally different things, it's not fair to compare them by performance. However, they both do attempt to match any element in the DOM as they both use the same catch-all selector *, so barring any special optimizations, it's safe to assume that the only overhead that comes with *:after lies with actually generating and rendering the pseudo-element.
Since we're on the topic of performance, remember that matching an element to * is almost instantaneous as it's basically a guaranteed match; it's only when you combine it with more complex selectors that it gets more expensive on a selector level, and while ultimately its performance scales the greatest with the number of elements you have in the DOM, it's still not nearly as expensive as actually rendering the styles unless you have elements in the thousands.
As for your use case, my opinion is that you generally do not need to create pseudo-elements for every element. If you're drawing something with CSS, see if you can limit your selector by context so you avoid rendering unnecessary boxes across the entire DOM, e.g. if you're only drawing within an element with a certain ID:
#mycanvas *:after,
#mycanvas *:before {
content:'';
}
After Question Edited
Just got a clear picture of what you are trying to ask here, so when you use *, it is going to select the elements anyways but that won't be precise as it selects all elements.. If you want, you can use something like
.container *:not(span) {
color: red;
}
Or (But the below one will select all elements nested inside .container)
.container * {
color: red;
}
Demo
Before Question Edited
I am not able to understand what are you asking here, but both selectors are COMPLETELY DIFFERENT.. they are used for different purposes, I don't know whether it's a typo in your question, but using *:after is often used with content which has to be embedded :before or :after.
So, for example
*:after {
content: " <";
}
Demo
And when you use this, * .after, will select elements having class .after
* .after {
color: red;
}
Demo 2
As far as the optimization goes, I don't think using * in general websites is a huge performance issue, I often use the selector below holding properties like
* {
margin: 0;
padding: 0;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
Also, last but not the least, I don't find any reason to use *:after as you won't be embedding some content using :after for each element.
Related
Does the universal selector * affect pseudo elements like :before and :after?
Let me use an example:
When doing this:
* { box-sizing: border-box; }
...doesn't the above declaration automatically include/affect pseudo elements like :before and :after as well?
Or, in order to affect pseudo elements like :before and :after, one has to declare this?
*, *:before, *:after { box-sizing: border-box; }
Does this make sense?
I have always used just * { box-sizing: border-box; } and never have had any issues with pseudo elements whatsoever. But I see many tutorials doing *, *:before, *:after but they never really explain why they include *:before, *:after in the declaration.
No, the universal selector * does not affect pseudo-elements (except indirectly via inheritance, as pseudo-elements are typically generated as children of actual elements).
The universal selector, like other named element selectors such as p and div, is a simple selector:
A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
A simple selector, and by extension any complex selector, targets only actual elements.
Although pseudo-elements (which are not the same thing as pseudo-classes mentioned above) can appear in selector notation alongside simple selectors, pseudo-elements are completely separate from simple selectors as they represent abstractions of the DOM that are separate from actual elements, and therefore both represent different things. You cannot match a pseudo-element using a simple selector, nor can you apply styles to an actual element in a CSS rule with a pseudo-element in its selector.
So, in order to match :before and :after pseudo-elements of any element, yes, one will need to include *:before, *:after in the selector. Having just * { box-sizing: border-box; } will not affect them since box-sizing is not normally inherited, and as a result, they will retain the default box-sizing: content-box.
One possible reason why you might never have had any issues with pseudo-elements is that they're displayed inline by default, as box-sizing has no effect on inline elements whatsoever.
Some notes:
As with any other chain of simple selectors, if * is not the only component then you can leave it out, which means *, :before, :after is equivalent to *, *:before, *:after. That being said, the * is usually included for the sake of clarity — most authors are used to leaving the * out when writing ID and class selectors, but not pseudo-classes and pseudo-elements, so the notation may seem strange and even wrong to them (when it is in fact perfectly valid).
The current Selectors specification that I link to above represents pseudo-elements with double colons. This is a new notation introduced in the current spec to distinguish pseudo-elements from pseudo-classes, but most box-sizing resets use the single colon notation to accommodate IE8, which supports box-sizing but not the double colon notation.
Although *:before, *:after applies styles to the respective pseudo-elements of any element, which includes html, head and body, the pseudo-elements will not actually be generated until you apply the content property. You do not have to worry about any performance issues as there are none. For a detailed explanation, see my answer to this related question.
I can only cite from the specification:
The universal selector, written "*", matches the name of any element type. It matches any single element in the document tree.
Element types are for example span and div.
Since pseudo elements don't have an "element type" and are not part of the document tree, it looks like the answer is no, it does not include pseudo elements.
However, since pseudo elements inherit the CSS properties from their "parent" (at least the ones that are inheritable) and the universal selector also affects the parent, it indirectly affects the pseudo elements.
Example
the color is inherited
the border style is not and the ::before element doesn't have a border
Does the universal selector * affect pseudo elements like :before and :after?
Let me use an example:
When doing this:
* { box-sizing: border-box; }
...doesn't the above declaration automatically include/affect pseudo elements like :before and :after as well?
Or, in order to affect pseudo elements like :before and :after, one has to declare this?
*, *:before, *:after { box-sizing: border-box; }
Does this make sense?
I have always used just * { box-sizing: border-box; } and never have had any issues with pseudo elements whatsoever. But I see many tutorials doing *, *:before, *:after but they never really explain why they include *:before, *:after in the declaration.
No, the universal selector * does not affect pseudo-elements (except indirectly via inheritance, as pseudo-elements are typically generated as children of actual elements).
The universal selector, like other named element selectors such as p and div, is a simple selector:
A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
A simple selector, and by extension any complex selector, targets only actual elements.
Although pseudo-elements (which are not the same thing as pseudo-classes mentioned above) can appear in selector notation alongside simple selectors, pseudo-elements are completely separate from simple selectors as they represent abstractions of the DOM that are separate from actual elements, and therefore both represent different things. You cannot match a pseudo-element using a simple selector, nor can you apply styles to an actual element in a CSS rule with a pseudo-element in its selector.
So, in order to match :before and :after pseudo-elements of any element, yes, one will need to include *:before, *:after in the selector. Having just * { box-sizing: border-box; } will not affect them since box-sizing is not normally inherited, and as a result, they will retain the default box-sizing: content-box.
One possible reason why you might never have had any issues with pseudo-elements is that they're displayed inline by default, as box-sizing has no effect on inline elements whatsoever.
Some notes:
As with any other chain of simple selectors, if * is not the only component then you can leave it out, which means *, :before, :after is equivalent to *, *:before, *:after. That being said, the * is usually included for the sake of clarity — most authors are used to leaving the * out when writing ID and class selectors, but not pseudo-classes and pseudo-elements, so the notation may seem strange and even wrong to them (when it is in fact perfectly valid).
The current Selectors specification that I link to above represents pseudo-elements with double colons. This is a new notation introduced in the current spec to distinguish pseudo-elements from pseudo-classes, but most box-sizing resets use the single colon notation to accommodate IE8, which supports box-sizing but not the double colon notation.
Although *:before, *:after applies styles to the respective pseudo-elements of any element, which includes html, head and body, the pseudo-elements will not actually be generated until you apply the content property. You do not have to worry about any performance issues as there are none. For a detailed explanation, see my answer to this related question.
I can only cite from the specification:
The universal selector, written "*", matches the name of any element type. It matches any single element in the document tree.
Element types are for example span and div.
Since pseudo elements don't have an "element type" and are not part of the document tree, it looks like the answer is no, it does not include pseudo elements.
However, since pseudo elements inherit the CSS properties from their "parent" (at least the ones that are inheritable) and the universal selector also affects the parent, it indirectly affects the pseudo elements.
Example
the color is inherited
the border style is not and the ::before element doesn't have a border
Does the star selector in CSS affect page rendering performance?
Are there any caveats using it?
* {
margin:0;
padding:0;
}
When it comes to performance, Steve Souders is the man:
Performance Impact of CSS Selectors
Simplifying CSS Selectors
Shameless quote from one of the reports:
The key to optimizing CSS selectors is
to focus on the rightmost selector,
also called the key selector
(coincidence?). Here’s a much more
expensive selector: A.class0007 * {}.
Although this selector might look
simpler, it’s more expensive for the
browser to match. Because the browser
moves right to left, it starts by
checking all the elements that match
the key selector, “*“. This means the
browser must try to match this
selector against all elements in the
page.
[bold emphasis mine]
For some properties using * can produce unexpected results.
* { color: blue }
li { color: red }
Now given <li><i>text</i></li>, the text will be blue!
One view is that it's not so much that the * is a performance problem, it's that good old favourite - there's an IE issue with it. It affects IE 5, 5.5 and 6 as well as Macintosh variants. Basically, there is something called the HTML star selector bug which applies as follows:
* html
This should be interpreted as no element match because html is root and cannot be a child element. IE interprets this as html.
* * body
Again, should match to no element because body cannot be a grandchild element - even though it is a child element of HTML. IE interprets this as * body.
* html body
This should match no element, but IE interprets this as html body.
The performance side is usually treated that applying * only means that the style applies to every element in a page. I rarely find that this is an issue in its own right - the point at which it would become an issue means that you've probably got way too much markup in there anyway. Similarly, as it applies to everything, it means you need to increase your code to cope with elements that shouldn't have that style. As with everything else, it's up to you to decide what the tradeoffs and balance should be.
Since I'm using the exact same rule in every of my projects and none have serious perfomance issues, I'd say: No, not as far as I know.
So, I'm not sure what I've stumbled upon here. I'm working with some CSS and I know it is common place to do something like this:
#content{
/* Style the content div. */
}
#content p{
/* Style all p elements in the content div. */
}
I'd like to give one specific p element a float:right style. Only one such p element will occur in the content element. Naturally, I'd just give this element an id, but then I had the idea to do it this way:
#content #right_floating_p{
float:right;
}
This works when I run the code, but I was wondering about best practice and whether or not this actually does anything scope wise. I could just as easily define a separate id for right_floating_p, but to me it feels natural that it should be defined with the content id because it will be used only on one p element inside the content element.
If anyone has any information about this syntax, please let me know. Thanks!
My recommendation is to only include the last ID. This is fairly standard separation of concerns. What if you want to change the first ID #content, but the last one #right_floating_p still makes sense and shouldn't change? There is more room for error if you specify something unnecessarily.
Other reasons this is good:
Smaller, faster (but barely) download size for your users.
More readable, in my opinion.
Faster (but barely) performance.
Over-qualifying tags is bad practice in general, as far as performance goes. Browsers read your selectors from right-to-left, by the time it interprets your #content selector, that information is pointless. My advice is to not trust that the browser will optimize for this.
Alvaro nailed it in his comment above.
The id must be unique on the page, but not necessarily across the whole site. So, for instance, if you had the #right_floating_p element on every page, but it had a #content element as an ancestor only on a certain page where you wanted it styled differently, then you'd want to use the #content #right_floating_p selector to apply the context-specific style.
I would suggest only using the most precise selector as you can, not only for readability and file size, but also for specificity.
CSS selectors have a specificity to them, so if you were to override it later (such as with a media query), the more specific selector will override the less specific one.
#content #right_floating_p {
color: red;
}
div #right_floating_p {
color: green; /* Will not apply, as it's less specific */
}
p {
color: black; /* Even less specific */
}
It will work having the first selector, but it's not necessary.
Does the universal selector * affect pseudo elements like :before and :after?
Let me use an example:
When doing this:
* { box-sizing: border-box; }
...doesn't the above declaration automatically include/affect pseudo elements like :before and :after as well?
Or, in order to affect pseudo elements like :before and :after, one has to declare this?
*, *:before, *:after { box-sizing: border-box; }
Does this make sense?
I have always used just * { box-sizing: border-box; } and never have had any issues with pseudo elements whatsoever. But I see many tutorials doing *, *:before, *:after but they never really explain why they include *:before, *:after in the declaration.
No, the universal selector * does not affect pseudo-elements (except indirectly via inheritance, as pseudo-elements are typically generated as children of actual elements).
The universal selector, like other named element selectors such as p and div, is a simple selector:
A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, or pseudo-class.
A simple selector, and by extension any complex selector, targets only actual elements.
Although pseudo-elements (which are not the same thing as pseudo-classes mentioned above) can appear in selector notation alongside simple selectors, pseudo-elements are completely separate from simple selectors as they represent abstractions of the DOM that are separate from actual elements, and therefore both represent different things. You cannot match a pseudo-element using a simple selector, nor can you apply styles to an actual element in a CSS rule with a pseudo-element in its selector.
So, in order to match :before and :after pseudo-elements of any element, yes, one will need to include *:before, *:after in the selector. Having just * { box-sizing: border-box; } will not affect them since box-sizing is not normally inherited, and as a result, they will retain the default box-sizing: content-box.
One possible reason why you might never have had any issues with pseudo-elements is that they're displayed inline by default, as box-sizing has no effect on inline elements whatsoever.
Some notes:
As with any other chain of simple selectors, if * is not the only component then you can leave it out, which means *, :before, :after is equivalent to *, *:before, *:after. That being said, the * is usually included for the sake of clarity — most authors are used to leaving the * out when writing ID and class selectors, but not pseudo-classes and pseudo-elements, so the notation may seem strange and even wrong to them (when it is in fact perfectly valid).
The current Selectors specification that I link to above represents pseudo-elements with double colons. This is a new notation introduced in the current spec to distinguish pseudo-elements from pseudo-classes, but most box-sizing resets use the single colon notation to accommodate IE8, which supports box-sizing but not the double colon notation.
Although *:before, *:after applies styles to the respective pseudo-elements of any element, which includes html, head and body, the pseudo-elements will not actually be generated until you apply the content property. You do not have to worry about any performance issues as there are none. For a detailed explanation, see my answer to this related question.
I can only cite from the specification:
The universal selector, written "*", matches the name of any element type. It matches any single element in the document tree.
Element types are for example span and div.
Since pseudo elements don't have an "element type" and are not part of the document tree, it looks like the answer is no, it does not include pseudo elements.
However, since pseudo elements inherit the CSS properties from their "parent" (at least the ones that are inheritable) and the universal selector also affects the parent, it indirectly affects the pseudo elements.
Example
the color is inherited
the border style is not and the ::before element doesn't have a border