Check out a free preview of the full Sass Fundamentals course:
The "Challenge 2: Solution" Lesson is part of the full, Sass Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Mike walks through the solution to Challenge 2 and takes questions from students.

Get Unlimited Access Now

Transcript from the "Challenge 2: Solution" Lesson

[00:00:00]
>> Mike North: So we're gonna go though the solution to this exercise. But first, we had a question online about what I'm using to test my CSS. So I'm gonna show you what exactly how I'm testing the CSS and then show you a real way of testing CSS that is not specifically oriented towards a workshop.

[00:00:25] So what I'm doing is, if I get rid of this, give myself some room, I'm doing two things and really only one of them is interesting. But the first thing I do here in my test, if you look at the tests.js file In your public folder and you're familiar with JavaScript, you'll see that oftentimes, I'll just end up calling this hasStyle function.

[00:00:57] So I'll take you where that hasStyle function is defined.
>> Mike North: It's here, I believe. Nope.
>> Mike North: There we go. This looks right. Here's my assert.
>> Mike North: I'm sorry. I'm jumping around here. It's in the root folder of the project in Public, js. And then tester and utils. So in tester, you see here is this assert that I'm using.

[00:01:31] And when I check.
>> Mike North: When I look at hasStyle, this basically goes amd fetches and element in the HTML. And then if nothing is found, I throw, right? Throwing is gonna be what indicates that there's a failure of some sort, right? So there's that throw.
>> Mike North: And then I use this function that's available on window called getComputedStyle.

[00:01:57] What this is gonna return is an object that looks like a completely exhaustive style declaration, with like every property possible to specify on an element. So you're gonna have everything from text decoration, to opacity, to font size, and I can iterate over those. And basically, on a property by property basis, assert that the important things I wanna check for have the values that I want to check.

[00:02:25] Now one down side of this is that things kind of get boiled down to, sometimes they get boiled down to values that look a different from what we specify in our style sheets. Which is why occasionally in these test failures, you're seeing RGB colors like I expected this RGB color.

[00:02:43] Like ultimately, that's the value that these things end up getting, even though we might have defined it using a hex color value. But I have no control over how it eventually gets resolved. But getComputedStyle is a great way of figuring out ultimately, on the screen, what's the style of this thing?

[00:03:03] After all the classes have been defined and everything comes out, what does it end up being? So then when I run through and I test everything, which I think is
>> Mike North: Down here. So I basically run those assertions one by one. And if they throw, I call unfail, which is gonna add an error message to the screen.

[00:03:32] So I kind of built this just for the workshop, you wouldn't wanna do this as a way of testing that your CSS is what you want it to be. Because it's a little bit too much like asserting that things are as you set them, right? Imagine if you had to say I set this variable equal to 15 and now I'm gonna assert that it equals 15 in a test like.

[00:03:58] There is really now a lot of value there. I'm gonna saw you something that is a step up. And this is company called Percy. They integrate with GitHub and provide you with image based diff testing. So what we're seeing here is like screenshots of a page. And when you run through your integration tests and your unit tests, like Travis CI or CircleCI, something like this, what it will do is it'll keep track of screenshots of the most recently applied, like most recently approved build.

[00:04:33] And if there is a per pixel difference as you take screen shots for the next build, which it does using an automated tool, that's like a headless version of Firefox. It actually like sends HTML over wire, like over the network, which is then rendered in Firefox, in their cloud.

[00:04:53] You can see here, we've got like red highlights where things have changed. You could even specify like certain selectors. Like take a screenshot of this box here, so you can like cut out the navbar so that's not gonna trigger changes on all of your screenshots. And ultimately, you can have maybe a product donor come in here and they just have to give a manual thumbs up saying like, yes these differences in the way the screens look, that is intended, that is approved.

[00:05:21] And then that actually integrates with the approval system in GitHub. Just like your test passes and fails. So if you hook this up with like a CD pipeline, continuous deployment pipeline, It can end up being a sign off, just clicking a button saying yes, this looks good, that results in your new app being sent to production, right?

[00:05:42] So I like this way of testing your styles better. It's sort of a bottom line thing, where if you change some colors, it would pop up. But you don't have to get into the granular nuts and bolts of each and every rule of your styles and each and every possible combination.

[00:05:59] Like asserting that those are what they are. Now this is something that you can't run locally very easily. It's also not free.
>> Mike North: So it's not really appropriate for the kind of exercises that we're going through. But the rumor that we can't test CSS is false. And image based testing is sort of the way to go about it as far as I know, right?

[00:06:23] This is what, in particular. My computer went to sleep, sorry. In particular, this is what like newspaper sites do. I know BBC has an open source library called Wraith that does something very similar to this. Where they're very sensitive to making sure that layouts of particular articles, because essentially, they have very dynamic content with.

[00:06:46] Their layouts are not fixed. And so they have a couple representative articles of several types and they just make sure that all their CSS works there. So that's the low down on testing CSS. It's sort of a new idea. Like we obviously know we would love to have test coverage around this area.

[00:07:04] But it is not well understood what the best practices are. This has worked well for me in enterprise apps and in tiny little startup apps and in my own little training web sites. I tend to use Parsey, just because it plugs in really easily.
>> Mike North: So with that, let's go through the solution to this.

[00:07:28] So what we were looking for, just as a reminder, is If we open up the exercise here. Let me make sure I'm still running it. And I am. So if we look in the parent folder, in our exercises folder, and look at the HTML, we'll see that what we have is a container with right nav applied to it, right?

