Less Cruft, More Power: Leverage the Power of the Web Platform

Una Kravets
Una Kravets

Una Kravets talk explored the newest evolution of CSS and HTML, specifically focusing on scroll animations, accessibility, and UI positioning. CSS continues to become more powerful, allowing for a clear separation of styling and content, as well as minimizing third-party dependencies. A significant portion of the talk revolved around enhancing user experience through scroll-driven animations. New techniques for creating user-responsive animations were introduced, including how to create a scroll timeline that interacts with the scrolling viewport.

To ensure a seamless user experience regardless of browser support, progressive enhancement was stressed. An example of this is to use CSS's '@supports' rule to check for feature compatibility. Una provided advanced CSS techniques for dynamic styling based on scroll position and overflow detection.

The topic then shifted to UI components, with a highlight on the Popover API. Techniques for animating popovers and compensating for lack of broad browser support were covered. This led to a discussion on positioning elements using anchors and the 'position: try' CSS property.

Finally, Una underscored the importance of attributing semantics to popovers to enhance web accessibility, including working closely with accessibility experts. The session concluded with encouragement for developers to continue exploring these new features of CSS and HTML.

Transcript

Who here loves the web?

Love that. Now, who here loves CSS? I love that, because that's more than I'm expecting. Because I always feel like CSS and HTML are the underdogs of web technologies. When you ask people, what's your favorite programming language, no one ever says CSS or HTML, except for maybe Adam over there.

So I love to be on the stage talking to, especially, full stack developers, people who are really focused on building apps, about CSS. And to get us hyped for this, I made a little trailer for this talk. Oh, let's go. Let's see. Do I have some sound here? I'm plugged in. There we go. And the masters of the universe! I am Adam. Developer.

And defender of the secrets of my code base. This is my app. My fearless friend. Fabulous secret powers were revealed to me the day I held aloft my magic CSS.

By the power of the platform! The platform! I am Adam! My app became the mighty battle. My app. And I became He-Man.

The most powerful developer in the universe.

So I think I need to work on my voiceover career, but I hope you're all hyped.

And one of those reasons is because CSS itself is getting way more powerful and much more declarative. So I'm excited to talk about this. And in my opinion, I think it's really important to learn about and to keep up with, because in today's web development environment, I think the best way to level up your developer

skill set is to take advantage of modern UI capabilities. So I hope that by the end of this talk, you feel the same. And there's so much to talk about, but really, a lot of time I get asked, like, why do I even need that? Can't I just, you know, build stuff in JavaScript?

Yes, I guess, in theory, but you get all these benefits when you learn how to leverage these web platform features. And the first is just separating your logic from your styling. Why are we constantly creating these styling components in the same place that we're creating our application logic? You know, DOM removal and addition and any user interaction from submission, that makes

sense to be in the scripting, but does it make sense to style a background in the same place? So the second is to reduce third-party dependencies. There's a lot of them out there that we just like to MPM install and use. And a lot of these features actually help to eliminate those because they provide a lot of these features natively. And then that means that you can reduce maintenance costs.

If you are building them yourself, if you have a design system, you don't have to actually continue to maintain all that code. And as the complexity grows, which means that it's, you know, the last thing is just making your life easier. That's the main thing. Another big benefit is making it easier to build accessible components with a lot of these built-in features.

So really, it's important to care about CSS and UI and all the new HTML stuff. So as I mentioned, there's lots of cover, but today I'm going to focus on three features, and those are scroll-driven animations, the popover API, and anchor positioning, because I think those have some of the biggest bang for your buck and are also on the cutting edge of, like, what's coming to the platform.

If we have time, we'll talk about styling dropdowns, like with select, but I don't think we'll have time. So we'll see. Let's start with interactions. The first is scroll-driven animations. Who's heard about this API? Okay. We've got a couple of hands here. With this, we get a lot of really cool new features that give us native browser-handled scroll animations.

So you can create things like this, which is a really cool just way to kind of scroll through a list or an option of, you know, picking a credit card. You can do stuff like this, where you have text kind of pop in or images kind of animate in. And the way to do this is pretty straightforward.

All we have to do is first set up a keyframe like we would with any CSS animation. This one's called fly-in. All we're doing is updating the transform, so it's going from negative 100 pixels to zero pixels, and the opacity from zero to one, and that's this sort of block quote right here that's animating in.

