The problem of CSS
Class name conflicts
When you write a CSS class, do you write a global class? Or do you want to write classes with multiple levels of selection?
You will find that nothing is good!
-
Too deep a hierarchy is bad for writing, reading, compression, and reuse
-
Too shallow a level can easily lead to class name conflicts
The problem gets worse when you add more styles, and it boils down to class name conflicts that are hard to resolve.
Repeat style
This problem is even more common, with repeated style values constantly appearing in CSS code, which is extremely difficult to maintain.
For example, there are only a few colors on a website:
- primary
- info
- warn
- error
- success
If there are more colors that are naturally derived from these hues, you can imagine that the colors will be all over the place like backgrounds, text, and borders, and once you have to adjust the colors, it’s a very big project.
CSS file segmentation problem
In large projects, CSS also needs to be broken down to make it easier to maintain the CSS code.
For example, if you have a module that does a caroute graph, it needs to rely not only on JS functions, but also on CSS styles. Since the dependent JS functions only care about caroute graphs, CSS styles should also only care about caroute graphs, and so on, different functions rely on different CSS styles, and common styles can be separated separately. This results in a different CSS file structure than in the past: more files, more finely split
At the same time, in the real operating environment, we want as few files as possible, this situation and JS encounter is consistent, therefore, for CSS, also need engineering management.
From another point of view, THE engineering of CSS will encounter more challenges, because CSS unlike JS, its syntax itself has not changed much after so many years (CSS3 is just a few more attributes), for the change of CSS syntax itself is also an engineering topic
How to solve
Over the years, no official solution has been put forward to solve the above problems, and some third-party organizations have proposed their own solutions to different problems.
Resolve class name conflicts
Some third-party organizations put forward some solutions to solve this problem. Common solutions are as follows:
Naming conventions
It provides a naming standard to resolve conflicts. Common naming standards include:
- BEM
- OOCSS
- AMCSS
- SMACSS
- other
Let me take BEM as an example:
BEM is a set of naming methods for CSS class styles. Other naming methods include OOCSS, AMCSS, SMACSS, and so on
BEM stands for Block Element Modifier
A complete BEM class name: block__element_modifier, for example, banner__dot_selected, can be used to refer to selected dots in the rotation diagram
The specific meanings of the three parts are as follows:
- Block: a large area of a page that represents a top-level division, such as banner, layout, article, etc
- Element: A component of an area, such as a banner image (banner__img), a container (banner__container), a header in a layout (layout__header), a title in an article (article__title)
- Modifier: Optional. Usually refers to a state, such as: the left side of the layout in the expanded state (layout__left_expand), the round chart dot in the selected state (banner__dot_selected)
In some large projects, if you use BEM nomenclature, you may add a prefix to indicate the purpose of the class name. Common prefixes include:
- L: layout, which indicates that the style is used for layout
- C: Component, indicating that the style is a component, that is, a functional area
- U: util, indicating that this style is a generic, utility style
- J: javascript, which means that this style has no practical meaning and is specifically provided to JS for retrieving elements
css in js
This is a bold solution, which argues that CSS itself is almost hopeless. It simply uses JS objects to represent styles and then applies them directly to the style of elements
In this way, CSS becomes object by object and can take full advantage of the JS language. You can:
- Returns a style object from a function
- Returns a common style extracted into a common module
- Use various features of JS to manipulate objects, such as blending, extracting, and splitting
- More variety
This solution is popular with React Native on mobile devices
The core idea of CSS in JS is to use a JS object to describe styles, not a CSS style sheet
For example, the following object is an object that describes styles:
const styles = {
backgroundColor: "#f40".color: "#fff".width: "400px".height: "500px".margin: "0 auto"
}
Copy the code
Since there are no class names in this way of describing styles, there are naturally no class name conflicts
How to apply styles to the interface is not its concern, you can use any technology, any framework, any way to apply it to the interface.
CSS in JS features:
- There is no possibility of conflict: Since there is no class name, there is no possibility of a class name conflict
- More flexible: can make full use of the flexible characteristics of JS language, with a variety of moves to deal with the style
- More widely applied: As long as the JS language is supported, CSS in JS can be supported. Therefore, it is very useful when developing mobile applications in JS language, because mobile applications may not support CSS
- Write the inconvenienceWriting styles, especially public ones, are not very easy to handle
- Add a lot of redundant content to the page: When dealing with CSS in JS in a page, the style is often added to the style attribute of the element, which will greatly increase the inline style of the element, and may have a lot of repetition, and it is not easy to read the final page code
css module
Very interesting and easy to use CSS modular solution, simple to write, absolutely not the same name
Limiting class names through naming conventions is too rigid, whereas CSS in JS is flexible enough, but hard to write. CSS Module opens up a new way to solve the problem of class name conflicts
Ideas:
The CSS Module uses the following ideas to resolve class name conflicts:
- CSS class name conflicts tend to occur in large projects
- Large projects often use build tools (WebPack, etc.) to build projects
- Build tools allow you to slice CSS styles into finer modules
- Like JS variables, it is difficult to have conflicting class names in each CSS module file. Conflicting class names often occur in different CSS module files
- Just make sure the build tool doesn’t have class name conflicts after merging the style code
Realize the principle of
In Webpack, as the CSS-loader that handles CSS, it implements the idea of CSS Module. To enable CSS Module, you need to set the configuration modules of CSS-Loader to true.
The implementation of CSS-Loader is as follows:
The principle is very simple. After the CSS Module is enabled, csS-Loader converts the class name in the style to a unique hash value.
The hash value is generated based on the module path and class name. Therefore, different CSS modules with the same class name will have different hash values.
How to apply styles:
The CSS Module introduces a new problem: the class name of the source code is not the same as the generated class name, and the developer only knows the class name in the source code, but does not know what the final class name is. So how to apply the class name to the element?
To solve this problem, CSS-Loader exports the mapping between the original class name and the final class name, which is described by an object
In this way, we can get the exported CSS module in the JS code to apply the class name
Style-loader removes all other information and exposes only the correspondence for the convenience of our application class name
Other operating
- Global name of the class
Some class names are global, static, and do not need to be converted, just use a special syntax at the class name position:
:global(.main){... }Copy the code
Class names that use global are not converted. Instead, class names that do not use global are used to indicate that local is used by default
:local(.main){... }Copy the code
The class name using Local indicates the local class name, which may cause conflicts and will be converted by the CSS Module
- How do I control the final class name
For the most part, we don’t need to control the final class name, because controlling it doesn’t make any sense
To control the final class name, you need to configure the localIdentName of the CSS-Loader
- Other Matters needing attention
- CSS Modules are often used with build tools
- The CSS Module only handles top-level class names. Try not to write nested class names, nor is it necessary
- The CSS Module handles only class names, not other selectors
- The CSS Module also handles ID selectors, but there is no reason to use them at any time
- Once you use a CSS Module, you don’t need to follow any other naming conventions as long as you keep the name of the class clear
Solve repetitive style problems
css in js
Although this solution can use JS language to solve the problem of repeated style values, but because it is too radical, many used to write CSS developers are not very comfortable writing
CSS precompiler
Some third parties have come up with an evolutionary version of the CSS language that supports advanced syntax such as variables and functions and then compiles them into normal CSS
This solution is very much like a build tool, but only for CSS
Common languages supported by precompilers are:
- less
- sass
The basic principle of
When writing CSS, it is often difficult to deal with some problems due to the limitations of the CSS language itself:
- Duplicate style values: for example, common color, common size
- Duplicate code snippets: for example, absolutely center, clear float
- Repeated nested writing
Due to the lack of official improvements to the CSS language itself, a number of third-party organizations have come up with solutions to these problems. One solution is precompilers.
The idea behind a precompiler is simply to write style code in a more elegant way and, through a compiler, convert it into traditional CSS code that can be recognized by browsers.
Currently, the most popular precompilers are LESS and SASS, and they are very similar. LESS is the main word here
- Lesscss.org/
- Less Chinese document 1 (unofficial) : lesscss.cn/
- Less (unofficial) : less.bootcss.com/
- Sass official website: sass-lang.com/
- Sass Chinese document 1 (unofficial) : www.sass.hk/
- Sass Chinese document 2 (unofficial) : sass.bootcss.com/
LESS installation and use
To use LESS, you must have the LESS compiler installed
The LESS compiler is developed based on Node and can be downloaded and installed via NPM
npm i -D less
Copy the code
Once less is installed, it provides a CLI tool, Lessc, that you can use to compile
Lessc less Code file The compiled code fileCopy the code
All talk and no practice fake handle:
Create a new index.less file and write it as follows:
/ / less code
@red: #f40;
.redcolor {
color: @red;
}
Copy the code
Run the command:
lessc index.less index.css
Copy the code
You can see the compiled code:
.redcolor {
color: #f40;
}
Copy the code
Basic usage of LESS
For details, see less.bootcss.com/
- variable
- hybrid
- nested
- operation
- function
- scope
- annotation
- The import
postcss
What is PostCss?
CSS engineering faces many problems, and there are various solutions to these problems. If YOU look at CSS in isolation, there’s a lot to deal with just the style itself.
Since there are so many things to deal with, why not lump them all together?
PostCss is based on this idea. PostCss is like a compiler that compiles style source code into the final CSS code
Does it look like LESS or SASS?
PostCss, however, is different from LESS and SASS in that it actually does some code analysis and gives the results of the analysis to plug-ins, which do the specific code conversion operations.
An official chart shows how postCSS works better:
This is a bit like WebPack, which itself does only dependency analysis, abstract syntax tree analysis, and the rest is done by plug-ins and loaders.
- Official website: postcss.org/
- Github address: github.com/postcss/pos…
The installation
PostCss is written based on Node and can therefore be installed using NPM
npm i -D postcss
Copy the code
Postcss library provides the corresponding JS API for converting code. If you want to use postCSS advanced features, or want to develop postCSS plug-ins, you need to use postCSS API. The documentation address of the API is api.postcss.org/
But most of the time, we’re all consumers, and we don’t want to use PostCss in code
Therefore, we can install another postCSs-CLI to complete the compilation from the command line
npm i -D postcss-cli
Copy the code
Postcss – THE CLI provides a command that calls the API in PostCSS to complete compilation
The command can be used as follows:
Postcss source file -O output fileCopy the code
The configuration file
Like WebPack, PostCSS has its own configuration file that affects some of the compilation behavior of PostCSS.
The default name of the configuration file is postcss.config.js
Such as:
module.exports = {
map: false./ / close the source - the map
}
Copy the code
The plug-in
Using PostCSS alone doesn’t make much sense; for it to really work, you need plug-ins
Postcss plugin market: www.postcss.parts/
Here are some common postCSS plugins:
postcss-preset-env
In the past, postCSS tended to use a large number of plug-ins, each of which solved some problems. As a result, installing and configuring plug-ins was cumbersome.
Postcss-preset -env is called postCSS preset environment, which integrates many common presets together and helps you complete the basic configuration. You only need to install one preset and many presets are installed.
After installing the plug-in, add the following configuration to the PostCSS configuration
module.exports = {
plugins: {
"postcss-preset-env": {} // {} can fill in the plug-in configuration}}Copy the code
There are many functions in this plugin, such as:
- Automatic vendor prefix
You can implement some new CSS styles that require vendor prefixes in older browsers
Such as:
::placeholder {
color: red;
}
Copy the code
This feature needs to be written as in different older browsers
::-moz-placeholder{
color: red;
}
:-ms-input-placeholder{
color: red;
}
::placeholder{
color: red;
}
Copy the code
To do this, you need to use the Autoprefixer library. Postcss-preset -env contains this library and automatically has this feature.
To adjust the compatible browser range, perform the following operations:
Method 1: Add the.browserslistrc file
Create a file. Browserslistrc, fill in the configuration
last 2 version
> 1%
Copy the code
Method 2: Add browserslist to package.json configuration
"browserslist": [
"last 2 version"."1%" >
]
Copy the code
Browserslist is a multi-line (array) standard string.
Its writing specifications are many and tedious, for details, see: github.com/browserslis…
In general, most websites use the following format for writing
last 2 version
> 1% in CN
not ie <= 8
Copy the code
- Last 2 Version: Compatible with the latest two versions of the browser
- 1% in CN: matches the browser used by more than 1% of the Chinese population. In CN can be omitted
- Not Ie <= 8: Excludes Internet Explorer whose version number is less than or equal to 8
When matching results, union is sought by default.
You can use the web site browserl. Ist/to query the browser whose configuration results are overwritten. Multiple lines are separated by commas.
The data of BrowserList is from the CanIUse website and is not particularly accurate because the data is not real-time
- The future of CSS syntax
Some of the cutting-edge syntax of CSS is in the works, but it is not a true standard. If you want to use this syntax, you need to compile it for browser compatibility
In the past, the cSSNext library compiled this syntax, but with postCSS-Preset -env, it automatically includes this feature.
Postcss-preset -env can be used to tell postCSS-preset -env which stage CSS syntax needs to be preset for compatibility processing, and the default is 2
"postcss-preset-env": {
stage: 0
}
Copy the code
There are five stages that can be configured:
- Stage 0: Aspirational – just an early draft, extremely unstable
- Stage 1: Experimental – Still extremely unstable, but the proposal has been accepted by W3C
- Stage 2: Allowable – not stable but ready for use
- Stage 3: Embraced – Relatively stable, perhaps with some minor changes in the future, it is becoming the final standard
- Stage 4: Standardized – W3C standards that all major browsers should support
With that in mind, let’s take a look at the CSS syntax of the future. Although some of the syntax is still in its very early stages, the plug-in exists and will still be recognized by browsers when compiled
(1) variables
The CSS syntax of the future will naturally support variables
Define common variables in :root{}, naming them with the — prefix
:root{
--lightColor: #ddd;
--darkColor: #333;
}
a{
color: var(--lightColor);
background: var(--darkColor);
}
Copy the code
After compilation, the original syntax is still visible, because the presence of some new syntax does not affect the browser’s rendering, although the browser may not be aware of it. If you do not want to see the new syntax in the result, you can configure postCSs-preset -env to preserve to false
② Custom selectors
@custom-selector :--heading h1, h2, h3, h4, h5, h6;
@custom-selector :--enter :focus,:hover;
a:--enter{
color: #f40;
}
:--heading{
font-weight:bold;
}
:--heading.active{
font-weight:bold;
}
Copy the code
The compiled
a:focus,a:hover{
color: #f40;
}
h1,h2,h3,h4,h5,h6{
font-weight:bold;
}
h1.active,h2.active,h3.active,h4.active,h5.active,h6.active{
font-weight:bold;
}
Copy the code
(3) nested
Same as LESS, except that nested selectors must be preceded by the symbol &
.a {
color: red;
& .b {
color: green;
}
& > .b {
color: blue;
}
&:hover {
color: #000; }}Copy the code
The compiled
.a {
color: red
}
.a .b {
color: green;
}
.a>.b {
color: blue;
}
.a:hover {
color: #000;
}
Copy the code
2, postcss – the apply
This plugin supports the ability to write property sets in CSS, similar to the blend of LESS, which takes advantage of CSS’s new syntax to define a CSS snippet and then applies it as needed.
:root {
--center: {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
};
}
.item{
@apply --center;
}
Copy the code
The compiled
.item{
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
Copy the code
Aid is actually cSSNext. Why is postCSS-PRESET -env not supported
3, postcss – color – function
The plugin supports the use of color functions in the source code
body {
/* Use the color #aabbcc without any processing, equivalent to writing #aabbcc */
color: color(#aabbcc);
/* Set the color #aabbcc opacity to 90% */
color: color(#aabbcc a(90%));
/* Set the red part of color #aabbcc to 90% */
color: color(#aabbcc red(90%));
/* Lighten the color #aabbcc by 50% (more white) similar to the lighten function in less */
color: color(#aabbcc tint(50%));
/* Darken the color #aabbcc by 50% (more black), similar to the Darken function */ in less
color: color(#aabbcc shade(50%));
}
Copy the code
The compiled
body {
/* Use the color #aabbcc without any processing, equivalent to writing #aabbcc */
color: rgb(170.187.204);
/* Set the color #aabbcc opacity to 90% */
color: rgba(170.187.204.0.9);
/* Set the red part of color #aabbcc to 90% */
color: rgb(230.187.204);
/* Lighten the color #aabbcc by 50% (more white) similar to the lighten function in less */
color: rgb(213.221.230);
/* Darken the color #aabbcc by 50% (more black), similar to the Darken function */ in less
color: rgb(85.94.102);
}
Copy the code
4, stylelint
Liverpoolfc.tv: stylelint. IO /
The Stylelint plugin detects errors in real time when you might incorrectly or improperly write CSS code in real development.
Since different companies may use different CSS writing specifications, Stylelint itself does not provide specific rule validation in order to remain flexible.
You will need to install or write your own rule validation scheme
Typically, we install the tylelint-config-standard library to provide standard CSS rule determination
Once installed, we need to tell the stylelint to use the library for rule validation. There are several ways to tell, the most common being to use files. Stylelintrc
//.styleintrc
{
"extends": "stylelint-config-standard"
}
Copy the code
At this point, if your code has any irregularities, an error will be reported at compile time
body {
background: #f4;
}
Copy the code
Two errors occurred:
- The indent should have only two Spaces
- The hexadecimal color value is incorrect
If certain rules are not expected, they can be set in the configuration:
{
"extends": "stylelint-config-standard"."rules": {
"indentation": null}}Copy the code
Set to NULL to disable this rule, or set to 4 to indicate that an indent has four Spaces. For specific Settings, see the stylelint document: stylelint.io/
But this type of error reporting needs to happen at compile time, so what if I want to automatically report an error in the editor as I write the code? To do this in an editor, install vscode’s stylelint plug-in, which reads the configuration file in your project and reports errors in real time.
Resolve CSS file segmentation
For this part, we rely on building tools such as Webpack, which use some loaders or plugins to package, merge and compress CSS files.
Use WebPack to split CSS
To split CSS, you have to think of CSS as a module like JS; To treat CSS as a module, you must have a build tool (Webpack) that has the ability to merge code, whereas webPack itself can only read the contents of CSS files and analyze them as JS code, thus leading to errors.
Therefore, there must be a loader that can convert CSS code into JS code
css-loader
Css-loader converts CSS code into JS code, which is shockingly simple: it exports the CSS code as a string.
Such as:
.red{
color:"#f40";
}
Copy the code
After csS-Loader conversion into JS code:
module.exports = `.red{ color:"#f40"; } `
Copy the code
The js code above is simplified by me and does not represent the real CSS-Loader converted code. The code converted by CSS-Loader will be a bit complicated and will export more information, but the core idea remains the same.
Such as:
.red{
color:"#f40";
background:url("./bg.png")}Copy the code
After csS-Loader conversion into JS code:
var import1 = require("./bg.png");
module.exports = `.red{
color:"#f40";
background:url("${import1}` ")};
Copy the code
In this way, webpack’s subsequent processing adds the dependency./bg.png to the module list, and then converts the code to
var import1 = __webpack_require__("./src/bg.png");
module.exports = `.red{
color:"#f40";
background:url("${import1}` ")};
Copy the code
Such as:
@import "./reset.css";
.red{
color:"#f40";
background:url("./bg.png")}Copy the code
Will convert to:
var import1 = require("./reset.css");
var import2 = require("./bg.png");
module.exports = `${import1}
.red{
color:"#f40";
background:url("${import2}` ")};
Copy the code
To summarize, csS-Loader does:
- Export the contents of the CSS file as a string
- Import other dependencies in the CSS as require so that WebPack can analyze the dependencies
style-loader
Since CSS-Loader only provides the ability to convert CSS to string exports, other loaders or plugins take care of the rest.
Style-loader can further process the code after CSS-Loader conversion, and add the exported string to the style element of the page
Such as:
.red{
color:"#f40";
}
Copy the code
After csS-Loader conversion into JS code:
module.exports = `.red{ color:"#f40"; } `
Copy the code
Style-loader converts to:
module.exports = `.red{ color:"#f40"; } `
var style = module.exports;
var styleElem = document.createElement("style");
styleElem.innerHTML = style;
document.head.appendChild(styleElem);
module.exports = {}
Copy the code
The above code is simplified code and does not represent real code. Style-loader is capable of avoiding repeated import of the same style
Remove the CSS file
Currently, CSS code is converted by CSS-Loader and handed over to style-loader for processing. Style-loader uses a piece of JS code that adds the style to the style element. In real development, we often want to rely on styles that end up in a CSS file. In this case, we need a library: mini-CSS-extract-Plugin
The library provides 1 plugin and 1 loader
- Plugin: Generates CSS files
- Loader: records the content of the CSS file to be generated and exports the style objects after csS-Module is enabled
Usage:
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
module: {
rules: [{test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader? modules"]]}},plugins: [
new MiniCssExtractPlugin() // Generate CSS files]}Copy the code
Configure the generated file name
Filename has the same meaning as output.filename, which is a style filename generated according to chunk.
Configure the generated file name, for example, [name].[contenthash:5].css
By default, there is one CSS file for each chunk.
Above is my share today, I hope to help you, if there is any problem, I hope you can correct, thank you!
📌 finally
If there are any mistakes in the webpack compilation principle, please give me your comments and be sure to listen to your comments
Finally, you can also follow my public account: “Front-end Hunter”, or add my wechat (wKavin) to communicate privately.