When working on large, lengthy, and crowded projects, it is important that all developers follow the following rules:

  • Keep CSS easy to maintain
  • Keep your code clear and easy to understand
  • Keep CSS extensible

In order to achieve this goal, we need to adopt many methods.

The first part of this document explores syntax, format, and CSS structure; The second part will focus on methodologies, frameworks, and ideas for writing and planning CSS.

CSS Document Analysis

No matter what document you write, you should maintain a common style, including common comments, common syntax, and common naming conventions.

The general

Keep the line width below 80 bytes. Exceptions to this rule include syntax related to gradients and urls in comments. There’s nothing we can do about this.

I prefer to indent with four Spaces instead of tabs, and split the declaration into multiple lines.

Single file versus multiple files

While some people prefer to write everything in a single file file, I started splitting styles into smaller files after moving to Sass. It’s all good practice. Whichever you choose, the following rules will apply and you won’t have any problems if you follow them. The only difference is the table of contents and the block title:

directory

At the beginning of CSS, I maintain a directory like this:

/*------------------------------------*\ $CONTENTS \*------------------------------------*/ /** * CONTENTS............ You 're reading it! * RESET............... Set our reset defaults * FONT-FACE........... Import brand font files */Copy the code

This directory tells other developers exactly what is in the file. Each item in this directory has the same block title as its corresponding block title.

If you are maintaining a single file CSS, the corresponding blocks will also be in the same file. If you’re writing a set of small files, each entry in the directory should have a corresponding @include statement.

Block title

Directories should correspond to block titles. As follows:

/*------------------------------------*\ $RESET \*------------------------------------*/ Copy the code

Block title prefix $allows us to use/Cmd | Ctrl + F command search title name limit search scope in the title block.

If you are maintaining a large file, empty 5 lines between blocks as follows:

/*------------------------------------*\ $RESET \*------------------------------------*/ [Our reset styles] /*------------------------------------*\ $FONT-FACE \*------------------------------------*/ Copy the code

These large gaps help distinguish blocks when flipping through large files.

If you’re maintaining multiple CSS files with include, simply include a title in the header of each file instead of a blank line.

Code sequence

Try to write rules in a specific order. This will ensure that you get the most out of the first C in CSS: cascade.

A well-planned CSS should be arranged as follows:

  1. Reset the root of all things
  2. The element typeThere is no classh1,ul 等
  3. The most general, fundamental design pattern for objects and abstract content
  4. Child elements All extensions that extend from the object and their children
  5. Repair for abnormal status

This way, when you write CSS in turn, each block automatically inherits the properties of the block before it. This reduces the amount of code that cancels each other out, reduces the number of special problems, and makes for a more desirable CSS structure.

For more information on this, Jonathan Snook’s SMACSS is highly recommended.

CSS style set analysis

[selector]{ [property]:[value]; [<- Declaration ->]} [selector]{[attribute]:[value]; [<- declaration ->]}Copy the code

When writing CSS styles, I’m used to following these rules:

  • Class names are hyphenated (-), except for the BEM nomenclature mentioned below;
  • Indent 4 Spaces;
  • Declaration split into multiple lines;
  • Declarations are in relational order, not alphabetical;
  • Prefixed declarations are appropriately indented to align their values;
  • Indent the style set to reflect the DOM;
  • Keep the semicolon at the end of the last statement.

Such as:

