CSS code "with a stifle"

Original author: Harry Roberts
  • Transfer
  • Tutorial
Chris Coyer recently answered questions from Smashing Magazine readers. One of the questions was about how to recognize CSS code with a "darling":
How can you tell if your CSS is acting? What signs indicate that the code is not optimal or that the developer wrote it through the sleeves? What are you looking at first to determine if the code is bad or good?

I thought I could expand and complement Chris's answer based on my own experience.

I work at BSkyB . I make large sites - I’ve been working on the last of them for more than a year. Bad CSS code gives me a lot of problems. When you have been working on one site for months, you simply cannot afford a bad code, and you must fix it.

I want to share a few things that I pay attention to first of all in order to give an impression of the quality, maintainability and cleanliness of the CSS code.

Cancel styles


Any CSS rules that override previously set styles (except when resetting styles) is a wake-up call. Cascading style sheets, by definition, should inherit from the previous definitions and complement them, and not cancel them.

Any definition like:

border-bottom:none;
padding:0;
float:none;
margin-left:0;

usually doesn't mean anything good. If you have to reset border, then most likely you installed it too soon. This is difficult to explain, so I will give an example:

h2{
    font-size:2em;
    margin-bottom:0.5em;
    padding-bottom:0.5em;
    border-bottom:1px solid #ccc;
}

Here we give the elements h2not only font size and padding, but also margins and underscores to visually separate the title from the rest of the content. But it may very well be that in another place we do not need either fields or underlining. Perhaps we will write something like:

h2{
    font-size:2em;
    margin-bottom:0.5em;
    padding-bottom:0.5em;
    border-bottom:1px solid #ccc;
}
.no-border{
    padding-bottom:0;
    border-bottom:none;
}

We now have 10 lines of code and an ugly class name. It would be much better to do this:

h2{
    font-size:2em;
    margin-bottom:0.5em;
}
.headline{
    padding-bottom:0.5em;
    border-bottom:1px solid #ccc;
}

8 lines, no cancellation of styles and a beautiful, meaningful class name.

Going down the stylesheet, add rules, not take away. If you have to undo previously set styles, most likely you added them too soon.

Imagine a CSS file with tens of thousands of lines with similar style cancellations. A bunch of extra code! Gradually add new definitions on top of the old, simpler ones, do not start building too complex rules too soon, otherwise you will write much more code, and it will be much less to do.

When I see that some rule overrides the previous one, I almost certainly know that the styles are not organized properly and need to be reworked.

Magic numbers


I especially hate them! A magic number is a meaningless value that is used because it "just works." For instance:

.site-nav{
/*    [styles]   */
}
.site-nav > li:hover .dropdown{
    position:absolute;
    top:37px;
    left:0;
}

top:37px;Is a magic number. The only reason it is here is that it turns out that the list items are 37 pixels high, and the drop-down submenus should appear at the bottom of the menu item.

The problem is that these 37 pixels are pure coincidence, and this constant can not be relied on at all. What if someone changes the font size in the menu item and it will be 29, not 37 pixels in height? What if in Chrome the menu item is 37 pixels high, and in IE 36? This number only works in one specific case.

Never, never use values ​​that "just work." In the previous example, it would be much better to write top:100%;insteadtop:37px;

And this is not the only problem with magic numbers. In addition to insecurity, they also create a communication problem. How can another developer understand where this number came from? If your code is larger and more complex than the above example, and some of the magic numbers suddenly stopped working, you will encounter the following:

  • another developer, not knowing where this number came from, will be forced to write the correct style for this case from scratch;
  • or if he is very careful, he will leave the number in place and try to solve the problem without touching it. Thus, a crooked and ugly crutch risks remaining in the code forever and grow with new crutches.

Magic numbers are bad. They quickly become obsolete, they interfere with other developers, they cannot be explained, and they cannot be relied on.

There is nothing worse than stumbling upon such an inexplicable number in someone else's code. Why is it here? What does it mean? Can I touch it or not? I ask these questions whenever I see such a number. And the most important question: “How can you achieve the same result without magic?”

Run from magic numbers like a plague!

Overly narrow selectors


Something like this:

ul.nav{}
a.button{}
div.header{}

These are selectors to which completely unnecessary refinements are added. They are bad because:

  • they are almost impossible to reuse;
  • they increase specificity;
  • performance suffers from them.

In fact, they could (and should) be written like this:

.nav{}
.button{}
.header{}

Now you can apply .navto ol, .buttonto, inputand quickly replace the element divwith the class when we bring the site into line with HTML5. Although browser performance does not suffer much from such selectors, it still suffers. Why force him to iterate over all the elements in search of a class , if you can limit yourself to just one class? Here are even more extreme examples:.headerheader

a.button

ul.nav li.active a{}
div.header a.logo img{}
.content ul.features a.butto

All of them can be greatly reduced or rewritten:

.nav .active a{}
.logo > img {}
.features-button{}

Every time I stumble upon overly detailed selectors, I try to find out why they are set that way, and is it possible to reduce them.

Hardcoded Absolute Values


Like magic numbers, they do not bode well. Here is an example:

h1{
    font-size:24px;
    line-height:32px;
}

It would be much better to write: Interlining is always better to set relatively, so that the code is more flexible. When you change the font size, it will change automatically. And if you set it in pixels, then you have to write something like this:line-height:1.333;



h1{
    font-size:24px;
    line-height:32px;
}
/**
 * Main site `h1`
 */