And then on the block quotes, we're just setting up this animation. And the timeline here is the big change, where we say animation timeline view. So we're looking at the scroller here as the view, or the viewport in this instance. I'm also giving this an animation range, so it's going from zero to 50% of that scroller.

Normally I would probably do like, you know, less than that, like 25% towards the bottom. But just to show this kind of animating over time, that's all the code you need. You don't have to have third-party dependencies, you don't have to write any scripts, you don't have to do any query selection. You can do this directly in CSS in a couple lines of code. And it's really ripe for progressive enhancement.

Here's another example, pretty much doing the same thing, where we're just animating opacity and scale. And you get these images that kind of nicely animate in from the bottom as a nice little progressive enhancement, where the user experience, if scroll-driven animations is not supported, would just be the images popping in as they would normally without the animation.

So I think that this is a great feature to progressively enhance. I don't think this is necessarily one you want to have a polyfill for, if you're doing something like those cases, where it's just like a nice little scrolly-telling feature. But progressive enhancement is awesome on the web. And as we heard this morning, the web doesn't break your stuff, which is also why it's so

hard sometimes working in standards, because you can't change stuff from the past. Another cool thing you can do is this effect, where you get this back-to-top button that you're animating in. And I remember using a library for this on one of my old websites. And now you no longer need to do this, you can just do this in a couple lines of code.

Another thing that you might want to check for is support of these features. So you can use as supports, and then check for animation timeline. And if the browser supports animation timeline scroll, then you can apply all these styles. And in this instance, because I'm animating display, which is now something you can do

too, you can animate from display none to display block on a timeline, I'm creating a new scroller. I'm calling this scroll timeline the root scroller on the HTML, so I'm not making a weird cyclical dependency by not including where the scroller is actually starting.

So then I'm just calling this animation timeline on the scroll timeline that I named here on HTML. And you have this button popping. It's not there. See, there's nothing to click on. It's display none, until it hits this animation range of 20% of this scroll.

And then from 20% to 30%, it appears, it fades in, and then we have this scroll back-to-top button. So there's just one more thing that you can do with anchor links, with CSS, natively now, no added scripting, which I think is pretty cool. Look, no JavaScript or TypeScript, whatever you want to use.

So another really cool, kind of fun, hacky thing you can do also with scroll-driven animations is overflow or scroll detection. Who's ever had to build one of these where you detect overflow? Yeah, because a lot of the time, if you have some kind of indicator icon or some additional styling for an overflow, you need to do this.

But a cool thing you can do is basically set a Boolean value. In this case, we're using a variable called canScroll. And then if there is a scroll, then this keyframe detectScroll will activate, because if you have an element without a scroller, you don't actually have the scroll timeline present.

So you won't get this value. So either declaring it or setting a value like one, and then you can use that value in styling. So I pulled this all from a great blog post from Brahmas Van Dam. There's the link to it. And this is one of the demos in that blog post, where it shows that you have these arrows

that appear if there's a scroller. And it's also dynamic, where this one's content editable. So I could add some content here. And then when I have enough content, the arrows appear. So this is all done without any scripting. This is all done by the use of these custom properties that we're creating.

So we're instantiating here. If there is a scroller, we're looking for the scroll timeline. And then here, we're calling these variables, where we have one value, which is the default value and then a fallback value, where if there is scroll, then this line would be valid. You'd have visible.

If there isn't, then it's an invalid line. It's ignored. It's a variable that doesn't exist yet. It's undefined. So then you wouldn't have these arrows visible. It would be hidden. So you can do a lot of these neat tricks now with some of these capabilities in CSS, which I think are cool.

And you can also do things like this, which is sort of like a scroll-a-telling experience, where you have these cards stacking and then staying in place until you're ready to exit that experience and move on to the rest of the page. Also as you scroll back, it reverses the timeline, too.

Another cool example is this kind of header UI that we see. And this can be done with just a couple lines of code, where you have your starting and your ending state, and you're applying these styles on this scroll timeline, given whatever range you want to apply them on.

So if you think this stuff is cool, definitely check out scrolldrivenanimations.style. This is a site that's full of a ton of great resources, a ton of demos, and more information about this API. But I think this is one of those features that really changes how we design for these scroll-based experiences.

So I think it's important to know about. Who knows about SDA now? Yeah, everyone should be raising their hand. We do! We know so much! Yeah, yeah. Another cool thing about this API is the performance benefits that you get from it. If you're animating properties like opacities and transforms that work off the main thread,

