This article is from the #React tutorial series: https://mp.weixin.qq.com/mp/appmsgalbum?__biz=Mzg5MDAzNzkwNA==&action=getalbum&album_id=1566025152667107329 )
1. CSS solution in React
1.1. css in react
In fact, CSS has always been a pain point for React, and it is also a point that many developers complain about and criticize.
Choosing the right CSS solution in componentization should meet the following criteria:
- You can write local CSS: CSS has its own scope and will not pollute the native content in other components at will;
- You can write dynamic css: you can get some status of the current component and generate different css styles according to the changes in the status;
- Supports all CSS features: pseudo-classes, animations, media queries, etc.;
- It is simple and convenient to write, and it is best to conform to the consistent CSS style characteristics;
- etc…
At this point, Vue does far better than React:
- Vue writes its own styles by
.vue
writing tags in files ;<style><style>
- Determine whether the written style is globally valid or locally valid by adding the scoped attribute;
- Use the lang attribute to set your favorite preprocessors such as less and sass;
- Set and change css according to the latest status through inline styles;
- etc…
Although Vue cannot be called perfect in CSS, it is simple, natural and convenient enough. At least the unified style will not cause multiple developers and multiple projects to adopt different styles.
In comparison, React officially does not provide a unified style in React:
- From this, there are dozens of different solutions and hundreds of different libraries, from ordinary css, to css modules, to css in js;
- Everyone is looking for the best or most suitable CSS solution, but so far there is no unified solution;
In this article, I will introduce four selected solutions:
- Option 1: How to write inline styles;
- Option 2: Ordinary CSS writing method;
- Option 3: css modules;
- Option 4: css in js (styled-components);
1.2. Common solutions
1.2.1. Inline styles
Inline style is an officially recommended way of writing CSS styles:
style
Accepts a JavaScript object using camelCase named properties instead of CSS strings;- And you can reference
state
the state in it to set related styles;
export default class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
titleColor: "red"
}
}
render() {
return (
<div>
<h2 style={
{
color: this.state.titleColor, fontSize: "20px"}}>我是App标题</h2>
<p style={
{
color: "green", textDecoration: "underline"}}>我是一段文字描述</p>
</div>
)
}
}
Advantages of inline styles:
-
Inline styles, there will be no conflict between styles
-
You can dynamically obtain the current
state
status
Disadvantages of inline styles:
-
You need to use camel case in writing.
-
Some styles have no hints
-
Lots of styles, confusing code
-
Some styles cannot be written (such as pseudo-classes/pseudo-elements)
Therefore, the official still hopes to combine appropriate inline writing with ordinary css;
1.2.2. Ordinary css
Ordinary css is usually written to a separate file.
App.js
Write React logic code in:
import React, {
PureComponent } from 'react';
import Home from './Home';
import './App.css';
export default class App extends PureComponent {
render() {
return (
<div className="app">
<h2 className="title">我是App的标题</h2>
<p className="desc">我是App中的一段文字描述</p>
<Home/>
</div>
)
}
}
App.css
Write React style code in:
.title {
color: red;
font-size: 20px;
}
.desc {
color: green;
text-decoration: underline;
}
This writing method is consistent with the writing method in ordinary web development:
- If we write according to ordinary web standards, then there won’t be much of a problem;
- However, in component development, we always hope that the component is an independent module. Even the style only takes effect within itself and does not affect each other;
- But ordinary css is global css, and styles will affect each other;
For example, Home.js
the logic code written:
import React, {
PureComponent } from 'react';
import './Home.css';
export default class Home extends PureComponent {
render() {
return (
<div className="home">
<h2 className="title">我是Home标题</h2>
<span className="desc">我是Home中的span段落</span>
</div>
)
}
}
I also wrote Home.css
the style code:
.title {
color: orange;
}
.desc {
color: purple;
}
In the end, styles will be layered on top of each other, and only one style will take effect;
1.2.3. css modules
CSS modules are not a React-specific solution, but can be used in any environment that uses a configuration similar to webpack .
However, if it is used in other projects, then we need to configure it ourselves, such as webpack.config.js
in the configuration modules: true
.
But React's scaffolding already has built-in css modules
configuration:
.css/.less/.scss
etc. style files are modified to.module.css/.module.less/.module.scss
etc.;- You can then quote and use it;
The way to use it is as follows:
The class name finally generated by this way of using CSS will be globally unique:
css modules
It does solve the problem of local scope, and it is also a solution that many people like to use in React.
But this solution also has its own shortcomings:
- The referenced class name cannot use the connector (
.home-title
) and is not recognized in JavaScript; - All
className
must be{style.className}
written using the form ; - It is inconvenient to dynamically modify certain styles, so you still need to use inline styles;
If you think the above flaws are OK, then you can choose to use it in development css modules
, and it is also a very popular method in React.
二. CSS in JS
2.1. Understanding CSS in JS
In fact, the official documentation also mentions the CSS in JS solution:
- "CSS-in-JS" refers to a mode in which CSS is generated by JavaScript rather than defined in an external file;
- Note that this functionality is not part of React, but is provided by a third-party library. React doesn’t have a clear stance on how styles are defined;
In traditional front-end development, we usually separate structure (HTML), style (CSS), and logic (JavaScript).
- But in the previous study, we mentioned that React believes that the logic itself and the UI cannot be separated, so there is JSX syntax.
- What about style? Style is also part of the UI;
- In fact, the CSS-in-JS mode is a way to write styles (CSS) into JavaScript, and the state of JavaScript can be conveniently used;
- So React is called All in JS;
Of course, this development method has also been criticized a lot:
- Stop using CSS in JavaScript for web development
- https://hackernoon.com/stop-using-css-in-javascript-for-web-development-fa32fb873dcc
Although there are criticisms, in our opinion many excellent CSS-in-JS libraries are still very powerful and convenient:
- CSS-in-JS uses JavaScript to give CSS some capabilities, including style nesting, function definition, logic reuse, dynamic state modification, etc. similar to CSS preprocessors;
- Still, the CSS preprocessor also has certain capabilities, but obtaining dynamic state is still a difficult point to handle;
- Therefore, it can be said that CSS-in-JS is currently the most popular solution for writing CSS in React;
What are the currently popular CSS-in-JS libraries?
- styled-components
- emotion
- glamorous
At present, it can be said that styled-components
it is still the most popular CSS-in-JS library in the community, so we styled-components
focus on the explanation;
Install styled-components
:
yarn add styled-components
2.2. styled-components
2.2.1. Label template string
ES6 adds template string syntax, which many people will use.
But there is another use of template strings: Tagged Template Literals.
Let’s take a look at a common JavaScript function:
function foo(...args) {
console.log(args);
}
foo("Hello World");
Under normal circumstances, we all 函数名()
call it through the method. In fact, there is another way to call the function:
foo`Hello World`; // [["Hello World"]]
If we insert other variables when calling:
foo`Hello ${
name}`; // [["Hello ", ""], "kobe"];
- The template string is split;
- The first element is an array, which is a combination of strings split by the module string;
- The following elements are the contents passed in module strings one by one;
In styled component
this way, we parse the module string and finally generate the style we want.
2.2.2. Basic use of styled
styled-components
The essence is to finally create a component through function calls:
- This component will be automatically added with a unique one
class
; styled-components
class
Relevant styles will be added to this ;
For example, the components we normally develop Home
are in this format:
<div>
<h2>我是Home标题</h2>
<ul>
<li>我是列表1</li>
<li>我是列表2</li>
<li>我是列表3</li>
</ul>
</div>
div
We want to add a special one to the outer layer class
and add related styles:
In addition, it supports style nesting similar to CSS preprocessors:
- Supports direct descendant selectors or descendant selectors, and writes styles directly;
&
The current element can be obtained through symbols;- Direct pseudo-class selectors, pseudo-elements, etc.;
const HomeWrapper = styled.div`
color: purple;
h2 {
font-size: 50px;
}
ul > li {
color: orange;
&.active {
color: red;
}
&:hover {
background: #aaa;
}
&::after {
content: "abc"
}
}
`
The final effect is as follows
2.2.3. props, attrs attributes
props
Can penetrate
Define a styled
component:
const HYInput = styled.input`
border-color: red;
&:focus {
outline-color: orange;
}
`
Components used styled
:
<HYInput type="password"/>
props
can be passed to styled
components
<HomeWrapper color="blue">
</HomeWrapper>
You can get the incoming data when using color
:
const HomeWrapper = styled.div`
color: ${
props => props.color};
}
- Obtaining
props
requires${}
passing in an interpolation function, whichprops
will be used as a parameter of the function; - This method can effectively solve the problem of dynamic styles;
Add attrs
properties
const HYInput = styled.input.attrs({
placeholder: "请填写密码",
paddingLeft: props => props.left || "5px"
})`
border-color: red;
padding-left: ${
props => props.paddingLeft};
&:focus {
outline-color: orange;
}
`
2.2.4. styled advanced features
Supports style inheritance
Write styled
components
const HYButton = styled.button`
padding: 8px 30px;
border-radius: 5px;
`
const HYWarnButton = styled(HYButton)`
background-color: red;
color: #fff;
`
const HYPrimaryButton = styled(HYButton)`
background-color: green;
color: #fff;
`
Use of buttons
<HYButton>我是普通按钮</HYButton>
<HYWarnButton>我是警告按钮</HYWarnButton>
<HYPrimaryButton>我是主要按钮</HYPrimaryButton>
styled set theme
Customize your own theme globally and Provider
share it with:
import {
ThemeProvider } from 'styled-components';
<ThemeProvider theme={
{
color: "red", fontSize: "30px"}}>
<Home />
<Profile />
</ThemeProvider>
styled
The content of the theme can be obtained in the component :
const ProfileWrapper = styled.div`
color: ${
props => props.theme.color};
font-size: ${
props => props.theme.fontSize};
`
2.3. classnames
Add class in vue
Adding dynamics to an element in Vue class
is a very simple thing:
You can do this by passing in an object:
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
You can also pass in an array:
<div v-bind:class="[activeClass, errorClass]"></div>
Even mixing objects and arrays:
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
Add class in react
React gives us developers enough flexibility in JSX. You can decide whether to add something through some logic just like writing JavaScript code class
:
import React, {
PureComponent } from 'react'
export default class App extends PureComponent {
constructor(props) {
super(props);
this.state = {
isActive: true
}
}
render() {
const {
isActive} = this.state;
return (
<div>
<h2 className={
"title " + (isActive ? "active": "")}>我是标题</h2>
<h2 className={
["title", (isActive ? "active": "")].join(" ")}>我是标题</h2>
</div>
)
}
}
At this time we can use a third-party library:classnames
- Obviously, this is a
classnames
library for dynamic addition.
Let’s use the most common use cases:
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', {
bar: true }); // => 'foo bar'
classNames({
'foo-bar': true }); // => 'foo-bar'
classNames({
'foo-bar': false }); // => ''
classNames({
foo: true }, {
bar: true }); // => 'foo bar'
classNames({
foo: true, bar: true }); // => 'foo bar'
// lots of arguments of various types
classNames('foo', {
bar: true, duck: false }, 'baz', {
quux: true }); // => 'foo bar baz quux'
// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, {
baz: null }, ''); // => 'bar 1'