[00:07:48] And we know that what we want is, for the sidebar, when we have right nav applied, to go to the right side. And the main content should come over to the left. So we're going to open up this source folder, app.scss. What we have here is the styles that are required for what we're looking at on our screen right now.

[00:08:09] And we are going to extend them so that the right nav does what we want it to do.
>> Mike North: So the first thing I'm going to do is I want to put right nav kind of at the bottom of my styles. This is a decorator class, right? This is, when we talk about bem, this would be a modifier.

[00:08:26] It's a flag that changes the way this block behaves. And we want it at the bottom, because we want to make sure that It is overwriting some of the default styles. Now it's overwriting the default styles anyway because we have another class added to it, which is gonna be right-nav

[00:08:49]
>> Mike North: But to me, it makes a little bit more sense to also have it below so that it's very clear. Even if you're reading it from top to bottom, you can get an idea of what this thing should do in general. And then you go down and you see, here are the different modes.

[00:09:05] Here's the mobile specific stuff and the right align stuff. And you're sort of easier on your colleague developers by doing this. So inside the right-nav, what we're going to end up doing is defining some of these same classes here, but in the context of right-nav being applied to the container.

[00:09:25] So we're gonna probably end up with a sidebar and a main in here somewhere.
>> Mike North: So currently, the side bar is 200 pixels while we're gonna keep that, right? And when right-nav is applied, we want it to float right.
>> Mike North: And now we'll see that it is overlapping on top of main content.

[00:09:49] If we were to inspect element, we can see that.
>> Mike North: It's over here, it's shrunken way down, It's all up in main element's business there. So we're gonna wanna undo some of the stuff up here that was done to make room for the side bar. For one, this margin left is not what we're looking for here.

[00:10:11] In fact, we're probably gonna want the exact same thing on the right side and from margin left to be 0. So did anyone notice that I've got these little stacks of things popping up to the left of my CSS style declarations? These are CSS triggers. This is a nice little visual studio code plugin.

[00:10:33] Let me make a little room for myself here so that we can show it on the screen more easily.
>> Mike North: So there are three things you need to worry about in terms of like the cost of a style declaration. And that is whether one or two or three of three things potentially needs to be updated as a result of applying this style.

[00:11:00] One of them is composite, one of them is paint, and one of them is layout. So an example of something that would affect layout is changing things that have to do with the box model of an element, right? It's width, height, padding, margin, something like that. Box shadow, right?

[00:11:18] And so in this case, margin right is definitely going to require layout. And so when we think about like reflowing, right? These are CSS things that when you apply them, things are gonna sort of potentially end up juggling around the screen a little bit. That is costly. That is asking the browser's layout engine to do some work.

[00:11:39] And it's not cheap work. Painting is relatively cheap. And that would be like changing the color of something. So if we go up here and we look at background here, this one is saying that it only require composite and paint, right? Background color could not change the organization of our elements on the screen.

[00:11:59] So you can see that the purple item here, which represents the layout, we don't have to pay that price for background.
>> Mike North: Compositing has to do with taking multiple layers of CSS and kind of figuring out what goes on top of what. So oftentimes, you can't get away from compositing.

[00:12:21] That's sort of the lowest level price that you have to pay, if that makes sense. And let me see if I can get one that just does compositing. I'm just taking a guess here.
>> Mike North: Yep, there you go. Opacity. Opacity is not changing any colors, right? So we don't have to like figure out that ff6631 is equal to what color and let's redraw that on the screen.

[00:12:47] But we have some intermediate layers in memory and the browser and we're gonna need to figure out how those things blend together. So those are those three layers. Compositing is sort of blending of things together. Painting is redrawing certain areas because you've changed those intermediate layers that get composited.

[00:13:07] One or more of them has, It needs an update because you've changed something about it that's going to mean we need to do something new there. And then finally, the most expensive is layout. And that really, the expensive work there is we have to recalculate the size of many things and figure out how they should all fit onto a screen of that particular width, right?

[00:13:28] This is very expensive. This is like much more expensive than either of the other two. So although oftentimes, you can't really get away with, there's not too much you can do with this information. One thing that we could see here, though, is if we had to choose between opacity and then changing the color to something like this.

[00:13:56]
>> Mike North: Right, like if we added an alpha channel to a color versus change the opacity, we can see that one's a little bit cheaper than the other. So this is getting into some really granular optimization stuff here.
>> Mike North: All right. Now, I promise I'm actually going through the solution here.

[00:14:15] It was a useful tangent. [LAUGH] So we're floating.
>> Mike North: So we've got margin auto here, we've got margin right of 220 pixels on main content. Margin left should be 0 for main. And now, we can see we're already looking pretty good. We've got our side bar on our right, we've got main content on the left.

[00:14:37] Those look like they're about level in terms of where those headings are. So it looks like the padding is not something I'm going to have to deal with. I will have to mess with the border a little bit here on the main element and move that border to the right and set border-left equal to none.

[00:14:59] And we should be good to go. And so now, if I go back to my HTML, remove right-nav and reapply it. So we've built a nice, lightweight little decorator class there that lets us toggle between two different layouts just by applying this secondary class that's acting like a flag.

[00:15:18] If we go and look at the CCS that was generated her. Let me get rid of my sidebar so we can see better. You can see that a lot of this is broadly used and these are just the two extra rules that were built for me. And now, we kind of get this two different states of the container represented in as concise a way as you could possibly get where you are writing from old CSS.

[00:15:45] But in our SaaS file, It's very clear that this concept of right-nav, it's sort of a property, it's a mode that this container can go into, right? It belongs in the context of that container.