Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Start a free Basic trial
to watch this video
There’s more to writing good CSS than simply knowing all the latest and greatest features and techniques. In this workshop, we'll cover best practices for making our CSS more efficient, maintainable, and scalable.
CSS Architecture
CSS Resets
Formatting CSS
Vendor Prefixes
Helpful Tools
-
0:00
[CSS Best Practices with Guil Hernandez]
-
0:04
[Guil Hernandez] Hi everyone, I'm Guil, one of the front end
-
0:06
design teachers here at Treehouse.
-
0:09
In this workshop we'll be covering CSS best practices.
-
0:13
These are methods we can use to make our CSS
-
0:15
more efficient, maintainable, and scaleable.
-
0:19
As we will soon find out, there is a lot more to writing good CSS
-
0:23
than simply knowing all the latest and greatest features and techniques.
-
0:28
Today's web sites and applications are larger than ever
-
0:31
and a lot hinges on the CSS architecture,
-
0:34
so CSS that is poorly thought out can be a strain on development in the long run.
-
0:42
In this workshop we will be covering topics such as
-
0:45
CSS architecture, classes versus IDs.
-
0:50
We'll also get into specificity in selectors,
-
0:54
and we'll then cover some CSS reset methods
-
0:58
along with ways to format our CSS and using vendor prefix.
-
1:04
Finally, we will get into some helpful tools
-
1:07
to help us write CSS with these best practices in mind.
-
1:12
When writing CSS our main goal should be that our CSS is
-
1:18
predictable, reuseable, maintainable, and scaleable.
-
1:24
So let's review these in detail.
-
1:28
CSS rules that are predictable should behave as we expect them to.
-
1:34
If we need to update or add any new CSS rules
-
1:38
they shouldn't affect other parts of our site.
-
1:41
Reuseable CSS should be decoupled from the html.
-
1:46
So if we need to add any new components or features
-
1:49
we shouldn't need to recode any patterns or solve any problems
-
1:54
that we've already solved with existing CSS.
-
1:58
Now one of the most important ones is making our CSS maintainable.
-
2:03
This means that we should not have to refactor any of the CSS
-
2:07
if we need to add updates or new features and components.
-
2:12
The added features or updates we make should not break
-
2:16
any of those other components in the site.
-
2:19
Now at some point our site or application will need to scale, which will then require
-
2:26
more developers working on and maintaining our site and our code,
-
2:31
so we need to write our CSS so that it can be easily managed
-
2:36
by other developers who are looking at our code for the very first time,
-
2:41
and there should not be a learning curve for them.
-
2:44
This is when a lot of these best practices come in to help us with a lot of these goals.
-
2:51
For example, keeping our CSS "DRY."
-
2:55
DRY, or "Do Not Repeat Yourself," is a common best practice
-
3:01
in web development where the main idea is to avoid
-
3:06
repeating these same chunks of code or patterns.
-
3:10
If we have bits of code that are repeated multiple times throughout the site
-
3:15
it's a good idea to refactor the CSS set
-
3:18
so that there's only one instance of that code—or one occurrence of that code.
-
3:23
This way each property and value pair is only defined once in our style sheet.
-
3:29
The idea with DRY is to group these repeated CSS properties together
-
3:35
into one rule then add selectors to those groups if they share the same property.
-
3:42
That way our CSS is more maintainable and we would only have to change
-
3:45
one line of CSS, which results into a cleaner html file,
-
3:51
and we only rely on those specific selector groups in the CSS.
-
3:57
For example, we might have a CSS file with 3 rules.
-
4:02
Each of these share the same padding and border radius properties.
-
4:08
The button and field rules share the same display property,
-
4:13
and the float property is only declared in this common rule here.
-
4:19
To make this CSS a bit dryer we can simply separate those shared properties
-
4:25
into 1 rule that groups the selectors using those properties.
-
4:29
So now the button field and column selectors
-
4:33
share the padding and border radius declarations,
-
4:36
and below that the button and field selectors share the display property,
-
4:40
and the column rule now only has that float property declared.
-
4:45
Now this was a very simple example of grouping selectors together
-
4:49
that share the same properties, but what if we have to deal with hundreds of lines
-
4:54
of CSS or large scale sites that have tens or hundreds of pages?
-
5:01
Well, object-oriented CSS, or OOCSS, can be really useful for this.
-
5:09
OOCSS was introduced by Nicole Sullivan in 2009,
-
5:16
and the base principles are a lot like our previous example with DRY.
-
5:21
The object in OOCSS is a repeating visual pattern.
-
5:27
That visual pattern then gets abstracted into
-
5:31
these independent blocks of CSS or modules.
-
5:35
Those modules can then be reused anywhere in our site.
-
5:39
So with OOCSS we will need to think more in terms of style patterns
-
5:44
instead of just styling these individual elements.
-
5:47
We'll also need to think of our web site or app as these code-independent
-
5:52
components that can be rearranged without affecting surrounding components.
-
5:58
OOCSS has 2 main concepts.
-
6:02
The first one is the separation of structure from appearance
-
6:07
and the separation of containers and content.
-
6:11
When we separate the structure from appearance it means that
-
6:15
once we spot these repeating patterns in our CSS we'll need to abstract them
-
6:21
into these separate skins that are reuseable.
-
6:24
We'll then need to name those skins logically,
-
6:28
and, finally, we'll add those skin classes to our html elements that require those styles.
-
6:35
For example, here in our CSS we again have 3 separate rules.
-
6:40
Now they all share the border, border radius,
-
6:43
padding, and box shadow values as we can see here.
-
6:48
Using OOCSS we can actually abstract those into a separate rule or object
-
6:54
and make that our base skin style, which can be reused anywhere in our project.
-
7:01
Then the html can still have those classes for container, box, and button,
-
7:06
but we can then append those skin classes
-
7:09
in the class attribute to bring in those space styles.
-
7:13
Now if skin needs to be changed we only need to change it once in the CSS.
-
7:19
When we separate containers and content
-
7:22
the style components we create should be code or location independent.
-
7:28
So the elements should be reuseable no matter where they are on the page,
-
7:33
and the CSS should not be specifically tied to the html or a location in the document.
-
7:41
The module should actually be able to adapt
-
7:44
to different containers and be easily themed.
-
7:48
When we separate containers and content all elements with those given classes
-
7:53
will also look the same on the page no matter what.
-
7:58
For example, we might have a page with a header and footer
-
8:02
that span the full width of our browser, but then we would probably like to have
-
8:08
these inner containers that need to be centered on the page, as we can see here.
-
8:14
So our html might look something like this
-
8:17
where we have the main header, main content, and main footer elements
-
8:22
with these header inner and footer inner divs nested inside.
-
8:28
These will need to share the same structural styles like width, margin, and padding.
-
8:36
Our CSS could look something like this with these 3 selectors
-
8:40
grouped into 1 rule that shares those properties.
-
8:44
With the separate containers and content principle in mind, we can abstract
-
8:49
those structural styles into their own reuseable class called global width.
-
8:56
Then in our html we'll just need to add that global width class to the class attribute.
-
9:04
Some of the benefits to using OOCSS is that it results in smaller style sheets
-
9:11
that are easier to maintain and scale.
-
9:15
It also makes our CSS predictable, which is one of our main goals when writing CSS,
-
9:21
and we could very well build an entirely new html page
-
9:24
without having to touch the CSS at all.
-
9:27
Once we've defined all these modules in the style sheet
-
9:31
we can sort of plug them in where needed.
-
9:34
For more info on OOCSS you can check out github.com/stubbornella/oocss
-
9:42
or check out the link I added to the workshop notes.
-
9:46
A similar method called Scaleable and Modular Architecture for CSS
-
9:52
was created by Jonathan Snook as a style guide that helps organize our CSS.
-
9:58
SMACSS is very similar to object oriented CSS
-
10:03
in that it helps structure our code for projects on any scale.
-
10:09
It also combines repeating CSS patterns into these reuseable components
-
10:14
we can use anywhere in our sites.
-
10:16
The difference is that SMACSS separates our components
-
10:20
into 5 general categories and those categories are
-
10:25
the base rules, the layout rules, the module rules,
-
10:30
the state rules, and the theme rules.
-
10:34
Our base rules in SMACSS define all the default styles
-
10:39
and how they should look no matter where they are on the page.
-
10:43
Base rules are directly applied to element selectors, not classes or IDs.
-
10:51
Base rules can be used as a CSS reset. It's very good for that.
-
10:57
For example, here we have base rules with our box sizing for all elements,
-
11:02
one that removes margins and padding from the body,
-
11:05
sets the body font styles and so forth.
-
11:10
The SMACSS layout rules are what divide the page into the major components.
-
11:17
For example, the main header, the sidebar, the footer,
-
11:21
and these components can then contain 1 or more modules.
-
11:26
For example, here we have some layout rules for our main wrap container,
-
11:30
the main headers and footers, and some of the layout columns of the page.
-
11:37
Our module rules are the reuseable modular components or the minor components.
-
11:44
Each module we create should exist as a stand-alone component
-
11:49
so it can be easily moved throughout the layout without breaking anything.
-
11:54
When we write module rules we should avoid using IDs and element selectors.
-
11:59
We should stick with those class names since they're reuseable.
-
12:04
For example, here we have examples of the main nav component,
-
12:09
callout module, along with maybe a login or search-box component,
-
12:13
and these should all be reuseable throughout our project.
-
12:17
We should just be able to plug them in wherever
-
12:19
we need to without affecting anything else.
-
12:21
Now we can also subclass these module rules if we need to change the look
-
12:28
because we want to place it in other parts of our site.
-
12:31
To do that it's best to use a subclass
-
12:34
instead of creating a new conditional style based on the new location.
-
12:40
Here are some examples of the subclassed module.
-
12:43
We might have these mod and searchbox components
-
12:47
that maybe need to be modified to use in the footer or the sidebar sections.
-
12:53
Instead of creating descendant selectors for mod and searchbox
-
12:57
we can create those subclasses that contain those modified styles.
-
13:02
Then in our html we can, for example, keep those searchbox and mod classes and, to
-
13:09
bring in the modified styles, we simply append those subclasses in the class attribute.
-
13:17
In SMACSS the state rules are what define
-
13:21
how the modules look when in a particular state.
-
13:25
These are the collapsed or expanded states,
-
13:28
maybe a success or error state, or a hover inactive state in a link.
-
13:34
State rules augment or override other styles,
-
13:38
and we can apply them to layout and module styles.
-
13:43
State rules can also be used with pseudo-classes, media queries, or JavaScript.
-
13:49
Examples of state rules are, as we can see here,
-
13:52
the hover rule for mod, maybe an active state or a transparent state.
-
13:58
We also have these hidden states and maybe a JavaScript specific state
-
14:03
for expanding or collapsing elements.
-
14:07
Finally, the theme rules are what define the color scheme or the typography.
-
14:13
Theme rules are similar to state rules in that they define how the layout might look.
-
14:19
So they are what separate the themes into their own set of styles,
-
14:24
so that they are easier to modifry.
-
14:26
Theme rules are optional because we may not have a need for themes in our project.
-
14:33
So, as Jonathan Snook states, "We'll need to think about our interface
-
14:37
as not only modularly, but as a representation of those modules
-
14:43
in various states because it will make it easier to separate styles appropriately
-
14:48
and build sites that are easier to maintain."
-
14:53
There has been a lot of discussion lately about using classes versus IDs.
-
14:59
So let's talk a little bit about when it's best to use a class or an ID in a selector.
-
15:04
It's best to use IDs as JavaScript hooks or as fragment identifiers in our page.
-
15:13
For example, here we have 3 anchor elements that target sections of the page
-
15:18
if their IDs match the # in our URL or in the href attribute.
-
15:25
Here we have IDs being used as fragment identifiers,
-
15:29
but we can then bring those in as JavaScript hooks,
-
15:32
for example in our search field and the submit button functionalities.
-
15:38
IDs are very heavy on specificity and they cannot be reused.
-
15:44
That is why it's best to use classes because they are more flexible for styling,
-
15:49
and they can always be reused.
-
15:52
So then back in our html file we can add those to the elements for the presentation.
-
15:59
Now there are a few more things to consider, for example,
-
16:01
we should avoid using the same class or ID for styling and JavaScript.
-
16:09
Doing that will make our architecture a lot more fragile
-
16:13
because we're setting up a lot of dependencies
-
16:15
between the CSS, JavaScript, and the fragment identifier.
-
16:20
If we need to create JavaScript specific classes
-
16:23
it's best to prefix them with something like JS.
-
16:27
This way they're easily identifiable as JavaScript hooks
-
16:31
and it decouples the presentational classes from the functional classes
-
16:36
and, most importantly, it reduces the chances of affecting JavaScript behavior
-
16:42
when we need to make those thematic or structural changes in the CSS.
-
16:48
For example, here we have some JavaScript specific classes
-
16:51
for maybe collapsing an element, hiding it, fading it,
-
16:56
or sliding it on the page.
-
17:00
This leads usa into how specificity is calculated in a selector.
-
17:05
Specificity is what determines which CSS styles are applied by the browser.
-
17:11
Selectors with the most specificity always take precedence over others.
-
17:17
Let's talk a little bit about the calculations a browser will make
-
17:22
in order to determine that specificity in a selector.
-
17:26
It's important to understand this conceptbecause knowing how the browser
-
17:31
will interpret your code can come in really handy when debugging CSS,
-
17:36
and it will also save you a lot of time.
-
17:39
The browser uses 4 categories to define the specificity in a selector.
-
17:45
One of those is inline styles, which use that style attribute and elements.
-
17:51
The others are IDs, next.
-
17:54
It uses classes, attributes, selectors, and pseudo-classes, and, finally, elements.
-
18:00
The browser then assigns a specificity value to each one of these categories,
-
18:06
and we can sort of think of them as points.
-
18:09
Each zero here represents each of the categories, respectively.
-
18:14
So no selectors are zero points across the board,
-
18:18
and if the selector consists of any of these four categories
-
18:23
one point is added to its respective category.
-
18:28
For example, 1 point will be added for every inline element,
-
18:32
1 point for every ID, 1 for every class, and 1 for every element selector.
-
18:38
Let's take a look at an example of a selector here.
-
18:42
Here we have a selector that has 1 class.
-
18:45
The browser then adds 1 class point, which gives us a specificity value of 1,0 or 10.
-
18:54
Next, if the selector has 1 ID and a class in the selector
-
19:00
the browser will then add 1 class point and 1 ID point
-
19:04
which then gives us a specifricity value of 1, 1, 0 or 110.
-
19:11
In another example, if we qualify that class by adding the list item element selector
-
19:17
the browser will then add 1 point for the element and our specificity value is 1, 1, 1.
-
19:27
If we then add an unordered list element selector to that nav ID
-
19:32
the browser will then add 1 more element point, which gives us that value of 1, 1, 2,
-
19:39
and, finally, inline styles are very heavy on specificity.
-
19:44
As we can see, it gives inline the value of 1, which results in a specificity value of 1000.
-
19:52
So other things to keep in mind with specificity
-
19:55
is that we should not rely on parent or descendant selectors
-
20:01
because they lower the specificity of child elements.
-
20:05
A better approach is using name spaces as modifiers.
-
20:10
That way they are self-contained and modular.
-
20:13
The modifiers can then be used anywhere and they're
-
20:16
not entirely location based.
-
20:19
For example, we can prefix moidified selectors with the base class name.
-
20:25
So here we have an element with the class title in the second rule
-
20:29
that we might want a modifier for the sidebar.
-
20:33
Well, instead of relying on that sidebar descendant selector,
-
20:37
we can extend it by creating a new modifier class named sidebar title.
-
20:45
Here's another example where we might want to adjust something for the sidebar
-
20:50
when it's inside the main footer.
-
20:53
For that we can create the modifier class using the main footer
-
20:57
name space right in front of sidebar.
-
21:00
It's very similar to subclassing module rules
-
21:04
with that SMACSS approach we covered earlier.
-
21:07
It's also important that we do not rely on tag selectors
-
21:12
because tag selectors are not reuseable and they can be easily overridden,
-
21:17
which then makes our CSS architecture more fragile.
-
21:22
Finally, we'll need to avoid those important declarations in our CSS values.
-
21:30
We should not use important unless absolutely necessary
-
21:34
because it breaks the natural order of the CSS cascade.
-
21:39
It overrides all specificity, even ones in inline style.
-
21:44
It has also been referred to as the "Jedi mind trick" of CSS.
-
21:48
So, as you can see, it's a very powerful declaration that we need to be careful with.
-
21:48
So, as you can see, it's a very powerful declaration that we need to be careful with.
-
21:53
To sum up CSS specificity, inline styles will win over external style sheets,
-
21:59
IDs win over classes, and important wins over all.
-
22:06
Next up, it's always good to use some form of CSS reset in our architecture.
-
22:13
Most CSS resets provide a baseline for styling our pages.
-
22:20
By completely removing certain browser style inconsistencies
-
22:24
like margins, padding, line height, and some of the heading font sizes
-
22:29
we're making sure that our page looks pretty consistent on all browsers
-
22:34
before we begin writing our main styles, but it's also okay
-
22:39
to leave in some of those browser default styles as we'll find out shortly.
-
22:45
The method we should avoid for CSS resets is using the universal selector.
-
22:52
When using that universal selector we have no control
-
22:56
because we lose inheritance in CSS values from parent to child elements.
-
23:02
It trumps any form of inherited style.
-
23:06
Because of that we'll need to write a lot of extra CSS to define a property
-
23:12
for both the parent and the child element.
-
23:15
It also affects the browser—the page load time—because the browser
-
23:20
has to run througth every page element to apply the reset properties.
-
23:26
A common CSS reset method is Eric Meyer's reset CSS.
-
23:33
Reset CSS provides a really good starting point.
-
23:36
We can then edit or extend as we need.
-
23:39
It also includes all the necessary and new html5 tags
-
23:44
like header, footer, aside, section, and so forth.
-
23:48
The good thing with this method is that we shouldn't need to include the entire reset,
-
23:53
just those attributes that we're using and restyling.
-
23:58
One of the most common methods these days is normalize.css.
-
24:03
Some advantages to using Normalize over other CSS reset methods
-
24:08
is that Normalize preserves those useful default styles,
-
24:13
so we don't need to redeclare styles for some of those common typographioc elements
-
24:18
like headers, paragraphs—they all preserve those consistently across the browsers.
-
24:24
Also, the form elements are cross-browser consistent.
-
24:29
Different browsers do have different styles for form elements
-
24:32
so Normalize keeps those consistent right from the start.
-
24:35
We can then remove entire sections of the normalize.css file
-
24:40
because the file size is very small and modular with detailed documentation
-
24:47
and, most importantly, it has great browser support.
-
24:51
Now it's important to keep in mind that we should not
-
24:53
have to write new CSS to reset previous styles.
-
24:59
If you find yourself doing that often,
-
25:01
you'll need to stop, reassess, then refactor your CSS.
-
25:06
Next we'll talk about the best order for formatting CSS rules.
-
25:12
One of those methods is the single line method,
-
25:16
which is the most space and size efficient,
-
25:20
and it requires the least vertical and horizontal scrolling in your style sheet
-
25:24
for writing and editing CSS,
-
25:27
but it is difficult to browse through and immediately target
-
25:31
the specific parts of the CSS as we can see here.
-
25:35
CSS rules can get complex so because of that most developers like
-
25:40
to use that multi-line method, where each property
-
25:44
and value declaration is on a separate line.
-
25:49
We can take the multi-line method one step further
-
25:53
with the multi-line indent format where indented blocks indicate
-
25:57
that we're targeting child elements of the selector above.
-
26:03
For example, here we have main-nav indented beneath main-header,
-
26:06
the column rule is indented beneath the main-content rule and so forth.
-
26:12
We should be minifying and compressing our CSS files in production anyways,
-
26:17
so we should use a method that allows us to navigate CSS quickly
-
26:22
so it will need to maximize readability
-
26:24
even if it means writing each property on a separate line.
-
26:29
Next, what about the property and value declarations?
-
26:34
The best way is to arrange them functionally in our CSS
-
26:38
where the properties are divided into these groups
-
26:41
and aranged in the most logical order.
-
26:44
Doing that improves maintenance and readability.
-
26:49
As we can see here, this rule has the positioning properties; width, height,
-
26:53
border styles, and the background colors all defined in separate groups,
-
27:00
which then improves maintenance efficiency, as we just learned,
-
27:04
and there are a lot of tools that can actually help us with the declaration order,
-
27:10
one of them being CSS Comb, which is a free tool
-
27:14
for sorting CSS properties into specific orders.
-
27:18
It helps us sort and categorize our CSS to improve maintenance
-
27:24
It actually has an algorithm that sorts CSS in the order that is as close as possible
-
27:30
to the decisions web developers would make when writing CSS.
-
27:35
If we were to do something like this manually it would involve
-
27:38
copying and pasting a lot of lines of CSS,
-
27:41
and CSS Comb will do it with just one click.
-
27:45
A tool like CSS Comb will come in handy when working with a team of developers
-
27:50
because it helps maintain our coding style across the team,
-
27:53
which then helps us understand the CSS better
-
27:56
and it helps us find properties much faster, which prevents errors in the CSS.
-
28:02
The cool thing is that code editors like Sublime Text 2 and Coda
-
28:05
all have these CSS Comb plugins we can use right in the text editor.
-
28:11
Next, what about vendor prefix?
-
28:15
It's important to follow up on browser support for many of the latest CSS3 features
-
28:22
so we'll know which vendor prefixes we need to include in our style sheet.
-
28:26
A good resource for that is caniuse.com,
-
28:30
which gives us a comprehensive compatability table
-
28:33
for browser support of all the latest CSS3 features.
-
28:38
Another one is the Mozilla Developer Network,
-
28:41
which is a valuable reference that describes
-
28:44
pretty much every CSS property and the latest browser support.
-
28:49
When writing vendor prefixes it's important to always include
-
28:53
the unprefixed properties last in the rule,
-
29:00
as we can see here with the transition and the linear gradient properties.
-
29:06
There are tools that can help us write these vendor specific properties.
-
29:10
My favorite is Prefixr at prefixr.com,
-
29:14
because we only need to write the properties once.
-
29:18
It then converts our CSS to cross-browser compatible CSS,
-
29:23
and it does that by filtering through CSS3 properties
-
29:27
then dynamically updating them with the necessary prefixes.
-
29:31
Code editors like Sublime Text and Coda
-
29:34
also have prefixer plugins you can use right in the code editor.
-
29:42
Next, if it's necessary, we'll need to provide a fallback method
-
29:46
for some of these CSS3 features,
-
29:49
because first we'll need to always develop with progressive enhancement in mind.
-
29:56
With progressive enhancement we start from a basic working example as our
-
30:01
foundation so it's an experience that all browsers will be able to provide to our users.
-
30:08
We then add those enhancement layers one by one.
-
30:12
With progressive enhancement it's important that we start with
-
30:15
semantic, well-strutured markup, then add that CSS layer
-
30:20
followed by the JavaScript layer.
-
30:23
This minimizes dependencies on a lot of CSS3 features
-
30:28
because we don't sacrifice the accessability for convenience.
-
30:33
We can also use feature detection as a last resort.
-
30:38
Now a really useful tool for feature detection is Modernizr.
-
30:43
Modernizr is a powerful JavaScript-based library
-
30:48
that detects support for html5 and CSS3 features.
-
30:52
It then allows us to provide a fallback
-
30:55
for those browsers that do not support certain features.
-
31:00
Modernizr tests for over 40 features in a matter of milliseconds, so it's really fast,
-
31:06
but we shouldn't need to include the entire library.
-
31:10
We can actually create a custom build only for those features we need.
-
31:16
Finally, there are tools that can help us write CSS using a lot of these best practices.
-
31:24
One of those tools is CSS frameworks.
-
31:28
With CSS Frameworks all these best practices are already baked in.
-
31:34
A good one to use is Foundation by ZURB.
-
31:37
There's also Twitter Bootstrap and others.
-
31:42
It's important that we do not use a framework just because
-
31:46
you don't understand CSS best practices.
-
31:50
We should use a framework to speed up our work flow,
-
31:53
so to make us faster, not necessarily better at CSS.
-
31:58
Next, another helpful tool is CSS preprocessors.
-
32:02
Preprocessors save us a lot of time writing CSS,
-
32:06
and they make our CSS modular and easily scaleable.
-
32:11
A lot of the useful features in CSS preprocessors are
-
32:15
being able to create variables, nest selectors,
-
32:19
create mix ins, and do math functions, along with a lot more features.
-
32:24
Some of the most popular CSS preprocessors are Sass, Less, and Stylus.
-
32:30
Preprocessors do require a bit of a learning curve,
-
32:34
but just remember that it's CSS after all,
-
32:38
and they're not a new language, just a new syntax.
-
32:41
Okay, so that will do it for our workshop on CSS best practices.
-
32:46
As we've learned, it's important we continue using
-
32:49
those best practices throughout our development process.
-
32:52
To learn more about CSS check out our learning adventure
-
32:55
on becoming a web designer or developer and our Deep Dives on html and CSS.
-
33:01
I'm Guil Hernandez, thanks everyone.
You need to sign up for Treehouse in order to download course files.
Sign up