This is a reply to @ppk's article "The CSS mental model"
I like the idea of explaining CSS to JavaScript developers using JavaScript analogies! I'm not really sure about the example you're giving, to be honest.
Would it make more sense to explain the declarative part as some code that runs on every frame to render the page again? Every part of a CSS selector then becomes either a loop or a conditional inside a loop. See below.
The given example (I dropped the :hover
for reasons later explained)
nav a {
background-color: red;
}
would then translate to this piece of code being run on every frame in a render loop.
Makes more sense, less correct
const allNavs = Array.from(document.querySelectorAll('nav'));
allNavs.forEach((nav) => {
const allAnchors = Array.from(nav.querySelectorAll('a'));
allAnchors.forEach((a) => {
a.style.backgroundColor = 'red';
}
});
More correct, but feels weird for people that don't know how CSS is interpreted
const allAnchors = Array.from(nav.querySelectorAll('a'));
allAnchors.forEach((a) => {
if (a.closest('nav')) {
a.style.backgroundColor = 'red';
}
});
I also think the :hover
example and pseudo-classes in general are harder to make sense when trying to explain the analogy, because the JavaScript equivalent is non-existent.
It would make more sense to explain it like this:
const allAnchors = Array.from(nav.querySelectorAll('a'));
allAnchors.forEach((a) => { // CSS selector: a {}
if (a.hover === true) { // CSS selector: a:hover {}
if (a.closest('nav')) { // CSS selector: nav a:hover {}
a.style.backgroundColor = 'red';
}
}
});
but in another way, that doesn't make sense, because it won't work. The :hover
example shows the main difference between the declarative nature of CSS and the imperative nature of JavaScript.
So, while I feel it perfectly shows the difference between the two, I don't think it's an obvious enough example to explain the difference, especially for people comfortable with either CSS or JavaScript, but not both.