More From Amit
- Follow Amit on Twitter
- Amit's pens on CodePen
- See other presentations Amit has given
- Amit's "Pushing CSS to the Limit" workshop
- Bramus's tweet
- Style Stage
- Some Antics: Let's Build a Style Stage Theme with Stephanie Eckles!
- Amit's Newton's cradle pen
- Amit's jumping checkboxes pen
[00:00:02] Ben: Howdy, howdy, y'all. Welcome back to Some Antics. Hopefully the daylight savings time over the weekend for Americans hasn't tripped y'all up too much with the timing. But happy Tuesday! It's great to be here, great to be live with you all again. And today I am joined by Amit! Amit, how's it going?
[00:00:21] Amit: I'm fine! How are you? Thank you for having me!
[00:00:23] Ben: I'm doing great. I'm super excited to have had the chance to meet you. We've been kind of chatting in the "greem" room — "greem" room, apparently — green room before the stream and you're just, I don't know, you're a lovely person to chat with.
[00:00:38] Amit: Thank you!
[00:00:38] Ben: And I'm super, super stoked to have you on. I wanted to call out—
[00:00:43] Amit: It's great to be here as well.
[00:00:46] Ben: My pleasure. My honor, really.
We've got a question from the chat as to whether this will be available later for viewing on demand. Yes. The stream will stay up on Twitch for two weeks. Also, we're going to be uploading the video to YouTube after it's all captioned and everything. I've just put a link to that in the chat as well. But thank you so much for the question there.
Chan's complimenting me on my shirt. I actually made, like, a private bet with myself, Amit, that Michael Chan — lunchdev — was actually going to personally compliment me on my shirt specifically. I wish I were joking. And that happened within the first minute of being live. So here for it.
[00:01:25] Amit: I missed it, sorry, but it is a great shirt.
[00:01:28] Ben: Thank you, thank you. And we're being raided by Jason Lengstorf. Wow, way to go! Howdy, howdy, Boop Crew. Loved the Remix talk! It's so good to have all of y'all here. If you're unfamiliar, Some Antics is a weekly stream where I bring on guests from around the web development and web design industries to teach something in a hands-on way about building great user experiences for the web, with a focus on accessibility and core web technologies. If you're here from Jason's stream, you're in the right place. This is… we're so excited to have you.
Today, we've got Amit on. Amit, would you like to introduce yourself for folks who haven't seen you around?
[00:02:05] Amit: Well, yeah. Hi everybody. If you don't know me, my name is Amit Sheen. I'm a web developer. I specialize in CSS, specifically in animation and perspective and 3D, and maybe you've seen my work in CodePen or in Twitter or in one of the CSS-relevant newsletters.
That's me in general.
[00:05:00] Ben: Good deal! So yeah, today we're going to be diving into that. I guess, should I go ahead and start sharing your screen and you can kind of talk us through what we're going to be doing today?
Do I share my screen? Do people show my screen?
[00:05:40] Ben: There you go, yes.
[00:05:40] Amit: Yeah.
[00:05:41] Ben: Your screen is now shared.
[00:05:42] Amit: Yeah, so in his lecture, he built this very simple accordion component. We all know this accordion component. I've built even a simpler one than he built. You click on an item; it opens. You click on a different one; the second one opens. You click it again; it closes.
But again, this is the component. We have just a selected tab, with tabClicked(), we have an Accordion component. It's just an accordion
<div> with the children. And AccordionItem that has a button as a header and a paragraph as an item. And this is the markup.
So, at his lecture, at the meetup that I've been here, he asked a question. He said, "This is the behavior of the component. But if we only have one item, okay? We want this item to be always open." And the question was, "How do we know if we have only one item or more?" And it's a good question! Because this "children" comes as an array, as a data structure, we can actually check the value of the length of it. And the solution that he was aiming for is this solution, is actually using the Children API. But you see there's a lot of coding. You need to check the Children API, and if it comes in a different way, you need to check them in a different way.
But actually, before he even started, before he explained all of this, when he asked "How do we know if there's only one item or more?," I raised my hand and I said, "With CSS." And everybody started laughing. So I said, okay, I need to make people understand that they should actually stop laughing and CSS actually was the correct answer.
So I just want to show that the example that he showed here using the Children API, it will work if I delete two items right now and I have only one item. So this item will always be open. Okay? But let's get back to my example that doesn't use this "children." And all we need to do — instead of using this code, this useEffect code — all we need is just one line of CSS. Very performant, very readable, this CSS.
We'll go here to the CSS. Oh, by the way, I haven't shown you. The CSS has an "accordionItem" class with the item header inside, and the item content with the height of 0. And it has the "isOpen." So all we need to do is add right here instead, in front of the "isOpen," to add in a pseudo-class of :only-child. And then, this item will always be open. And if I have more than one item, the behavior would be as usual. And if I have more than either of them, the behavior will be as usual, and if I have one item, then it will always be open.
And do you have any questions so far? By the way, I'm not following the chat, if there are questions from the chat.
[00:09:49] Ben: There's just already some love for it. For instance, Kevin Powell says…
[00:09:53] Amit: Hey, Kevin!
[00:09:53] Ben: "Love how simple CSS can make things like that."
ActiveB1t goes, "I absolutely agree, techniques should focus on their main purpose. When they do, they help each other be more effective."
It's great. It's excellent.
So, do you have any more questions? Or we can go to the next example.
[00:12:01] Ben: Mhmm.
[00:12:01] Amit: And it's just easier. And, you know, the easiest solution is normally the better one, or the more correct one.
[00:12:09] Ben: Absolutely.
[00:12:11] Amit: So, let's see another example, and we're gonna use a different pseudo-element. This is a very simple
<dialog> element. This is the dialog. We have… wait a minute. Yep. Yeah.
This is the dialog. We have the Dialog component, we with the
<h2>, and the
<footer>. The footer has the buttons inside of it. But we're not going to talk about
<dialog>. We're just going to talk about the footer itself. Let's see, we have here the outline, just to see the footer. Just going to talk about the…
Why doesn't it work?
Yeah, just go ahead and talk about the footer itself. So, the footer is, as I said, it's dynamic and it has two buttons inside of it, because the dialog gets its props. It gets this "approvedProps" and a "cancelProps." And if you get any prop, you can render a button with the prop, with the relevant props. And as I said, it's dynamic.
So if I'll comment out one button, so I will have only one button here. And if I'll comment the other button, so obviously I will have the other button. But the question is, what happens if I comment both of them out? So now, I won't see any buttons, but I will see the component itself. Okay. If we add the outline again, we will see the component itself.
[00:13:44] Ben: Mhmm.
[00:14:11] Ben: Mmm!
[00:14:11] Amit: What if, instead of a footer, it's a menu, and it's like an array of elements that you need to run through? You don't really use it. How do you not render an element when it's empty? Easy! CSS!
We'll go back here to the CSS. And right here — this is the dialog, this is the footer. And the footer, let's just add an :empty! Sorry, :empty! And if it's empty, we can add a "display: none," for example! And right now, that's it! It's gone! And if we do have a component inside of it, if you do have a button inside of it, it's gonna render. And it doesn't matter if it originally has two, three, or 200 buttons. The second this dialog is empty — that the footer is empty — it won't render.
And I know it's not really best practice to render something to the page and then remove it from the page. It's correct. But sometimes, this…
By the way, this type of solution doesn't work 100% of the time, obviously. But when it does work, sometimes it's makes more sense to do it like that and not starting all these ifs and conditions and complicating your code.
[00:15:33] Ben: Absolutely.
[00:15:33] Amit: And by the way, it doesn't actually have to be "display: none." You can, instead of "display: none," just remove the border. Let's say "border: none." So now, you don't have a border. Or you can actually just say, "padding: 0," which will actually look kind of okay.
And again, the second I will bring one of the buttons back, all of the style is going back to the original style. And again, this is by simply using a pseudo-class.
One more example that I want to show is using a list. Okay? I'm running through the examples because I thought that people would have more questions.
[00:16:24] Ben: Y'all, if you have any questions, please go ahead and put them in the chat.
[00:16:29] Amit: Yeah! If not, I have more examples. It's okay.
"We mostly don't." Okay!
So this is just a List component. Originally, it was something else, but this is a user list. And normally in these types of components, we're going to get the list from a fetch, but here I've got the user data hardcoded. But I'm going to leave it like that. And all I'm doing is just, I'm mapping the users from the user data, and I'm mapping it to
<div>s, and this is what it is.
And what our designer wants is that this list, one item is going to be aligned to the left, and then to the right, and then they want them to alternate.
And actually, the developer that did this mission wasn't me. It was a different guy. And he obviously used here, he put the user. He actually used the index. And he just added, right here, if the index modulo 2 equals to 0, then add "left." If not, add a class of "right." And he just added two more classes, obviously. And in the CSS, he added two more classes. And I said, "No. Why do you want to add those classes? You don't need to."
So instead, we can come over here. This is the CSS, obviously. This is the user. Right here in the user, instead of adding "left" and "right" classes, we can use the :nth-child. We all know the :nth-child. But not everybody knows we can actually add "odd." So if we're going to add "odd," we can add "align-self," I think, "flex-start." And then everything's going to be to the start. And just like we added "odd," we can actually add "even." And this is going to be "flex-end." So now we have the alternating design.
And why I think this is better than using classes, because this way you… for example, let's say I want this design to be just on desktop, and if you move to smaller screens, I want it to be again in the middle. All I need to do is just add a media here. Let's say that the media is… let's say "min-width: 600px." So I just need to move those inside the media! And now, in bigger screens, I had a design, and in smaller screens, they all move back to the middle. And the change in the layout doesn't reflect any change in the markup, and that's the way it's supposed to be.
This is a great tweet by Bramus that I think that, if you don't know it, go follow him. He says, "Repeat after me: A change in layout should not require a change in markup." And it's absolutely true. And if you have a chance of leaving the markup as is and changing the layout using CSS, let CSS control the layout and don't use any markup changes if you want to change the layout.
[00:20:06] Ben: Mhmm.
[00:21:08] Ben: Can we pop a few of those open just to take a look and really, like, hit that example home for people?
[00:21:12] Amit: Yeah! Yeah, absolutely. Let's take… There's one thing I do want to show. Let's take this one, this one, and this one. And check out just the navigation, okay? So here it's in the middle. Of course, take a look at the entire site. Everything looks very different. Those three sites actually have the exact same HTML. But even look at the navbar. Here it's over here, and here it's in the middle, and here it's in the top. And you can actually look at some examples, like I think this one—
[00:21:54] Ben: Okay, I'm going to, real quickly, give a motion warning for this one. I think we're going to get some, like, Zoom choppiness, but like that one I know needs, like, a bit of a motion warning for anyone who's not great with, like, flashing animations.
[00:22:08] Amit: Yeah, sorry. Yeah, you're right. So this actually has a lot of flashing. But you can see here that the navbar is even in the right, and it's fixed in the right. Or it's actually… I think it's not fixed. It's absolute. Not absolute. Sticky. Sticky.
Yeah, so there's a lot of great examples.
[00:22:30] Ben: It's worth calling out, like, when you say the markup's the same, you don't just mean, like, oh, it's the same, like, elements and everything. Like, even down to the classes and the selectors, like, the markup is identical. The only difference, basically, is that it's pulling in a different stylesheet, right?
And I remember actually talking with Steph when it came out, and I actually asked her, "Isn't it, like, detached from real life?" I remember asking her that question. And she said, "Well, no, because you'd need to know it. You need to understand the power of CSS." And, well, yeah! This is the way to understand the power that that CSS has.
So again, sometimes using CSS is not the easiest to maintain, specifically if you're working with teams that maybe those teams involve some full-stack developers or people that don't really know all the specific things that you do with CSS.
[00:27:12] Ben: Yeah. Alright!
[00:27:14] Amit: Yep.
[00:27:14] Ben: Did you have more examples you wanted to kind of show off?
[00:27:17] Amit: Yeah, there is! There is, there is, there is. We talked about pseudo-classes, but what about pseudo-elements? Obviously! ::before and ::after! This is the most important thing, and seriously, I don't know how people don't use ::before and ::after more. I see it as the superpower of
<div>, specifically when it comes to styling, because it makes every
<div> you have like three boxes and you can add everything you have, everything you want. If you want, like, a weird border, use a pseudo-element!
Instead, let's, again, go back to CSS. Right here in the list itself, we're going to add something that we've seen before. We're going to add the :empty. But then we're going to add the ::after. And the ::after pseudo-element gets a nice little content property, and in the content we can say… let's say "No results." And yeah! So now, we can see it here and we can actually style it. We can say that the color is red, and we can say that the border is 1px solid, and let's set the background, and let's have the padding of "1em 3em" just so we can see it. I just want to show that you can actually style it any way you want.
And again, if we can come here and if we do have a result, we will see the results, and the second we don't have results… so, whoops. Yeah, the second we don't have results, it's automatically going to show us the "No results" sign.
And I know some of you actually thinking, and you are right, "I'm not going to use it because I'm not going to use content that is hardcoded inside my CSS." Obviously, you shouldn't do it, because this is really not good practice. But you can actually come here to the list itself, and you can add the text as a prop. So let's say "noRes" — "noRes" — and let's say "blah, blah, blah."
[00:31:11] Ben: And that works because you're spreading that on the underlying
<li> element, right? Like, if you scroll down to your List component?
[00:31:19] Amit: Yeah, obviously!
[00:31:19] Ben: Okay.
[00:31:19] Amit: Here I am spreading it.
[00:31:22] Ben: I was initially very surprised but, no, okay. It's because you're spreading the props on that underlying
<div>. Got it, got it.
[00:31:29] Amit: Yeah, yeah. I actually forgot to mention it. Yeah, obviously it will work only if you spread the props. But yeah, so you can actually see it if you want to. Here in the list, you can actually see that this is the noRes. You can see the attribute right here.
[00:31:53] Ben: Very cool.
[00:31:56] Amit: And by the way, this is, here in the dialog, this method of adding the content, this is the way I use it to add the buttons. You can see the buttons. have a ::before, and ::before has the attribute of the content because here it comes in the content.
And while we're here, the last thing I actually want to show is… obviously in the original component, I also have an onClick action, and I have a Button component that maps the theme into classes. Here, I didn't have the Button component — I used a native
<button> — so I actually triggered… I actually used the prop itself, the theme itself, to style the button. You can actually use a prop — again, because I'm spreading the props here, you can actually use a prop to select a specific element.
[00:33:09] Ben: Very neat.
We have a question in the chat from ActiveB1t who wants to know, "Do we know how well screenreaders handle text in CSS pseudo-element content?" Do you want to take this, or should I?
[00:33:21] Amit: I think you're much more suitable for this answer.
[00:33:27] Ben: Okay, so pseudo-elements actually are factored into what's called the "accessible name computation" for an element, the accessible name being the, like, identifier, the label, the title, name, whatever you want to call it for an element once you navigate to it with a screenreader. So pseudo-elements are supposed to be factored into that calculation. And I think — I think — that can be more reliable when you're using interactive elements like buttons, so, like, if you add a pseudo-element to a button, but I'm pretty sure it should factor into things like this as well. And I can actually put a blogpost that I've got in the chat — nice — where I actually talk about exactly that. But what you're going to want to look for, ActiveB1it, is specifically WCAG's, quote, "Accessible Name and Description Computation" formula or algorithm or something like that.
It should be factored in. Whether or not it's actually factored in I think kind of depends a lot on the individual browser and assistive technology, but I think at this point it's reasonably stable. It's not a technique I would necessarily rely on very often—
[00:34:48] Amit: I agree.
[00:34:48] Ben: —but it should work most of the time.
[00:34:53] Amit: Yeah, I agree. And this is, by the way, something that I do need to mention maybe a bit more. This type of solutions obviously doesn't work all the time. I'm not saying every time that you need to do something, do it with CSS. Again, you use your head. Find out what is the best way. I am saying this is one way that you should consider, and not cancel it out just because it's CSS.
[00:35:59] Ben: Yeah, I think I just saw, like, the :link and :any-link ones at the top. I don't think it quite clicked for me that the :link one only matched unvisited links. That's really cool. Yeah. :local-link — wow. Wow! Wait, wait! :local-link has been there the whole time?! How long has that been there?! Here I am, like, oh, I've been doing this stuff with, like, fancy attribute selectors with, like, operators, like, you know, like the caret equals for, like, starts with. Okay. Who knows?
[00:36:41] Amit: "No specification found." The support's not as good, I think.
[00:36:48] Ben: Yeah. Okay, alright.
[00:36:51] Amit: We can check…
[00:36:52] Ben: Ohhh, okay. "The link ones are not really supported," Steph says, Got it. Thank you, Steph!
[00:37:09] Amit: Yeah. But there is a lot of different pseudo-classes, so go and check them out. And obviously, I do also different types of pseudo-elements, but ::before and ::after are the pseudo-elements that most of us use. But there is a few more.
[00:37:31] Ben: Very cool! Yeah. So, pseudo-classes, pseudo-elements… those tend to be kind of, it seems like, some really powerful tools in your toolkit. Using attributes for some of these things as well is huge. Yeah!
[00:37:50] Amit: Yeah, I think that the main takeaway is that you actually, first of all, start considering CSS as a valid solution. But anyway, build a strong, semantic, structural markup because it will help you control your layout later on. And it's better for a lot of reasons, but one of it is it's going to help you control your layout. And use more ::before and ::after, because they do give you superpowers.
"Has Amit made sudoku with pseudo-elements?" Are you daring me, Alex?
[00:38:35] Ben: I think you've been dared! I think you gotta make it now.
Okay! Well, we actually have a bit of time. While we're here, do you want to show off some of the very cool things you've made to, like, push the limits of what CSS can do?
[00:38:55] Amit: Yeah! If you are talking about things I am doing, well, let's go to my CodePen. I think that's the best place to show.
So yeah, people that normally know me know me for things like this one. Yeah, this is pure CSS animations. And this is the types of things I do, and I like to, as I said, push CSS to the limit. Specifically, I actually started doing animations just as a way to test things, because instead of checking one value, you can actually test a lot of them. You can test a range of values. And when you start using animations, things start to look nice and you can start building from there. And I'm doing an animation a lot. I'm dealing with… I'm also working with canvas and with Three.js and things like that, but I'm known for the things I'm doing with CSS.
I actually have a workshop now, if you don't mind me promoting it. It's actually called "Pushing CSS to the Limit." It's a workshop I'm doing with Smashing Magazine. It's four days full of CSS animations, and movement and 3D and perspective and everything. Yeah, this is the link in the chat. Thank you. Yeah, so if you are interested in going into this world and creating — and by the way, in this workshop, I am focusing more in, like, real life. I'm trying to focus in on more real-life components like checkboxes and info cards and radio buttons and inputs and titles and headlines and textboxes and so on. But things that you can use interactions, micro-interactions with 3D. Things that you can actually use in day-to-day and not just weird, you know, card towers. Yeah!
"I'm over here…" — you DO know CSS! I just know different parts of CSS! I'm talking about Building… BuildingBedrockLayout. Yeah, I just don't know different parts of CSS. And you can learn it also. It's not very hard. It's not.
Travis. Hi, Travis.
Yeah! That's it.
[00:41:35] Ben: Okay!
[00:41:57] Ben: Totally understand how that is. I've definitely been on kind of the receiving end, on the guesting end of streams, and it's like, "Aw, man, if I had, like, all the time in the world, I would have come up with, like, two or three more demos, and I would have done this and this and this, and it just doesn't happen."
Yeah. So, chat, again, if you've got any questions, now's a great time to ask them. Otherwise, we might start wrapping up early, but I figure there's gotta be at least a question or two.
Where do you…? I guess one—
Oh yeah! I guess Travis wants to know how are you doing accessibility for something like the ping pong table? Like, what considerations do you have in mind for that?
[00:42:40] Amit: Yeah, so that's a good question. I actually… so, when I'm doing animations like the ping pong table, I'm not thinking about accessibility, because first of all, there's nothing to be accessible. It can't be really accessible, and it's just a proof of concept. It's not really an item.
But here, for example, this is a checkbox I've made. Let's make it a bit bigger. It's a regular checkbox, but when you click it, it flips. Like, it jumps.
[00:43:22] Ben: Love that.
[00:43:22] Amit: And this is 100% accessible. So it has a tab, and it has keyboard navigations, and you can check it with screenreaders. It's absolutely accessible. I've checked it a couple of times.
So when you are working with animation, 3D animations, it's definitely not a reason to give up accessibility. But when I'm creating, you know, 3D animations like the ping pong table, I don't think about accessibility because it's just not relevant. It's not what I'm supposed to show.
[00:43:57] Ben: It's not what the demo's for. Totally.
[00:43:59] Amit: Yeah, it's really not what the demo is for. But again, when I am doing buttons and info cards and things like that, I'm trying to think about accessibility and I'm trying to think about keyboard navigation and screenreaders. And by the way, here specifically, I don't have reduced motion, I don't do reduced motion, but normally you should also use reduced motion. The media query for reduced motion.
And this is, by the way, the rule of thumb. When you are working with animations, three rules of thumb. One is "don't hide content," because sometimes, you have a lot of
<div>s — like here, we have six
<div>s — so don't hide content. The second rule is "don't forget keyboard navigation." And the third, as I said, "don't use animations, use prefers-reduced-motion."
[00:44:57] Ben: Absolutely. Travis was a great question. Thank you.
Yeah! This has been excellent. And you've got some kudos in the chat, like ActiveB1t says that the examples you provided were very clear.
[00:45:09] Amit: Thank you. And by the way, if anybody wants to check out those examples or if you have questions about it, the best place to get me is on Twitter. And yeah, I like to talk about frontend so, yeah, just hit me up on Twitter and then talk about anything that's relevant or not relevant.
[00:45:35] Ben: Absolutely. And I'm going to put a link to your website in here as well.
Yeah, so I think let's go ahead and I guess start wrapping up. Amit, thank you so much for your time. This has been fantastic.
[00:45:48] Amit: Thank you!
[00:45:49] Ben: These lovely, lovely demos. Like, I just, I really want to compliment you on your demos. You've done a great job curating those—
[00:45:57] Amit: Thank you.
[00:45:58] Ben: —for us, so I want to thank you for your time. I put a link to your Twitter and your website and your CodePen all in the chat. So y'all, if you're interested in any of this kind of stuff and how Amit is using CSS to just create delightful experiences and solve problems of design, please go check those resources out, go follow Amit, and I think you should absolutely take his workshop. I think if any of the stuff that you've seen today is appealing to you, you should go check out his Smashing workup, and I'm sure you're going to learn a lot there.
Also, if you're into accessibility and core web technology streams on the regular, follow Some Antics here on Twitch. We actually have a—
[00:46:46] Amit: Follow Some Antics!
[00:46:48] Ben: Thank you! Thank you, thank you.
We actually have a stream this Thursday at 4pm Central. The tweet just went live for that a couple minutes ago. But Larry Hudson is going to be coming on to talk about document accessibility, so how do you make PDFs accessible. That is something that I have zero experience in. But he's promised that it's going to feature some Eleventy, which is a subject that, as many folks here would know, is near and dear to my heart, so I'm super, super excited for that. Let me actually get a link to that in the chat as well. There is a calendar link there, so add that to your calendar.
Additionally, next Tuesday, I will be live at 1pm Central. I'm bringing Patrick Hulce on. Patrick is the creator of the Lighthouse CI tool. He used to work for Google. He built the Lighthouse CI tool. And he'll be talking about debugging web performance, so I hope to see y'all there as well.
[00:47:43] Amit: I'm going to be there.
[00:47:45] Ben: Awesome! Looking forward to it!
And chat, stick around. I'm going to find someone to raid. I'm sure there's someone else live. Amit, again, thank you so much for your time.
[00:47:55] Amit: Thank you for having me.
[00:47:57] Ben: See y'all on Thursday! Bye, y'all!