Check out a free preview of the full Professional CSS: Build a Website from Scratch course
The "Wrappers & Containers" Lesson is part of the full, Professional CSS: Build a Website from Scratch course featured in this preview video. Here's what you'd learn in this lesson:
Kevin discusses layouts and introduces the idea of creating a wrapper or container to limit the width of content. He demonstrates how to add a wrapper and explores different approaches for creating modifiers for the wrapper. He also discusses the advantages and disadvantages of each approach and provides examples of how to implement them.
Transcript from the "Wrappers & Containers" Lesson
[00:00:00]
>> Kevin Powell: Next up, we wanna start talking about layout a little bit. And I mentioned that I wanna start doing it from sort of a big picture point of view and then working our way down a little bit. So for me, a big picture point of view is creating some sort of wrapper or container.
[00:00:13]
I'm gonna talk about the naming of them in a second, but I'm just gonna full screen this right now. This we can see the content right now is stretching from one side of the page to the other, which we definitely don't wanna happen. In most designs you get, there'll always be some sort of limitation on the total width of things, and so this is a very common design pattern to end up.
[00:00:36]
I'll just put that here. To have your containers or your wrappers, I didn't put any in when I was going through things. Again, if you did already, that's awesome. But all the way up at the top here, where I have my site-header, I do wanna limit the width of those.
[00:00:52]
So in the site-header, I could just come in. There's two ways of doing this. If you did it like I did, where you did everything already, you can actually select within VS Code, everything there. If you're on Windows, it'd be Ctrl + Shift key, you're on Mac, CMD + Shift key, and you hit wrap, and it gives you a wrap with emit option.
[00:01:12]
And once you've select that, I'm just gonna push Enter or Return on my keyboard. And then I can do .wrapper and hit Enter, and it wraps the whole thing. So my starting wrapper is there and the ending one is there. If you don't like using that, we can just manually do it, I'll probably do that for the next sections.
[00:01:30]
But we do wanna have this, or as I keep saying, wrapper or container, because the really common name for these is container. The common but not as common is wrapper. I used to use container all the time. Every time I did it, it was just the name I liked, and wrapper was used as well, but I like container.
[00:01:50]
And then we got container queries in CSS, and I find having a container query and then having a class that's container that has nothing to do with container queries. Potentially confusing. So that's why I switched and started calling them wrapper. But again, the naming convention for those is completely up to you.
[00:02:09]
So inside my hero, once again, we can come in and I'm just gonna do it this way. Instead, I can do a wrapper, grab that closing div, and just drag it down to where I want it to go instead of using the shortcut. It doesn't really matter how you go through, whether you're using the shortcut to wrap things or we're doing it this way, .wrapper, hit Tab, grab that one here.
[00:02:34]
It's a little bit hard when you're dragging to know where you want it to end, you're just looking for those closed sections. This is also specific to this design, just before we go through it, because in this design, we have these alternating background colors. If you don't have alternating background colors like this, then you might be able to get away with one single one and put all the sections inside of it.
[00:02:52]
So it really depends project to project on how you're gonna have to organize this. But because we do have the alternating background colors where we need the background to stretch the whole size, this is the easy way to do it. There are some interesting CSS tricks where you could actually get background colors to bleed outside of wrappers, but I don't wanna get into doing that.
[00:03:12]
It's kind of weird and you might come across it in the future, actually. And people might not understand what's actually happening, or you won't understand your own code cuz it's kind of strange how it works. So I like keeping things simple. There's also ways of doing this with grid.
[00:03:31]
We have a grid set on your body and then the contents being placed inside of it. It's a pattern that I actually kind of like, but on a project of this size, I'd like just coming in and making sure I have these, even if it's a little bit tedious to add them after the fact.
[00:03:45]
I'm not gonna put one in my footer. You could put one, but our content is so small. Maybe I'll regret it and I'll have to add one later, but I think I'm gonna leave mine like that for now. And then we can come up to my styles and we need to decide where we're gonna put it.
[00:03:59]
And if you're using layers, I'm just gonna collapse the ones we have, we created our reset, our base. We have utilities and you have to decide where you think something like wrapper should go. I personally like having a layout. The idea of putting it in the base makes sense to me just cuz it is something that's sort of generic general.
[00:04:20]
So if you're throwing it in there, I think it's fine. Oops, I did layout. I do this all the time, and then can't figure out why my CSS is broken. It's layer layout. The reason I like doing it this way, my layout classes are gonna be very generic ones.
[00:04:41]
It's not gonna be a specific layout for, say, the bento grid, we do the bento grid. No, I'll probably make that a component. But I just like separating away from the base just because it sort of gives me more things to organize things in, and it makes it easier for me to find something.
[00:04:57]
I know if it's very generic, it's styling my element selectors, it's probably in the base. If it has to do with layout in any way or generic layout, it's in my layout one. Again, if it's a utility, it goes in my utilities and so on. But the way I'm setting up my layers is definitely not the way you necessarily have to set them up, I just wanna make that really clear.
[00:05:17]
.wrapper or .container, and we have to decide how we're going to do this as well, because as I mentioned, we have three different ones, right, actually better. Let's go back to the course website for a second, just because here I took a picture with some lines on it to show us that we have variations of it.
[00:05:36]
So we have to decide how we're gonna create the variations of it and which one ideally. If you do have variations, you probably have a default one, and then the variations based off of the default one. So you have to decide which one the default is. I tend to choose sort of with my colors, where I like having a middle and then things that get lighter and darker, or font sizes that go up and down.
[00:05:57]
I tend to do the same thing with my layouts, where I choose the middle one as sort of the default. Again, it depends on the project, but it could be the most commonly used one as well, again, looking across all the pages. So it depends project to project a little bit on that front, but I'm gonna choose this top one as my default wrapper, and then we can modify them for these two that are right here.
[00:06:21]
The other fun part is figuring out how big it should actually be, cuz there is a bit of a problem in getting sizes from Figma. So I can just click into these and I can see it. And again, my UI is super small, but on the right side, you should see what the actual width is of that element.
[00:06:38]
And so that sort of can inform you on what the size is gonna be, but we'll see what the problem with doing that is. So in this case, I'm gonna do a max-width of 1130, whoops, that's Num Lock is off, 1130, which is the size from the Figma.
[00:06:57]
That's the width, it might be 31 or something, I'm gonna round it off a bit. If we do that, we need a margin, and I'm gonna use the logical property. I talked a little bit about it before, but a margin-inline of auto. The nice thing with margin-inline, it's the inline axis, so it's your left to right axis, and it's not gonna touch the top and bottom ones.
[00:07:16]
Sometimes you'll see just a regular margin: 0 auto, just cuz we don't wanna touch the top and bottom ones. So we're just saying it's 0. It was already 0. And potentially, you could run into a time where you have a utility or something else where you actually need to add margin on one of them.
[00:07:36]
And then if you add a margin shorthand, it overwrites this, it causes problems. So I only want a margin on the left and right, so I like doing the margin-inline. It's a nice quality of life thing I find as a developer. And the last thing is, at small screen sizes, it's still stuck to the side of the page, which I don't want it to be stuck to.
[00:07:58]
So I would generally look at the Figma file. Go over to the mobile version of it, and just get the space that's coming between these. Again, generally, you could either do math, get the width of the big one, get the width of the small one. You could draw a box, sometimes the design will actually be provided, but I'll just let you know this time.
[00:08:20]
And I'm gonna do padding-inline, cuz again, I want this only on the left and the right. It's 16 pixels, I'm gonna 1rem. If you prefer pixels, you can definitely do 16 pixels, it's not gonna cause a big issue one way or the other. I've just gotten so accustomed to using rem, I use them for everything.
[00:08:38]
But if you prefer pixels for spacing and other things like that, when people zoom in out, the pixel gets modified anyway. So the difference between the two in this case is gonna be very, very small. There's a few edge cases where you might see a few differences, but that should work.
[00:08:53]
We can see now I have a bit of space around the sides, and if I did this properly, when I go larger, here we go. We're holding your content. We're wrapping our content, we're preventing it from getting too big. So that's off to a decent start. Nothing amazing, but a nice simple win.
[00:09:10]
I wanna talk about the problem with the max-width here. This max-width is based on exactly the max-width that I grabbed from the Figma file. When I came to here and I got the width of this area, which if I double-click enough, there we go, that'd be 1130 pixels wide.
[00:09:30]
The problem now is when I added this padding-inline, it's actually because we did the box sizing change in our reset. That 1130 is 16 pixels smaller on each side now, we've actually reduced that total space. This is one of the problems in getting sizes out of Figma. If it's a width or a max-width that you're getting from something, you do have to be careful about the width of the element plus how the padding is interacting with it.
[00:09:55]
In a lot of cases, you're gonna be completely fine. If it's an isolated component, you probably not even getting the width of it anyway. But in a case like this, [LAUGH] this is something I've recently started doing, is actually saying that the box-sizing of this one thing is content-box.
[00:10:14]
And resetting this one thing back to what the default was. I don't do this on personal projects or things that aren't based specifically on a Figm file, but I've run into enough things in Figma where I grab the size of it. And then when I get to here, my line breaks are all messed up, or the width isn't matching exactly what I thought it would be.
[00:10:30]
And it's just because of the padding reducing the actual max-width, the content is a little bit narrow. And with 1rem, you won't see it too much, but if you go up to 2, or you have bigger padding on the sides, you see it more and more. There's definitely other ways of accomplishing this.
[00:10:44]
You can actually do a calc here to bring the padding back into the total size. If you prefer that, you could definitely do it with that approach, but I don't know. This works and it's simple, so I tend to do that. If you do it, and this is something you're gonna be working on, you might wanna put a comment here about why you're actually doing it, cuz it might be kinda weird to see it.
[00:11:07]
This is not conventional, you will not see a lot of people doing this. But when working with Figma files, every now and then, I found that it can actually be useful to do it. But yeah, just really fast, if you'd prefer the other one, you could do a calc, and it's + 2rem, or the pixel value, or whatever.
[00:11:26]
You do need to double whatever this value is because it's 16 on each side or 1rem on each side. So it's either something like that or something like this, you can choose which one you'd prefer to use. I don't know, the math here, I don't think we really need it, but if you prefer that approach, there's no problems with it at all.
[00:11:49]
>> Kevin Powell: There's another way we could actually do this without doing it this way, that just uses a width and uses a min function, and you could definitely go down that route as well. I like it, but just for simplicity, this works really well. I think this type of approach is a nice way to go, but it does leave us with the question of how we can make modifiers from here.
[00:12:10]
And so one option is we have our wrapper-wide. This would be the demo way of doing it, wide. And then you have a wrapper--narrow, let's say, something like that. Oops, this is probably the most common way people create modifiers. If you haven't seen Bem before and you're wondering why I'm doing double hyphen, the Bem approach, the double hyphen, is just to say that we're taking this and then making a slight change or tweak to it.
[00:12:43]
So we change the max-width either to be bigger or smaller. This is probably the most common way that I see people do things. So if this is how you prefer working, 100% go that way. I'm gonna offer up an alternative and I'll let you decide which one you like better.
[00:12:59]
And the alternative is to instead use the data attribute, which looks kind of weird if you've never seen it before, equals, let's say, y. And doing it that way, and people will be like, why would you do a modifier with a data attribute? It looks kinda strange, it's not something we're used to seeing.
[00:13:19]
I agree, it does raise the specificity as well, cuz now we have a class selector, plus we have an attribute selector. With the wrapper, it's maybe not the type of thing where you'd actually run into an issue with it. But with other things that have modifiers, like buttons, where you might actually be hooking into it with JavaScript to change the button, state.
[00:13:41]
Or change the way the button looks, or other things, data attributes or JavaScript are the best. And they're easier to deal with with classes, cuz sometimes you may have three classes, and then having to remove one of them or change only one of those. If you have data attributes, it's just a lot easier to work with.
[00:13:56]
And depending on what you think, but let's say this two column area needs to be wide. So you can have wrapper wrapper--wide, like that, which completely fine. If I did it with data attributes, I'm just gonna do it on multiple lines, and say, data-width = wide. I just find it's very clear what's happening.
[00:14:23]
So I have a wrapper and my wrapper has a width of wide. Again, it comes really down to personal preference. I know a lot of people don't like this, or it makes them feel icky or strange, probably cuz it's different. If that's the case, I would actually recommend that you try doing it for this project just because it's something different.
[00:14:40]
And whenever you come across different things that feel different or strange or that you shouldn't do them, it's worth experimenting with it and trying it. And then at the end, you'll be like, no, I still hate it, and that's fine. You just go back to using the regular modifiers after.
[00:14:51]
If you really don't wanna use this and you wanna use modifiers, that's completely fine. There is one last advantage to the data attributes, though, it allows us to use nesting. So I could do like this instead, with an ampersand, and we used a little bit of nesting with our media query before.
[00:15:10]
So let's just come here, max-width is, there we go. I think this one is 1330.
>> Kevin Powell: So, we could do it this way with the ampersand. And when you're using nesting in CSS, the ampersand is just a placeholder for the initial selector on the outside. So this would just be wrapper.data-width = wide, and this would work.
[00:15:37]
If you're using a preprocessor or a post-processor, something like Sass or post CSS, their nesting would allow you to do this, and that would work. In native CSS, this doesn't work. You can't put this here because the ampersand in native CSS is actually a live selector. It's a placeholder, but it's not getting compiled to anything.
[00:16:00]
So writing it this way would actually be the same thing as writing it like this. And that's just gibberish, it doesn't mean anything at all, cuz the browser doesn't know what this is, basically, the --wide. So one of the reasons I do like the data attributes as well is because I can nest them in this way.
[00:16:19]
And again, that's the equivalent of not nesting it, and this is the placeholder for my .wrapper there. One thing people don't like with the ampersand usually comes into the readability of it's a bit weird. You do get used to it, and because this is part of native CSS, if we come and take a look at that area where I have the wide one, which I think is this area in your DevTools.
[00:16:41]
It wasn't that one, I'll make this bigger in a second. I think I screwed up something. No, it's probably the section or this one.
>> Kevin Powell: I didn't save my file.
>> Kevin Powell: Wrapper, there's the wide one. Okay, so if I make this a bit bigger, you can actually see that the selector here is exactly the same selector I'm getting.
[00:17:08]
In the days of preprocessors, the compiled CSS would be different. You wouldn't be able to find that selector directly, it would change when it compiled. Here you can see the line of code that it's written on, and you can see exactly what the selector is. So it's a little bit up to you.
[00:17:23]
Again, if you don't like nesting, you don't have to nest it. If you don't like the data attribute on here, you don't have to use the data attribute. But for me, I'm really partial to this, and we're gonna see other use cases of creating modifiers like this that might convince you that it's not a bad idea.
[00:17:43]
>> Speaker 2: Hey, Kevin, since padding is being used with a rem unit, when a person has a larger default browser font, will they have a larger padding? And is that a problem?
>> Kevin Powell: Yes, so they would have a larger padding. In general, because I use rem everywhere, everything's scaling up.
[00:18:05]
And so if they've boosted things enough, I sort of want all of that scaling to happen together, which is why I tend to use rem for a lot of things. Not so much for the spacing down the sides, but say you're doing it with a gutter on a grid.
[00:18:18]
If all of a sudden all of the grid stuff is getting bigger, but the gap is still only 16 pixels, they're almost gonna look like they're touching. Whereas, if that gap is increasing in size as well, it just creates a bit more of a consistency. But it's definitely also one of those things that you probably wanna test and just see what actually happens.
[00:18:37]
And there's definitely arguments for both sides on that, and I've seen both, and they're both good. So I think, yeah, it's a hard one to have a definitive answer for.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops