 Welcome to another episode of GUI Challenges where I build interfaces my way and then challenge you to do it your way, because with our creative minds, combined, we'll find multiple ways to solve these interfaces and explore the diversity of our skills. And today we're building this little comparison cider, look at how fun this is. It totally scales with the viewport, it works across all devices, you can use your keyboard, and it's just a few lines of code. So we're going to build this one live. Let's get started. Did the debugging corner. All right. So let's check it out across all the different browsers. Just make sure that what we're building is working across all of the places and ways that our visitor might be trying out our experience. And so here we have an iPad. I've updated all my simulators. Everything's looking good. I can grab the thumbnail and move it back and forth. I can click on either side, Firefox, either side, grab that thumbnail, go back and forth, click it on the either side. I think that's pretty nice being able to click around here. It is an iOS and on Android. Let me get that thumbnail. Yeah, go back and forth. Everything is great. And of course we saw it already working inside a Chrome. All right. So I want to build this one live today. I think we can get it done in just, you know, 10 minutes or so. So hang with me. We're going to build this one from scratch and going from how I did the light and the dark theme all the way into having a mask that's being driven by an input type range. And let's go check it out. Let's write some code. I'm going to do this one inside a code pen today. And let's start with the HTML. Let's get ourselves something to do. So we're going to make a compare kind of widget. So we'll start it with a class name of compare to kind of names based off. We'll even base all of our styles off of that selector and nest them. So kind of all stays contained. It'll be nice. Okay. And inside of here, we're going to have two sections that we need to compare. I'm going to call them like before and section after, if I can, you know, type or whatever after there we go. And inside of each of these, just put something for now. So here we'll do something. And then this one will be, you know, for now. Oh, Emmett, come on. Yeah, for now. And then down here, we're going to need an input type range. And those are the essential building blocks of what we're going to do. And let's move on to setting some styles in here. So I'll pull this up here. I'll make a compare selector. Notice I'm working inside of a layer here. This is nice because then I can put all my styles at the top and not worry about the cascade because this layer comes after this one. And so I have proper, like, well, it's also that it comes after, but it's also inside of it. So anything inside of here is going to win over these, which is just kind of a cool little trick. And then so for the light and the dark theme, this is it so far. It's just color scheme, dark light. And here, if I change it to light, I'll get the light theme. And if I specify dark and light, that's me saying, hey, this page is totally cool. It being light or dark. Just follow whatever the user's preferences are browser. And then what it also does additionally is gives you these system keywords that allow you to change the colors of stuff, which is super cool. And we'll get into that. All right. So we've got our compare selector and the compare selector is going to be display grid because we're going to make a grid pile. I don't know. I'm sure we've used it a ton of times in here. And a grid pile is like this. We're going to give all of the direct to children the same area. And now they're going to stack on top of each other. Look at that stacking on top of each other, stacking on top of each other. And that's one of the ways that you can get these things to compare back and forth is because they're on the same grid cell. They're on top of each other. And then what we're going to do is create a mask that kind of goes back and forth between them. And so let's target our sections next. And these are also going to be display grid. These are just display grid with place content center because we just want all the content to be in the center. And that's kind of optional. I mean, you can do something else. If you like, oh, it looks like I'm in Chrome. It hasn't quite got the new selector syntax yet for nesting where you can omit the the and or the, you know, preface like symbol here. So I'll just go ahead and put it in there anyway. It's probably a better idea. I put it in there anyway. Okay. So now everything's there. But we also have like you're kind of like hard to tell which is which. So let's go before we'll do like a linear gradient. We'll wait a sec. We'll do a background that's linear gradient. We'll go to right and we'll say hot pink to Rebecca purple. Excellent. Oh, yeah, that's hot. Okay. And then we'll say after. And this one is going to be, let's see, cyan to lime. Okay. So now when we pull these back and forth, we'll be able to really see the difference between those items that we have in there. So let's see, should we do the mask next or should we do the input type range? Let's let's style our input type range because that's looking, that's not like the demo that I showed, right? The demo didn't have a huge bar across the middle. You couldn't see the slider. You could see the thumbnail and the thumbnail was very vertical. So let's, let's figure out what, uh, and how, how I did that. So we're going to do input type, uh, let's me type equals range. And in here, we're going to say appearance, appearance is none. Excellent. It's background needs to go away. So background is none. Excellent. Uh, we're going to do cursor pointer on this. I think that's what I have. We can put that cursor pointer anywhere else we want. And then another thing, this is like a nice little set of polish years, WebKit tap highlight color to transparent. And that's because you noticed on mobile, when we were tapping around on the left and the right hand side to kind of move our slider, it wasn't flashing the whole page. Normally there's a tap highlight on there to kind of tell users that their interaction has been recognized by the browser. And I'm saying, you know, I don't, I don't want that. Why don't you go ahead and make that transparent and I'll take care of any, um, you know, UX feedback that's going on inside of here. Okay. And then we're going to target the kind of WebKit specific pseudo element with the WebKit slider thumb selector. You can find these in the dev tools. If you look, in fact, Firefox is very good at showing you the different parts of its, um, HTML elements. So I'd recommend you go check that out. It's pretty sweet. We can't group, um, the selectors either this WebKit slider thumb, like we can't do this and say, and, um, the Moz range them, I wish we could, um, but since one browser understands one and the other one doesn't understand the other, they kind of break. So we have to separate them. So I'll just kind of do that while I'm here. Yeah, Moz range them. I mean, I already typed it right here. We'll do appearance none. Oh, I'm copying and pasting too early. I should have just waited. But in here, we're going to say a width value that we like. I put four pixels. I mean, you can kind of change this to whatever you want. We want its height to be 100 dbh. We want it to span the height of the viewport, at least the height of the container. We might be able to get away with percentage, but for now, that's what I did. And here's where we can use one of the system colors. That's dynamic. I'm going to say background color is canvas text. And that's going to be the browser's text color. So see how this text color, I haven't specified that text color. That's just because we're in the dark theme, which has light text. If I switch to the light theme, this would be dark text. And that would mean also that this, well, here, let's just do it like what I've talked about. We can just see it. I switch to a light theme. The text goes dark canvas text switch to switches to a dark text color. And then the canvas value. So if you're wondering what canvas text is, there's also canvas and canvas will be the background of the HTML document. That's kind of handy too for different things. Okay. So we've got the WebKit slider thumb. It's styled. Look at that. It looks like a vertical range because a lot of these comparison things have like this vertical bar that you can see where the cutoff is between the mask. And so I'll pop in here. I'll do another one. So that way we have Firefox and Chrome and Safari all with a styled thumb on a slider. Everything's disappeared and gone. That's really nice. Okay. And so let's let's move forward. Let's make our first mask. So we're going to keep our background on there for now. And we're going to write mask. Now, if I'm just going to write mask, I need to go change this to use auto prefix or because otherwise I'm going to have to write the style twice. And I just don't feel like doing that right now. So I'm going to turn that on and let the, let the, um, the build tool of CodePen do that for me with auto prefixer. Okay. So now we need to make a gradient and it's so we're making a mask and the mask is an image. So this is shorthand. We could say mask image. We're going to pass a linear gradient. We're going to say to write again, because we kind of want to have a gradient that goes like show this area. Here's a line and then don't show anything after that. And so we're going to say to write, um, we're going to say, uh, the color of black, because black is going to be, um, the, the part that's showing. And then we're going to say, oh, let's just start at 50%. So this is the transition hint. And if you don't know what a transition hint, it's a sort of way to change the easing between two color stops. So since we're going to have two color stops at the top and the bottom, um, we're setting, this is the middle point and this middle point, it's going to eventually be going to be dynamic powered by JavaScript. And here we should see something. Okay, good. So we are correctly masking. Now it's not tied to our bar at all. And look, we lost our bar. And I think that's because all of a sudden we find ourselves in a Z index issue and there is our bar back. So now we're just sort of not relying on the DOM order to do our ordering, uh, in terms of like layering on top of each other. We're saying specifically we want the input type range to be Z index one, which is larger than any of the other ones. And therefore it goes on top. Okay. So now we see our comparison. We've got our value here 50%. We can pretty much copy this pasted over here and we're going to reverse it because we want the opposite effect. So now we've got transparent here and black over here. And there we have a split some now. That's fun. Uh, but we can see half of one and half of the other and kind of the last little part here is for us to tie it all up with JavaScript. Well, it's not the last little part. We're going to do a couple more things, but to do that, we're going to take our transition hint or color hint here and we're going to set it to a var of like position mask position. I don't know. You can name it whatever you want. We'll put 50% as a default in there. And the reason that I'm doing 50% as the default is because an input type range, the minimum is zero by default. The maximum is a hundred by default and the value by default is 50%. So it's already in the middle as like a 50 50 range split and I just kind of leaned into that and let it go. So we've got that input type range there. So we have our mask. We have, um, all of our different variables set up. I think we're ready to write a little bit of JavaScript. So we need to give our input a name or like an ID. And I'm going to say ID is range because I'm a really good at naming things, obviously, right? What's cool, though, is when you give things an ID, you can reference them directly from your JavaScript. You don't have to do a query selector or anything that you can only have one on the page. And so they're all rolled up and aggregated onto the window object and you just reference them. Anyway, I'm going to say on input. So whenever a value changes, I want you to call this function. And I'm going to set the document dot body dot style, uh, property. I'm going to set a custom property called position to range dot value. And now I think all we're almost there. So we have position, position. We're setting the range dot value. We're missing a percentage. So right now, like if we were to go look, uh, it's setting a value and it's being inserted into here, but it's not a percentage value. And that's what's expected in the type for, uh, input type range, a length percentage. So it could be a length, like a amount of pixels. But in this case, I want to use percentage. So I'm just going to, uh, concatenate. Well, I'm going to use single quotes, uh, the percentage symbol on there. So now when that custom property gets injected into this value here, it is a percentage and now we can scrub back and forth. Look at that. We're making progress. Okay. So our JavaScript is working. We've got this all working, but if you notice something, when we use the keyboard, can you see it kind of like, um, it snaps. Like it, look at it as I try to move it very minimally. It's very snappy. It's snapping. That's because the step value of an input type range is one by default. If I set this step to point one, I now get 10 more positions in between that one. And I'm no longer in that kind of really snappy position. I'm getting decimal values. And so it's much smoother. The trade off though, which I do think is worth mentioning here is the keyboard moves much slower. So if your repeat rate is kind of low, or even if it's kind of high, like my repeat rate on my keyboard is pretty high. That's not the best keyboard experience, but I suppose you could nudge it. Anyway, this step value is up to you if you want to smoothen this out. Or if you didn't mind it, where it was at the step value of one. Okay. And then in the demo, what I had is I didn't have gradients or text in there. I had content. So let's compare something cool. So I'm going to get rid of our background. Actually, let's leave the backgrounds there looking pretty cool. Let's just change our H ones. So I'm using pop lows, trans humans. These are like cyber punky, uh, trans artistic illustrations. And they're super cool. There's all sorts of great ones. And in the demo, I had one looking to the right, like this person is awesome. Jumping. Oh, that one's cool. And then one person looking to the left. So let's find one looking to the left, uh, that person's sweet. Oh, nice. Okay. So cube leg and jumping. I think I have those stash. So if I'm going to go to my code pen assets, uh, do I have jumping and robo leg? Oh, pondering. Let's let's do pondering just because it's there. Okay. So we'll copy as image. This one's looking to the right. We'll grab another one looking to the left and looking to the left, looking to the left, looking, oh, left, left, left. Ooh, there we go. Copy as image and paste. Okay. So I can already kind of see a little bit of an, uh, like an issue that's going on here, which is our images are too large. So we could say in our compare selector here, we can target any images. Oh, I'm going to have to make sure I specify the symbol here. And I'm going to say image, um, let's see max inline size is a hundred percent. That's a pretty classic one. Probably won't. Okay. That made some difference, but it's still too tall for this viewport. So I'm going to say max block size, a hundred dvh, which I think matches. Yeah. The height of our range thumb, except let's even shrink it up to 80 just so that it fits in there and has some spacing. Doesn't feel so cramped. Ah, there we go. Oh, and the gradient backgrounds are cool. Oh man, the original demo should have had some of those. That's sweet. Um, all right. Well, that pretty much concludes what we're building here today. We've got a all contained inside the compare class here. We're setting display grid piling all of the direct descendants on top of each other. So this is the slider, the before and the after elements. We're targeting the sections and saying, Hey, put your content in the center. There it is. Everything's in the center. We saw it work with texts. We're coming with images. All good. We've got our before selector. That's targeting just that one before section, the after section, giving them some styles. The trick with the masks was to invert the way that they're going. I could have actually, let's try this. If I go, let's use the exact same one. Oh, but see, okay. What I was thinking, well, let's just do it anyway. I could go to left and leave the rest of these styles pretty much the same and get the same effect. Oh, not the same effect. Oh, that's because of the root of where the image is starting. Oh, that is cool though. Actually, it's like sliding doors. Needed sound effects. Didn't it? It's kind of a trippy effect. Okay, let's go back to where it was. I was wrong. You can't just flip those. Oh, I got to undo again to write. Yes. There we go. So we stacked these images on top of each other. We reversed the way that the mask position is working. So the mask is setting a transition hint that's allowing us to target one value, move them back and forth. The zeros at the end of here set the start to the beginning of the gradient and this one to the beginning of the gradient, which is a great way to make hard stop gradients. And this transition hint is making sure that there's space in between both of these. So it's kind of a cool little trick. I like it. I obviously use it a lot and showed up really nicely here in this mask. Then we styled the input type range. We basically stripped it of everything that it has. We gave it a little bit of some interaction customizations and we styled the thumb to just look like a line. And the rest of it all comes for free with the input element. We wrote a little bit of JavaScript to set a custom property. We could have set the custom property on the compare element with a little selector, maybe even an ID, but I was lazy and put it on the body. All good. You can name those custom properties, whatever you want. And that is how you make yourself a nice little comparison widget. So I hope you liked this GUI challenge and stay tuned for more. I'll see you around though on the next one. Take care, y'all.