you actually get some nice, really clear performance benefits on scroll. So this is a demo done by one of the folks on our team, Yuriko, who works with partners, and she explored the way that you would do this right now with scroll observers and just

classic JavaScript mechanism for doing these kinds of scroll animations, which have historically been really non-performant. They've been janky, and that's why people say, don't do this kind of effect. But now, if you're doing it with the native browser features, you don't have to worry about that if you're animating the properties that work off the main thread.

And we've already seen some pretty big changes from people who have implemented these features. This is from Andy of Tokopedia, who used scroll-driven animations, and they said they were able to reduce 80% of their lines of code compared to using the conventional JavaScript scroll events that they'd used before.

And this was to create a little navigation bar that popped in from the product pages. And the average CPU usage reduced from 50% to 2% while scrolling. So whoever said CSS and HTML can't affect performance, this is huge, and there's a lot

of these features that do things like this, even in small ways. This is a big way. So definitely leverage the power of the native platform where you can. So now I want to talk about UI components, which can be a pain to implement sometimes.

Who here has had to build layered UIs, like popovers, menus? Almost everyone. And who here enjoyed it? There's one person. I don't believe you. So I'm really excited to talk about the popover API with you all, which is one of those features

that really makes it a lot easier to do a lot of these effects that you need for these layered APIs. And a really exciting thing is that next week, this is going to be stable across all browsers because Firefox 1.25 is landing on April 16th.

That's the current date that is set for that to go stable, which means that it will be in baseline, which is so exciting because this is such a key feature. And now we have popovers all over the web. No, I joke. This is everywhere. These are everywhere.

These are in menus, tooltips, select pickers, all over the web platform because it's how we interact with things on the web. So a lot of this comes just from popover. You get all of these benefits. One of them is promotion to the top layer, which is a separate layer that sits above

the rest of the page. It is a sibling to the rest of your body content for the DOM, your DOM content. So you don't have to worry about managing z-index anymore. You don't have to worry about if you have z-index 99999, will that win? Now you can promote something to the top layer where it's on a whole separate layer from

everything else. There's also light dismiss functionality, which is optional if you're doing an auto popover. You get that behavior where you can click away or outside the bounds of that popover to close it and then return focus. So you don't have to do all the click handlers and manually build all of that. There's also this default focus management.

So if you tab into a popover, the next tab stop will be within the popover and keyboard accessibility that's built in. So hitting the escape key or double toggling will close the popover and return focus. And then finally, component bindings. So you don't have to worry about ARIA live and all the different regions when you open the popover.

All of that is built into the browser. And it's all done with one single attribute. Yet literally one HTML attribute does all of this stuff that if you have tried to build

these features, you know how hard it is. And when I say one attribute, I really mean that's pretty much it. So to build a popover, you can create an element and you can give it any type of role. It could be nav, it could be div, whatever you want. Give it a popover attribute. You need to give this an ID to be able to trigger it.

So say this is my popover and then a button to open the popover with a popover target. So now we're connecting this button to the popover itself. So this is an example of just a basic popover where I can click in, I can tab in, I can double toggle this to close, I can hit escape to close too.

And all of that is built in with just this line. These lines of code. I'm telling you, it's beautiful. And if you want to have more control, you could do this manual popover. So in this case, if I click away, it doesn't close. If I hit escape, it doesn't close. But double toggling the popover will close it.

And hitting this button, which I have set a popover target action on, to hide will close it. I'm also connecting that to the popover with the popover target. So just a couple more lines of code, you could have a lot of this functionality and control with this feature set. You've probably already been using popovers too.

GitHub is using popovers in production on their homepage, in their PR review. Keith Circle is on the GitHub team. He's been heavily involved in the development of popover and bringing it to the web platform. So shout out to Keith. And what they do is they ship this polyfill. I do think this is a good use case for shipping a polyfill for unsupported browsers, which

Keith actually helped a lot to get this out too. It is the Oddbird polyfill. You can install it, import it. There's a CDN link. You can use it here. So here's more information about it if you are interested in popover with the polyfill. So to animate popovers, there are a flurry of new features, and unfortunately these aren't

as well supported yet. Oh gosh, Photoshop is updating. Who here is in Adobe? So what's really cool about this is that it lets you do effects like this where you're animating in and out. So this is kind of coming in from the bottom and out through the top, and you could have these different popovers. As I click on one, the others close.