.site-title{
    font-size:36px;
    line-height:48px;
}

And so every time the header font size changes. This is much better:

h1{
    font-size:24px;
    line-height:1.333;
}
/**
 * Main site `h1`
 */
.site-title{
    font-size:36px;
}

It seems to be a small difference, but in a large project it can be of great importance.

By the way, this applies not only to line-height. Almost any absolute value that is hard coded into the code should be suspicious.

The only case when it really makes sense to hardcode the absolute value is when working with things that should always have a certain size, for example, sprites.

Brute force


This is one of the most extreme particular cases of hard-set magic numbers and some other tricks that are used to make layout work:

.foo{
    margin-left:-3px;
    position:relative;
    z-index:99999;
    height:59px;
    float:left;
}

This is a terrible style! All of these ugly rules are fancy for the sole purpose of stuffing an element into the right place at all costs. Such code indicates either a very poorly designed layout, or a lack of understanding of how the CSS block model works, or both at the same time.

If you have a well-thought-out layout and understand the block model, you are unlikely to have to use brute force. If I see such code, I immediately try to figure out what the problem is, and whether or not to go back a few steps to get rid of the need to write such crutches.

Dangerous selectors


By dangerous selectors I mean ones that are much wider than necessary. Here is the simplest and most obvious example of such a selector:

div{
   background-color:#ffc;
   padding:1em;
}

Why, why cover everyone divon the page with this carpet bombardment? Why would anyone need a selector like aside{}? Or header{}, or ul{}? Such selectors are much, much wider than necessary, and lead to the fact that we will have to cancel the styles that we have already talked about.

Let's look at an example in header{}more detail. Many people use this element to create a page header, which is completely correct. But if you write styles for it like this:

header{
    padding:1em;
    background-color:#BADA55;
    color:#fff;
    margin-bottom:20px;
}

then this is completely wrong. An element headerdoes not necessarily imply the heading of the entire page; it can be used several times in different contexts. It is much better to use a class, for example .site-header{}.

Defining such detailed styles for such a common selector is very dangerous. They will leak into completely unpredictable places as soon as you begin to reuse this element.

Make sure your selectors hit right on target .

Here is another example:

ul{
    font-weight:bold;
}
header .media{
    float:left;
}

When I see how styles are applied to an element or to a very generalized class, as in this example, I start to panic. I know that they are too universal and I will have problems. These styles can be inherited in places where it would be completely undesirable, and I have to cancel them.

Reactive use! Important


You !importantcan use . And this is a really important tool. However, it should be used wisely.

!importantmust be used proactively, not reactively.

This means that it can be used when you are absolutely sure that you will always need this style to take precedence, and you know about it beforehand.

For example, you are sure that you always want to see errors in red:

.error-text{
    color:#c00!important;
}

Even if an error message is displayed inside a block in which the text color is blue, we can be sure that the error will remain red. We always want to report the error in red, and so we write right away !important.

But when we use it !importantreactively, that is, in response to a problem that has arisen, when we got confused and instead of sorting it out, go ahead, then this is bad.

Reactive use !importantdoes not solve the problem, but only hides it. It is necessary to treat the disease, not the symptoms. The problem did not go away, we just blocked it with a super-specific selector, while we had to do refactoring and architecture.

ID


This kind of "bad smell" is very important when working in a large team. I already wrote that id is bad , because they greatly increase the specificity of selectors. They are of no use and should never be used in CSS. Use them to associate HTML elements with JavaScript code, but not to style them.

The reasons for this are simple:

  • id can be used on the page only once;
  • the class can be used as much as you like;
  • most of the rules applied to id can be scattered across several classes;
  • id is 255 times more specific than a class ;
  • This means that you will need to apply 256 classes to the element in order to outweigh one id.

If this is not enough for you, then I don’t know what else to say ...

If I see id, I immediately try to replace it with a class. Excessive specificity of selectors ruins large projects, so it is vital to keep it as low as possible.

Finally - a little exercise. Try to elegantly solve this problem . Hint: so - not elegant; and so too.

Blurry class names


A vague name is one that does not specifically describe the purpose of the class. Imagine a class .card. What is he doing?

This is a very vague name, and vague names are bad for two main reasons:

  • you cannot guess what it means;
  • it is so general that it can easily be accidentally overridden by another developer.

The first point is very simple: what does it mean .card? What style does he ask? Task cards in the project management system? A playing card in an online casino? Credit card image? It’s hard to say because the name is too vague. Let's say we mean a credit card. Then it’s much better to name the class .сredit-card-image{}. Yes, much longer, but much, much better!

The second problem with vague names is that they are very easy to accidentally override. Suppose you are working on an online store site. You use a class .card, meaning the number of the credit card associated with the account. And another developer at this time adds the opportunity to buy a gift and attach a congratulation card to it. And he also calls the class .card, and writes for him his own rules, which conflict with yours.

This can easily be avoided by using more precise class names. Classes are kind of .cardor .usertoo foggy. They are uninformative and easy to accidentally redefine. Class names should be as accurate as possible.

Conclusion


So, we looked at a few examples of the "with the soul" code. These are things that must always be remembered and avoided with all their might, or rather, only a small part of them, in fact, there are many more. When working on a large project that lasts months and years, it is vital to keep the code in good shape.

Of course, there are exceptions to each rule, but you need to approach them individually. In most cases, this code should be carefully avoided.


Also popular now: