Learning Principles for Improving Your CSS

This article will cover some basic principles and tips on how to learn and become better at CSS, based on personal experience.

Learning Principles for Improving Your CSS

In today’s article I will mostly talk about my own experience, and what I have learned about CSS after almost one year and a half of heavy practicing.

First, let me remind you that CSS is an extremely simple language. It can be summed up in 3 words: selector, property, value. Nothing more, really. This is why some people don’t like CSS at all: because they feel like children playing with LEGOs.

Yup. Explain the basics of CSS to a 9 years old child and he or she will be able to create a website. Not a complex one I agree, but maybe a few pages with headers, links, content, images, and such.

But the fact that CSS is an easy language doesn’t mean everyone is on the same level. Some people use CSS like a chimp uses a fork, some people are okay to good with it, and some people can do magic with it.

From what I can tell, I’ve been playing around with CSS for almost two years now and on what I would call a heavy level for something like 7 months. I’m still far from perfect, and there are still some tricks I don’t know or understand.

Anyway, there are a few things I understood over the months and I’d like to share them with you. One more time, it’s not code snippets or useful tricks, it’s more like general principles and good practices. Here is what I will cover:

  1. Don’t rush your code and keep it simple
  2. Know the basics and learn the tricks
  3. DRY
  4. OOCSS
  5. CSS3: learn what you can do and what you can use
  6. Progressive enhancement and graceful degradation
  7. CSS preprocessors
  8. Keep an eye on the future
  9. Read other people’s code
  10. Keep practicing

What do you say? You’re ready? Okay let’s go.

1. Don’t rush your code & keep it simple

Don’t rush your code

This is more like a general advice, it’s not specific to CSS. When you’re about to develop something, start by thinking about it. Ask yourself a few questions:

  • How would I do this?
  • Is there another way?
  • How can I optimize it (to be maintainable, clean, cool, etc.)?

Rushing into the code may lead to time loss. What if you spent one hour creating something to realize you can’t do it this way and have to start all over again? This shouldn’t happen.

Spending hours on a CSS slideshow to end up with SlidesJS or Adaptor is a shame. Not because you didn’t succeed, but because it was a complete waste of time. On a tight deadline, you may suffer from such a mistake.

Keep it simple

CSS is a simple language but things can easily become complex. Especially if you want them to be. In most cases, the simplest idea is the better idea. When you want to achieve something, always ask yourself if there is not a simpler way to do it. You’d be surprise how often the answer is ‘yes’.

As an example, if you want a really simple horizontal navigation with only links, you have multiple ways to do this:

  • Float the list elements
  • Set the list elements to inline
  • Set the list elements to inline-block

Pick the simplest and set the list elements to inline. No need of a clearfix hack. No need of an inline-space fix. It only needs a regular padding, nothing more. End of story.

2. Know the basics and learn the tricks

To be good at CSS, or to be good at anything in life, you have to know the basics. You can’t become a maestro if you’re not comfortable with the most common things in the discipline.

The basics of CSS

What are the basics in CSS? Everybody will tell you a different story; it’s more like a feeling thing here, but if you want my opinion, there are two things to understand above all to really get into CSS:

  • The box-model. Every single element in CSS is a box (block or inline), with a width, a height, and eventual padding, margins and borders. Most important thing ever. Read more about it here.
  • The specificity. Knowing which rule is the strongest is really important to debug your CSS. For more information about this, read the specs: Assigning property values, Cascading, and Inheritance

The tricks

Once you’ve understood this, you’re on a good way. Now, you’ll only need to learn tricks and deal with special cases. And you’ll never stop finding some. Let me show you a few of them.