You can see how these stack and these animations can be, at least for now, used as a progressive enhancement until we get more browser support there. So to create this, there's a couple of funky things that you've got to do. I like to break this out by the before open state, the open state, and the exit state. So for the before open state, we have this new primitive called starting style.

And because we're animating things from display none to display block or grid or whatever as they appear on the page, we have to teach the browser what it means to style it before it exists. And so that's why we have starting style. And here we're saying start with this transform at 20 pixels. So it's sort of south a little bit.

And then as it exits, it's going to be at negative 50 pixels. So it kind of it goes up. And then we're also animating this opacity. So we have the settings popover. We're styling this popover open state with the starting style of the popover open state for the before open.

Then we're styling that popover open state with the actual, like when it is open, this is the resting state. And then we're styling the default of settings popover with the exit state as it leaves to the negative 50 pixels. And this is on the element itself. So that is the default exit state before we're opening it.

And there's one more key property here called allow discrete. This is a feature that enables us to animate display and to animate previously unanimated and unanimatable discrete properties that initially would just flip on in the first frame. Now they're animating with this animation at 50%.

That's another thing to kind of turn on. You could honestly just copy and paste these animations because they can be a little complex. I think once you kind of get the hang of it, it makes sense. So anchor positioning is another really cool feature that has been close to my heart and I'm very, very excited to see land.

Have you all ever tried to build something that's anchored to another element? Especially, yeah. Yeah, I'm seeing a lot of nodding. And how fun was that? So fun. So we're going to make it actually fun because I've been playing with this API and it's really fun to use. It is mostly fully implemented in Canary right now.

And hopefully we'll be landing soon. So to create anchors, there's a couple ways to do it. The first is the implicit anchor in HTML. So similarly to how we would create popovers, you can create an anchor. So first, say the anchoring, the anchored element is the popover. So that's the thing that like the tool tip that we're anchoring to something else.

We would have this anchor property with this anchor attribute with the name of the ID of the thing that we're anchoring it to. So that's really all you have to do here. You have to give an ID to the thing that we're using as the anchor and then connect it to the thing that we're anchoring to it with its ID.

So those two things for implicit anchors. And now that means we could do things like this, where instead of appearing in the middle like a dialogue or some other non-connected element, it's actually connected to the button that we're pressing as an anchor. And then we can use the properties of that anchor to position it with absolute positioning.

So we can position it bottom right. And that's what I'm doing in this, where we have this anchor being positioned. The bottom of that popover is being positioned at the top of the anchor, at the top of the button. Plus we have a little spacer here for the arrow of one rem. And then the right of the anchor is being positioned at the right of the button.

So we can use the values of that anchor to position things in this absolutely positioned layout mechanism. So you can also have a different way to set this up, which is anchor name. Where with this button, we have this popover target equals menu, and that's going to open up this menu. And so we give that an anchor name of menu.

Now we can use position anchor in CSS, so you don't have to do this in HTML, to call that anchor name and then apply the style. So now when we're using the anchor function, we can set that up with the anchor name and then the position value that we want to pull in. So anchor name menu left, anchor name menu bottom for the positioning of this. And you can have multiple anchors.

So in this case, we have a submenu now. So if I click this open, there's a submenu where I have this submenu anchored to one of the list items in that menu. And we're just doing this again with calling the submenu, positioning it, and giving it this initial style.

But if I want to adjust this, say I want to give it some responsive design, you can do that with position try. So I love anchor. So with position try, I can set up the second position. So say that's on the bottom.

Now I'm reapplying some margin, the left and top position. And then when I resize it, it knows when it hit the edge of its viewport, and it can just shift. And so what you do there is you set up the styles, you set up the position try, and then you set the position try options, where this is the option I'm going to try if the other

stuff doesn't fit. And it feels really magical, because no script is required. You don't have to do resize observers, you don't have to do any kind of additional handlers. It's all done in the browser. So you can do stuff like this, where you have your initial position, and then you set up like position try right, and switching it position try bottom, and then your position try options.

And there's another feature called position try order, where you can actually tell the browser how you want it to order those things. So you can do most width, most height, most block size, most inline size. Those are the options. Pretty cool. And you can have multiple anchors too, so you can anchor to multiple things in the UI.

So in this case, I have first anchor on the top left, next anchor on the bottom right, and I'm calling both of them to position the top left with this first anchor, and the bottom right with the second anchor, where I'm saying anchor to. And that's totally doable, and it's responsive, it's customizable, it's dynamic, it's just

