If you haven’t checked in on CSS’s newer and more advanced selectors for a couple of years, come see what you’ve been missing! Where once CSS selectors formed the “tradie’s tool belt” of every front-end developer, these days reliance on preprocessors like Sass and sophisticated template frameworks leads most developers to grab the same hammer to solve every problem: class selectors.
Kevin Yank will take you on a whistle-stop tour of the CSS selector landscape, from surprising new tricks in trusty standbys like attribute selectors, to enticing (and occasionally heartbreaking) glimpses of the future like :matches and :has.
CSS selectors allow us to point to parts of our document and say, “I want to control how you look”.
There is very little that is new in CSS Selectors today, and what is being made available by the standards body is more like paper clips and rubber bands than the power tools we want.
We are not making the best use of selectors we do already have, and the selectors we do have can be used in new and clever combinations to deliver greater control and create desirable effects.
(whoosh) – So you can see, a recurring theme, obviously I have a great passion for CSS, and I think to be quite honest it continues to be undervalued in terms of its importance.
And a lot of our focus, and this might be a cause of frustration for you, and I, having had a few conversations over the last couple of days, I sense that it is.
And it certainly is for me, as often we live up here in this high-level abstraction land of frameworks, and libraries, and bootstraps, and whatever.
And we kind of ignore the underlying technologies. And that’s one of the things that Web Directions is always focused on.
We’ve never even had a session on jQueries, right, even back in the day, because our real interest is focusing on the enabling technologies, and then we can build on top of those.
And it’s kind of a source of frustration to me that there’s all these amazing things in CSS that people just don’t know about, or if they do know about, they think it maybe doesn’t work very well, or maybe they’re not quite sure how to use it. And one area in particular around that is CSS selectors.
So our next speaker is gonna delve a bit more deeply into these, and hopefully leave you with a sense of there being a lot more to CSS selectors than maybe even you, with years of experience, might have realised.
So, our next speaker is Kevin Yank.
If you’re here in Melbourne, I’m sure you know Kevin. He’s worked for many and wrote for many years at SitePoint, developed lots of courses at Learnable, you know, he’s educated whole generations of web people, and it’s been a great privilege of mine to know him for many, many years.
It just so happens to be his birthday today, right. We’re not gonna sing or anything, but I’ll just flag that with “Happy birthday to ya, Kevin, well done.” 23 again.
(laughs) And on top of everything else, he loves doing improv theatre, and so if you ever get the chance to see him around, you should go see him.
Yeah, we’re not gonna mention the improv? Right. Just pretend I didn’t say that.
But would you please welcome Kevin Yank to come tell us all about the latest in CSS selectors. Thanks.
(audience claps) – Hello, everyone.
Between now and lunch, we’re going to look at CSS selectors.
No prizes for picking them out of this slide, they’re the things in pink, they’re the part of CSS that let us point at elements in the page and say “I want to style you.” So, in this talk, I’m going to be showing you what’s new in CSS selectors, and I’m gonna move quickly onto why there’s nothing new in CSS selectors, and then we’ll finish strong with how to be MacGyver. So what’s new? We have pseudo classes for styling radio buttons and checkboxes, we have pseudo classes for valid and invalid form fields using HTML5 form validations.
And because pretty much every form starts out invalid, because all the fields are empty, you probably don’t want to use these, or your form will look very red when it first shows up. So there’s this proposal for a user-error pseudo class that would only turn the style of the field when the user had typed something into it.
That’d be nice, but there’s no support for it just yet.
We have all these pseudo classes for selecting children of a container.
And these last four are especially interesting, they let us do all sorts of things, like select the fourth child, select every second child, select the fourth child onward, select everything up to the fourth child, select every third child starting with the first, select the third-to-last child, and the third-to-last child onward.
So, pretty much any combination of children that you could think of, you can style them with these pseudo classes.
There’s the empty pseudo class that lets you style an element if it doesn’t contain anything.
So, if you’ve got a div in your page that will get injected into it by your Java Script form validation error messages, and if you don’t have any error messages at the moment, then you probably don’t want to display that div at all, and so you can make it display none under those conditions. This pseudo class is a little finicky, because if your element, the div at the bottom here, contains so much as a line break, that pseudo class no longer matches, and you get an ugly red border, about one-pixel high box.
That’s why there’s a proposal for the blank pseudo class, which will ignore white space as well, still coming soon.
The target pseudo class lets you match the element that has the ID referred to by the fragment identifier in the URL.
And we can use this to do cool stuff like light boxes without Java Script.
So here I’ve got a hyperlink on the right, and it points to the message ID in my page, and if I click that, the light box that was formerly hidden will now be displayed, because we have the second style rule that now applies to it.
And then that light box could contain another hyperlink that links back to the empty fragment identifier, and clicking that would close the light box, all without a shred of Java Script.
There’s a not pseudo class.
Here I’ve got some articles on the page, and I want a border between each one, and the old way of doing this would be to apply a bottom border to every single article and then add another rule to remove the bottom border from the last article.
We can now do this more efficiently using “not,” and “not” reverses the meaning of whatever simple selector you put inside it. So here I’m saying any article that is not the last child gets a bottom border.
Here’s another example of using “not.” This first rule will match any hyperlink that does not have a class attribute on it. So those could be the hyperlinks coming out of your content management system, the ones that are in the core content of your site, and then all of the links in the chrome, the surrounding structure of your site, you can style with class selectors like this one. And the reason this approach is valuable is that first selector and the second selector are mutually exclusive.
No element will match both of these selectors. And so you’re not getting into a specificity war between your selectors.
Also, you don’t have to roll back all the styles you apply to your standard links in your specific links. These two sets of styles can coexist peacefully and not have to interact with each other.
This is the general sibling selector.
You’re probably familiar with the adjacent sibling selector, that’s the + in the selector you see there. Those who know it know that the + selects the following sibling after the previously matched elements.
So in this case, the trigger class is on my div, and by doing + * I’m selecting the following sibling element. If I changed that + to a ~ I now select all of the following divs in the same container.
And this turns out to be handy for all sorts of reasons. Now you might be thinking, “That’s old news. “I’ve seen all this stuff before, “it’s been around for years.” And you’d be right, and you should be using all this stuff if you’re not.
But I promised you new things, so I went looking for what’s truly new in CSS selectors.
These are the, this is the array of attribute selectors that we have available to us, and you can now add a letter i to the end of them, and then the value in these selectors will now be matched case insensitively.
I don’t know why you would want this.
I don’t want this, so I’m moving on.
This is the “matches” pseudo class, okay.
I’ve got an old-style selector here, it matches visited and unvisited links in ordered and unordered lists, and because of those alternatives, I basically have to write four different selectors. If you’re familiar with SaaS, you can reduce the repetition by going for nesting instead.
But now we can do the same thing natively in CSS by using matches to express the alternatives in this one selector.
But this is just syntactic sugar.
It’s not letting us style anything we couldn’t style before or achieve any new visual effect.
(audience laughs) This is the “placeholder-shown” pseudo class. I’m really scraping the bottom of the barrel now, in case you couldn’t tell.
This lets us style a form field if it is currently empty and displaying a placeholder.
Some browsers have let you style that placeholder text itself, but now we can also style the surrounding form field. Boring! Why is there nothing new in CSS selectors? Well, we get new CSS features and new selectors when we ask for them as developers.
And right now, we’re not asking.
Because we’re all doing stuff like this.
This is Twitter bootstrap, where you can create a perfectly serviceable search field, just by picking LEGO bricks out of the box and applying class attributes to every single element in the page.
And even if you’re writing your own styles, you may have embraced methodologies like BEM, Block Element Modifier, where, again, everything is a class.
This example here is the nav block on my page. You can tell because it has a class of nav. and every single element inside it that I might want to style has a class of nav __ and then a unique name.
If I want to style it differently, I give it a different name, and I call it a day. Even if you’re getting onboard with CSS modules, we’ve recently adopted these at Culture Amp, and they are changing our game.
We love them.
But really, at the end of the day, it just amounts to making it easier to write these long, unique class selectors. The ones on the left here can be really short, generic names, and you don’t have to worry about them clashing with other classes in your other modules, because the CSS modules compiler extends them into these long, unique class names, and then uses those names in your markup as well. These techniques amount to abandoning HTML semantics. We are no longer styling things because of what they are, but because of what we have told them they should look like. And this can result in unfortunate flubs like this one, where I’ve made a span look like a button, even though really it isn’t.
Whether you think this is a problem or not probably has a lot to do with whether you are building sites whose semantics closely match with the ones that HTML makes available to us. So if you’re building sites with documents in them, those semantics, the meanings of HTML tags, are probably quite useful to them, and you probably enjoy using them.
But if like me, you’re building a web application, that’s a graphical user interface that just happens to be displayed in a browser window, the HTML document semantics aren’t that useful, and you probably don’t feel too bad about casting them aside in favour of the control that you get from classes, and you might spend your time worrying about ARIA rules instead, for accessibility. But whatever the reason, we are turning into these people.
For those who don’t know, this is a clip from a sketch comedy show called Portlandia.
I’ll just give a nod to the box, ’cause I’m about to play some audio.
Here we go.
– I’m Bryce Shivers.
– I’m Lisa Eversman.
– And we put birds on things.
– Today we’re gonna go to a store on Mississippi Ave.
Nothing has birds on it, but you know what we’re gonna do? We’re gonna put birds on things.
– Spruce it up, make it pretty.
– Thank you.
– [Bryce and Lisa] Put a bird on it! – Putting a bird on this teapot.
It’s a bird.
Bet ya it’s flying all over the beach.
– What a sad little tote bag.
I know, I’ll put a bird on it.
Did you see this bag before? I didn’t.
Now there’s a bird.
(laughs) It’s flying. It’s free.
– We put this bird right on this card.
– [Lisa] It’s so pretty.
– You like that, ma’am? – Fantastic.
(scraping) – [Lisa] Putting a bird on toast.
– Put a bird on it! – Look at this.
I just sewed this bird right onto the pillow. – Oh, you missed a spot.
– Ow! The hell are you doing? – (Kevin laughs) I won’t spoil the ending, but if you want to know how it ends, come and see me at lunch.
We are turning into the “put a class on it” people. We show up, and we want to make our site all pretty, and we have only one tool for doing it, and that’s put a class on everything.
And what kind of craftspeople are we if we only have one tool for achieving the effects we do? Heydon Pickering spoke at CSS Day in 2014 in Amsterdam.
He gave a talk called “Effortless Style.” It’s available for free online, and if this topic interests you, I suggest you check it out.
But briefly, he spoke about prescriptive versus axiomatic styles.
And what he said was that if you prescribe the appearance of every individual element in your page, you’re taking a really unintelligent approach to styling. Whereas if instead you can come up with axiomatic selectors that style the relationships between elements in the page, you can create really intelligent selectors that have unexpected and desirable behaviours that arise out of them.
Our over-reliance on class attributes is colouring the future of CSS.
And I wanted to take a couple of moments to look at the CSS Selectors Level 4 Working Draught. This is the current document at the W3C that is shaping the future of CSS selectors. Here’s a couple of features.
This is the “local-link” pseudo class.
It would let you style hyperlinks that link out of your site differently from hyperlinks that stay within your site.
This would be totally handy.
I would use this all the time.
There is no browser support and no sign of it coming. This is the “reference combinator.” It lets you style one element because an attribute of another element refers to it.
So in this example, if I mouse over the label, because it’s four attribute points to the field, I can style the field when I mouse over the label. We saw in Simon’s talk yesterday from Kogan reference to the checkbox hack.
This is the checkbox hack on steroids.
I can’t even begin to tell you the possibilities that this would open up.
There is no browser support and no sign of it coming. And in fact, both of these features have just been edited out of the current Editor’s Draught of Selectors Level 4, due to lack of interest. And that is the lack of interest of everyone in this room. This is the “has” pseudo class.
It is still in the Selectors Level 4 Draught. And this is the holy grail of selectors.
I’m here to tell you, for as long as you’ve been doing CSS, you have wanted this pseudo class, and I know I have, too.
You might know of it as the “parent” selector, and what it lets you do is style an element by virtue of what it contains.
So, in the first example here, I’m styling hyperlinks that contain an image as their immediate child.
Right now I could easily style that image, but if I wanted to style the hyperlinks surrounding it, I would have to put a class on it.
Instead, we can do it with this nice selector. The second example is even more exciting.
I’m styling sections that don’t contain headings. That would be a messy piece of template code to have to write to put a class attribute on every section in your page, but now you can do it with this selector.
As with many things in life, you have to read the fineprint, though.
This Selectors Level 4 Draught also introduces this new concept of profiles.
And it has created the dynamic profile, which is every other selector in CSS, and then there’s the static profile, which is just for this “has” pseudo class.
And basically it locks it in a box and says, “This is only gonna work in Java Script.” You can’t use it in your style sheets, because it would be too hard to make browsers perform well with that being dynamically applied to the page as it changes.
I think decisions like this are being made without our voice.
And I’m not saying it’s the wrong decision, but I’m saying we need to be at this table and be arguing back about how useful a feature like this would be in our style sheets.
We want power tools, but right now what we’re getting amounts to little more than paperclips and rubber bands. By the way, this is the most depressing piece of stock imagery I’ve ever spent money on, and I blame all of you.
(audience laughs) Fortunately, I know a guy who’s pretty good with paperclips and rubber bands.
For those who aren’t familiar with TV from the 80s, this is MacGyver.
He was an action hero who was famous for getting himself into scrapes, and it’s probably easiest if I just show you. (“MacGyver Theme”) So there he is freeing a hostage from terrorists by using bits and pieces he found around their compound.
If all we have is paperclips and rubber bands, let’s see if we can build us a couple of bamboo aeroplanes .
This is the “lobotomized owl” selector.
Again, created by Heydon Pickering, who I’m indebted to for much of this talk.
It is * + *, and it lets us do clever things like this. This selector will match any element that has another element before it as a sibling.
And by using it to apply a margin-top to all of those elements, you very nicely get these margins between the blocks in your page.
If you really know your CSS, you know that inline elements ignore any top and bottom margins that you try to apply to them.
So this really nicely isolates its effect to just adjacent blocks on the page.
You don’t have to jump through any hoops to avoid margins above and below these blocks or on the surrounding div.
Pickering loves this technique so much, he just puts it in his CSS reset and uses it as a starting point.
If you know your CSS… Oh, sorry.
It works really well on nested blocks as well, as you can see.
But if you know your CSS, you might say that you can achieve the same thing more clearly with :not(:first-child) And I’d say you’re close.
You also have to add :not(:root) so that you’re not styling the body element as well. But this would be equivalent, except that it’s Internet Explorer 9 or higher only, and this selector has a remarkably high specificity with two class selectors in it.
So, if you try to override it, you’re gonna get into a specificity war with this second version.
The lobotomized owl, however, has a specificity of zero, which means that every possible selector will override it very easily, and lets you do things like this where you say, “Okay, margins between all my blocks, “but if I happen to have two paragraphs “next to each other, get rid of that margin, “and instead use a text indent on the first line “of the second paragraph.” Really cool, and this is using CSS2, stuff we’ve had forever.
Here’s another bamboo aeroplane: quantity selectors.
Because this is a responsive design conference, I assume you all know about media queries, where if I have this nav bar on my page, and I start resizing my browser window and it gets a little tight, I could create a media query that would prevent this from happening by switching to a different styling approach at narrower page widths.
And I could take this even further for mobile devices. Of course, we all know this.
But what if we could write a selector that was responsive not just to the browser window’s size, but to the actual content in the page? So, once again, I’ve got my nav bar here with four elements in it, and what if, through the content management system in our site, our content people go in and add a fifth category? Things are getting a little tight.
I’m feeling a little uncomfortable.
And if they add a sixth, I know my page layout is gonna break.
But often these decisions are made long after we have done our work on the site. So, to make our layout more robust, it’d be great if we could respond to this change in the content by changing styling approaches.
Can we do this? Can we write a selector that will match all of the children in this container if there are six or more of them, for the sake of argument? Here’s with 10.
We’ll start humble and just find a selector that lets us style a special case.
This special case being if there is just one element in that container.
That’s very easy using the only-child pseudo class. So here we’re increasing the font size on that child if it happens to be an only child, if there’s only one element in the container. And if it makes sense to you, we can also swap the logic around and make the special case be if it’s not an only child. Easy enough, but we’re a long way from what we’re looking for.
Let’s be a little more ambitious.
Let’s try and create a selector that matches all of the children if there is an exact number of them. In this case, the six on the bottom.
So if I’ve got those six children, how can we achieve this style only when there’s exactly six? Well, we’ll start with this selector here.
And this selector will match the first child if it is the sixth-to-last child and the first child. And that will only happen if there are exactly six of them.
And then once I’m able to match that one, I can use the general sibling selector, `li, to match all of the following siblings in that container.
And then I just combine these two selectors into one, and I’m able to apply that style when there are exactly six children in that nav bar.
We’re almost there, but what we’re going for is a style that will apply if there are six or more children. So we need to be a bit more flexible, and I’m gonna try and style this nav bar that has ten children in it.
So this selector, nth-last-child(n+6), this will match the sixth-to-last child, the seventh-to-last child, the eighth-to-last child, and so on.
Which means if there are five or fewer, it won’t match anything.
But once I’ve matched the first few children, I can then use, again, the general sibling selector, `li, to match all of the following list items and combine these two selectors, and there we go.
We have a selector that will match all the children if there are six or more of them, and we’ve done it.
And just to give you something to do when you get home, this is the opposite version, this first selector here will match all of the children if there are five or fewer of them. So there you go, a couple of bamboo aeroplanes using nothing but spare parts that were lying around. I hope I’ve rekindled your interest in CSS selectors, and I hope you’ll join me in demanding the selectors we deserve in future browsers. Thanks.
(“MacGyver Theme”) (audience claps) – [First Speaker] I’m not sure that there shouldn’t be a trigger warning for MacGyver.
(laughs) He did flag it was coming, I guess.