The full text contains more than 4,000 words and is expected to take 30 minutes.

As we all know, CSS matches elements globally by selector name. It has no scope. For example, if you use the same class name in two different places on the page, the style defined first will be overwritten. CSS has always lacked the concept of modularity, and naming conflicts will continue to haunt you. Each time a selector name is defined, it takes into account whether the same name is used in other files, especially in component development. ðŸ’Ģ ðŸ’Ģ ðŸ’Ģ

Ideally, as we develop a component, we should be able to name its elements as we please, as long as it is semantic, and not worry about whether it conflicts with styles outside the component.

Similar to AMD, CMD, CommonJS, ES Modules, etc., in the JavaScript community, the CSS community has produced corresponding modular solutions: BEM, OOCSS, SMACSS, ITCSS, CSS Modules and CSS-in-JS, etc.

Based on the characteristics of these CSS modularity solutions, I simply categorize them into three broad categories:

  1. CSS naming methodology: Using artificial conventions for naming.
  2. CSS Modules: A CSS file is an independent module.
  3. Css-in-js: Writes CSS in JS.

CSS naming methodology

In order to avoid the problem of CSS selector naming conflicts, and to achieve better MODULarity of CSS, the CSS community in the early days of the birth of some CSS naming methodologies, such as BEM, OOCSS, SMACSS, ITCSS, SUITCSS, Atomic CSS and so on.

They almost all have a common trait — adding lengthy prefixes or suffixes to selectors and trying to artificially generate globally unique names. This undoubtedly increases the complexity and maintenance cost of class naming, and also makes HTML tags bloated.

BEM

BEM (Block Element Modifier) is a typical CSS naming methodology proposed by the Yandex team (China’s equivalent of Baidu) before 2009. Its core idea is to ensure the uniqueness of the selector through the uniqueness of the component name, so that the style does not pollute the component.

The BEM naming convention is.block-name__element-name–modifier-name, that is. Module name __ Element name — The three parts of the decorator name are clearly distinguished by the double underscore __ and the element name by the double dash. You can also use custom naming styles, such as hump, single underline, single line, and so on, while keeping the core ideas of BEM.

Child selectors are not recommended in BEM because each class name is already globally unique, except in cases where blocks are nested within each other.

<! -- Example module -->
<div class="card">
  <div class="card__head">
    <ul class="card__menu">
      <li class="card__menu-item">menu item 1</li>
      <li class="card__menu-item">menu item 2</li>
      <li class="card__menu-item card__menu-item--active">menu item 3</li>
      <li class="card__menu-item card__menu-item--disable">menu item 4</li>
    </ul>
  </div>
  <div class="card__body"></div>
  <div class="card__foot"></div>
</div>
Copy the code
.card {}
.card__head {}
.card__menu {}
.card__menu-item {}
.card__menu-item--active {}
.card__menu-item--disable {}
.card__body {}
.card__foot {}
Copy the code

Write BEM more efficiently using the parent element selectors of Sass/Less/Stylus:

.card {
  &__head {}
  &__menu {
    &-item {
      &--active {}
      &--disable {}
    }
  }
  &__body {}
  &__foot {}
}
Copy the code

OOCSS

OOCSS (Object-oriented CSS) is the object-oriented CSS. It draws lessons from the abstract thinking of OOP (object-oriented programming) and advocates the abstraction of the element style into multiple independent small style classes to improve the flexibility and reusability of the style.

OOCSS has two basic principles:

  1. Independent structure and style. That is, do not write layout styles such as positioning and size in the same selector as presentation styles such as font and color.
  2. Separate containers and contents. Make the behavior of the object predictable, avoid position dependence, and the child elements should display correctly even when they leave the container.

For example, we have a container that is 1/4 of the width of the page, has a blue background, 1px gray borders, 10px left and right margins, 5px top margins, and 10px bottom margins. For such a style, we used to create a class for the container and write the styles together. It looks like this.

<div class="box"></div>

<style>
  .box {
    width: 25%;
    margin: 5px 10px 10px;
    background: blue;
    border: 1px solid #ccc;
  }
</style>
Copy the code

Use OOCSS, however, we cannot do this, OOCSS requirements for this container to create more “atomic classes”, and each style has a class, this is for the sake of the back style can reuse these components, to avoid repetition and to write the same style, take this instance, we add the following class to the container:

<div class="size1of4 bgBlue solidGray mt-5 ml-10 mr-10 mb-10"></div>

