 Welcome to this workshop on creating user adaptive interfaces. You made the right choice today in which workshop you chose, because this one is GM packed with tons of goodness. I'm glad we have extra time. I've given this workshop before and I might have diverged a little bit and embellished some areas and went over time. But guess what? We have enough time today for me to embellish as much as I want. Well, not as much as I want, but enough and I think that means you're going to get a better presentation today than I gave before. Also, I'll share a link to it at some point, but I have the other video, the one that I did at Google I.O. That's only 45 minutes instead of this one that's going to go over an hour. And it'll probably give you a whole bunch of different information because I'm not going to necessarily be reading a script. I'm going to be very much trying to describe to you how I think about building interfaces, how I think about my CSS when writing it and just what my mentality is. And you'll find that it's very user centered. I'm building very much for a wide audience. I want the audience to show up and have an experience that just feels right. They shouldn't even need to think about user settings. They should just show up. The web page should render really fast and should have all of the necessary kind of conveniences that we've come to know and love about this magic paper called a web page. Right, it delivers this content to you and it just form fits to your screen and looks beautiful and has buttons that are tappable and all sorts of good stuff, but we can do better. And that's what we're going to focus on today. So let's talk about a little bit before we begin like what we're building. We'll preview what it is like. Here's our interface here on the right I've got it's a settings page. And so this is a form. There's a form wrapping both of these little content sections here. And the goal here is someone's going to be coming to your application, coming to your setting settings page and setting settings inside your app. And that settings page is going to be reading a bunch of user preference settings that are coming from the operating system that the browser is passing down to us for us to hook into in our CSS. And we get to adapt our page to this particular user. It's really exciting stuff. It's a growing area. And let's just dig into what I mean by user adaptive. We talked about it a little bit, but users these days have indicated many preferences on, you know, and whether that's like their operating system or whatever. So they want the operating system and the apps to look and feel like theirs. User adaptive interfaces are those which are ready to use these preferences to enhance the user experience, to make it feel more at home, to make it feel like it's theirs. Like really, that's truly what we're doing, because if it's done correctly, a user may never know that the page has adapted that I think is the secret here because you can make a user adaptive interface, but someone might have to choose it in your UI. Maybe you show a light and a dark theme in your interface, which is still a good idea. But those are things that they had to explicitly choose per your page. We're focused mostly today on the ones that come through transparently. Like imagine you got into a car and it just adjust. Well, I mean, they do sometimes adjust the seats for you. But what if it adjusted the font size of the dashboard? What if the music was tuned to your volume? All these sort of things because your presence was in there. And if someone else gets in the same car, they get a different customized experience. And we want that to happen without asking. We want these things just to feed right into there. And if you want, you can later add additional ways for someone to toggle these. But this is what we're headed towards now. It should feel at home right away. So what are some of our user preferences that we have to choose from here? Device Hardware Choice is a preference that users have made. Their operating system is a choice. Their apps and their operating system colors are preferences. Their app and operating system document languages and preferences. You can come from a different country. And the way that you want to read is a different direction than here in the Americas. And the amount of preferences that are present is only seeming to grow. So we're going to tackle a lot of these today and show how CSS can help you wrangle these. A web page is not able to access everything about a user's preferences. And that's for good reason. You can follow that link, but they're essentially fingerprinting vectors where someone can start to track users based on all these preferences. So here's a few examples of things that you can use from your CSS today. You're probably super familiar with this one right here. Device View Port Size. And the Device View Port Size would be the size of the actual screen that's being used. So a physical screen, whether it's a big monitor or their phone, these are physical devices and you can query them with CSS to adapt your layout to fit that screen better. You have device orientation. So you can know if something is in landscape or portrait. This becomes really critical for doing adjustments in your layout. We'll do one today. Font Size. Right. So in case you haven't adjusted yours, there are multiple places on your phone to adjust your font size. I got fly. Well, again, maybe multiple places to adjust your font size. You have your operating system where you can adjust your font size. Maybe your parents have done that. They go into their phone and they bump up the font size. So all the text messages and everything that they get are a little bit larger for them to read, or maybe you've gone into your operating system and adjusted the font size preferences in the settings of your browser. Did I say operating system? I meant browser this time so you can go to your browser and set settings. You can also adjust the font settings on a per page basis with command plus and command minus. All of these are ways for the user to have already brought a font size preference to the page. And you really shouldn't care that much. You want the user to read your stuff. So why don't you make it available to adapt to their preferences? And one of the things that we'll talk about there is relative units and building upon the font size that the user has brought to the table. So instead of setting a font size for the whole page, we're going to build up from whatever it is their base reading preferences, right? Cool. OK, there's more to go. We have online and offline capabilities. You can check to see if someone's online or offline network quality. They are, you know, a high speed internet or they are low speed internet. You can adjust the amount of images you serve them and stuff like that. Color scheme, light and dark. So in their operating system, have they said that they want light or dark and their preferences can play right into your page? We're definitely going to work on that one today. Interface animations. So this is the concept of reduced or not. Some people get very queasy from too much animation and it's usually animation that's out of their control. So today when we do any of our animations, we're going to focus on doing color crossfades and opacity crossfades because those won't cause motion sickness. And they're also generally secluded to smaller areas. And we're going to be mindful of anything that does have motion and we're going to reduce it just to media query with input quality. So you can know someone's coming from a, you know, a really course. They call it course because it's not very fine, like a mouse is very fine and it has a really high precision rate in your finger. I don't know about yours, but mine are pretty big and clunky. And you can query for that to see if someone even has a fine pointer or a course pointer and you can adjust the hit area of something like, for example, a checkbox. So we're going to do that today. We're going to adjust checkboxes to be larger for users that are not using a mouse. If they have a course input device, we'll give them a larger tap area so that their, you know, humongous fingers can get in there nice and good. We're also going to make sure that this is using logical properties so that we can obey someone's document direction and writing mode. I'm sure you've seen Manga or other different publications where the document is a different direction than left to right and top to bottom, which is what we have in Latin or English. How can we make our page just automatically whatever the user's preference is for document direction or writing mode? We'll show you that. And then this last one here is display mode. So someone's launching it from a PWA app on their home screen where they kind of get more viewport into the device. You've got standalone and minimal UI. So these are ways for you to query how this page is being displayed. Are we just in a browser tab or are we kind of launched in a full screen experience and you can adjust your layout based upon that? Here's some things that you can't do, but they're coming soon, which is reduced data or light mode. So on your operating system, maybe on your desktop or your mobile, you can go say that I would prefer less data, less network traffic to be used. You can also do this in your browser. And maybe your browser of choice does this for you by default, where there's a light mode and it does its best to reduce the amount of requests that are being sent to your phones. So if you're paying per megabyte, that you don't have to pay as much money. And soon we have a media query that'll let you tap into that to know if they want it reduced or not, and you could serve less images. Color range, every device these days tends to be an HD device and it has tons and tons and tons of colors. And we need a way to know if the device that this is being viewed on has that capability. And if it has all those colors, we're going to tap into that and show colors that are in that more vibrant range or maybe in a darker range. Some screens have lots more rich black colors to choose from, right, like an OLED screen. OK, and we've got contrast coming. I think this one's actually out or it's very nearly out. And this is in the operating system. You can specify that you need high contrast or you need reduced contrast or something and you can go specify what's your preference in terms of contrast and reading. Some people like light contrast, especially at nighttime when they're not trying to see, you know, vibrating text on a background. So anyway, we can tap into that and then transparency, whether or not transparency is kind of ruining things for people's vision. They can go specify that in the operating system. They don't like it. And in our apps, we could go reduce our transparency. Pretty cool stuff. So media queries are pretty much what unlocks all this. CSS and the web enable adaptation and responsiveness through these media queries. A declarative condition that contains a set of styles is that if that condition is true. So the most common being a condition on viewports has the device if the size is less than 800 pixels, like the device has less than 800 pixels. Then let's supply some better styles for that particular use case. So user adaptive, again, let's just kind of like recap what this is. Like an let's talk about what an unadaptive interface is, is one that changes nothing when a user visits it. It is essentially delivering one experience to everyone with no ability to adjust it anywhere from the operating system or any buttons that are in the page. A user adaptive interface could have five different appearances and styles for five different users. The functionality is the exact same, but the aesthetics are perceived better and the usability interface is easier for users who can adjust to the UI. Right. It's adjusted for them. Their preferences that they clearly articulated are just there on the page. And at that point, they think about less. And when they have to think about less, they're going to focus on the task that they're there for more. So today, what we're going to build is we're going to build a user adaptive form that adapts to the following different criteria. The system color scheme, that's the preference by offering a light and dark color scheme for users and the surrounding UI elements. So this whole page, so here look, we can even toggle it right here in DevTools. Here's the dark theme. We have some nice dark colors. Everything is still within the sort of brand blue that's in this page. And then we have the light theme. And we're going to do that all with custom properties and we'll build that from the ground up today. The system motion preferences by offering multiple types of animation. As I tab through here with my keyboard. You can see that there's a grow here. There's a color transition here. The color on the background of this whole element here is all is a lighter to show that there's a focus here. And we see a focus ring around the interactive element. And we'll talk about how we get those things and how we're going to reduce motion. So here, if I go to emulate reduced motion, I can emulate reduced and see as I tab through, we no longer grow this animation. It just instantly becomes larger and we are still cross fading the colors, though, so kind of interesting. Yeah, I love how the background fades in and out with these different sections. Anyway, very cool. We're going to look at small and large device viewports to offer mobile and desktop experiences. Specifically, we're going to go into landscape on mobile and ensure that we see both of these sections side by side. Right. If I'm going to swap this landscape, I should see this type of landscape layout here, whereas if I didn't write the media query, it would be a single column. And on a mobile device on landscape, I'm like, why you get why is it single column? I just thought I would get to. So anyway, we're going to go make sure that that's in there. We're going to accept various input types like keyboard, screen reader, touch and mouse. And we'll talk about how we adapt to these different methods of input that people want to they need to make choices and cause a change in the UI. How do we make sure that we're adapting to all these different user types and we want to make sure that any language and reading mode works great? We should be able to come into the elements panel here. At the very top, we can change the direction to right to left and look at most of it. Oh, looks like we have a little bit of a padding issue here. Maybe we'll debug that today. I'm interested to see what that regression was. Probably a lack of a like a logical property. We have a bug me where we're going to get to solve. OK, cool. So those are what we're working towards today. And this is essentially what it starts like. As you can see, this whole stark image here, here is what we start with. So in terms of like saving time, I've provided the HTML today. The HTML will come with various things and we'll talk about some of it as we go. But this is the default styles. We have only a little bit of CSS here to make sure our SVG aren't looking humongous. I could have put some inline sizes on them there, but I decided to put that style here. And we're going to build this up from this skeleton. So we have a strong foundation of a form that is already usable as it is. You could submit this to the server and you could use JavaScript to see what all these values are. It's a usable form as it is. It's just not adapting and it looks kind of crusty. So we're going to fix all that. Things that we're going to learn, we're going to learn. Let's see how to make light and dark things, light and dark themes. You'll all show you my strategy for doing that with custom properties. We're going to build animated and accessible forms, which we've already looked at. We're going to lay out responsive forms. There's lots of cool layout stuff coming. And we're going to use relative units and logical properties. And I think we're going to solve a bug, too. I'm really interested. I'm glad we have some extra time. I'm curious at what is there. OK, let's see. This Codel Lab is focused on user adaptive interfaces, non-relevant concepts and code blocks are glossed over. Yeah, I just talked about that, like the HTML. It's not an HTML lesson today. We're going to be focusing on the CSS and we have plenty to talk about and just the CSS alone. So let's go to the next section, getting set up. Hopefully everybody can see these pages. And if they want to, they can follow along. It'll give you this link to this code pen. So here, I'll just copy this link and paste it in the chat for anybody who doesn't have this open or doesn't want to. So everything you need is also in the GitHub repository here. So you can go here and fork or just clone the repository and build it and work locally, if you like, if you don't want to work online with code pen. And I think the code pen path is really easy today. So we're going to work on that one. And I'm going to go ahead and fork this right now. Excellent. Let's see, this is going to be CSS 2021 workshop. Yeah, yeah. Okay, and if you don't have an account, create one to save the work, click fork. Okay, you can also work locally. So we'll skip through here. If you want to run the project, there's some install steps there. It's not that big a deal. You don't have to use Node, but Node is how the project was built by default. It uses the build tool called Veet, which I'm a really big fan of. Very unobtrusive, very minimal, very fast and pretty much just lets you write whatever you want. It has, it has very, I don't know, it's just very unopinionated, which I like. Okay, so about the HTML, this lesson covers aspects of the HTML, used to support user adaptive interactivity. So this workshop has a specific focus on CSS. And when we're ready to start, let's just, let's get started in here. We're ready to begin our first set of CSS. All right, so in this section, adaptive interactions, we're going to have, by the end of it, we're going to have game pad and keyboard support. We're going to have mouse and touch support and we're going to have screen reader or similar assistive technology support. I like to start here. The HTML is very foundational and it's the way that you can reach into assistive technology screen readers and keyboard is just having strong structural markup that represents the goal of your interface really well. So some attributes for the HTML, the HTML provided in the source is a great starting point because semantic elements help group, order and label your form inputs. We look over here, we've got a form element with a section inside. There's going to be two sections. There's a header for each one of those sections. And then the field set element is the thing that's got the border around it that's wrapping each of these sections. Each of the field sets is going to have a field set item class with a picture that's got an icon, another little stack, a grid stack that we'll see here in a second, a label and an input. And we'll talk about some of those things and why they were put that way. So forms are a key interaction for a point of business. It's important that the form can adapt to many types of input the web can facilitate. For example, it's likely, or it's likely important to have a form that's usable on mobile with touch, right? This is usually kind of 101 right now that you need to have that. And in this section before layout and style, we're going to ensure that we have adaptive input so that, yeah, your finger or your mouse both get a great treatment on this design. So grouping inputs, the field set element in the HTML is for grouping similar inputs and controls together. In your form, we have two groups, one for volume and one for notifications. This is important to the user experience so whole sections can be skipped. Ordering elements, the order of the elements is provided in a logical order. You can see here, if I just click in here, so right now it's in a single column. I can click into our thing and tab through and see our tab experience. So it tabs through logically. This is how we'd expect to tab through and we'll talk about that more later. Users of the web have become accustomed to moving through their forms with their tab key. I think it's critical, sometimes way faster than even using mouse. Which fortunately, the browser takes care of most of this for us. So using elements like button, input, H2N label automatically become keyboard or screen reader destinations, right? I can tab into this over here and hit left and right and toggle these values without any JavaScript and I can do it multiple ways from multiple different device types and the browser is just gonna do that for us some of the freebies we get. So the above video demonstrates how that tab key and arrows move through it just showed that in person. But the blue outline, okay, as I tab into it, look it's like shrink wrapped on there. It's very tight around the input elements. So let's add the following styles to make the interaction have some breathing room. So we're gonna start with a focus style on our inputs and go ahead and just pop that right in the bottom of our CSS. Now as I tab through, look, we have some space. Space is one of those weird things that when you add it, it just sort of gives things a little bit, it just goes a long way having a lot of good space. Things that look shrink wrapped off and feel cramped and they just, they're not as inviting as something that has space. So things to try, in case we're in here, we already did tab and shift tab, we moved around, we changed some of the values where I can tab down here into these check marks which are also inputs. So notice they have additional space and I can hit space bar to toggle those. And if we had a Bluetooth gamepad, you could move through the form as well and hit just A on your controller or on your switch and watch these values go up and down. Super fun. Okay, let's do something for the mouse interaction. Users of the web have become accustomed to interacting with the forms with their mouse. I mean, yeah, mouses are pretty popular. Try using your mouse on the form, sliders and checkboxes work, but we can do better. Those checkboxes are pretty small, even for a mouse. Those are tiny. So let's enhance the way that this works. So how you get to, let's see, see how you get to user experience, can it connect labels and inputs? Yes, let's talk about labels and inputs. So right now, if we didn't have a label that had this attribute for here, you can see this is for media volume. And then we have an input down here that's named media volume. This is important because without those, notice how the default layout here is a block level layout and our checkbox is above the label. And then there's even some messaging text. It honestly looks like this checkbox belongs to get notified, but that's not the case. By using a label and connecting them through the HTML, I can now click on the label itself to toggle the checkbox value. And when I hover over the label, I don't know if you can see it in here. But when I hover over the label, let me zoom out a little bit, you can see the color of it change. And that's because the browser is signaling to the user that this is an interactive label with that checkbox. So we're connecting them together for screen readers and we're connecting them together for mouse users as well so that they know which label and which checkbox have a relationship there. It's an explicit connection that improves the user experience for screen readers and pretty much everyone, right? So here's an example of no association and then an example of having the association. Some 101 form creation right there, but those are some of the user experience benefits we get from that. So I already put those inside the HTML. Let's talk about screen reader interaction. So assistive technology can interact with this form and with a few HTML attributes can make the user experience even smoother. So notice here in this video, as I tabbed through with a screen reader, it's stopping on things that aren't important for someone who can't see like the icon. They don't need to know the icon. They just need to know the label call volume and the input slider itself. Maybe they even need to just go through the sliders and the sliders can tell a label to the screen reader. So for users navigating the current form with the screen reader in Chrome, which by the way is Command F5 is a really great way to invoke your screen reader on Mac. We have an unnecessary stop at the picture element, but we can fix that by adding Aria hidden true to the picture. So if we scroll in here, we can see that the Aria hidden true is already present. And as I tab through, it's skipping those icons now. And that's just nice. You're helping screen reader users not have unnecessary stops with just a little bit of HTML to add into there. And we can see here now, it's also different. Using tab on your keyboard is not the same thing as using a screen reader. Screen readers will stop on more items than the tab key will. And you can see that here where the label and the input are both getting stopped on in this video. And so it's a good idea here, down here in things to try to try figuring out what screen reader is built into your operating system. Give it a try. I think you'll find a lot of interesting things and a lot of interesting powers it has. Like it can jump all over the page whereas like the tab key can only really go linearly like down or up. The screen reader technology can jump right to various sections and pros of it can really navigate around or decide really well. Okay, let's go to the next section where we get to start doing some layouts since most of those HTML attributes and things were already done for us other than this outline offset that we put in here. Also outline offset can be animated and there's like a really cool snippet that we could add maybe later that will animate that on focus. So on focus it kind of grows to the space that we want it there. And we'll see if we get there. Okay, adaptive layouts. Oh, by the way, if there's any questions like I see, I think one that's popping up right here, there's a triangle square in circle in the very bottom right of this Google Meet that we have here. And there's something called activities and something called Q and A. If you have a question, I'd love for you to put it there and we'll go through these at the end when there's extra time and try to burn through as many of these questions and answers as we can. So try to funnel your questions into the Q and A section of the activities of Google Meet. All right, in the adaptive layout section by the end we're gonna have created a spacing system with custom properties and relative units. We're gonna write CSS grid for flexible responsive alignment and spacing. We're gonna use logical properties for internationally adaptive layouts. That's just so much fun to say. And we're gonna write meta queries to adapt between compact and spacious layouts. Yes. So we're gonna turn that crusty little form over here that does no responding really other than it's liquid. And we're gonna turn it into what we see here in the middle on the left where it's still bones but you can tell that by having a layout and write spacing it gets you a lot of the way into getting this done. All right, let's kick this off. A nice key to a nice layout is a limited palette of spacing options. This helps content find natural alignments and harmonies. Well, it's probably opinionated on my part but I do think that a less is more mentality does help you here. So custom properties, this workshop builds upon a set of seven custom property sizes. Let's just put these right into style.css. I'm gonna grab this root tag, go to the top of my style section, hit paste. I'm actually gonna bring this up because we're gonna spend a lot more time in the css section. Okay, and you look at the names, we have like extra, extra small, extra small, small and look at the relative units. We have 0.25 rem, 0.5 rem, one rem, one and a half rem, two rem, three rem, six rem. And that's the sort of ramp up of spacing that I created in here. And I like this naming for these custom properties. These are global custom properties because I think this is verbiage that you might find in your day to day with someone. Someone might say, hey, will you make that spacing extra large? And you can say, why yes? And that's literally the name of the custom property because I've aligned it with the way that we talk about it. And that's just kind of nice. And then I also use rem units for exclusively legible whole unit sizing that adapts and is mindful of a user's preference. So if you haven't studied rems yet and why they're relative to user's preferences, there's a link here for you to check out. But the, I like the whole unit side of sizing here too. Like notice how we have one, two, three and six. We have a quarter rem, a half rem and one and a half rem. There's not a whole lot of like 0.875s or kind of awkward to think about sizing or like 14 pixels versus 18 and stuff like that. I really like thinking about like one rem. I also find that one rem is something that I use a lot. And it's just like generic spacing, one rem. It's a healthy amount of space between the two items. And one rem also, I'll just briefly go into how this is a user preferences. When the user can change their operating system font size or they change the font size in their browser or if they zoom, the rem unit is gonna be respectful to that size that comes in. So one rem will equal the base font size of their preference and you can build up from there. And I find that it's really healthy to think about that way. So these extra small and extra, extra small, these are underneath that particular user's preference size. But we're not gonna set font sizes to anything like this. Like I like to set my base font size at one rem and we'll probably get there too. But then it's setting the stage for I'm respecting user's preferences and I'll build up from there. Let's do some page styles. So next you need to set some document styles, remove margins from elements and set the font size to a nice sans-serif. All right, so we'll add the following CSS. You could kind of think of this CSS as a reset and you're not wrong, but it's a pretty minimal reset. There are a much stronger resets that you can go use. And since I'm starting from scratch, this is okay for me to use. Maybe it's not okay for you to zero out all the margins of every elements, but look at how we squeezed everything down. And that's because we're gonna be using CSS Grid and Gap today to space out our elements. And so we take out all the margins so that we can exclusively work with Gap. I find Gap to be just a delight as well as CSS Grid. And we'll get into how CSS Grid is also the only layout tool that we're gonna use today. I love Flexbox. I got nothing against Flexbox, but Grid stole the show in this particular layout. So we'll get there. Okay, so this is our first use of some of the space in custom properties. This begins our space journey. Play on words, cheesy, okay. And let's talk about some of the logic properties in here. So box sizing, border box and margin zero. Hopefully you're familiar with why it's nice to set box sizing to border box by default. The default is content box. And I think most people expect the border box to be contributing to the size of the element. So anyway, we're gonna treat it that way today. Now this is interesting. HTML block size 100%. The page by default is only as tall as the content. And there's two parent elements before you even get to that size of the content. You have the HTML and then underneath that, you have the body. The HTML and the body both have a size, but they're sized on the content. Like I said, we want, I think most people expect, the page that you load to at least be the height of the viewport. So by setting HTML block size 100% and block size is equivalent to height in most scenarios here in logical properties. We'll get into more logical property definition in a second. We're telling the HTML document explicitly, notice it's not min height or max height, we're saying height 100%. HTML, you need to be the size of the viewport. Then critically, the body element here says min block size 100%. So that way the body can grow beyond the viewport, become scrollable inside of that 100% space. So if you've ever used 100 VH, you're probably going for a result similar to something like this, where you want it to fit the viewport, but there's some side effects for the 100% or 100 VH and that's a whole other story. That's why we're getting 100 DVH, 100 SVH. We're getting new viewport height units to account for the fluctuation that 100 VH is not always 100 VH of what you think it is. So anyway, by using HTML as block size 100% and body as min block size 100%, you set yourself up for a full viewport experience that doesn't have to any of the side effects of VH units. So this is kind of a hot tip if you're building something that needs to be the full viewport height. And this comes in critical for our layout because we're eventually going to center these. Let's see, where's our demo? We're eventually going to center this in the page and we want to have that height set there. So then we have padding blocks start and padding block end. We could have used the shorthand here, but this is saying padding block top essentially and padding block end. So for Latin, these are both going to be in an English language that's like, okay, so like your paragraphs stack on top of each other, right? You can make it paragraphs like blocks. You could think of text like your handwriting as inline. The letters go left or right, but the paragraphs stack on top of each other. These are blocks and inline. And the block start is going to be the top of the block and the block end is the bottom. So essentially we're padding the body on the top and the bottom. With our var space extra small and it doesn't really do much here yet, but on mobile it became really important that you had some space on the top and the bottom. Okay, that was a pretty long explanation for our first little snippet, but hopefully you're like, whoa, this has already got stuff in it that I wasn't expecting. It's going to keep coming in. So be excited. All right, let's do some typography. So the font for this layout is adaptive. The font for this layout is adapted. The system UI keyword will use whatever the user's operating system has decided is the optimal interface font, right? Okay, so here we go. Let's just drop it in. Boom, drop in a few of these. Okay, well it looks like body. I'm just going to go ahead and throw body up in here. Not required if you're following along. I'm going to anyway just for cleanliness. Okay, so font family system UI and then I have a fallback of sans serif. System UI is kind of new-ish. It's not that new, but if you want you can provide a fallback of sans serif which will probably be like Helvetica. It just depends on what the operating system is. So notice I'm not setting. So this is our body font. This is like our text font. Just we want it to be legible. I always like making my web pages look as much like a native app as possible since that's where most people are spending a lot of their time outside of the browser. And so when they visit the browser and they visit my experience, if I'm using system UI, if they're on Linux, they're going to pull in the system Linux font. And that means my web page will look just like an app looks. If you're on macOS, you get their gorgeous San Francisco font which is a variable font and it has all these really amazing superpowers. So you're basically tapping into a font that the operating system has spent hours and days and designers have just completely perfected that font for the operating system. And you just get to use it. You just get to say system UI. And boom, you have a font that's optimized for every single language that that operating system can serve. And you know that you get all the weights without downloading extra weights and the list goes on, why it's awesome. So for my body text, my paragraphs and other things like that, I like to keep them as legible and normal as possible. And like unexciting, I guess. And so I use the system UI keyword count. Your headers and other things, those are places for using a decorative font or something like that. And it's a lot more fun. So anyway, that's what I'm doing with system UI here. The H1, H2, H3, I'm leaving them the default font size, but I'm changing the font weight to somewhere in the middle ground. They're a little too bold. Here, we can even comment it out to see what it looks like. Yeah, it's a little too bold. It's not that big of a change. And then we have a small here that says line height 1.5. And this is the small here. I think this is a small here. And I set the line height to 1.5 because it was a little too squishy before. And I wanted to give it some space. Oh, look, I even say that right here. It's otherwise too bunched up. I said squishy today, but I said bunched up earlier. Same thing. All right, logical properties. Let's get into these. Good, because I've introduced them a couple times and it's time to kind of break them down for anyone who's not familiar with logical properties. So notice the padding on bodies using logical properties, block start and block end to specify the side of the box, okay? Logical properties are all about specifying the size or the side of the box. Logical properties will be used extensively throughout the rest of the code lab. They too, like a REM unit, adapt to a user. So we'll get, okay, yeah. This layout can be translated into another language and set to a natural writing mode to document directions to the users accustomed to their native language. Logical properties unlock support for this with only one definition of space, direction and alignment. One definition to rule them all as opposed to managing margin left and left to right languages and then swapping all of the margin left to margin right and a right to left language. That can be a lot of work managing that where you could have just said margin inline start and then you don't care. You, in Latin, it was the same thing as left for you and it could be in any of the language at any other time and you're gonna have proper spacing. So if you're building a button with an icon, think about these things or a gap, but we'll get into that. Okay, so anyway, here's a good example. Latin here is shown blocks going top to bottom and inline going left to right. We have Hebrew here showing blocks going top to bottom, but inline going right to left and Japanese going, let's see, it's top to bottom, right to left. And it's, yeah, we see our blocks are going from this way and our inline is traveling a downward direction. And all of this you get for, you'll have proper spacing if you're using logical properties. And I like to think about them too like in a stage or on the mountain. So like I'm a snowboarder skier and when we're looking up the mountain and we're talking about our run and how we wanna travel down it, it can be really confusing because when we're looking up the mountain and we say left, it means something different than when we're looking down the mountain and we say left. So what we do is we say skier's left or skier's right. And that way the person kind of takes their physical body out of the equation of the measurement and actually imagines themself at the top of the mountain looking down. And that's what skier's left means is you're always putting yourself positioned at the top of mountain looking down and then skier's left. Another thought process that's similar to this is like you have starboard and port on a boat. These are sides of the boat that aren't about where you're standing right now because the left side of the boat is different if you're in the back of the boat looking forward if you're in the front of the boat looking backward left is different. So by saying starboard and port you're literally taking your own personal physical space out of the way that you would talk about the side of the boat. You talk about the side of the boat that's logical that everyone on the boat no matter where they're standing can understand which side of the boat you're on. So hopefully you're like, okay, that's fine. And maybe you want that and hopefully it sounds desirable. It's a small switch and it sounds like you'll see a lot of new words in here like inline and block and trust me with just a little bit of practice you can easily get your way out of margin left and margin right and into margin inline start and margin inline and start to build your experiences that reach a wider audience without having to think about more. You literally will spend a little bit of time up front right now learning logical properties and reach more users with less CSS. So the results are very exciting. It does take a little bit of learning. So hopefully this is a good primer into why that's important. All right, CSS grid layouts. The grid CSS property is a powerful layout tool with many features for tackling complex tasks. You'll be building a few simple grid layouts and one complex layout. You'll also be working from the outside in from a macro to micro layouts. Your spacing custom properties will become critical as not just for padding or margin but for column sizes, border radius is a radii. That's just fun to say and more. So here's a screenshot of Chrome DevTools overlaying each CSS grid at one time, right? Here we go. Let's go turn that on. So you can pop into your open your DevTools and pull up our demo site. And you can start turning on these grid badges. So you can see that they're labeled here. Here, here, here. You can see everywhere where there's a CSS grid and you can just go turn these things on. Boop, boop, boop. You can go turn them all on. Boop, boop, boop, boop. Now you can see how all the spacing is working across the whole thing. You can see the gap and you can see the container that's inside of them. And it helps you figure out like what is the spacing and how is the spacing work inside of here? And we'll probably use those to debug our issue that we saw earlier. And you can also find these things in the layout tab right here. So if you go to the layout tab and scroll down, you'll see every single grid that's on the page. You can go to the grid nice and quick. You can change the color of the grid. So notice someone's like a salmon. And I'm like, no, no salmon, hot pink, right? Bam, you can change it. And that's really nice for making a picture or just understanding the different ones. So you can change the color. Oh, look, I made it hot pink in that picture too. I would, I would make it hot pink. I'm a big fan. Okay, so that's a little bit about layout overlay tools and stuff like that. I think those are really fun and interesting. And let's start with our first grid layout. So this is for main. So main, if we look at our HTML is wrapping everything. I'll pop that right underneath. I'll just go to the bottom here. Our main. So our main has display grid, a gap of space XL. So you can see the XL spaces right here. Cause really that's the only, we have one, we have two children in here. We have the form and we have an H1 as children of main. And then we're placing content center, which we could have a whole episode on just what placing content versus placing items is, but it's trying to put things into the center as a group. And then we have some padding spacing small, spacing small is remember one REM. So we're going to see that one a lot in here. Okay, let's move on to our more complex layout. This is our form layout. Cause if we look right now, we're still not responsive. And we want to, we want to get there. Let's talk about this layout here. And notice how it is now responsive. So what happened? First off, the form needs to be explicit about its maximum growth size. This is not a normal CSS property that you need to put on a layout, but in this particular one, we had to tell the grid that it's okay to grow up to this size. Like if I comment this out, essentially it won't go into the two column layout anymore because it's a little too eager to wrap. And by giving it a max width, did I say width? There's a width in here. Max inline size, logical properties, they still slip into like the old verbiage. I've been, we're a width and left for over 10 years. You notice anyway, I'm still working my way out of it. So max inline size. Now we have the availability. We've told the grid layout algorithm that it's okay to grow up to this size. You thought that that would be the default, but it's not. It's a weird critical thing in it. And it's critical in this particular layout because of this that we've done down here. Repeat, auto fit, min, max, min. And we'll break this down in just a second. So we've got gaps in here. This is a row gap and this one is a column gap. So we've cut them just slightly different so that when we go into this view, there's more space here. And when we go into this view, there's a little less in that one. We're aligning items to flex start. So check this out. Here, let's go to display. I'm gonna pop this open in debug mode so that we can go look at our current version in debug, pop open the dev tools. And I wanna look at some of our spacing. So there's that spacing. Here's our grid and we'll grow like this. Okay, first off, well, look, we can actually even go into here and show some of this stuff. Here's our flex start. Is it showing it to us here? I don't see the little arrows. I see our gap. So if you hover over the gap, you can see the gap. I can see that we have the grid icons, but flex start should be showing some little arrows. Essentially what flex start is doing with the align items is notice how the bottoms here aren't the same. If I got rid of that property, it stretches them to fit. It should stretch them to fit. Once that was my understanding of what was happening because our form has two sections and our whole goal of setting them to align items is cause stretches to default and we wanted their intrinsic size to come through. Maybe we'll see that more in a second. But that was the goal of that is we wanted to allow each of these to be their own size instead of being stretched to the same size. It just made more sense that each of these sections could bring their own height to the table based on their content. Okay, let's go to the definition here of repeat auto fit min max min. So the way that you can get wrapping with a CSS grid is you have to give it an algorithm that it's called like a placement algorithm where it's gonna try to place new columns until it hits the edge and then it'll replace another one. And with repeat, this is how you kind of tap into that as you're repeating an algorithmic concept, we're going to repeat auto fit. So that's how it's trying to auto fit these items into there. We're gonna say, here's a min and a max range for you to specify for each of these items when you're placing them a CSS layout grid. We want to minimally have it be at least 10 characters wide, but have it go up to 100%. And that's because look, it can go up to 100% here, right? We're talking about these sections, but we don't want it to go below 10 characters. We want it to have at least a column of text that can be read. And so we've set a minimum, but we've also a set of minimum that allows it to grow. And then a maximum here of 35 characters. And that's what's locking it at this size here. That's a size of 35 characters. And I thought 35 characters was really nice for reading things like this, like these notifications. Having them at 35 characters starts the text wrapping at about a spot where I thought legibility was right. So setting a max inline size to something with characters or setting your columns to characters is really great for text content because you're essentially articulating a width that's based on reading. And so right, you want a human to be able to read it. We know that like paragraphs are optimally between 60 and 75 characters wide. And so we can make our little smaller sections be half of that and just have a nice reading length so that they're not going too long. And so that's how we clamped our sizes here is we passed this min max function which allows a column to be flexible, but we also tap into the auto fit capabilities and we repeat that. So as many children that show up in this grid will attempt to be placed this way. And since we give it the max inline size of something large, it says, ah, I've reached a large space that's okay for me to grow to. I'll go ahead and wrap these items into two. Cool, that was our most complex layout that we have here. And it looks like there's a lot of notes in here that you could go read about also in case you want to review how that particular layout function worked. This is a very common layout for me to do. I never remember how it's written. So if you're like looking at this going, can he write that without looking? The answer is no. I'll get really close because I think about it like RAM here, me and Yuna, because you have repeat auto fit min max. RAM, anyway, that's one of the ways we try to remember it. Maybe that'll help you. Okay, let's move on to the section layout here. We have display grid with a gap. Oh, this is a classic one for me. So often I'll employ grid just to get a gap because margin is a lot less easy to manage. It's not dynamic with the number of children. You always have to make an exception for the first to the last one. And with gap, you just get to sort of like, let's see, we have a link to this doc here. Boop, it's at the top of the chat here, but maybe you didn't get the history there. No worries, okay. So our section, yeah, I call these just for gap all the time and I'm like, display grid, I don't need you to do anything else because display grid by default stacks items vertically. They're blocks just like divs naturally are, but by making a container display grid, then you can start to use gap. And so it's essentially just a way for you to say, hey, take this layout that's already a block level layout, but give it some gap. So I call it just for gap. So our sections now have that and that's between our headers and the field sets. Our headers and the field sets now have that space. Okay, let's check out our field set elements here. Let's pop those in, paste our styles. So we're zeroing out the padding. We're setting display to grid because again, we're gonna bring in some gap. Notice our gap is one pixel. That's a very unique thing. And we'll go over that in just a second because we're gonna create in this layout here. Let me get rid of our overlay. If we zoom in, do you see that little hairline right there? It'd be really tempting to make that a border, but then you'd have to do border bottom, border bottom, border bottom, not last item, no border bottom or whatever, right? You'd have to make an exception. And so instead, I made a gap of one pixel and later when we go put the color in, we'll put a color on the whole field set. And since there's a gap one pixel between each, we get a hairline border, border in quotes, between each element, which also means you could like animate this whole thing and slide it in and out. And anyway, that's why I did that. That's where the one pixel comes from is we're getting that hairline border. We're also setting the border radius to look vars space small, one rem. So we have a nice border here, one rem and the overflow is set to hidden. Okay, cool. Let's move on. Field set item. So these are each item inside of the field set. Boop, display grid again, right? Okay, yeah, we're using grid throughout the whole entire thing. So just get ready to see lots of display grid. And we have grid template columns. So our first one is vars space large. So our first column, if you look to see here, let's go into our, I'll save this, pull this open. If we inspect here, let's set up our field set item. This is our, here, I'll just zoom in here. This is our column. We just created that large one and that created a space for the icon to exist. And then here's the gap that we threw in there. And our padding. So we added some padding amongst all the sides as well. Ooh, I have a feeling that this is where our bug is. Right here. Let's see if I'm right by the time we get to this later. Because this is a physical side. This is all the sides physically. And I'm pretty sure that, well, maybe that's not it. Because right and left are the same. Okay, we'll see it. Anyway, this isn't logical. This is all the physical sides. And we can break that out into the logical sides. But it looks like, we'll see, we'll see, okay. We've got our gap that was between our icons here. So yeah, essentially what was interesting about this layout is the grid template columns. The first one uses our spacing elements, right? Because we're choosing from the harmony that's in our app and we're creating a space for the icons to live inside of. And we'll center them inside of there soon. So this layout is responsible for centering the icon and the checkbox associated labels and controls. The first column of the grid template creates a column wider than the icon. So a child has somewhere to be centered within. Centering is really hard. There's like five different types of centering in CSS. So it is a difficult thing. It's also not just CSS' fault. Centering itself is conditional and contextual. And there's anyway, like I said, there's a lot of different types of centering. I have a whole post on web.dev. It's like my top five centering techniques. And you can go find that article to learn more about how I think about centering. I also pit them against each other and say which one's the best, like it's a robot battle. Anyway, this layout demonstrates how many design decisions really have to be made inside of the custom properties. So paddings, gaps, and columns were all sized within the harmony of the system. Perfect. Let's talk about our field set item picture. Let's grab this, drive it down here. Okay, we've got block size and inline size. So we're talking specifically about this icon. The icon is within a picture element. And the reason that we did that is it is a visual item and we're able to sort of add some, well, you could go look at the HTML to see, but there was the ARIA hidden property in there and some other things. And I just like wrapping images and pictures. Just seems to make sense. Plus you get a containing element that you can style like this. So we're setting the block size of the inline size to space XL. We're setting the clip path to 50%, which we'll see soon, clip path to 50% with circle will give you a perfect circle around any element. And then we're able to animate that percentage in there to give the appearance of a grow or shrinking circle on the element. Kind of cool. So we're kind of like clipping it like a mask and then we're going to adjust the mask to do the effects. Like here, let's just go check out that effect really quick because we'll get there. See as I tabbed in, oh, we still have reduced motion. Reduced motion, we'll go into animation. See how the tab kind of grew in right there? And that's all being done with clip path. Cool, display inline grid and place content center. So that's setting the picture element to a grid and then setting its content in the center and that's going to center the icon inside of the space that it's articulated here. Perfect. Let's move on to this one. Ooh, our first pseudo class selector with the is pseudo class functional pseudo class selector. Gotta love them. Okay, so field set item, if it is a picture or an input type checkbox, place self center. So if it's a picture or input type checkbox, ah, let's see, if I go undo this, let's look at our checkbox adjust backed. Oh, yep, see it's at start, start. So it was our item here in the picture and we'll set place self center center and we'll see these things center inside of the, ooh, did I skip a heading element? I saw a little comment in there. See, what was that? I think you skipped the header element styling. The headers, like you mean like these headers, those were in the beginning, I didn't really styled them very much. They're kind of unstyled, but maybe we'll come back to that. Thanks for pointing that out. We'll see if I did in fact, skip that. Okay, so we centered our icons. We've got some SVG work to do. So we're gonna set the size of our SVG that we like. We're gonna set those to block size medium. So you can see that they shrunk just a little bit there, which means I can also go to the top and get rid of this style here, this SVG block size too, because we're using our spacing variable that we created earlier to stay within the harmony of our sizing. Let's look at small stack. This is our only utility class. It's in the whole thing. Paste that here. I call it small stack because it's just got an extra small gap between it. So this class small stack is on a few elements inside of here. You could see them spaced out as we did that, right? Not a whole lot of change, but it gave us this ability to put some space between a few elements. Let's inspect it here. So we've got, here's a small stack. So you could see it right there. We're just putting some space between this header message here and the small. Then we've also got one being used here, right? So we have a consistent gap between them. And we're just, again, kind of using just for gap. It's a very similar layout as the other ones we've seen. Okay, cool. Let's look at our input type checkbox. Here's something I really like to do is increase the size of the checkbox. So if we scroll down here, you can see how it grew. Let me cut that back out. You can see our normal size checkboxes was like almost the exact size of my mouse cursor, which requires a lot of fine pointing. If I set the inline size and the block size, so essentially the height and the width to one of our spacing elements, look again a nice larger checkbox and they're all made with vectors. So they look great. And now I have a much easier hit area. And we can adjust this later if we like inside of a media query for course touch for finger and make that even larger. So we could go from a small to a medium sized and make it even easier for fingers to tap. So we'll see if we get there. All right, things to try. Oh yeah, open up the elements panel, turn on those grid badges, start looking at the gap. Yep, so let's get the gap in the styles pane. And there's all sorts of good things that you can start to do in here. Like if I look at this icon here, this is our picture element. See this inline grid icon here. So here we have display inline grid and there's this icon. If you click this icon, it will show you which kind of alignment it's using for that particular grid and you can change them. And it's really nice. You can get a nice visual for how you're positioning things. Okay, media queries. Yeah, the following CSS adapts the styles based on viewport size orientation and with the intent to adjust spacing or arrangement to be optimal within a given viewport. Let's grab both of these. So these are essentially mobile first and the reason that we can tell that they're mobile first is because they're using min width and if it's 540 and above, we're gonna increase some spacing and if it's even larger than 800, we're gonna go even more. So this is kind of like how we're increasing our compact. So we're going from a compact layout on mobile and as we get more space, we're gonna get more spacing there. So could you see the shift? So here's the compact layout. We go here, we get a little bit more spacing. We grow and a little bit more spacing. Oh, I see we've only targeted main. So let me save this. So open up our demo here. I'll reload and we'll go onto main here. So we can see our padding around the edge but padding doesn't really stick around with the dev tool. So I'm gonna use Visbug here really quick. Here's our padding. Let me hide Visbug. This is just a design tool I made that helps you visualize a bunch of different and interesting things on the page in this particular case padding. So I'm gonna select that element. So the padding stays and as I resize, we can watch the padding adjust, right? Just shrunk right there, shrinks and it's gonna shrink again and shrinks again. So we'll be able to use this similar concept within more elements inside of here to see these shrink too. Right now, these aren't shrinking or growing with the rest and we'll get there. Well, it took a second. All right, so cool. I'll just refresh in here, come back to our demo and Visbug is free to download. If you want, you can send me a message and I'll send you a link to it or just look it up. It's V-I-S-B-U-G here. I'll just send that right here. Also a web here. I'll just go to visbug.web.app. You can also try it before you install it here. It's a Chrome extension. That also works on Safari and Firefox. So you can get these nice visual tools and all the other browsers. Okay, and let's talk about our form. Hey, look, it's another repeat, no auto-fit. Oh, no, it is auto-fit. So we have another RAM layout. Okay, let's grab our form and pop this in down here. Roll this open. Okay, so what are we doing? We have a custom property called repeat that's scoped locally to the form here and we set it to auto-fit. The reason that we did that is so that in a media query for orientation landscape and min-width 640, this is when our device goes into landscape mode. So we're having at least 640 pixels wide on the device. So we need to make sure that there's enough width to go to two columns and is the device in landscape actually? And if it is, we want to ensure that it's not auto-fitting, that it's actually, in fact, two columns. We're being very explicit about it here. We're kind of taking the auto layout out of it. We're not auto-fitting at all. We're saying two columns layout grid, two columns don't do anything other than two. And that's how we can tell it specifically on that, in this particular scenario here, what size and layout that we want. So we'll just briefly go over this one here. We have a repeat var repeat. So that's our auto-fit by default, but maybe it's two min max at, oh, look, it's almost the exact same one, a minimum of 10 characters, but able to scale up to 100%. You'll see that this is a way to make this area more flexible. There's CSS tricks articles, very specific about this value inside of min max. And it's pretty tricky, but ultimately this is what you can take away from it, something similar to this. And then a max of 35 characters. And so that's allowing us to, again, be specific about two columns on a device that is in landscape mode. Cool. All right, field set item. Looks like we got a media query for this one. Where was our field set item before? I'll go put this next to it, right here. Paste that, and what do we got in here? And we have a field set item, grid template columns. Ooh, that even gave us some space. I saw it. So we're saying if the browser width is above 540 pixels, and we're going to set the grid template column size to XXL, so it was just large, and now it's double large, still having a flexible unit for the rest of it here. We're going to change the gap to be a small gap, and we're gonna adjust the padding here. So, oh, look, I think this is going to be our padding. Look, there's our zero. Do you remember when we went right to left, and there was like a side that had no padding? It was a mystery? Pretty sure that that's it. Okay, that's gonna be fun. I'm pretty sure that's it. Anyway, so we have top, right, bottom, left. Oh, that's totally it. We're gonna get it. Anyway, and we'll come back and fix it, and that sounds like fun. And so we're adjusting our padding based on more space. So we should see it grow. Yeah, that means we can save this and come back into our code panel over here, launch this bug again, pull up our padding tool and stick it on these items and watch them adjust. Yep, there's our smaller amount of padding. And as we get above 540, it grew, and that left-hand side went to right zero. In fact, let's just try. Oh, look, my directionality on my document is gone. Oh, that's because CodePen doesn't have it. So let's say dur, oh, let me type in here, dur equals right to left. Let's just nip this bug right now. There it is. Okay, so we're already experiencing it. I'll query in here. I'll look at our field set item. Now it's the one that was in question. We have padding here is being specified at the left-hand side is zero. The left is zero. Let's fix it. And we're gonna fix it with logical properties. Check it out. It's coming to here are specified where we wrote that. So what we're gonna change is when you use the shorthand of padding it's all the physical sides. The quick way to get to the logical version is to say padding block. Now that's gonna be the logical sides of things. And that's gonna be top first. Oh, I need a semicolon here. Here's our top. So let's take that right out of there and take the bottom out. Oh, look, they're the same. Guess what? We don't even have to write that then. We'll just say padding block. It'll repeat them just like Martin does. Then we'll say padding in line. And we'll take these two values. Let's see it. Wait, so we had top, right, bottom, left. So zero is the inline start and our right is this one. Okay, we'll cut that old value out of there. We'll hit save. So notice how nothing changed in our layout over here. I'll refresh. I'm gonna have to add our attribute again over here. We'll say direction equals right to left. We're fixing bugs in a live demo. That is exciting for me. I don't know if that's exciting for you. Anyway, I'll have to go update the example here but that was a critical lesson, right? Of when a physical padding and spacing property bit you as you try to go into another writing mode. And anyway, be careful when you're using the padding and margin shorthands. I often will expand mine into the shorthands that you saw here, padding block and padding in line. You might even be familiar with something like padding X or padding Y where people have tried to give you the ability to do left and right in just one line of CSS. So anyway, you have that with logical properties and it just saved our bacon. Look at that. I'm happy with that. Okay, so I'm gonna move on to the next section. Adaptive color, how much time do we have? It's 12.01, we got like 30 minutes. All right, cool. Hopefully we can get to some questions. Let's burn through. I'm gonna burn through the color section a little faster. Let's try to pick up the pace a little bit. We're gonna adapt to dark and light color preferences. We're gonna have a color scheme derived from a brand hex and we're gonna have accessible colors. Cause of course, and now we're gonna take our layout which is looking like this, which is kind of just like skeleton and bones. And we're gonna turn it into something harmonious and have a color scheme. And we're gonna do that with HSL. Sounds for hue, saturation, lightness. There's many ways to write color. HSL is unique in that it has a lightness value which is really common for people to say, I just want like a lighter color. And you can stay within a single hue and then you can adjust the saturation. So we're gonna create one with HSL and calc because we can do a calculation on the values that we pass into the HSL function. So let's scroll down here to custom properties. In this section, we're gonna build a set of custom properties for use within the rest of our styles. Similar to our spacing system that we built. It's gonna be a color system. Oh, look, that's like literally what's written right there. Assume the brand color for your app is pound zero AF, right? A designer always gives you a hex value and that's not useful for us to do light and dark and unless you're in SAS or some sort of preprocessor and we wanna be in just vanilla at CSS today. So our first task is to convert the hex value to HSL. How do I convert? I'll show you. So if I just highlight anything here, so I hit command shift C in my DevTools to get to this. This is called the element inspect thing. Anyway, click the element that I wanna inspect. I'm just gonna set the color to that hex value and it looks like a nice blue and watch this as I hold shift and here I'll just zoom in and I'll hold shift and click and convert that to HSL. So DevTools will convert colors for you. Look, I can go back to a three digit hex. You saw the six digit hex. We've got our RGB and our HSL and I'm gonna go take these color channels out of there. So H, the hue is 200. The saturation is maximum at 100% and the lightness is at 50%. So this is like a really bright middle blue or something like that. And I like how HSL can read like that too. Okay, so we took out our color channels. This conversion reveals your brand's color channels. Now we can use Calc on it. Great, so here's our brand channels. So I'm gonna stick these into our root. Boop up into the top. Okay, so it's, oh, I don't need that. There we go. So there's our hue, saturation, lightness, nice and named. These three channels, we can use these and build upon them for a bunch of variants. And I think that's the exciting part about colors is when you have like a base and then you're building off all these different trees of color systems. So since your color, my color scheme is dark by default that's how we're gonna start today. So you don't have to work that way, but that's how I'm gonna work. I'm gonna start that by saying text one and text two. So we're gonna start creating custom properties that use the HSL values. So the first one here, text one, is gonna be of the same hue. So it's gonna be 200, which is gonna be a blue. It's gonna be very mildly saturated, but very light. Our text, this is our dark theme. So our text needs to be a light, a light text on a dark color. We'll get to our dark surfaces in a second, but notice that they're barely saturated and they're pretty light. So they're not quite to white. 100% in lightness would make it white. And then text two is the same little mild amount of saturation, but a little less bright white. So that's gonna give us our secondary text color that's kind of subdued. You know, like you might choose a light gray or something like that. Scroll down. Let's grab our surface colors, put those right underneath. So here's our surface. We have the same hue. Notice the hue is just carried right through all of these. The saturation is still pretty low on these, but notice the lightness. So our surfaces are dark. They're almost near black with 10% 15% 20 and 25%. So we have four variations of dark, dark blue to use as surfaces and two very light, light blue colors to use as text colors. And if we come back to our example, notice how everything in here has a blue harmony to it. And this is the way that we're doing that. And if I switch to dark, you can see that the dark even has a blue harmony to it. And this is all through HSL. All right, so what's our next section here? And we've got a light theme. Yes, let's build upon the light theme. And also we're not using any of these yet, but we'll get there. So we'll take this whole media query here, we'll pop it underneath our root. We'll say if the user prefers color scheme light, we want these colors inside of the root. So brand should be full color here. So full hue, full saturation, full lightness, exactly as the designer gave it to us. That's our brand color. Do we do brand up here? I don't think we did brand up there. Did we do brand? Oh, look, I missed it. Brand, brand should go underneath here. Ah, I noticed this one has saturation cut by two, because when you're in a dark color scheme, you do not want a really bright, vibrant, saturated color. You want desaturated colors. At night, a blue will naturally have a lot of vibrance to it. And so we cut it in half here. That's what I meant by calc. We calculated off of the brand color, a half saturated brand blue. And then in the light theme, we go full on. Okay, so here's also, we're gonna put these text colors in our light color scheme here. I'm gonna pop these under here. Excellent. So wait a sec, that's our old one, isn't it? Yeah, here's our light theme. Here's the text colors we want. I was like, the lightness on these is really high. These are like white text colors. I'm like, we're not building that. We need to build a dark color scheme. So here we go, text one, same hue, vibrant saturation, and really dark, 10%. Again here, but not quite as dark. So 20% difference in the darkness and look 20% darkness or difference here. So you can kind of like our text colors, each of them have a 20% difference in lightness. And that's how we're getting that nice variation in them. You can play with these numbers to see what you like. But a strong tip too, is notice how we're in the 80s and the 60s, and down here we're in the 10s and the 20s. If you keep a range of about 50% between your text color and your surface color in the lightness channel, you can get yourself into a really healthy spot for accessible colors. So you're gonna ensure there's enough contrast because your lightness has a big enough gap between the values that you're choosing. And you can control that here in your HSL. So you can kind of guesstimate your way there, but always test, always go back through and test to make sure everything's looking good. So those are our text colors. Here, let's pull in our surface colors. Look at these ones, these ones are almost white. So we have surface one at 90%, 99%, 96% and 85%. They're still all blue. They're still barely saturated because light blue colors or just light colors don't need a lot of saturation for that to come through, but they're almost white. And that's why in our layout here, look at this layout, it is almost nearly white. Some of these look white in fact, but they are not. And you can tell, so this is gonna be 99% white probably on this one. So anyway, let's move on to using the color system. Yes, the exciting part. Let's go to our body and use our surface one and text one. I like it when my surface and text numbers, so text one, surface one, you can use them as a pair and using them as a pair is a good way to think about again, good contrast in your colors. So let's see underneath our custom props in our body here. We'll paste this and immediately we should start to see something exciting. Yes, I'm on a dark theme as my color preference. I can see that the background has, you've been used that surface one and the text color is text one. So everything is that nice bright primary text one color. Cool. Let's start making our exceptions and build this thing out. Our field set item has the surface three background color. All right, field set item has the background of surface three. We'll see that pop in here. Excellent. The picture element has a background color of surface four. Field set item picture, here we go. So we're just using the color system that we built now and look, yeah, so by using that lightness adjuster in these colors in those surfaces, we're now able to create these different surface colors and textures just by adjusting that lightness. So everything's on brand, on theme, but still has a nice contrast and a nice complimentary color set to each other. So let's see, we've got our field set item SVG. What's that item SVG right here? That's gonna be filled with text two. So that's our lighter color, a little more subdued and there it is right there. So it's not quite as bright as these ones are. A little bit more subdued, also a little bit more blue. So as we got a little bit lighter in the color, more of the saturation came through. Let's see, focus. Ah, so this is a new selector, isn't it? We haven't done focus within yet. So we've got focus within SVG. Let's just pop that right underneath here. So this says if the field set item and any of its children have focus, find the SVG and give it a fill of brand. So if I hit tab and I focus into here or even just click into one of these, look at how that goes to blue. So we're bringing our brand blue color into this by using focus within. So I really like focus within as a interactive CSS pseudo class. It allows you to do a lot of really cool stuff because as people are using things, you can highlight other parts of the UI and I'm pretty sure we continue to do that in this. Okay, so here's our small, small color. I think this is a new selector too, huh? Do we have a small in here? Maybe it's at the very bottom. Oh yeah, we had it small with like that like line height adjustment, huh? There it is. So it's gonna be, it's gonna get the secondary color, right? That makes sense. It's a small secondary color set text too. That's gonna be these. And there they go. They pushed back just a little bit so they don't compete as much with the headers. And lastly, for dark form controls, we're gonna add color scheme, dark light to our root element. And what this does is this signals to the browser that you have a light and a dark theme. And did you see our sliders just got dark and they got subdued? The brand color is now lighter and look at our checkboxes, they're dark. I'm gonna go ahead and comment that out again so we can see white sliders, white checkboxes, that's the light theme that the browser supplies. And we have a very vibrant blue. I'll bring this back in. We'll go to a slightly less bright blue as well as a dark checkbox and dark slider. So really cool touch to put on your interfaces that color scheme. And the color scheme does have other impacts on your page but since we've set the background colors and stuff on it, it's all good. So anyway, let's keep moving on. Adaptive animation. So now we have adapting color, we have adapting layouts, we have adaptive spacing, we have adaptive inputs, right? We can use this from all these different interfaces. We need to do adaptive animation. Our border looks like we did something wrong. Our field set border looks like it needs something. What does it mean? Our field set has border radius. Does it need a border like one pixel solid? I feel like it needs a surface color, surface three. Can't quite see it, how about surface two? I'm gonna have to go check that out. I'm sure it's in there somewhere but it looks like our border is... Oh yeah, we've got someone saving it. Yes, thank you. Surface four, surface four for border and background. Thanks for saving me there. Y'all are so helpful. I appreciate it. Ah, that does, that looks nice. Okay, because look, now our border matches our little hairline because we set the... This was a critical thing we almost missed. Thank you so much, Donovan. Appreciate that. Following along, keeping me in my spot, this is awesome. Okay, so what we wanna do now is we wanna add some animation but we only wanna add it for folks that won't throw up from it. I hope that's obvious. Anyway, it's really easy to do in CSS and I'll show you how. So, first thing we're gonna do is we're gonna go to our field set. We'll take and we'll add a new transition in here. I might change up how we do that today because here's prefers reduced motion, no preference. Here's our transition. I want to only add transitions if it's okay. Oh, you know what it is is we're transitioning the box shadow and that's okay. Okay, so we're gonna go to our field set. Totally cool to transition a box shadow. And when the field set has focused within, we're gonna increase that box shadow. That's gonna give us a lifted effect. That's not gonna be super noticeable here in the dark theme because dark shadows are really tough but in our light theme, you can see that it's now lifted off the bottom here. So if I click off, it kind of folds back down and as I interact with it, it lifts. Notice how this one is focused. So we've got like a focus on this item here. We've got a lift. We've got icons highlighting and all that coming from with focus within. So let's keep building upon this. So our field set item, we're gonna transition the background color. Color is totally okay to transition for folks who need reduced motion. So we're gonna set transition background color, 0.2 seconds ease. I like ease, it's like a default easing. See, we're really starting to come along in here, right? So field set item, we were doing the background color. Oh, we haven't set the focus within yet. Okay, so we're able to transition that back color but we're not changing it yet. So let's go ahead and change it. Field set item focus within and we'll set the background to our surface too and that is focus within and there it is. Now it looks darker. So we're bringing attention to this particular zone and when we made this darker, look at this surface that popped right out. So our icon gets to shine. Cool stuff. We've only got four surface colors in this app and we're gonna look at how dynamic it is. You don't need a whole bunch of colors. You can do stuff with just a little bit. Okay, here's the one that we do want to be reduced and this is why I like to tuck them inside of this media query here. So we're gonna be field set item picture. Let's find that here. Pop it underneath, paste. So what I like about this is it says prefers reduced motion, no preference. This is essentially somebody, a user that has not changed the value AKA they're okay with motion and if they're okay with motion, then we're like, okay, well let's go do some cool stuff. Like animate the clip path, which definitely has a grow and a shrink animation that is a little wobbly looking and it's easy enough for us just to put this all behind this little media query here. So this media query, if the user is okay with motion, let's grab the picture element. Let's set its clip path to 40%. So we shrunk it from what it was. It was 50%, which fits its entire box. We're gonna shrink a little bit and then we're gonna wait for focus within here and if there's focus within, we're gonna target that picture and we're gonna set the clip path to 50%. So we're essentially shrinking the clip path, but when they focus inside, we're gonna scale it up and when they focus out of it, it'll scale back down and we're gonna get this little scale effect and let's test it out as we interact with this. Look at that grow. That's so satisfying little touches for that UX, okay? And that's it. That's the clip path animation for there and congratulations. We have finished it. What time is it? We've got 15 minutes for Q and A. Awesome, let me go check out what we got in the section over here. Let's see, for performance, should we animate the opacity of the silhouette with a box shadow? Okay, for performance reasons, there are a few things that we animated in this example that aren't typically high-performing things. I would recommend that if you want to be very considerate of performance, you should always animate opacity or transition or transforms, except this is gonna be, I don't know, a little controversial, I guess. Things that don't have a lot of surface area are fine to animate properties that aren't expensive, especially if they're not gonna be pushing other elements around. So clip path is very self-contained. It's not a GPU accelerated animation property, but as you saw, and I've done a lot of testing on old devices, clip path when done on animations in small spaces is totally fine. Furthermore, background color, which we've done a few color animations here, are also not typically GPU accelerated. Chromium is working on accelerating them so that the RGB accelerated, but for now they're not. But again, since they're not layout impacting and they're only color paint impacting, they're much cheaper than things that are gonna move other elements around. So you could say that I, well, and really, yeah, some of the animations in here aren't as performant as they could be, but again, they're so small that they're negligible. So even on a really low-end device, like I've got one right here, everything's still actually nice on there. Even the low-end devices still have a really big GPU, or not a big GPU, but have a big brain these days and can get a lot done. So that's a good question though. And clip path and background color are set to be GPU animated properties before Q2 next year, something like that. And people are hacking on it so that you won't have to worry about it. But it's a great question. All right, I'm gonna go to the Q&A section and not read that chat anymore because I'm hoping people packed this thing up. Woo-hoo, we did. Did they get upvoted? They did get upvoted, sweet. Okay, so I'm gonna start the ones that got a thumbs up first. And then it's like top to bottom ones with thumbs up. And then I'll just start at the top in there. So Timmy has probably off topic nice, but as much as we like REM, it seems challenging to build a design system using REM. Ooh, this is a good one. Okay, I believe the most challenging part is that design tools don't have a concept of a REM. Everything that gets done outside of the browser that gets told to you, it gets told to you in something other than a web unit. You get told them in pixels, which are absolute units, which is a great way to squash user preferences. You get told things in dips maybe, and dip is an Android value and it's like a DPI relevant value and that's not important for you either. As pixels and REMs will both be DPI, whatever. I think the biggest problem is something internally in a team. And so for many years and still to this day, I translate pixels to REMs for designers. They don't have the means to do it. You're gonna have to do it for them. So it is challenging, but once you lay down the spacing system, here's what I've always done is I love sitting down with designers. Take their pixel spacing system or their pixel font size system, go eyeball it into REMs in your browser as close as you can, but round some of the values. Don't use like a 0.95 REM or something like that. Just use one REM and then work with them to nudge the REM based system into something that they find visually pleasing and find a compromise. Same thing with colors, they're gonna give you hex and turns out the future of the internet is not hex. It's in well, LCH lab, display P3. Designers are gonna start giving you colors. Well, you're gonna start telling designers that they can use more colors soon. And that's also on the, so basically the web is way more powerful than most design tools and the handoff sucks. So it's on you to bring and help educate and translate. You've always been a translator in the front end. You're translating a wish and a dream into a reality. And sometimes that means you need to adjust the units that are being used. I hope that is mildly accessible or acceptable as an answer. I could riff on that forever, but thanks to me for the question. I wanna burn on to the next one. Oh, look, we got more votes. Okay, so Lori's at the top here. I normally wrap inputs in label elements to get the benefits you showed for the for attribute. Yes, I noticed the lab does not do this. Are there any trade-offs here? There are trade-offs. They're not bad trade-offs. Some of them are designed trade-offs. There's even one I think I cheated in there where I used display, oh no, I took out the display contents because I did have some wrapped in a label. Sometimes I'll wrap them in a label like I have a GUI challenge where I built a switch element with a checkbox and I wrapped that checkbox in a label because I got some nice tap functionality and some other things for free. I think it can be argued that the relationship is what you're trying to build, right? You're trying to say this label and this input are together. Now you can either do that with an explicit relationship of hierarchy. You've put the checkbox in the label, later obviously together, or you can specify it with some metadata that's attached to the elements themselves. So maybe you want the label and the checkbox to be far away from each other, but you want them to still have a relationship. You'd want to use the attributes. If you want them bundled together and they're always going to be in that little spot, maybe you want to make them parent-child relationship. I don't think there's any humongous reasons to choose one over the other. The important thing is that you're thinking about it and that is important to me. You need to be thinking about the user and thinking about the relationship between your labels and your inputs. So you're already a leg up on a lot of other folks. I don't know of any specific reasons to use or not use one. Maybe there's a blog post. Someone wants to share. Great question though. Okay, is it more preferable to use REM for root space instead of M or pixel? This is another good one. Okay, so I use REM because, again, I like the whole unit nature of it. One REM being the base font size that the user has. And so I know that if I use one REM as a spacing unit somewhere, it's going to be akin to how their brain wants to see the font size like if they have a large font size, they're going to want more space between their elements also. And so using REM, I get to bring that throughout the whole application. REM being a very global root centric won't change value. M can change on you. So you might use M, one M in one location and one M in another location and get a different result. And so I use REM because I want consistency in that spacing system. If I want a contextual spacing system that builds off like a little contextual font size, M is a great choice. And pixels, I don't like to use pixels unless I'm doing something like border radius or absolute positioning. And there's a couple of other exceptions where like I don't really need the border radius to be based on the user's font size. Like there's usually a border radius that we want and that's a pixel value. Totally fine, use a pixel value there. So again, it's thinking about the user and what is the user bringing and do I want their preferences to travel into this particular design element that you're working towards? So I use REM. There's also more units about to come out like the root character unit. So I really, you saw me use the CH unit in here. I love that unit, especially for sizing content, headers, small elements, paragraph elements, labels. I really love using the character unit because it's like you really want it to optimize for a reading length. And so you can specify it almost very specifically with the character unit. And soon we'll get root character, RCH. And I don't think I'll switch to RCH for my unit, but maybe. I really like the CH unit. I also use a lot like one CH or two CH because again, their whole units, they read well, they travel well amongst all these use cases, but the CH unit is like the M unit. It will change contextually based on its use case and location. Awesome question. Okay, let's see. Haven't custom properties seen cut? Let's see. Haven't custom CSS properties been abandoned for good? They definitely have not. I don't know where you heard that. And that's crazy. And I don't mean that's crazy. I'm sorry, but it's like, I've never heard anyone say that before. No, they're more powerful than any preprocessor variable ever. They're kind of incredibly amazing in terms of reactivity. They're minimal. You can put a thousand of them on a page or more and they're all gonna be performant. They are absolutely fantastic. In fact, I have a bet that custom properties are about to explode. Anyway, well, we can talk about that later. See what are we out of time? We've got six minutes. Okay, cool. Will this be available to watch later? No, but let me share. I don't think it will, but let me share one that will. I've got this link to the existing one right here. Boop, boop. I'll throw this in the chat. So this is my Google IO version. It's half the time. And I think that has a time stamp on it. No, who cares? Anyway, there you go. Really hope the Q&A questions are sorted so it follows all the likes. It did have it. I didn't think they were sorted, but I can go query them in the last little set here and make sure I get the ones that are high voted. Let's see. There's one with five. There's one with eight. Let's go with the eight. Okay, Lori, could you elaborate more as to why you use gap over margins? Yes, would you like, would you feel a little hacky to set grid without understanding more? Sure, that's fair enough. Like if you're not familiar with grid and you're in gap, you've been using margins all this time, you don't have to start adapting gap. I just found that margins generally, when you used on like a parent container to like lay out children, always came with little exceptions where it'd be like, margin block start 20 pixels or one rem, like I would use, and then I was like, oh yeah, the one on the bottom, the one on the top now has extra space and it should have been hugging the container. So then you have to write a new selector and you're like, first of type, that is this thing, margin block start, none. Or you write a selector that's like, find all my children that are not the first child and then give the, and it's just like, it just doesn't really read that well. It also feels very particular, like it's targeting a very specific scenario where gap is just like space will be between all the children and never around the edge. And so often what I'll do is I'll set my padding and my gap to the same custom property because then the container and the space between them is all the same. And it's just a couple of lines of CSS instead of maybe three or four. I think it's pretty common that a lot of people find that managing the spacing on the parent is a lot easier to adjust later than it is to go find each child and make their margin different. Here's a critical reason though to not use gap, which is if you need different spacing between your children. Gap is a one space between everything only, you can do row and column, but you can't say like the first row gets one RAM and the second row gets four RAM and you can't adjust it. So that would be a use case for margin. Like if you needed some sort of ramp as things got more spaced as they went down. Nice, would you feel a hacky to set grid without understanding more? Oh, you're saying it would feel hacky. I mean, grid, yeah, we look at the CSS statistics of grid and flexbox. They are still, flexbox is the one that's more used. Gap is on flexbox now too, but grid is still at like a low 10% of usage on web pages. So don't feel bad if grid is not super familiar for you yet, but it is something I would very much say invest in the syntax gets very familiar very quickly more familiar quickly than I think flexbox did. But anyway, that would be my thoughts there. Let's see, do we have any other high ones? Okay, any tips on how to best integrate these techniques into a design system? Like I said, work with your designers. I love sitting down with designers and saying, here's what I made based on what you gave me, let's make it even better. Their eyes always notice things that mine don't and it's a learning experience for me. And I've been doing that for so long that a lot of my design decisions like you saw in here are based on experiences that I've had with designers when I sit down with them. So I'd say work with them directly and try to help them understand the reason for relative units and the reason for making some of these decisions about color and font and stuff like that, that the user is not, basically there's always a war between design control and design adaptation. And the more control that someone wants so that they try to put in there, the more they're gonna fight the user that's just like, why can't I just read it or whatever there's just gonna be, there's always this little weird war. And so try to help designers fall into this space of working with existing stuff instead of trying to rain down a new design system. It's almost like line heights is a good one. Like designers will give you this like type ramp and they've got all these line heights for all these different font sizes and those get really messy over time. And instead you could have used to use a unit list line height, got something approximately much closer but that's much more dynamic and doesn't have any of the baggage of like hand managing font size and line height every time you use them somewhere. So I don't know, there's just always kind of a difficult and appropriate like struggle between like design control and design flexibility. And you can pick which side of that you wanna be on and just help each other find a middle ground. Design systems are about finding a middle ground. I think at least you're trying to empower all sorts of different people. See, do you know how the will change property can optimize animation and when it should be used? Yes, the will change property is a hint to the browser that you will be changing something. It's able to, ahead of time, as soon as it reads that that's there, you can store in its memory that this thing will be changing. So will change is really great for things that you're going to be changing a lot. Like let's say you're hovering and it's gonna be changing all sorts of different transition values. Like you're following the mouse and you're gonna be setting X and Y in a transform. That's a really good thing to tell the browser, hey, will change transform. It's about to be firing at a rapid rate at you. Like, you know, the mouse is gonna be moving the screen refresh rate. It's a good time to tell the browser that this thing will change. You can't overdo will change. So you can basically prepare the browser so much that its brain explodes. That's not real. But it's like it will become overloaded. It will pack so much ahead of time into memory and preparation for your animations that things start to fall out. It runs out of memory. And so a common thing, I was like a low-end device, if too many things have will change, everything starts to suffer because now nothing is optimized. It's a property to be used sparingly, but when it's used in the right scenarios, it can be awesome. You can also conditionally apply it. So let's say your mouse entered a zone that you're gonna be setting something really rapidly. You could set will change as soon as the mouse is in there. You're will changing and you are changing it a lot. Then the mouse exits. That thing's not gonna change as much anymore. Rip the property off there. There's also a way to use will change to help your text not do a shift. So if you're transforming something with text in it, you might see the text get kind of blurry and then come back in and then like has this like snap effect where it goes from the GPU layer, like the little bitmap that it moved into spot. And then it goes back into a fully rendered vector thing. You can tell it will change transform there and it will maintain the bitmap version the whole time. So you never see that transition between like vector text and animation ready text. You can keep the layer in memory. So that's about layers. Will change is a great way for you to articulate layers that are gonna be changing a lot or that you want to stay changed. Stuff is fun. Y'all, there is a discord. You should ask more questions and let me send a little invite over here. Check this out. Bring your questions in here. I'm happy to answer more. Boom. There is the discord link. Please feel free to join. Ask more questions. There's other channels in there too for you to ask other types of questions. I'm a little out of breath. So I had, but I had a good time. I'm so glad we fixed that bug. I gotta go update the thing. What a sneaky little bug too. The physical sides of the shorthand came after us. Anyway, thanks everybody. Take it easy.