A great deal can be accomplished with pure CSS, but the power of the syntax is limited by its inability to affect certain elements. Understanding those limitations is the first step to determining whether a CSS-only, hybrid JavaScript-CSS script or pure JavaScript solution is best for your web design and development problems.
What’s CSS Good At?
The easiest way to describe CSS selectors is that they work from the outside in of the DOM, and from top to bottom. For example, it’s easy for link foo to affect the appearance of a div
with an id
of bar in the code below.
<a href="#">foo</a>
<div id="bar">
<p>Content
</div>
So long as B follows A
, we can use a simple adjacent selector:
a:hover + div#bar {
/* rules for appearance of the div */
}
It’s possible to do this even if foo isn’t right next to bar:
<a href="#" class=foo>foo</a>
<a href="#">boop</a>
<div id="bar">
<p>Content
</div>
With the following CSS:
a.foo:hover ~ div#bar {
/* rules for appearance of the div */
}
But CSS can’t do “backwards” selection:
<div id="bar">
<p>Content
</div>
<a href="#" class="foo">foo</a>
In the code above, foo
cannot influence the appearance of bar
.
It’s entirely possible to work “down” through the DOM with CSS:
<div id="bing">
<p><a href="#" class="boom">Content</a> here
</div>
… using a descendant selector:
#bing:target p a.boom {
font-weight: bolder;
}
But CSS can’t work from the “inside out”: there’s little you can do to the .boom
link that will affect the #bing
container, at least using CSS. In some cases you can provide the impression that interactions with child elements alters the appearance of their parents – a good example would be my Reverse Focus UI technique – but it’s not technically possible.
What Else Can’t CSS Do?
- Poor click event support
- CSS doesn’t have good support for click events.
:hover
is fine, but:focus
is mostly constrained to form elements, and:target
, as it is currently implemented in browsers, usually carries a significant presentation deficit. - No walking backwards through the DOM
- As mentioned, CSS can’t work backwards through the source order. It’s possible to provide the appearance of A following B, and thus able to affect it:
<a href="#" class="foo">foo</a> <a href="#">boop</a> <div id="bar"> <p>Content </div>
The CSS:
a.foo { position: relative; top: 5rem; } a.foo:hover + div { border: 1px solid red; }
… will present foo below bar, while continuing to affect it.
- No loops
- We can use CSS to easily fade one element, but fading five or more in a row, one after another, usually takes an excessive (and inefficient) amount of code. We need to use JavaScript or CSS pre-processors to accomplish that: I’ve shown an example in the recent past.
- 4096 selector limit
- An unusual limit that is increasingly encountered by developers as stylesheets get larger, longer, and more complex. Any version of Internet Explorer before version 10 has a limit of 4096 selectors per stylesheet, and will ignore any declarations after encountering that number.
Conclusion
The optimal solution is to use each web technology for the task it is best at: CSS for presentation and simple animation rules, JavaScript for ad-hoc selection and manipulation of the DOM. The optimal result is often a hybridized combination of the two, an example of which I will present in the very near future here in this blog.
Photograph by Yasunari Nakamura, used under a Creative Commons license
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.