Viki

Viki 写东西的地方

努力上进且优秀
github
email
x
steam
bilibili
douban

CSS Style Isolation and Performance Optimization

Development history of CSS:

Native CSS rules are globally effective. To avoid style conflicts, many solutions have been developed.

BEM Naming Convention#

To avoid naming conflicts at the development level, make class names more meaningful, provide more description and clearer structure, and make CSS more readable, the BEM (Block, Element, Modifier) front-end CSS naming convention was introduced by the Yandex team:

  • - hyphen: used as a hyphen to connect multiple words of a block or sub-element
  • __ double underscore: used to connect blocks and their sub-elements
  • -- double hyphen: used to describe and modify the state or type of an element
/* Block represents a single component or module */
.article-detail {
  display: flex;
}

/* Element is a component of the block */
.article-detail__button {
  width: 120px;
  height: 36px;
}

/* Modifier is used to describe and modify the state or type of an element */
.article-detail__button--primary {
  color: #fff;
  background-color: #3af;
}

However, the drawback is that the BEM naming convention is tedious to write by hand, has low development efficiency, and is difficult to maintain.

CSS Modules#

CSS Modules are essentially CSS files that cannot be used independently and need to be used with build tools. They provide many new features to native CSS, such as explicitly writing:

  • Local and global CSS rules can be explicitly written
  • Can be loaded and used in JS files as modules
  • Class names are converted to hash values during packaging to prevent CSS class name conflicts
/* style.css */
.className {
  color: green;
  background: red;
}
.otherClassName {
  /* Supports style composition */
  composes: className;
  color: yellow;
}
.otherClassName {
  /* Supports importing from other files */
  composes: className from './style.css';
}
/* The above styles are by default locally scoped */

/* Local scope */
:local(p) {
  color: #333;
}
/* Global scope */
:global(p) {
  color: #333;
}
import styles from './style.css'
// import { className } from "./style.css";
element.innerHTML = '<div class="' + styles.className + '">'
// element.innerHTML = '<div class="' + styles['class-name'] + '">';

When used with webpack, the configuration is as follows:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: {
          loader: 'css-loader',
          options: {
            modules: {
              // Custom hash name, can use variables
              localIdentName: '[path][name]__[local]--[hash:base64:5]'
            }
          }
        }
      }
    ]
  }
}

The effect after packaging (class names are converted to custom hash name format):

._2DHwuiHWMnKTOYG45T0x34 {
  color: red;
}

._10B-buq6_BEOTOl9urIjf8 {
  background-color: blue;
}

Sass, Less, and Stylus#

To facilitate front-end developers in writing CSS, many preprocessors have been developed:

In general, they have the following features in addition to differences in syntax and certain features:

  • Default local scope
  • Support for nested rules
  • Support for style composition and inheritance
  • Support for importing external style files of the same preprocessor (@import)
  • Allow the use of variables and functions (color functions, etc.)
  • Class names are hashed during compilation, avoiding conflicts

In addition to these, different preprocessors also have different features such as conditional statements and loop statements. Please refer to the documentation of the corresponding preprocessor for details.

One thing to note is that if the @import imports a native CSS format file, it will generate additional http requests.

On the other hand, if the @import imports a file specific to the preprocessor, it is imported at the syntax and semantic level, rather than importing native CSS. It will be processed during compilation and only one CSS file will be generated, without increasing http requests.

/* Importing native CSS will increase http requests */
@import 'reset.css';

/* Preprocessor format, less is the file extension of the corresponding preprocessor, such as scss, styl */
/* body.less */
body {
  background: #eee;
}
/* style.less */
@import 'body.less';

PostCSS#

With the continuous development of front-end engineering, more and more tools have been developed to delegate repetitive work to build tools. In the CSS field, PostCSS has emerged.

There is a saying about PostCSS that I think is very true:

PostCSS can be called the Babel of the CSS world.

PostCSS analyzes the syntax tree (AST) of CSS and processes the analysis results to complete a series of tasks that are considered tedious and complex by front-end developers. Common use cases include:

  • Using language syntax validation tools to detect syntax errors, such as stylelint
  • Transpiling and polyfilling CSS next-generation syntax rules
  • Implementing specific functionality with plugins, such as automatically adding browser prefixes using autoprefix

CSS Performance Optimization#

Common ways to optimize CSS performance:

  • Reduce file splitting: Requesting multiple CSS files is subject to network constraints
  • Reduce CSS nesting, recommended to not exceed three levels
  • Remove unnecessary CSS selectors, use CSS selectors wisely, for example, no need to add other selectors before an id selector
  • Reuse styles of similar elements, such as button, input elements, etc.
  • Reduce the use of universal selectors (*) and attribute selectors ([name=nav]), as these selectors usually require traversing all elements
  • Remove invalid and duplicate styles, for example, some properties have inheritance, so if the parent element defines them, the child elements do not need to set them again
  • Separate common CSS rules between pages into separate CSS files, such as normalize.css, so that the browser only needs to load them once (cached for subsequent use)
  • Use CSS sprites to reduce the number of requests for images and icons
  • Use CSS compression tools or project compilation and packaging tools to optimize CSS
  • Reduce the use of @import, as it will generate additional requests and affect the loading order (except for CSS preprocessors)
  • Minimize frequent and significant layout reflows (window, element, text size changes, layout switching, size calculations, etc.) to reduce rendering overhead
  • Avoid using JS to change individual CSS styles. If necessary, define CSS classes and change styles by changing class names
  • Reduce the use of complex and performance-demanding CSS animations
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.