 Hello, my friend and friends. Here we are on the CSS Day website. And the reason we're here is because if we come down to here, I posted about the CSS Day a little while ago and on my Discord server and on Twitter. A few people were talking about this section down here where we highlight one of the people's names, where we hover on top of it. It highlights the name and the image gets bigger and it works in reverse too. If I go on Josh here, you can see it's making Josh's image bigger, but it's also highlighting his name at the same time, which I think is kinda cool. So yeah, it's a nice little effect and just to say before we dive into it, the reason I was posting about it in the first place is because I am going to be speaking at CSS Day. I'm really honored to be doing that. It is in Amsterdam on June 6th and 7th of this year. And just look at this list of people that I'm gonna be talking with. I'm just really honored to be speaking at it and it is their 10th anniversary. Really, really excited for this. So if you are interested, I'll put a link down below. If you wanna check out the tickets or anything and if you are able to make it, definitely let me know because I'd love to meet you while we're there. But let's get into how we could do this because it actually turns out this effect is over 10 years old now. It's almost 11 years old when they first created this and I wanted to see how I could do it with modern CSS instead of doing it the old way. I'm not gonna be focused on how to get it to work within this specific layout. I just wanna look at the effect itself with how the hover and everything could work using modern CSS instead of the older way of doing it because I thought it'd be a fun little challenge to be able to do. And so we're gonna start here with wrapper just to hold our content. And in here, there's two things that I think we're gonna need. One is something to set up our grid and then we're gonna have the list here. But I'm gonna steal a little bit of how they did theirs even though we're gonna be using a modern CSS way of doing it. But I'm gonna do something like this to start with and we'll break this down really quickly where we're gonna have a div of a speaker grid. I guess it could be a section or something else, whatever you need. But we'd want this outer div here and then we want the UL inside of that. I think this layering is going to make a little bit more sense a little bit later. Basically, I don't want my UL to be a grid though because I don't want each list item to be on its own grid row. That would just become hard to manage. So I think this is going to be the easier way to do it. And then for each one of the speakers, we have a link. The link has the name as well as their image included in the link. And then all the way at the end, outside of the link, we have the name of their talk or what they're gonna be doing. We have Jeremy and Miriam here who are the MCs, but then we have all these, just the general topics that are outside of the link. So if we set it up like that, for now, we get something that looks like this. So let's jump on over to the styles. You can see I'm doing a bit of a dark mode here. So I do have a little bit of code written down here at the bottom, but it has nothing to do with what the layout of our site actually looks like right now. And the first thing we're gonna do is just turn off the list that we have here basically just because we want this to have a list style of none and the margin and padding of zero just to make it a little bit easier to manage. Now what we wanna do is we wanna set up a grid obviously, but let's come and look at sort of what we're after where I have three columns here. I have this big space here and then I have this area which is my regular, the actual list is over here. So what I'm thinking for this is to do something like this where we have my speaker's grid. Grid and so obviously we need to display grid on there and we want a gap of say one RAM just to create some spacing around stuff and I have my dev tools on so we can see the grid is there. And what we wanna do, and if you don't know how to do that just in your dev tools, you have a little grid thing, it's on all of the different browsers have some sort of feature like that these days. And then let's start off really simple where we can do a grid template columns of repeat and I'm just gonna do two columns of 1FR for now to create two separate columns that we can see. The reason I'm doing that to start with is just to show you sort of the basic idea of what I wanna do here and then we're gonna quickly level it up from there. So we're gonna do is we're gonna take this entire UL we're gonna move it over, we're gonna do that by just saying that it has a grid column of two over three. So what we're doing here is we're going from line number two all the way over to line number three here so it's positioning it within that column. Perfect, that's fine but I wanna move my images over to this one. That's where, how would we do that? Well, let's go and grab my images and you know what I'm gonna do? I'm actually gonna use some nesting in here. So if you're not used to nesting let's a little modern CSS. We said we're gonna do modern CSS and it's gonna make my life a little bit easier since I didn't put class names on anything. So if I save this, this works. This is just my parent selector. So it's my speaker grid UL is basically what that would become exactly the same selector I had before and then so I can also come here and then I can just say image and select all the images that are inside of my speaker's grid. Again, this is my parent selector here. They've removed the requirement of having that in your nesting but if I do that, oh look, Chrome has updated and we can do it this way now instead. Okay, I didn't realize Chrome had updated their nesting syntax to fit the finished version of it. So we can just do it like this with the little ampersand and it's a little bit cleaner. So we'll do it this way then. This is my UL that's in my speaker grid, my image that's in my speaker grid and actually just really fast before I position this if you want to use nesting, that's cool but it is not ready for production yet. Browser support is far from perfect. I'll put a link in the description just so you can get an idea of what it is. That's not to say you can't do everything I've done. I'm doing in this demo without nesting. Nesting is more just for dev experience than it is anything else. So everything here would work outside but I said modern CSS so we're gonna stick with it. So here let's do a grid column and this is what we can't do right now. I can't do a grid column of one over two because these aren't grid items. These are inside my UL and these are actually inside the line inside the A but I wanna pull them out and I wanna put them into this grid column. There is a way I can do that and it's by using a position of absolute on them. When I do that, it's still not gonna work. You can see they're still just, they're all stacking on top of each other. They're not going where I want them to and just to highlight that even more, let's come on here and do a left of zero and a top of zero and when I hit save they're going relative to the viewport itself. This grid column means nothing right now but we can change that by coming on the speaker's grid here and making this the containing block and we do that by saying this has a position of relative and now because the speaker grid is position relative these are position absolute. The speaker grid is the containing block. It's the nearest ancestor that has a position other than static. They are living, they're now being positioned relative to my speaker grid and because my speaker grid has the display grid on it they are living inside of that grid. Cool, right? And this is sort of part of the basis of what's going to make all of this work. You'll notice my grid changed color there and everything went onto one line. I was a little confused on why they, I had Miriam and then MC was on the next line under and I was confused about why and I just came here and made a small change and I had a space and I removed a space and I tried putting one. When I did that everything that was on multiple lines was no longer on multiple lines. I don't know. I guess it just needed a hard refresh once they pulled the images out of the flow. That's the only thing I can guess, but there we go, at least it's working. And yeah, so this is the idea that we wanna do there by positioning my images, position absolute. But obviously we need a bit more of a robust grid because I need to have my three columns, I need a space and then I have this on the side. So for me the easiest way to be able to do that is let's come here and we're gonna say that we're gonna have a column count and we're gonna do three and then we're gonna say a row count. We're gonna say five and that's just to match the idea here. I'm really basing it on this is my grid, right? So speaker grid, I'm thinking of the images. That's why we're gonna use those. And whenever I have grid, we have longer declarations. I find it easier just to come in with these types of things. And for more settings that we might wanna change, let's come in with a column size. And for now I'm gonna say a hundred pixels. We'll probably modify this in a little bit and let's say a row size as well and we'll say 50 pixels just because we sort of have that aspect ratio type thing going on over here. Let's jump back on over to here. Just so we can see how this is gonna get set up with our grid and I apologize it's my face that's on top. I was just the last one in the list but I don't like staring at myself but there we go, we'll get rid of that soon enough. So what we're gonna do is get rid of this grid template columns that I have right here and we're gonna replace it with this long declaration that we have right here. Where I'm using the repeat syntax for this part. So we're gonna say repeat and then my column count. So we have three columns that are gonna be my column size. So three columns of 100 pixels. Then I just put a 60 here. We could always come in with a better number and then a one FR. So if I hit save on that, it's not gonna look fantastic but we're gonna get this which is broken because I said columns count here instead of column count. So there we go. So we get one, two, three that are at 100 pixels each. Then we get a 60 pixel and then we get this 440 at the end and that one's gonna be the one that's a bit more adaptable depending on the screen space that we have available to it where if it runs out of space, it can kind of squish and grow a little bit. And now I wanna do the same thing for actually declaring some rows and we're not gonna see this quite yet. Sorry, when I, there we go, it's back. When you scroll, sometimes the grid preview thingy gets a little mucked up. But this one we're gonna do is we're gonna have an auto at the top end and this is where my main grid is going to be in the middle. So again, it's going, we're gonna have five. You know, this is the number five here. So we have repeating five times and then our row size is 50. Now it's a little bit mucked up right now and we're not really seeing it because everything is in that auto column at the beginning. And when I, oh, there it is. Now that I scrolled down, you can see we're getting our grid down there at the bottom with the rest of everything. We just need to get everything onto that grid properly. Now the reason I'm doing this auto at the beginning and the end here is because if we look at their grid, we have like some, you know, we have some space at the top and the bottom and I just wanna sort of keep that space as something that we can work around with and the auto should work really well with that because if this ends up being like, so they had a whole bunch of speakers, well, this would probably get longer, but whatever. If the images were taking up too much room, those autos could reach zero and then it wouldn't cause any issues along the way. So that will work for me. And then there's a few different ways that we could actually approach this, but these days I really like using line names. So I'm gonna add one more thing to make this declaration even longer, which is over here. I'm gonna call this one list start and then we're gonna come over here and do a list end because I want my list to live in that last column over here and we're also gonna come here. I'm gonna say that we have my list start over here because it's the lists on the rows, the list will start at the top and go all the way down to the bottom. And so over here, we're gonna say that this is my list end. And the cool thing with that is I can come here instead of doing a grid column or a grid row, I can actually say that this is a grid area now of list. And this is because when you use the list start, list end syntax, you can do a grid column of just list and it knows the start and end. It's using those as you're starting an ending points. And if you have grid rows and grid columns that have the same name, it's going to create an implicit grid area. So you can actually use the grid area and you can see it's showing up in that last section and it's covering that whole area, right? And the other advantage with this is, again, that idea that this list, let's just put a border on here, border of five pixels, solid lime so we can see it. I'm not worried about every one of these list items creating a separate row. Because as I said earlier, that would become a little bit of a nightmare on managing this other grid that we're gonna have here. And having these all connected is really important too because we need these images to be part of this and they're actually part of this link because when we hover over stuff, whether it's this or the image itself, we wanna have those hover effects coming in. So that's really gonna be easy to do because they're all part of the same link but we need to take a little bit of extra work here and just setting up this grid to work properly but this makes our life a lot easier by having sort of an outer grid and this list is just positioned where we need it to be and now we can get our images where we need them to be too. So we'll take off that border and now we'll worry about getting our images in the right spot. So here we don't wanna, we could do this where I could say my image, like suck my first image with an nth child and put it in my, you know, right here. And then the second one, then the third one, then the fourth, fifth, sixth, seventh, eighth, ninth but that's kind of annoying because every time you add a new speaker, then you have to position where they would be on the grid and that would be kind of annoying. And I think a little bit more interesting is selecting ranges. This is how they did it on theirs as they selected the ranges. They were using position absolute. We're gonna be setting them up on the grid while we're using position absolute too but they sort of use their magic numbers on the left and the top, I think, to position things correctly. We're just gonna be setting them up on our grid. So to select ranges, there's a few different interesting ways that we can do that. And so I'm gonna do, I'm gonna paste this in and we'll sort of explore this quickly. You'll see I'm taking my speaker's grid, then I'm selecting my list items and then I'm getting the images that are inside of those and I'm using the list items to count and that's because I can't count based on my images that are here. And the reason for that is my images are always the first and child one, right? Like it's the first image or I guess end of type. It's the first item. They're always the first thing because there's, you know, if I look at my speaker's grid, this wouldn't be an enthriled too because it's inside of this link which is inside of this LI. We're not reaching it. So I wanna look at my speaker's grid and then count based on my list items that are in there and then grab the image based on there. So this one is going to be our every third image. So we're starting with the first one and then doing one, two, three and it's grabbing that one. One, two, three and it's grabbing that one. So we're getting every third image. Then this is exactly the same thing but we're starting at the second image. So we're going here. We're going starting at the second one. Then we're doing one, two, three and we're getting Rachel. Then we're doing one, two, three. We're getting Julia. And then we're doing the same thing here but starting with the third one. So then it's a, we're starting here and then one, two, three and we're getting Mathias. One, two, three and we're getting Roelle. You get the idea. So it's at save and you can see we get some columns appearing. Now we can do the same for our rows, but our rows are a little bit trickier because we really need to get specific ranges of content. For these ones, I can just say every third, every third, every third, based on different starting points. We can't do that for the rows. We really need to say from this element to this element, but we can also do that with nth child. And so let's hit save here and you're gonna see everything sort of starts falling into place. We have a few little bit of issues with some overlap. We'll fix that in a second. But let me explain what I'm doing now and I should have a comment here. This is my first row, first row. And so what we're doing is we're using a negative n. And if you don't know how negative n works, it means we're sort of counting backwards. So we're going from the end and we're gonna go all the way to the third element. So we're basically saying like starting at the third one, let's go here, starting here, and we're gonna select everything backwards from there. So go from here and then go backwards and it selects those three. So these three are gonna go across the top. Perfect. Then we want this next three here. So we can use that same trick, but we're gonna create something that's a little bit different because we're gonna say start at the fourth one. So we're gonna say start one, two, three, four. So start at Josh. And then here we're saying go to the sixth one and start counting backwards. So it's gonna go to Mathias here and it's gonna do Mathias, Rachel and Josh because these are the only three that are within this sort of range that we've created between these two right here. They're gonna do the same thing. We're gonna go from the seventh one to the ninth one, from the 10th one to the 12th one, from the 13th one to the 16th one. Then we're just setting up the grid rows that each one of these needs to be on. We'll hit save or we already had hit save. So they're all showing up in the right spot. We need them to look a little bit better. So let's come back up to style those images. I don't think we necessarily need this, but I'm gonna say the width is 100% just to make sure nothing weird happens. The height is 100%, which will squish them. And then we can do an object fit of cover. And then it's going to do that. Now one thing this isn't doing, if you look at their original one, it was much more zoomed in on just the eyes of the image. And then when you go on top, it's sort of zooming out. And I have a feeling there's a bit of custom stuff going in just because if we look here at Julia, notice how it follows her eyes, even though her eyes are off center a little bit. So I'm wondering if they custom did it. I didn't look at their specific one, but they really made sure to be in on their eyes. So I'm not quite as zoomed in in a sense. And what we could do is you could go on each one within not position, but an object position. You can move them around. Let's just say, I don't know, 25 pixels. You see it moves the item around. I think this would be really hard to get correct. And I don't think there's a way to like zoom in more. We'd have to play with the aspect ratios and other stuff. So it's gonna be a little bit different from how they got theirs because there's a set up as a background image. They could just do background size and make the image a lot bigger. But I think the end result is going to get us close enough. And if we look at theirs, they also have those the border radius on it. So we can come in at a border radius of, I don't know, 0.5 or something to give us some round corners. Let's turn off that grid and you can see it's looking pretty good. And we're almost there. We have this one last sort of step that we need to do where we want it when we hover on top of one of them, we're highlighting the name and we're highlighting the speaker. And it's actually really easy to do. So let's come in here. We're gonna stick with inside our speaker grid. We have our UL, we have our image. We'll go in between the two and we'll choose our A. And I'm gonna say is hover and focus. Just we get both the hover and the focus states here. And let's just come in. So the link will get a background color. I have some variables set up. So let's just do a primary 400. And I think I need my CLR in the front there. So if I save there, since we get, it's highlighting the one that we're on top of, but that should work here too. So that's magical in my opinion. This is really the cool part of it because the image is inside of that link when we hover on top, we're getting it to highlight the right person along the way. I find that just really neat and really cool. And that's sort of why I wanted to tackle this was to figure out how they did this part. And I think that's really neat. If you haven't seen is before, this is the same as doing like a hover and doing a separate a focus, but we're just combining it together using the is there. Cool. Obviously we can have that little decorational thing that would fill in the middle, but I think that's looking pretty good. And then using nesting once again, we can come in here and select the image that is inside the link. So when we hover on them, I guess we want them to get bigger. So we can say the scale is two and scale is its own property now. So we can do that. And let's just say the width is, I don't know, a hundred pixels. The height is 100 pixels. And let's just see what that looks like. So if I hover on top, it's working. Cool. Now we're gonna have a little bit of an issue, but we're gonna see how we can fix it too. Obviously there's a Zed index issue. So let's come here and do Zed index of two. So when we do that, they should always be on top at least. So that's a good thing. But there's a problem because what we're gonna wanna do on these images, I think lower down, yeah, right here is the regular image. It's kind of weird. I'm gonna move this after my image, just because of the way the nesting is working there. I find it weird having my regular image than the hover image. Just doesn't work for me. So we're gonna come here and we can say transition of, I guess we're gonna do everything. So let's just say 500 milliseconds for now and see what it looks like. Cool. The problem now is when we, soon I'm on that, I'm gonna come off the, like Roelle's image here. Like I'm following Julia, as soon as they come off, Roelle's comes in front again. And that's because we're only getting this Zed index while the hover is happening. We're not having the Zed index when we're off the hover. And that's kind of annoying. It's not a big deal, I guess, at the end of the day, but you see how like there, you see as we come off, that other image is popping in front. So there is a trick to fix that. And I'm gonna come down here and we're gonna say at keyframes and these keyframes we're gonna do is, let's just call it Zed index hack. I'm gonna say 0%, 99%, Zed index is going to be a one. And so the reason I'm putting that on there is, and I'm not putting 100%, I guess it could even go to 100% because of how I'm doing this. We'll try with 100 and if we have to, we'll knock it down to 99. But basically I want my images to get a Zed index of one when we're not hovering on them. We want it to be on our images. I'm just gonna come after this A. I'm gonna do this where it's A, not hover comma focus. And then here we're gonna say our images. So an image that's inside a link that's not being hovered or focused, and this is gonna be weird and I'll explain it in a second. We're gonna say animation is my Zed index hack and we'll say 500 milliseconds. We could, I guess, make a custom property there because we're using that 500 milliseconds in a few spots, but I'm just matching the transition timing I have. So now let's go on Rachel Andrew here. And when I go off, notice how she's staying in front of Julia. Let's turn this off for a second. We'll come here just to remember that when I'm on Rachel and when I go off, she was like this image of Julia that's right underneath there. When we go off, she was falling behind it as soon as we started zooming out. It's happening with the image of Mathias as well that's next to her. So we get this weird little glitch going on and this solves that from happening because we have it there and then when we come off, you see it's always staying in front and this is gonna work for every one of the images. The reason this is working and it's kinda weird is I'm doing, as soon as we have the Zed index, it's going in front because normally my images don't have any Zed indexes on them. There's nothing. So when we're hovering, we're going Zed index two, so it's coming in front because when we didn't have that Zed index two, if you remember it just goes behind everything and it's really, really awkward. So we said Zed index two to make sure that it's in front of everything when we're hovering on it. But when we let go, it's going back to its natural order of everything. We don't want that to happen. We want it to stay in front, but not like, actually we could probably get away with this also being a two and you'd be okay. Let's just see. Oh, see there because you'd get this potential problem going on because they're both in that hover state. They're both within that 500 milliseconds. We run into an issue. So we do want that to be a one. We want this number lower than that one. So as soon as I have run a new image, that one Zed index is higher as the other one is moving backwards again. And the real trick here is we're not doing a forwards or anything like that. So once this animation is finished, we're going from zero to 100% with a Zed index of one. And as soon as that animation is done, the Zed index is no longer being applied to that anymore. So we have the hover, then we're not hovering. So as soon as we stop hovering, we enter this world where we add that animation on, as soon as that animation is done, after 500 milliseconds, it loses its Zed index and it falls back into the regular world of everything else again. And so yeah, I think it works really well. If you go really too fast, maybe every now and then you catch a glitch. Obviously it's not exactly the same because we're not so zoomed in on the eyes. But just like playing with the scale by using object fit, I think it works out pretty well on the overall thing. We can play around with the sizing of everything here too, the width and the height plus the scale. Obviously, oh, I have a max width on my images just because down lower I have a reset. So you could always do a max width of the same size or something else, just to make sure if you wanted them to go beyond their actual max width, plus you have to take into account the scale here. Of course, you could just make this an obscenely large number like 100 VW, just to get rid of the max width you had on there if ever you need your images to be really big. But yeah, I think, you know, play around with it. And obviously the width and height here is getting doubled. So just take that into account too. But I think it works out pretty well. It's again, not exactly the same, but pretty close. And so I hope you like this effect too. I hope you learned a couple of things along the way. I think it's a lot of fun. Obviously we'd want to do some improvements here as well just with the colors right now. And I think my background color plus my text color here is probably not as high contrast as it should be. I didn't put any alts on the images though. I'm not sure if I need to, just because the name of the person is here and then this is here and the images are sort of decorational. So I'm not 100% sure if we'd actually need to have alts on there. They're sort of decorational to me since this is giving the context of what the image is. So I don't, yeah, I think maybe leaving those as empty would actually be fine. If you have any opinions on that, please do let me know down below. And if you enjoyed this video, you would probably really enjoy this one that is right here as well. And with that, I would like to thank my enablers of awesome Andrew, Simon, Tim and Johnny, as well as all my other patrons for their monthly support. And of course, until next time, don't forget to make your corner of the internet just a little bit more awesome.