I have seen that it is a performance hit to do something like:
a[rel^=ext] {
Which makes sense. But I have also found a bit of code in a template I used that does this for each section on the site:
#print {
#section-name {
color: #000;
background: #fff;
}
}
I figured I could just use [^] to select them all and making one rule and saving lines of code. Then I found out that would be a performance hit.
So I checked and discovered that there is an outer div with an id. So then I thought I could do #idName section.
But that uses an element, so again would probably be a performance hit I assume.
Does anyone have any information where I can find out more about performance and which way would be the quickest. e.g. is the performance hit on a bigger file worse or the computation of many selectors worse?
As a further part, I find this sort of thing very interesting, does anyone have a good, reliable way to test these things? Using online services gives a different result each time, so would require thousands of goes to make good numbers. Does anyone know a good way to undertake these actions?
Per Eoin's request, I'm making an answer for future visitors (as I think this is useful).
From this link: https://www.sitepoint.com/optimizing-css-id-selectors-and-other-myths/
The following snippet runs on 50,000 nodes. The console output will give you an answer on performance for specific selectors.
const createFragment = html =>
document.createRange().createContextualFragment(html);
const btn = document.querySelector(".btn");
const container = document.querySelector(".box-container");
const count = 50000;
const selectors = [
"div",
".box",
".box > .title",
".box .title",
".box ~ .box",
".box + .box",
".box:last-of-type",
".box:nth-of-type(2n - 1)",
".box:not(:last-of-type)",
".box:not(:empty):last-of-type .title",
".box:nth-last-child(n+6) ~ div",
];
let domString = "";
const box = count => `
<div class="box">
<div class="title">${count}</div>
</div>`;
btn.addEventListener("click", () => {
console.log('-----\n');
selectors.forEach(selector => {
console.time(selector);
document.querySelectorAll(selector);
console.timeEnd(selector);
});
});
for (let i = 0; i < count; i++) {
domString += box(i + 1);
}
container.append(createFragment(domString));
body {
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
.btn {
background: #000;
display: block;
appearance: none;
margin: 20px auto;
color: #FFF;
font-size: 24px;
border: none;
border-radius: 5px;
padding: 10px 20px;
}
.box-container {
background: #E0E0E0;
display: flex;
flex-wrap: wrap;
}
.box {
background: #FFF;
padding: 10px;
width: 25%
}
<button class="btn">Measure</button>
<div class="box-container"></div>
From the sitepoint link as well, here is some more data with information to back it up:
The test was bumped up a bit, to 50000 elements, and you can test it out yourself. I did an average of 10 runs on my 2014 MacBook Pro, and what I got was the following:
Selector : Query Time (ms)
div : 4.8740
.box : 3.625
.box > .title : 4.4587
.box .title : 4.5161
.box ~ .box : 4.7082
.box + .box : 4.6611
.box:last-of-type : 3.944
.box:nth-of-type(2n - 1) : 16.8491
.box:not(:last-of-type) : 5.8947
.box:not(:empty):last-of-type .title : 8.0202
.box:nth-last-child(n+6) ~ div : 20.8710
The results will of course vary depending on whether you use querySelector or querySelectorAll, and the number of matching nodes on the page, but querySelectorAll comes closer to the real use case of CSS, which is targeting all matching elements.
Even in such an extreme case, with 50000 elements to match, and using some really insane selectors like the last one, we find that the slowest one is ~20ms, while the fastest is the simple class at ~3.5ms. Not really that much of a difference. In a realistic, more “tame” DOM, with around 1000–5000 nodes, you can expect those results to drop by a factor of 10, bringing them to sub-millisecond parsing speeds.
The takeaway from all this:
What we can see from this test is that it’s not really worth it to worry over CSS selector performance. Just don’t overdo it with pseudo selectors and really long selectors.
Another test here: https://benfrain.com/css-performance-revisited-selectors-bloat-expensive-styles/ covered data-attribute and regex selectors. It found:
Data attribute
Data attribute (qualified)
Data attribute (unqualified but with value)
Data attribute (qualified with value)
Multiple data attributes (qualified with values)
Solo pseudo selector (e.g. :after)
Combined classes (e.g. class1.class2)
Multiple classes
Multiple classes with child selector
Partial attribute matching (e.g. [class^=“wrap”])
nth-child selector
nth-child selector followed by another nth-child selector
Insanity selection (all selections qualified, every class used e.g.
div.wrapper > div.tagDiv > div.tagDiv.layer2 > ul.tagUL >
li.tagLi > b.tagB > a.TagA.link)
Slight insanity selection (e.g. .tagLi .tagB a.TagA.link)
Universal selector
Element single
Element double
Element treble
Element treble with pseudo
Single class
Here are the results. You should note they are from 2014 browsers. All times in milliseconds:
Test Chrome 34 Firefox 29 Opera 19 IE9 Android 4
1 56.8 125.4 63.6 152.6 1455.2
2 55.4 128.4 61.4 141 1404.6
3 55 125.6 61.8 152.4 1363.4
4 54.8 129 63.2 147.4 1421.2
5 55.4 124.4 63.2 147.4 1411.2
6 60.6 138 58.4 162 1500.4
7 51.2 126.6 56.8 147.8 1453.8
8 48.8 127.4 56.2 150.2 1398.8
9 48.8 127.4 55.8 154.6 1348.4
10 52.2 129.4 58 172 1420.2
11 49 127.4 56.6 148.4 1352
12 50.6 127.2 58.4 146.2 1377.6
13 64.6 129.2 72.4 152.8 1461.2
14 50.2 129.8 54.8 154.6 1381.2
15 50 126.2 56.8 154.8 1351.6
16 49.2 127.6 56 149.2 1379.2
17 50.4 132.4 55 157.6 1386
18 49.2 128.8 58.6 154.2 1380.6
19 48.6 132.4 54.8 148.4 1349.6
20 50.4 128 55 149.8 1393.8
Biggest Diff.
16 13.6 17.6 31 152
Slowest
13 6 13 10 6
Related
New to Grid.js, and by no means a css Expert.
I am trying to style alternate rows, which seems like a common use case that should be simple enough to implement, but I can't seem to get to 1st base.
It appears that I can not even apply a simple style to tr elements. There is no indication in the docs that tr styles are supported, either by using literals or style classNames.
columns: ["Name", "Email", "Phone Number"],
data: [
["John", "john#example.com", "(353) 01 222 3333"],
["Mark", "mark#gmail.com", "(01) 22 888 4444"],
["Eoin", "eoin#gmail.com", "0097 22 654 00033"],
["Sarah", "sarahcdd#gmail.com", "+322 876 1233"],
["Afshin", "afshin#mail.com", "(353) 22 87 8356"]
],
style: {
tr: {
'background-color': '#69c'
}
}
}).render(document.getElementById("wrapper"));
And if I can't get a simple style to work, there's no hope of getting this to work:
tr:nth-child(even) {
background-color: Lightgreen;
}
Turns out, styling alternating rows is not that hard. This sample helped:
https://codesandbox.io/s/gridjs-bpf9g?file=/src/styles.css:0-57
It's not necessary to include style: class. The css tr selector works by itself.
new gridjs.Grid({
columns: ["Name", "Email", "Phone Number"],
data: [
["John", "john#example.com", "(353) 01 222 3333"],
["Mark", "mark#gmail.com", "(01) 22 888 4444"],
["Eoin", "eoin#gmail.com", "0097 22 654 00033"],
["Sarah", "sarahcdd#gmail.com", "+322 876 1233"],
["Afshin", "afshin#mail.com", "(353) 22 87 8356"]
]
}).render(document.getElementById("wrapper"));
/* styles.css */
tr:nth-of-type(even) td {
background: #fff;
}
tr:nth-of-type(odd) td {
background: #fea;
}
I am trying to target an element with specific class inheritance. When using Chrome Dev tools, I see that the style is as specific as it gets and still it is crossed out and not being used.
I am using SASS and the following code:
.post-item, .post-type-project, .project, .type-project {
.post-text {
width: calc(35% - 15px);
}
}
I don't want to use the !important hack, because it breaks other CSS rules.
As a quick primer on CSS specificity in general, you can use the base-10 method to calculate the "weight" of a rule.
elements & pseudo-elements = 1
classes & pseudo-classes = 10
id's = 100
inline = 1000
So in this example, the first rule in your scenario is:
0 elements & pseudo-elements = 1 * 0 = 0
5 classes & pseudo-classes = 10 * 5 = 50
0 id's = 100 * 0 = 0
0 inline = 1000 * 0 = 0
TOTAL = 50
Calculating your rule, you've got a specificity of 30 (3 classes). In order to take precedence it needs to have a value greater than 50 (or exactly 50 and be declared after the other rule).
While you can add a single ID to the list, and it will bump up the specificity high enough to override the first rule, you are also limiting the rule to only one specific location. While you've avoided using the !important flag, you've introduced another issue.
Consider the you are trying to make sure a door is locked, but have this rule:
house door.exterior {
state: unlocked;
}
Alice isn't home, and you want to make sure Alice's door is locked, so you specify:
#alice door.exterior {
state: locked;
}
When Bob and Carol aren't home:
#carol door.exterior,
#bob door.exterior,
#alice door.exterior {
state: locked;
}
We've accomplished locking the doors, but we've both added a maintenance issue and obscured the reason for locking the doors. We'd need to add the rule for every person whose house we want to lock. We would be much better off by using a lower specificity rule that is semantically significant.
house.owner-away door.exterior {
state: locked;
}
CSS is often a balancing act between too specific and not specific enough. In this case the rule you're trying to override has 2 semantic classes that are overriding your rule, it specifies that it applies to posts in a post-list and only applied to post-text that follows a post-image. If these rules also apply to your rule, use them, if not, look around and see what other more general rules you can use.
Note While the base-10 method is an easy way of representing relative specificity, a single selector at each level will override any number of selectors at the next. For example, having 11 element selectors does not override 1 class, even though this method will calculate it at a higher value.
Try to verify that your code is placed lower in the compiled file. Otherwise try to strengthen the weight of your selector by an id (for example):
#parentContainer{
.post-item, .post-type-project, .project, .type-project {
.post-text {
width: calc(35% - 15px);
}
}
}
do it like this, increasing the nesting by adding one more item
body{
.post-item, .post-type-project, .project, .type-project {
.post-text {
width: calc(35% - 15px);
}
}
}
or
body .post-item, body .post-type-project, body .project, body .type-project {
.post-text {
width: calc(35% - 15px);
}
}
}
I was wondering if it's possible to use Polymer's core-icons.html file to display an icon as a background-image in CSS. What I want is to reference an icon in my stylesheet like this:
#arrow-forward {
background-image: url(route to polymer icon/arrow-forward.svg);
}
So far I've tried this without success:
#arrow-forward {
background-image: url(bower_components/core-icons/core-icons.html/arrow-forward.svg);
}
I'm wanting to do this so that I can easily create more customized controls for image sliders/other plugins.
You can't directly reference core-icons (or the the upcoming iron-icons) for use in CSS because they don't exist as files/base64 data. If you look in the source code for core-icons.html, you'll see why your reference doesn't work; the icons are svg paths:
<!--
...
#group Polymer Core Elements
#homepage polymer.github.io
-->
<link rel="import" href="../core-icon/core-icon.html">
<link rel="import" href="../core-iconset-svg/core-iconset-svg.html">
<core-iconset-svg id="icons" iconSize="24">
<svg><defs>
<g id="3d-rotation"><path d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08-.16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.07.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03-.15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56-.05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2.52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-.68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43C9.1 8.05 8.76 8 8.39 8c-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18.85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48-.08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11.1-.25.18-.41.24-.16.06-.36.09-.58.09H7.5v1.03h.77c.22 0 .42.02.6.07s.33.13.45.23c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8.55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27H12v8h2.3c.55 0 1.06-.09 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-.4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.13-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91V9.12h.97c.72 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zM12 0l-.66.03 3.81 3.81 1.33-1.33c3.27 1.55 5.61 4.72 5.96 8.48h1.5C23.44 4.84 18.29 0 12 0z"/></g>
<g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z"/></g>
...
I'm wanting to do this so that I can easily create more customized
controls for image sliders/other plugins.
Polymer's world view is that elements are composable and core-icon is no exception, allowing you to do accomplish your goal without without using the svg's directly in your css.
You can style core-icon:
<style>
core-icon[icon="cancel"] {
color: red;
width: 48px;
height: 48px;
}
</style>
<core-icon icon="cancel"></core-icon>
You can compose other elements with core-icon as well:
<core-menu-button icon="menu">
<core-item icon="settings" label="Settings"></core-item>
</core-menu-button>
This only touches on the surface, and I highly recommend reading the documentation on core-icon, which gives further examples.
I am having soome problems with the :nth-child pseudoclass.
What I want to do is select the 9th child, and than every following 6th child.
so first 9
than 15
than 21
than 27
than 33
etc.. etc..
I thought that it should work by putting this in my css:
.child-div:nth-child(9n+6) p {
margin: 0;
}
It didn't..
I tried al diffrent formules like 10n+6, 6+9n and so on..
I followed this tutorial
But that didn't explain it eighter.
Does someone know why it doesn't work, can you only make formules like 4n+4 or something?
You were close to solution :
.child-div:nth-child(6n+9) p {
margin: 0;
}
Working example here : http://jsfiddle.net/5Y49A/1/
That's what you need:
.child-div:nth-child(6n+9) p {
margin: 0;
}
This means it selects every sixth element starting from the ninth.
Check out this online tool if you have problems with nth-child:
:nth tester
I believe you want
.child-div:nth-child(6n+9) p {
margin: 0;
}
This means every 6th item, starting at 9.
Using a formula (an + b). Description: a represents a cycle size, n is a counter (starts at 0), and b is an offset value.
It should be
.child-div p:nth-of-type(6n+9){
margin: 0;
}
As you probably know, if you will to use :before and/or :after pseudoelements without setting text in it, you still have to declare content: ''; on them to make them visible.
I just added the following to my base stylesheet :
*:before, *:after {
content: '';
}
...so I don't have to declare it anymore further.
Apart from the fact the * selector is counter-performant, which I'm aware of (let's say the above is an example and I can find a better way to declare this, such as listing the tags instead), is this going to really slow things down ? I don't notice anything visually on my current project, but I'd like to be sure this is safe to use before I stick it definitely into my base stylesheet I'm going to use for every project...
Has anyone tested this deeply ? What do you have to say about it ?
(BTW, I do know the correct CSS3 syntax uses double semicolons (::before, ::after) as these are pseudoelements and not pseudoclasses.)
So I ran some tests based on #SWilk's advice. Here's how I did it :
1) Set up a basic HTML page with an empty <style> tag in the <head> and the simple example he provided in a <script> tag at the bottom of the <body> :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Performance test</title>
<style>
/**/
</style>
</head>
<body onload="onLoad()">
<div class="container"></div>
<script>
function onLoad() {
var now = new Date().getTime();
var page_load_time = now - performance.timing.navigationStart;
console.log("User-perceived page loading time: " + page_load_time);
}
</script>
</body>
</html>
2) Fill up the div.container with loaaads of HTML. In my case, I went to html-ipsum.com (no advertising intended), copied each sample, minified it all together, and duplicated it a bunch of times. My final HTML file was 1.70 MB, and the div.container had 33264 descendants (direct or not ; I found out by calling console.log(document.querySelectorAll('.container *').length);).
3) I ran this page 10 times in the latest Firefox and Chrome, each time with an empty cache.
Here are the results without the dreaded CSS ruleset (in ms) :
Firefox :
1785
1503
1435
1551
1526
1429
1754
1526
2009
1486
Average : 1600
Chrome :
1102
1046
1073
1028
1038
1026
1011
1016
1035
985
Average : 1036
(If you're wondering why there's such a difference between those two, I have much more extensions on Firefox. I let them on because I thought it would be interesting to diversify the testing environments even more.)
4) Add the CSS we want to test in the empty <style> tag :
html:before, html:after,
body:before, body:after,
div:before, div:after,
p:before, p:after,
ul:before, ul:after,
li:before, li:after,
h1:before, div:after,
strong:before, strong:after,
em:before, em:after,
code:before, code:after,
h2:before, div:after,
ol:before, ol:after,
blockquote:before, blockquote:after,
h3:before, div:after,
pre:before, pre:after,
form:before, form:after,
label:before, label:after,
input:before, input:after,
table:before, table:after,
thead:before, thead:after,
tbody:before, tbody:after,
tr:before, tr:after,
th:before, th:after,
td:before, td:after,
dl:before, dl:after,
dt:before, dt:after,
dd:before, dd:after,
nav:before, nav:after {
content: '';
}
...and start again. Here I'm specifying every tag used in the page, instead of * (since it is counter-performant in itself, and we want to monitor the pseudo-element triggering only).
So, here are the results with all pseudo-elements triggered (still in ms) :
Firefox :
1608
1885
1882
2035
2046
1987
2049
2376
1959
2160
Average : 1999
Chrome :
1517
1594
1582
1556
1548
1545
1553
1525
1542
1537
Average : 1550
According to these numbers, we can conclude the page load is indeed slower (of about 400-500 ms) when declaring content: '' on every pseudo-element.
Now, the remaining question now is : is the extra load time we can see here significative, given the relatively big test page that was used ? I guess it depends on the size of the website/project, but I'll let more web-performance-knowledgeable people give their opinion here, if they want to.
If you run your own tests, feel free to post your conclusions here as well, as I'm very interested in reading them - and I think I won't be the only one.
My answer is: I don't know, but one can test that.
Read about Navigation Timing and check out this example page
The most simple example of usage:
function onLoad() {
var now = new Date().getTime();
var page_load_time = now - performance.timing.navigationStart;
console.log("User-perceived page loading time: " + page_load_time);
}
So, go generate a few MB of html full of random tags, and test.