creative with a couple lines of CSS. Another cool layout, it gets cooler, my friends. Another cool layout mechanism is inset area, which lands with anchor positioning. And so this is a way to just very declaratively, explicitly say, I want my inset area position

to be bottom, or right, or top left. And if you want it to span multiple areas, you could do top span left. So you start at the top, and then you span to the left. Or if you want top span right. And this is another way to very explicitly say how you want things to be positioned. You can also use logical properties if you want.

Or if you want to use properties that are just directional, that works too. That's often the case that you want with things like menus. So this new feature just makes it so much more explicit in how you're positioning things, just a little bit easier to read. And I think it's a nice addition to anchor positioning. But it doesn't end there, my friends.

There's more. And that is these position try keywords. So you don't actually have to create all of the options and permutations yourself. You can use these keywords of flip inline, or flip block, or flip block and flip inline.

So now what we can do is have something like this, where all we're saying is we're positioning this at the bottom of that anchored element, at the top of the anchor. Then we're going to use this new keyword called anchor center, which you can use for justification and alignment. And then we're setting the position try options to flip block.

So if we resize this now, I didn't even have to specify what the second position was. The browser knows to flip this in the block direction. And you can even write this in two lines of code if you wanted to use inset area top, and then position try options flip block. And there you have a fully functioning tooltip.

We got a popover here with these fallback options for positioning. So it's really cool. We see these all over the web. Here's more of He-Man. And this will automatically just swap directions with that one keyword as I scroll. And it doesn't fit on the screen anymore. So I think that this is a very, very powerful API.

And even more powerful when you combine it with other APIs. So you can combine things like popover with anchor positioning and CSS trigonometric functions to create these cool effects. And you can use translates. If you know geometry, you can start to really think outside the box in how things animate so it's not so linear and boxy and more organic.

And we can have this exist on the web platform and kind of flutter out into these positions with some animation, not duration, where it's starting later. I forgot the word. I don't know how to speak. Delay. Animation delay. So we can have this exist in icons.

So this is like a Pinterest-inspired menu using anchoring, trigonometric functions, and popover. And this is like the web I want to see. More creative styles. Native applications have this. Why can't we have this on the web? Well, we can, my friends. One important note is that popover has no default semantic role. But you can give it semantics.

So it has a lot of built-in accessibility in terms of interaction with the browser, but not in what the actual role or meaning of that element is. So you can say it's a menu or a tooltip. If it's a dialogue element, then you should use dialogue. The dialogue will inert the rest of the page, so you can't actually interact with the rest of the page while the dialogue is open.

So that's also a nuance that you might want to have with dialogue. And then for selection, the select element, which is getting a ton of upgrades. We're making it customizable. I don't think I'll have time to talk about it too much, but come find me, and I will blabber on. Trust me. But there's also additional updates for popovers and dialogues, one of those being invoke target.

And invoke target gives you the ability to create these invokers in HTML to open those elements declaratively, like with popover, where I showed you how all you need is to create this popover target, and then you hook it up to an ID. Well with dialogue right now, it still requires JavaScript to open a modal dialogue, so you have to have a separate file and open it in a different place.

With invoke target, which is currently available in all the tech previews in Canary, in all the modern browsers, you can try this out. With invoke target, you can declaratively open it. We're making the behavior a little bit more similar, so that you choose the right semantics for the right goal.

There's also interest target, which lets you hover over things like in Wikipedia, those links, and show interest, whether it's a focus or a hover, to then open the tooltips, which is everywhere. It's in Twitter, it's in GitHub, it's Wikipedia, it's all over the web, and really hard to create in an accessible way. It's really hard to build that.

So we've been working with a lot of accessibility experts in these open source working groups and community groups to get this right. And then for popover, for anchoring, we're getting things like tethering. Oh, my slides are gone. Well, I'll keep talking. For anchoring, we're getting things like tethering to be able to style those arrows, and then

also instead of swapping positions, being able to slide something to keep it in the viewport, which is something that I've had to implement before, and it was not fun. So I think that we are almost at time anyway. Maybe they're calling me off the stage. That's what's happening. So I just want to say thank you so much for your time.

I hope that I've inspired some of you to check out these new features and to love CSS and to say that it's your favorite programming language next time you're asked, MCs. And that's all I have for you today. Thank you so much.

Related Talks