The “I forgot to position the parent” trick
.child {
	position: absolute;
	top: 0;
	left: 0;

/* This was forgotten */
.parent {
	position: relative; // Or anything else than static

And this is the moment you’re like “what? Why is my element on the top left edge of the page?”. Sure, you forgot to set a position to the parent (relative, absolute, whatever is not static).

The “stacking context” trick
.parent {
	z-index: 1;
	opacity: 0.5;
	transform: rotate(5deg);

.child {
	z-index: -1;

Every single front-end developer in the world struggled at least once with stacking context issues. Basically, it means you can’t apply z-index to a child of an element (or a pseudo-element) which has already a stacking context (triggered by either z-index or opacity or a transform); there is no workaround. Once you know it, you don’t forget it, trust me.

Note: for more about z-Index and the CSS stack, I recommend this wonderful blog post by Steven Bradley.

The “I forgot to clear the floats” trick

Your layout is going crazy. Blocks are flying everywhere. You’re crying because you don’t understand what you did wrong. Then check your floats! In most cases, you just forgot to clear them.

Note: if a parent only contains floated elements, it will collapse on itself unless you clear the floats, or set its height / overflow.

I could go on and on with this stuff, but it’s not the goal of the article. My point is that CSS has a lot of special and peculiar cases and people discover new ones everyday. You’ll have to get stuck on some of them to know they exist and how to deal with them next time.

3. DRY

DRY stands for Don’t Repeat Yourself, and once again it’s not specific to CSS. It’s more like a common practice when you’re coding, whatever the language you’re dealing with.

So the main idea is to avoid repeating the same chunks of code X times when you can do it only once. In some languages, it can mean using functions but in CSS, it often means using reusable classes instead of targeting a specific element (more on that in the next section about OOCSS). However, sometimes it’s something really simple like refactoring. Let me explain myself.

If you happen to spot a snippet of code multiple times in your style sheet, it could be a good idea to refactor it in order to end up with only one occurrence. Have a look at the following:

.navigation li {
	color: #333;

.navigation li a {
	color: #333;

/* Refactoring */

.navigation li,
.navigation li a {
	color: #333;

See? You may wonder what the point of this is since the result is clearly the same. There are two things to consider: performance and maintainability.

About performance: less lines means faster parsing for the browser’s CSS parser. To put it simple, the parser will apply the color to both rules at once instead of doing it twice.

About maintainability, I think it speaks for itself. By doing this, you only have to change one line instead of two if you have to edit the color. Okay, no big deal when it’s only 2 lines to edit. But what about 50? Or 300?

Further readings on DRY CSS


What is this thing?

OOCSS stands for object-oriented CSS. You’ve probably all heard about object-oriented programming languages. Basically, it means using “objects”, usually instances of classes (which consist of attributes and methods). So you may ask, what the relation with CSS could be?

First of all, let’s say it’s more like a concept or best practices than a real thing. CSS can’t really be object-oriented since it’s not a programming language: there are no namespaces, no functions, no methods, no programming classes, no conditional statements, etc. This is why some people will laugh when you talk about OOCSS.

Even if I have to agree with this, we can still optimize the way we do CSS to ease the process, make websites faster and improve maintainability.

How do we do that?

To put it very simple, it means using classes. A lot of classes. Think of your website with “modules” or “components” if you want. Try to spot repeated patterns and make them “objects” (classes) in order to reuse them.

To be a little more precise, it would mean essentially two things:

  • Separate structure and appearance
  • Separate containers and content
Separate structure and appearance

Separate structure and appearance can be important since graphical stuff can be used in multiple places on the website and in various types of elements, right? Take the following chunk of code, it can fit to a button, to a box, to a picture, whatever:

.my-box img {
	border: 1px solid #444;
	border-radius: 5px;
	box-shadow: 0 0 5px rgba(0,0,0,0.1);

Now instead of what we’ve just done, we could create a class named skin or something, and apply it to the elements that need it.

.skin {
	border: 1px solid #444;
	border-radius: 5px;
	box-shadow: 0 0 5px rgba(0,0,0,0.1);

This results in a much more comprehensible and maintainable style sheet and faster parsing.

Separate container and content

I think this is one of the most important rules of OOCSS: code independent components, not stuff for a specific place in your current design. Things should be reusable whatever their place on your site is without coding them again. Let’s take the following example:

#main h2 {
	color: #343434;
	font-size: 25px;
	line-height: 20px;
	border-bottom: 1px solid rgba(0,0,0,0.2);
	box-shadow: 0 1px rgba(255,255,255,0.4);

Okay. Now what if I want the exact same styles on a level-2 heading in the footer? Or, to style a level-3 heading in the exact same way (for whatever reason)? The right way to go would be to create a class and give those styles to this class, not to the elements itself.

What about the “never use IDs” thing?

When Nicole Sullivan came up with the concept of object-oriented CSS, this one was one of the hottest topics. Indeed CSSLint, a CSS code quality tool by Nicholas C. Zakas and Nicole Sullivan, recommends against the use of ID selectors.

To understand Nicole’s point of view, it’s important to understand that IDs can involve some specificity issues since they have the highest specificity score. Take the following code as an example (from CSSWizardrysource here):

<!-- HTML -->
<div id="header">
<a href="#">Foo</a>
<a href="#">Bar</a>
<div class="tweet">
<a href="#">Follow me on twitter</a>
<div class="tweet">
	<a href="#">Follow me on twitter</a>
/* CSS */
#header a { color: #f90;  }
.tweet     a { color: #000; }

To turn the first Twitter link black, you have two options: either give it an ID, or using the hammer bash !important. If header was a class instead of an ID, the problem wouldn’t have existed.

This is the part why Nicole Sullivan said “no ID”.

I’ll end this section by quoting Harry Roberts on the topic:

[…] I have decided that a blanket ban is sensible. Save yourself many potential headaches and never use IDs in your CSS files.

But of course, IDs can in principle still be used and are perfectly valid.

What’s my feeling about OOCSS?

As far as I’m concerned, I’m not entirely familiar with it. Mostly because I’ve never worked on a huge website involving multiple front-end developers. Let’s face it, this is probably very useful for larger architectures, but not for the little one-page website you do for your baker.

However, even if I don’t use OOCSS in my projects, I try to focus on important things like reusability of components, maintainability of the style sheet, performance and such. Those are the things OOCSS focuses on, so in some way, I’m not so far from it.

Further resources on OOCSS and the ID question

5. CSS3: learn what you can do and what you can use

Okay, enough with concepts. Let’s talk about real stuff. Let’s talk about CSS3. Although there is not really one thing called CSS3:

Unlike CSS 2, which is a large single specification defining various features, CSS 3 is divided into several separate documents called “modules”. Each module adds new capabilities or extends features defined in CSS 2, over preserving backward compatibility. […] Due to the modularization, different modules have different stability and statuses.

From Cascading Style Sheets on Wikipedia

But let’s agree that we are talking about the new features that modern browsers understand.

Nowadays, CSS3 is everywhere: from border-radius to gradients, from transparency to shadows and pseudo-elements.

Learn what you can do

In my opinion, you can utilize CSS3 is to reduce the number of HTTP requests (images), the size of the markup and JavaScript resources. Let’s have a closer look:

  • Border radius: 1 line of CSS instead of 4 containers + 4 images
  • Opacity and alpha channels in color: 1 line of CSS instead of a semi-transparent PNG
  • Advanced selectors: no need for JavaScript
  • Flexbox: a few lines of CSS instead of a whole JavaScript library
  • Gradients: a few lines of CSS instead of a repeated background image
  • Multiple backgrounds: no need for multiple containers
  • Pseudo-elements: no more extra markup for decorative elements

And I could go on and on but I think you got it. My point is: learn what you can do with CSS3. You have to create a table of contents? You should know you can do it with pure CSS thanks to CSS counters. You need to set a fancy custom border for this client site? You should know there is a border-image property to do this.

You can do a million things with CSS, and it’s even more true when it comes to CSS3. It’s important to know what you can do, and what you can’t. Sadly, there is no magic potion for this, you have to read the documentation and explore. From there, you’ll learn that you can make calculations with the calc() property but you can’t achieve 6 perfect equal heights columns layout without to struggle like hell.

Learn what you can use

The biggest problem with CSS is the fact that not all browsers support the same properties. Worst, they don’t even handle some properties in the same way when it comes to CSS3. This will be your biggest curse when experimenting with CSS3.

As an example, take the simplest CSS3 and well-known property ever: border-radius. Well, there are still browsers being used that don’t understand rounded corners (IE8 and below and Opera Mini). Actually, even Firefox and Chrome don’t render border-radius the same way (or haven’t always done).

What does this mean for you as a front-end developer? It meant that if you have to display rounded corners in ALL browsers, you’ll can do it the old fashion way: multiple backgrounds + multiple images or do it both ways and serve the right one to each.

When I have to do something in CSS, this is my process:

  1. How am I going to do this?
  2. Okay, I get it. Is it part of the CSS2.1 specification?
    1. Yes: easy peasy, end of story.
    2. No, go to step 3.
  3. What’s the browser support?
    1. Good: easy peasy, end of story.
    2. Not so good, go to step 4.
  4. Is it an enhancement or a vital feature?
    1. It’s just an enhancement: I do nothing for unsupported browsers or add a simple fallback.
    2. It’s a vital feature: go to step 5.
  5. How am I going to make it work in unsupported browsers?

Let’s make a real live example, right? With something simple, like a gradient. Let’s go.

  1. How am I going to do this?
  2. Okay, I get it. Is it part of the CSS2.1 specification?
    • No, gradients are CSS3 stuff.
  3. What’s the browser support?
    • Not bad, but not perfect. IE8 and below and Opera Mini don’t support CSS gradients.
  4. Is it an enhancement or a vital feature ?
    1. It’s more like a graphical improvement, no big deal. I’ll add a plain color as a fallback.
    2. It’s a compulsory graphical element: I have to make it work for unsupported browsers.
  5. How am I going to make it work on unsupported browsers ?
    • I’ll have to use a background image.

Thanks to this little step-by-step process you know how to do something with CSS (if it can be done), if you can use it concerning browser support and how to create fallbacks.

Note: always remember the target audience of your website or application. If you’re creating web content for an iPad app or a flexbox explorer, you will be able to use a lot of CSS3 features without worrying about fallbacks. However if you’re building a website for a bank, remember a lot of people still use IE8 and below.

Providing fallbacks

Depending on the situation, providing a fallback for unsupported browsers can be either ridiculously simple or super annoying. Indeed, there are different cases. Let’s see.

No fallback or simple fallback

When it’s some kind of user experience improvement with no consequences when unsupported, you’re not even forced to provide a fallback. This is cool.

There are also some properties which are easy to deal with when it comes to fallbacks. Generally, you only have to write two versions of this property: first, the fallback, then the cool version for browsers that support it.

.my-element {
	border: 1px solid #666;
	border: 1px solid rgba(0,0,0,0.3);
	background: #708090;
	background: hsl(210, 13%, 50%);

In this case, browsers not supporting rgba and hsl won’t read the lines 3 and 5, so you provide alternative versions on line 2 and 4. For supported browsers, they will first apply the alternative version then override it with the cool one.


Nowadays, we can hardly talk about CSS3 without mentioning Modernizr. It’s a JavaScript library that tests support for HTML5 and CSS3 features on page load. This may sound heavy, but it’s well optimized and quite fast.

Anyway, sometimes you have to know exactly if the browser is supporting one specific feature. For, let’s say, providing an alternative version requiring other CSS properties.

/* Normal version */
.dropdown {
	opacity: 0;
	pointer-events: none;

.trigger:hover .dropdown {
	opacity: 1;
	pointer-events: auto;

/* Fallback with Modernizr */

.no-opacity .dropdown,
.no-pointerevents .dropdown {
	opacity: 1;
pointer-events: auto;
display: none;

.no-opacity .trigger:hover .dropdown,
.no-pointerevents .trigger:hover .dropdown {
	display: block;

To provide such a fallback, you have to rely on classes added by Modernizr (.no-opacity and .no-pointerevents). You can’t have both versions simultaneously.

Whatsoever, please always remember to draw fallback, this is really important. Vital features have to be supported on all browsers old as well as new, and if in any case they are not, you have to warn your user.

So either you start with a simple basis and improve it for recent browsers, or your start with a modern basis and you decline for older ones. More on that in the next section.

Further resources on CSS3:

6. Progressive enhancement and graceful degradation

Those are two terms you’ve probably already heard about, especially graceful degradation, however there is a subtle difference between both.

Progressive enhancement

Progressive enhancement is when you establish a baseline of usable functionalities and features and then improve the user experience according to browser support.

Using the HTML5 required attribute to warn the user that a field is missing before submitting can be considered a progressive enhancement. It’s improved user-experience speaking thanks to the native browser engine.

Graceful degradation

You got graceful degradation when you provide an alternative or lower version of your features in case they are not supported. Basically, it’s going from top to bottom.

A very simple example would be the warning you put between the <canvas> tags to inform users with browsers that don’t support it that there is something they can’t see.

This page uses HTML5 Canvas. Please use a recent browser to see this content. To get another browser, go to <a href="http://browsehappy.com/">BrowseHappy</a>

What’s the difference?

In the end, there is none. You have features for advanced browsers and features or fallbacks for legacy ones. It’s more a process thing: either you code for the cool browsers, giving fallbacks for the old ones, or you do it the other way. It’s up to you.

Anyway, my point is: user experience doesn’t have to be the same in all browsers. Actually, it’s not even possible since browser engines are different. Whatsoever, you have to provide basic features for everyone, but please improve your website or application for modern browsers. They are good, they provide native features: use them.

Further readings on progressive enhancement and graceful degradation

7. CSS preprocessors

Aaaah, preprocessors… The hot question at the moment. Are they useful? What for? Should I use one? Which one? I think this is one of the most debated topics about CSS at the moment.

I’ll try to be as objective as possible for this section. Let me start with this: if you don’t want to use a preprocessors, then don’t. This will never be an issue. This will not make you a bad front-end developer. This will not make you unable to do some kind of things. But you should give it a try to make your own opinion about it.

Okay, enough with the disclaimer. What is a preprocessor, generally speaking? A preprocessor is a kind of tool that compiles a given syntax into an actual language used by another program (in this case: the browser). There are preprocessors for many languages: there is Markdown or Jade for HTML. There is LESS, Sass and Stylus for CSS. There is CoffeeScript for JavaScript. There is CakePHP for PHP and so on.

What’s the point?

A CSS preprocessor gives CSS some particularity from object-oriented languages. Things like:

  • variables
  • functions (with parameters)
  • namespaces
  • nesting
  • conditional statements
  • operations
  • and many more

Sounds appealing, right? Maybe you’d like an example to figure out what’s going on there. Let’s take the following CSS for a navigation bar.

.navigation {
	width: 800px;
	width: calc(100%-150px);
.navigation li {
	color: #444;
.navigation li a {
	text-decoration: none;

Now a processed version of it (SCSS).

$main-color: #444;

.navigation {
	width: (100%-150px);
	li {
		color: $main-color;
		a {
			text-decoration: none;

Basically the preprocessor will translate this into the regular CSS version. It will be exactly the same, except for the calculation. It will run the operation itself and display the according result without any need of the calc() function.

So you end up with a more comprehensible (nesting and variables) and maintainable (variables and functions) style sheet. It was a very dummy example, but in a real project, you will feel the difference.

How to choose one?

There are a few CSS preprocessors out there, each one with its own advantages and particularities. Anyway, all of them do more or less the same stuff, so the one you choose is really up to you. Here are the main options when it comes to CSS preprocessors:

  • Sass (written in Ruby)
  • LESS (written in JavaScript)
  • Stylus (written in JavaScript)
  • Crush (written in PHP)

The best way is to get to know them and experiment and see what fulfills your and your project’s needs best. There are many factors that play a role; listing them all would be out of the scope of this article but you can find some relevant resources below.

What’s my feeling about CSS preprocessors?

I’m not an expert when it comes to CSS preprocessing, but I like it. It provides very useful features missing in CSS like variables, nesting and conditional statements.

I’ve played a little with LESS, and it did pretty much what I wanted. At least until I started things a little bit more complicated as you may have read in my last article about CSS Loading Animations (for loop + vendor prefixing + keyframes).

I also gave a quick shot to Sass and Compass. To my surprise, it was incredibly easy to install and run through Ruby. I was scared but it’s very very intuitive, trust me. So in the end, Sass + Compass looks amazing, seriously. You can also read more about why I switched from LESS to Sass in this article on my blog.

Anyway, I’m still completely able to write regular CSS without a preprocessor, and most of the time this is what I do. But in the end, I think we will all use one, whichever it is. CSS really lacks some useful things, and CSS preprocessors are here to fix this.

Further readings on CSS preprocessors

8. Keep an eye on the future

Languages are evolving. It’s very true with CSS. CSS specifications are never finished, and browsers are not waiting for them to add new features to their engine.

Regarding this, my best tip would be to stay alarmed about what’s coming. I know you may not be able to use it right on launch, but knowing which feature is now in Chrome Canary, soon in Chrome stable and Safari, then Opera, then Firefox and so on, is important in order to gain perspective of what the CSS problems and possible solution are.

Resources to keep an eye on the future:

9. Read other people’s code

One of the best ways to learn how to code is to read code. Thankfully, CSS is client side, so you can read it on every single website on the web with a web inspector like WebKit Inspector, Dragonfly, Firebug, etc. Plus, the web industry is somewhat really focused on open-sourcing, meaning people are glad to share their sources with you.

Another great way to learn is to follow tutorials. Take an easy tutorial, and do it step-by-step. Then try to redo it from scratch. If you happen to be stuck, have a glance at the solution, then continue by yourself.

When you’re comfortable with CSS and want to get deep into it, you might want to have a look at unexplained demos and experiments. People create stuff everyday, you’ll always find something you can’t do.

Regarding this, a few months ago Chris Coyier, Tim Sabat and Alex Vazquez launched CodePen, some sort of platform to create, share and explore front-end code (HTML, CSS, JavaScript). CodePen also includes a bunch of tools like libraries (jQuery, jQuery UI, MooTools, YUI, Prototype, Zepto, Dojo, Ext JS, PrefixFree, etc.) and preprocessors (HAML, Markdown, Slim, LESS, SCSS, Sass, CoffeeScript) if you need.

Further resources to find examples of other people’s code:

10. Keep practicing

You know what’s said about learning: we learn by doing. So my best advice is to keep practicing as for anything else. The more you practice, the better you’ll be. Practicing doesn’t necessarily mean doing a website from scratch. Just pick a simple shot on Dribbble and try redoing it with pure CSS. The result may not be useful, but what you’ve learned, definitely is.

And as I said before in “Know the basics and learn the tricks”, CSS is full of special cases. Learning how to deal with them is part of the job in writing CSS. And the only way to know they exist is to practice, find one, have a look at the solution, and go on.

I’d also suggest you to share your code. It’s always helpful to get constructive feedback, so be sure to ask people to review your code once close to be finished. Simply drop them in a JSFiddle, share and ask for feedback.

Index and credits

Since this article mentioned a bunch of various links and resources, let me gather them all in the same spot:

Thanks a lot for reading this article. I’m hoping it will help you somehow to improve the way you learn and use CSS. As always, if you have anything to share and comment, please do. 🙂


Tagged with:

I am a front-end developer from Grenoble (France) with a passion for HTML5 and CSS3. Plus, I'm a geek and a gamer. I am the author of Browserhacks and Wild Web Watch.

View all contributions by

Website: http://hugogiraudel.com

Related Articles

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.