.widget{ padding:10px; border:1px solid #BADA55; background-color:#C0FFEE; -webkit-border-radius:4px; -moz-border-radius:4px; border-radius:4px; }. Widgets - heading {the font - size: 1.5 rem; line-height:1; font-weight:bold; color:#BADA55; margin-right:-10px; margin-left: -10px; Padding: 0.25 em. }Copy the code

We can see that.widget-heading is a child of the.widget because the style set of the former is one level more indent than the latter. This indentation allows developers to quickly pick up such important information when reading code.

We can also see that the declaration of.widget-heading is arranged according to its relevance:.widget-heading is an inter-line element, so we add font related style declarations first, followed by others.

Here is an example that is not broken down into multiple lines:

. The t10} {width: 10%. The t20} {width: 20%. The t25} {width: 25% a quarter / * * / t30.} {width: 30% t33} {width: 33.333% / * * / by one-third . T40} {width: 40%. The t-50} {width: 50% 1/2 * / * / t60} {width: 60%. The t66} {width: 66.666% two-thirds / * * /. T70} {width: 70% .t75 { width:75% } /* 3/4*/ .t80 { width:80% } .t90 { width:90% }Copy the code

In this example (from Inuit. CSS’s Table Grid System), putting CSS on a single line makes the code more compact.

Naming conventions

Generally I use a hyphen (-) to connect class names (e.g..foo-bar instead of.foo_bar or.foobar), but I use BEM (Block, Element, Modifier) nomenclature in some cases.

BEM nomenclature makes selectors more formal, cleaner, and more semantic.

The nomenclature follows the following format:

.block{} .block__element{} .block--modifier{} Copy the code

Among them:

  • .blockRepresents a basic abstract element;
  • .block__elementOn behalf of a.blockA child element of;
  • .block--modifierOn behalf of.blockA different state or version of.

For example:

.person{} .person--woman{} .person__hand{} .person__hand--left{} .person__hand--right{} Copy the code

The basic element we describe in this example is a person, and then that person could be a woman. We also know that people have hands, which are part of the human body, and the hands have different states, like the left hand and the right hand.

This allows us to delimit the selector’s namespace and communicate its functions based on parent elements, such as whether the selector is a child (__) or a different state of its parent (–).

Thus,.page-wrapper is a separate selector. This is a canonical name because it is not a child or other state of another element; Widget__heading, however, is associated with other objects and should be a child of the.widget, so we should rename it to.widget__heading.

BEM nomenclature is ugly and rather verbose, but it allows us to quickly learn the functionality of elements and the relationships between elements by name. At the same time, the repetition part of THE BEM syntax is very good for GZIP’s compression algorithm.

Whether or not you use BEM nomenclature, you should make sure that the class is properly named and that there are not many words in it. Abstract element names to improve reusability (e.g..ui-list,.media). Child elements should be named as precisely as possible (e.g..user-Avatar-link). Don’t worry about the number or length of class names, because well-written code gzip also compresses efficiently.

HTML in the class

To ensure legibility, class names are separated by two Spaces in HTML tags, for example:

Copy the code
      

The added whitespace should make it easier to read and locate when using multiple classes.

JavaScript hooks

Do not use classes marked with CSS styles as JavaScript hooks. Mixing JS behavior with styles will not allow them to be treated separately.

If you want to bind JS to certain tags, write a JS class. Simply delimit a namespace with a.js- prefix, such as.js-toggle,.js-drag-and-drop. This means that we can bind BOTH JS and CSS through class without causing trouble.

  Copy the code

The tag above has two classes, one of which you can use to style the sortable column and the other to add sorting.

I18n

Although I’m British and I always spell colour rather than color, for the sake of consistency I think it’s better to use the American spelling in CSS. CSS and most other languages are written with American spelling, so color:red in.colour-picker{} lacks uniformity. I used to advocate both spellings, for example:

.color-picker, .colour-picker{ } Copy the code

But I recently worked on a large Sass project that had so many color variables ($brand-color, $highlight-color, etc.) that it was hard to maintain two spellings for each variable and twice as hard to find and replace.

So for consistency, name all classes and variables with the usual spelling of the project you’re working on.

annotation

I use a document block-style comment of no more than 80 bytes in line width:

/** * This is a docBlock style comment * * This is a longer description of the comment, describing the code in more * detail. We limit these lines to a maximum of 80 characters in length. * * We can have markup in the comments, and are encouraged to do so: * 
       

Lorem

* * We do not prefix lines of code with an asterisk as to do so would inhibit * copy and paste. */ /** * This is a DocBlock style comment. * * This begins with a more detailed and longer note body. Of course, we want to keep the line width under 80 bytes. * * We can embed HTML tags in comments, and that's a good idea: *

Lorem

* * If the tag is embedded in the comment, do not prefix it with an asterisk to prevent it from being copied in. * /Copy the code

You should describe the code in as much detail as possible in comments, because what is clear and understandable to you may not be so to others. For every section of code you write, write a comment to explain it.

Extended use of comments

There are many advanced uses for comments, such as:

  • Quasi-qualified selectors
  • Code label
  • Inheritance marker

Quasi-qualified selectors

You should avoid overmodifying selectors, such as ul. Nav {} if you can write. Overmodifying the selector will affect performance, affect class reusability, and increase selector privacy. These are things you should try to avoid.

Sometimes, though, you might want to tell other developers what classes are for. In the case of.product-page, this class looks like a root container. It could be an HTML or body element, but you can’t tell from.product-page alone.

We can describe the scope of our planned class by prefixing the selector with a quasi modifier (to comment out the previous type selector) :

/*html*/.product-page{} Copy the code

This way we can know exactly what the scope of the class is without affecting reusability.

Other examples are:

/*ol*/.breadcrumb{} /*p*/.intro{} /*ul*/.image-thumbs{} Copy the code

This allows us to know the scope of a class without compromising code privacy.

Code label

If you write a new set of styles, you can label them, for example:

/** * ^navigation ^lists */ .nav{} /** * ^grids ^lists ^tables */ .matrix{} Copy the code

These tags allow other developers to quickly find relevant code. If a developer needs to find a list related section, he can search ^lists and quickly locate.nav,.matrix, and other related sections.

Inheritance marker

When you apply object-oriented thinking to CSS, you will often find two parts of CSS that are closely related (one is the base, one is the extension) but separate from each other. We can use inheritance tags to establish a tight connection between the original and inherited elements. These are written in the comments as follows:

In the basic style of the element:

/** * Extend `.foo` in theme.css */ .foo{} Copy the code

In the extended style of the element:

/** * Extends `.foo` in base.css */ .bar{} Copy the code

This way we can establish a close connection between two pieces of code that are far apart.

Write CSS

The previous chapters focused on planning CSS, which are easy to quantify. This chapter will explore something more theoretical, as well as our attitudes and approaches.

Writing a new component

When writing a new component, write the HTML section before you start working with CSS. This allows you to determine exactly which CSS properties can be inherited, avoiding duplication and waste.

By writing the markup first, you can focus on the data, content, and semantics, and then add the required classes and CSS styles later.

Object-oriented CSS

I write code in object-oriented CSS. I divide components into structure (objects) and appearance (extensions). As analyzed below (note that this is not an example) :

.room{} .room--kitchen{} .room--bedroom{} .room--bathroom{} Copy the code

We have many rooms in the house, and they all have common parts: floor, ceiling, walls and doors. These shared parts can be placed in an abstract. Room {} class. But we also have other rooms that are different: a kitchen might have tiles, a bedroom might have carpeting, a bathroom might not have Windows but the bedroom might have them, and the walls of each room might be different colors. The idea of object-oriented CSS allows us to abstract out the same parts into structural parts, then extend those features with more concrete classes and add special handling methods.

So instead of writing lots of different modules, try to figure out the recurring design patterns in those modules and abstract them away, write a reusable class, use that as a base and then write special cases of other extension modules.

When you write a new component, break it down into structure and appearance. Write structural parts with the most generic class to ensure reusability, and write skins with more specific classes to add design methods.

layout

All components do not declare widths, but are determined by their parent elements or the grid system.

Never declare height. Height should only be used for things that have a fixed size, such as images and CSS sprites. Height should not be declared on elements p, ul, div, etc. Use a more flexible line-height if necessary.

The grille system should be understood as a bookshelf. They’re the ones that contain content, not the ones that are content themselves, like when you build a bookshelf and put things in it. Rather than declaring their dimensions, separating the grid system from the elements’ other attributes helps with layout and makes our front-end work more efficient.

You should not add any styles to the grid system, they are used only for layout purposes. Add styles inside the grid system. Do not add box model attributes under any circumstances to a grid system.

The UI size

I set the UI size in many ways, including percentages, PX, EM, REM, and nothing at all.

Ideally, the grid system should be set in percentages. As mentioned above, because I use a grid system to fix column and page widths, I can ignore element sizes.

I use REM to define the font size and use PX to make it compatible with older browsers. This can have the advantages of both EM and PX. Here is a very nice Sass Mixin that can be used to generate REM and old browser-compatible PX, assuming you declare base font size elsewhere.

@mixin font-size($font-size){ font-size:$font-size +px; font-size:$font-size / $base-font-size +rem; } Copy the code

I only use PX on elements that have a fixed size, including images and CSS sprites that have a fixed size with PX.

The shop name

I’ll define some classes that are similar to the grille system to declare the size. These classes can be used for double header sizing, read Pragmatic, Practical font sizing in CSS for this.

shorthand

CSS abbreviations should be used with caution.

Write something like BACKGROUND: red; This property is easy to do, but what you’re saying is that you’re declaring background-image: none; background-position: top left; background-repeat: repeat; background-color: red; . While most of the time nothing goes wrong with this, it’s worth considering giving up on abbreviations just once. Background-color: red; .

Margin: 0; This statement is clean and concise, but it should be as clear as possible. If you just want to change the margin, be specific and write margin-bottom: 0; .

At the same time, the properties you need to declare should also be clearly written, so that shorthand does not affect other properties. For example, if you only want to change the bottom margin, don’t use margin: 0, which clears out the other margins.

While shorthand is good, it’s also easy to abuse.

ID

Before we start working with selectors, keep this in mind:

Never use ids in CSS.

In HTML, ID can be used for JS and anchor location, but in CSS, just use class, not an ID at all.

The advantage of Class is that it is reusable and not very private. Privacy can be a problem in a project, so it’s important to reduce it. ID is 255 times more private than class, so do not use it in CSS.

The selector

Make sure your selectors are short and efficient.

Selectors located by the position of page elements are not ideal. For example, a selector like.sidebar h3 SPAN {} is too dependent on relative position, and it is hard to maintain the style if you move the span outside of H3 and sidebar.

Complex selectors will affect performance. The more complex the selector structure (e.g..sidebar h3 span is three layers, and.content ul P a is four), the more overhead the browser has.

Try to make styles independent of their positioning and keep the selectors clean.

As a whole, the selector should be as short as possible (for example, only one layer structure), but the class name should not be too short; for example,.user-avatar is far better than.usral-avt.

Remember: class doesn’t matter if it’s semantic; Concern should be given to whether they are justified. Don’t stress the semantics of class names, and focus on names that are sensible and timeless.

An overdecorated selector

As mentioned above, an overdecorated selector is not ideal.

An overdecorated selector is one like div.promo. Chances are you can get the same results using.promo alone. Of course, you may occasionally need to modify class with element types (for example, if you write a.error and want it to look different in different element types, e.g..error {color: red; } div.error { padding: 14px; }), but it should be avoided most of the time.

Another example of an overdecorated selector is ul. Nav li a{}. As mentioned earlier, we can delete ul immediately because we know. Nav is a list, and then we can see that a must be in Li, so we can rewrite this selector to.nav a{}.

Selector performance

Browsers are getting better and faster at rendering CSS, but you should still focus on efficiency. This problem can be avoided by using short, unnested selectors, not using a global selector (* {}) as a core selector, and avoiding the increasingly complex new selector of CSS3.

Core selectors: the browser resolves the selectors in right-to-left order, and the right-most element is the element in effect for the core selectors.

The purpose of using CSS selectors

Rather than trying to use selectors to locate an element, it’s better to simply add a class to the element you want to style. Let’s take a selector like.header ul {}.

Suppose the UL is the site-wide navigation for the site, is in the header, and so far is the only UL element in the header. .header ul{} does work, but it’s not a good idea. It’s very outdated and very obscure. If we add an UL to the header, it will use the same style we wrote for the navigation section, even if that’s not what we intended. This meant that we either had to refactor a lot of code or write a lot of new styles for the later UL to offset the impact.

Your selector must fit the reason you want to style this element. Think, “Am I locating this element because it’s ul under.header, or because it’s my site navigation?” This will determine how you should use the selector.

Make sure your core selector is not a type selector, nor is it a high-level object or abstract selector. For example, you won’t find selectors such as.sidebar ul {} or.footer. media {} in our CSS.

Be clear: Find the element you want to style directly, not its parent element. Don’t assume HTML won’t change. Use CSS to hit the elements you need directly, rather than cutting corners.

For the full story, see my article Shoot to Kill; CSS selector intent

! important

Only for supporting classes! Important. Use! Error {color:red! important; }.

Avoid active use! Important. For example, don’t use CSS as a cheat when it is very complex, clean up and refactor the previous sections, keep the selectors short and avoid grouping with ids.

Magic numbers and absolute positioning

Magic numbers are numbers that “happen to work,” and they are very bad to use because they treat the symptoms rather than the root cause and lack extensibility.

Hover ul {top: 37px; dropdown-nav li:hover ul {top: 37px; } Moving the drop-down menu down is far from a good idea, as 37px here is a magic number. The reason 37px works is because. Dropbox -nav happens to be 37px high.

Hover ul {top: 100%; dropdown-nav li:hover ul {top: 100%; }, the dropbox will move down 100% no matter how high the. Dropbox -down is.

Think twice before you put numbers in your code. If you can replace it with a keyword (top: 100%, “pull from top to bottom”), or if you have a better solution, try to avoid direct numbers.

Every number you leave behind in your CSS is a promise you make and don’t keep.

conditional

Styles written specifically for IE are largely avoidable, and the only things that need to be done specifically for IE are things that IE doesn’t support (PNG, for example).

In short, if you refactor CSS, all layouts and box models don’t need to be extra IE compatible. That means you basically don’t use IE compatible writing or anything like that.

Debugging

If you want to solve CSS problems, remove the old code and write new ones. If there are problems with old CSS, writing new code can’t fix them.

Cut out the CSS code and HTML until it’s bug-free, and you’ll know what the problem is.

Sometimes writing overflow: Hidden or some other code that hides the problem will make an immediate difference, but the overflow aspect may not be a problem at all. So we need to address the root causes, not just the symptoms.

CSS preprocessor

I use Sass. It should be used flexibly. Use Sass to make your CSS more powerful, but don’t make it too complicated to nest. In Vanilla CSS, use nesting only where necessary, for example:

.header{} .header .site-nav{} .header .site-nav li{} .header .site-nav li a{} Copy the code

This is not used in normal CSS at all. The following is a bad way to write Sass:

.header{ .site-nav{ li{ a{} } } } Copy the code

If you use Sass, try to write it this way:

.header{} .site-nav{ li{} a{} }Copy the code