<style>
  .size1of4 { width: 25%; }
  .bgBlue { background: blue; }
  .solidGray { border: 1px solid #ccc; }
  .mt-5 { margin-top: 5px; }
  .mr-10 { margin-right: 10px }
  .mb-10 { margin-bottom: 10px; }
  .ml-10 { margin-left: 10px; }
</style>
Copy the code

The biggest advantage of OOCSS is that it maximizes style reusability and significantly reduces the overall amount of CSS code. The downside is obvious, you need to collect a large number of class names for each element, which can be a lot of manual work 😅.

In OOCSS, class names should convey both the object’s purpose and generality, such as mod, complex, POP, etc. Naming CSS classes too semantically, such as navigation-bar, limits them to the navigation bar and prevents them from being applied elsewhere on the web.

SMACSS

SMACSS (Scalable and Modular Architecture for CSS) is a Scalable and Modular CSS Architecture proposed by Jonathan Snook in yahoo 2011.

SAMCSS divides components into five categories based on their functions and features:

  1. Base defines the default style for HTML elements, which can contain selectors for attributes, pseudo-classes, and so on.
  2. A Layout divides a page into sections and can be used as a high-level container containing one or more modules, such as left and right columns, a grid system, and so on.
  3. Modules, also known as objects or blocks, are reusable modular parts, such as navigation bars, product lists, and so on.
  4. State describes the appearance of any module or layout in a particular State, such as hidden, active, and so on.
  5. A Theme, also known as a skin, describes the appearance of a page and can modify the styles of the first four categories, such as link colors, layout, and so on.

SMACSS recommends using prefixes to distinguish different parts:

  1. The underlying rules apply directly to elements and therefore do not require prefixes.
  2. The layout prefix isl- 或 layout-, e.g..l-table,.layout-gridAnd so on.
  3. The module prefix ism-Or the name of the module itself, for example.m-nav,.card,.fieldAnd so on.
  4. The state prefix isis-, e.g..is-active,.is-currentAnd so on.
  5. The theme prefix istheme-, e.g..theme-light,.theme-darkAnd so on.
<form class="layout-grid">
  <div class="field">
    <input type="search" id="searchbox" />
    <span class="msg is-error">There is an error!</span>
  </div>
</form>
Copy the code

ITCSS

Inverted Triangle CSS (ITCSS) is a CSS architecture that is easy to extend and manage. It is compatible with CSS naming methodology such as BEM, OOCSS and SMACSS. ITCSS uses the idea of layering to manage your style files, similar to MVC layering in server-side development.

ITCSS divides CSS style rules into the following levels:

  1. Settings: Global variables used by the project, such as color, font size, etc.
  2. Tools: Mixins and functions used by the project. As of Tools, no specific CSS code is generated.
  3. Generic: Basic Settings, such as reset.css and normalize.css.
  4. Base: The most basic elements, such as IMG, P, link, list, etc.
  5. Objects: Certain design patterns, such as horizontal centering,
  6. Components: UI Components, such as button, Switch, Slider, etc.
  7. Trumps: Styles used for auxiliary and fine tuning, available only for this layer! important.

The hierarchical logic of ITCSS becomes more concrete and more restricted to a specific scenario.

According to the idea of ITCSS, you can organize your CSS style files like this:

│ ├─ Colors. │ ├─ Colors. │ ├─ Colors-layersThe SCSS │ └ ─ ─ breakpoints. SCSS ├ ─ ─ the tools / │ ├ ─ ─ mixins. SCSS │ └ ─ ─ functions provides the SCSS ├ ─ ─ generic / │ ├ ─ ─ box-sizing. SCSS │ └ ─ ─ the normalize. SCSS ├ ─ ─ base / │ ├ ─ ─ img. SCSS │ └ ─ ─ the list. The SCSS ├ ─ ─ objects / │ ├ ─ ─ the grid. The SCSS │ └ ─ ─ media. The SCSS ├ ─ ─ Components / │ ├ ─ ─ buttons. SCSS │ └ ─ ─ the slider. The SCSS ├ ─ ─ trumps / │ ├ ─ ─ widths. The SCSS │ └ ─ ─ gaps. The SCSS └ ─ ─ index. The SCSSCopy the code

Here are a few itCSs-based template projects for your reference:

  • Github.com/itcss/itcss…
  • Github.com/gpmd/itcss-…
  • Github.com/cameronroe/…

CSS Modules

📚 mentioned above these CSS named methodology, although has not applicable to today’s workflow automation and large front environment, but they have the time background of its birth, has promoted the development of the CSS modular, behind the design also worthy of our study, even sometimes we still can see their shadows in some occasions.

Developers get frustrated naming prefixes and suffixes by hand, and CSS Modules, a true modularity tool, is born.

CSS Modules allow us to import a CSS Module just as we import a JS Module. Each CSS file is an independent module, and each class name is an attribute of the object exported by the module. In this way, you can explicitly specify the CSS style to be referenced at use. Also, CSS Modules automatically confuse the ID and class into globally unique hash values when they are packaged to avoid naming conflicts.

Here only lists some core features of CSS Modules. For more details, please refer to the official website or Ruan’s “CSS Modules Usage Tutorial”.

CSS Modules features:

  • scope: Names in modules are local scopes by default, defined in:localThe name is also local in scope and is defined in:globalThe names in are globally scoped, and global names are not compiled into hash strings.
  • named: For local class names, CSS Modules recommend using camelCase to make JS files cleaner, i.estyles.className. But you can still use it doggedlystyles['class-name']Permitted but not encouraged. ðŸĪŠ
  • combinationUse:composesProperty to inherit the style of another selector, which is different from Sass’s@extendThe rules are similar.
  • variableUse:@valueTo define variables, but you need to install PostCSS andpostcss-modules-valuesThe plug-in.
/* style.css */
:global(.card) {
  padding: 20px;
}
.article {
  background-color: #fff;
}
.title {
  font-size: 18px;
}
Copy the code
// App.js
import React from 'react'
import styles from './style.css'

export default function App() {
  return (
    <article className={styles.article}>
      <h2 className={styles.title}>Hello World</h2>
      <div className="card">Lorem ipsum dolor sit amet.</div>
    </article>)}Copy the code

Compile result:

<style>
  .card {
    padding: 20px;
  }
  .style__article--ht21N {
    background-color: #fff;
  }
  .style__title--3JCJR {
    font-size: 18px;
  }
</style>

<article class="style__article--ht21N">
  <h2 class="style__title--3JCJR">Hello World</h2>
  <div class="card">Lorem ipsum dolor sit amet.</div>
</article>
Copy the code

CSS Modules integrated

Using CSS Modules in Webpack (enable Modules for CSS-Loader) :

// webpack.config.js -> module.rules
{
  test: /\.(c|sa|sc)ss$/i,
  exclude: /node_modules/,
  use: [
    'style-loader',
    {
      loader: 'css-loader'.options: {
        importLoaders: 2.// Enable CSS Modules
        modules: true.// With CSS Modules, it's easy to automatically generate BEM style names
        localIdentName: '[path][name]__[local]--[hash:base64:5]',}},'postcss-loader'.'sass-loader',]},Copy the code

Using CSS Modules in PostCSS (using the PostCSs-Modules plugin) :

// postcss.config.js
module.exports = {
  plugins: {
    'postcss-modules': {
      generateScopedName: '[path][name]__[local]--[hash:base64:5]',,}}}Copy the code

Used with the CSS preprocessor

It is recommended to use CSS Modules with a CSS preprocessor (Sass, Less, or Stylus).

The CSS preprocessor provides many useful features, such as nesting, variables, mixins, functions, and so on, while also making it easy to define local or global names.

:global(.title) {
  color: yellow;
}

:global {
  .global-class-name {
    color: green; }}Copy the code

VSCode extension support

Writing CSS Modules code in VSCode is not smart enough by default.

You can install the CSS Modules extension.

CSS-in-JS

React breaks the old “separation of concerns” principle of web development by adopting a component structure that forces HTML, CSS, and JS code to be written together. It looks like a technological step backwards, but it’s not.

React encapsulates HTML and CSS in JS, giving HTML and CSS a whole new “programming capability”. For HTML, JSX is a syntactic extension of JS, which you can think of as HTMl-in-js; For CSS, a series of third-party libraries have been developed to enhance the ability to manipulate CSS in JS, called CSS-in-JS.

With the popularity of React and the popularity of component-based development, this new approach of “mixed concerns” has become mainstream.

Any application that can be written in JavaScript, will eventually be written in JavaScript. —— Jeff Atwood

The CSS-in-JS library now has dozens of implementations, and you can quickly try different implementations on CSS in JS Playground. Here are some popular CSS-in-JS libraries:

  • Styled-components:github.com/styled-comp… 33K (recommended)
  • Emotion:github.com/emotion-js/… 13k
  • Radium:github.com/FormidableL… 7K (no longer maintained)
  • Styled System:github.com/styled-syst… 7k
  • Styled-jsx:github.com/vercel/styl… 6k
  • JSS:github.com/cssinjs/jss 6 k.

Styled – components 💅

Styled – Components is the most popular CSS-in-JS library, and is widely used in React.

It uses the template string functionality provided by ES6 to construct “style components.”

// styles.js
import styled, { css } from 'styled-components'

// Create a style component called Wrapper (a section tag with styles)
export const Wrapper = styled.section` padding: 10px; background: deepskyblue; `

// Create a style component called Title (an H1 tag with some styles)
export const Title = styled.h1` font-size: 20px; text-align: center; `

// Create a style component called Button (a Button label with some styles and a primary parameter)
export const Button = styled.button`
  padding: 10px 20px;
  color: #333;
  background: transparent;
  border-radius: 4px;

  ${(props) => props.primary && css`
    color: #fff;
    background: blue;
  `}
`
Copy the code
// App.js
import React from 'react'
import { Wrapper, Title, Button } from './styles'

// Then use these style components just like the other React components
export default function App() {
  return (
    <Wrapper>
      <Title>Hello World, this is my first styled component!</Title>
      <Button>Normal Button</Button>
      <Button primary>Primary Button</Button>
    </Wrapper>)}Copy the code

More tips (please refer to the official documentation for more details) :

  • You can pass parameters to style components by interpolation (props), which is especially useful when you need to dynamically generate style rules.
  • You can use the constructorstyled()To inherit the style of another component.
  • usecreateGlobalStyleTo create global CSS rules.
  • Styled – Components automatically adds the browser compatibility prefix.
  • Styled – Components Based on stylis (a lightweight CSS preprocessor), you can use nested syntax directly in style components, as in Sass/Less/Stylus.
  • The Babel plug-in, babel-plugin-styled- Components, is strongly recommended (although this is not required). It provides support for a better debugging experience, such as clearer class names, SSR support, compressed code, and more.
  • You can also use styled- Components in Vue, vue-styled- Components, but no one seems to do that
  • By default, CSS code in template strings does not have smart hints and syntax highlighting in VSCode. Extensions need to be installed.

Correct posture for writing CSS in Vue

Method 1: Using Scoped CSS (recommended)

To enable component style scoped CSS, add the scoped attribute to the

Behind the scenes, Vue adds a globally unique attribute selector to all elements in the component, such as [DATA-V-5298C6bf], so that CSS within the component only applies to elements in the current component.

<template>
  <header class="header">header</header>
</template>

<style scoped>
.header {
  background-color: green;
}
</style>
Copy the code

Compile result:

<header class="header" data-v-5298c6bf>header</header>

<style>
.header[data-v-5298c6bf] {
  background-color: green;
}
</style>
Copy the code

Method 2: Use CSS Modules

To enable CSS Modules, add the Module attribute to the

Behind the scenes, Vue injects a calculated property called $style into the component and obliquates the class name, which you can then use in the template via a dynamic class binding.

<template>
  <header :class="$style.header">header</header>
</template>

<style module>
.header {
  background-color: green;
}
</style>
Copy the code

Compile result:

<header class="App__header--382G7">header</header>

<style>
.App__header--382G7 {
  background-color: green;
}
</style>
Copy the code

Correct posture for writing CSS in React

React doesn’t give us anything like Vue Scoped, and we need to implement CSS modularity in other ways.

React has a lot of CSS postures. Here are some of the most common:

  1. Styled Components: Styled components is the most popular and useful CSS-in-JS library, which combines some of the most popular syntax of CSS, JS and React development. It is easy to use and powerful.
  2. Using CSS Modules: Managing CSS externally, and then mapping the class name inside the component, it assigns a globally unique hash to each class. In addition, these two plugins will help you better use CSS Modules in React: react-css-modules and babel-plugin-react-CSs-modules.

CSS Modules and Styled components are two distinct CSS modularization schemes. The essential difference is that the former manages the CSS externally, while the latter manages the CSS in components. Styled Components are recommended if you are comfortable with the CSS-in-JS programming model. If that’s too radical for you, use CSS Modules. It doesn’t matter which system you choose to use to manage the project.

The resources

  1. BEM: A New Front-end Methodology — Smashing Magazine
  2. Battling BEM CSS: 10 Common Problems And How To Avoid Them — Smashing Magazine
  3. An Introduction To Object Oriented CSS (OOCSS) — Smashing Magazine
  4. MicheleBertoli/css-in-js: React: CSS in JS techniques comparison
  5. CSS Modules Usage Tutorial – Ruan Yifeng’s weblog
  6. Introduction to CSS in JS – Ruan Yifeng’s weblog