This is the fifth day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

The whole front end has been componentized world, and CSS design does not exist at the beginning of componentization, so the original CSS itself does not support componentization, so in the current componentization framework are in need of a suitable CSS solution.

Selecting the right CSS solution in componentization should meet the following criteria:

  • You can write local CSS: CSS has its own scope and does not contaminate elements in other components
  • You can write dynamic CSS: You can take some state of the current component and generate different CSS styles based on the state changes
  • Support all CSS features: pseudo class, animation, media query, etc.
  • Easy to write, preferably consistent with the CSS style characteristics
  • And so on…

Inline style

Inline styles are the official recommended way to write CSS styles:

  • Style takes a JavaScript object with a small camel named attribute, not a CSS string
  • You can reference the state in state to set the associated styles
import { PureComponent } from 'react'

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      color: 'red'}}render() {
    return (
      <>
        <div style={{
          fontSize: '20px',
          color: this.state.color}} >Use of inline styles</div>
      </>)}}Copy the code

Advantages of inline style:

  • Inline styles, no conflicts between styles
  • The state in the current state can be dynamically retrieved

Disadvantages of inline style:

  • You need to use the hump symbol
  • Some styles don’t have prompts
  • Lots of styles, code mess
  • Some styles cannot be written (such as pseudo-classes/pseudo-elements)

So the official hope is still inline appropriate and normal CSS written in combination;

Common CSS

Normal CSS is usually written in a separate file and introduced later.

This way of writing and ordinary web development in the way of writing is consistent

One big problem with this approach, however, is that by default, all written styles are global, making it easy to overwrite styles

.foo {
  color: red;
}
Copy the code
import { PureComponent } from 'react'
import './index.css'

export default class App extends PureComponent {
  render() {
    return (
      <>
        <div className="foo">Use of inline styles</div>
      </>)}}Copy the code

css modules

CSS modules are not a React specific solution, but can be used in any environment that uses a webPack-like configuration

However, if CSS Modules are used in other projects, then we need to configure them ourselves

In the React scaffolding, CSS Modules are already built in

We will just have to do. The CSS /. Less /. SCSS etc. Style files are modified into the module. The CSS /. The module. The less /. The module. The SCSS, etc., after can reference and use

import { PureComponent } from 'react'

// Introduce CSS modules
import style from './index.module.css'

export default class App extends PureComponent {
  render() {
    return (
      <>{/* 1. Use CSS modules. 2.<div className={ style.foo} >Use of inline styles</div>{/* style.foo-title is not valid in JS, so use style['foo-title'] or change the style name to a small camel, such as fooTitle */}<div className={ style['foo-title'] }>title</div>
      </>)}}Copy the code

CSS modules do solve the problem of local scope, and it’s a solution that many people like to use in React.

However, this approach has its own disadvantages: it is not convenient to modify certain styles dynamically, and you still need to reference dynamic styles inline

css in js

CSS in JS is mentioned in the official documentation:

  • “Css-in-js” refers to a pattern in which CSS is generated by JavaScript rather than defined in external files
  • Note that this functionality is not part of React, but is provided by third-party libraries. React is not clear on how styles should be defined

In traditional front-end development, we often separate structure (HTML), style (CSS), and logic (JavaScript).

However, in React thinking, logic and UI are inseparable, hence the SYNTAX of JSX.

Similarly, React considers styles to be part of the UI

In fact, csS-in-JS mode is a way to write styles (CSS) into JavaScript and make it easy to use JavaScript states

React is called All in JS

Css-in-js uses JavaScript to give CSS some capabilities, including style nesting similar to CSS preprocessor, function definition, logic reuse and other functions, as well as dynamic state modification that CSS preprocessor cannot do

Therefore, CSS-in-JS is currently the most popular solution for writing CSS with React

What are the most popular csS-in-JS libraries?

  • styled-components
  • emotion
  • glamorous

Styled – Components is still arguably the most popular CSS-in-JS library in the community, so we use Styled – Components as an example

#The installation
$ yarn add styled-components
Copy the code

Tag template string

const name = 'Klaus'
const age = 23

function foo(. args) {
  console.log(args) // => [ [ 'my name is ', ', my age is ', '' ], 'Klaus', 23 ]
}

// Label template string
foo`my name is ${name}, my age is ${age}`
Copy the code

Style Settings

The most used third-party library for setting style styles in React is styled- Components

Styled components The core principle of styled- Components is that the tag template string is used internally for style concatenation and processing

style.js

/ / introduce styled - components
import styled from 'styled-components'

// Styled [tag name] -- is a function that returns a React component
// For the React component returned, we add the style to the new component -- this type of component is generally called styled style components
// We can replace the original tag with a new component with styles
// The returned component will generate a unique ID as the component's style name to resolve style conflicts
export const AppWrapper = styled.div` color: red; font-size: 20px; /* Child style Settings */ /* If multiple styles need to be set, they need to be separated by semicolons (that is, semicolons can not be omitted, even if the last line of CSS style) */ ul, li {list-style: none; Hover {color: blue; } / set * * pseudo elements / & : : before {content: 'the username:'}} `
Copy the code

App.js

import { PureComponent } from 'react'
import { AppWrapper } from './style.js'

export default class App extends PureComponent {
  render() {
    return (
      <AppWrapper>
        <ul>
          <li>Klaus</li>
          <li>Alex</li>
          <li>Steven</li>
        </ul>
      </AppWrapper>)}}Copy the code
Attribute to penetrate
import { PureComponent } from 'react'
import styled from 'styled-components'

const CustomInput = styled.input` background-color: gray; `

export default class App extends PureComponent {
  render() {
    return (
      <>{/* The type attribute is set on the CustomInput, but styled- Components have attribute traversal, so the Type attribute is actually set to the original input tag */}<CustomInput type="password" />
      </>)}}Copy the code
Attrs properties
import { PureComponent } from 'react'
import styled from 'styled-components'

// the attrs method returns a function
// We can set the attributes of the component in the attrs function
const CustomInput = styled.input.attrs({
  placeholder: 'Klaus'
})` background-color: blue; `

export default class App extends PureComponent {
  render() {
    return (
      <>
        <CustomInput type="password" />
      </>)}}Copy the code
import { PureComponent } from 'react'
import styled from 'styled-components'

// When styling components, you can use functions
// The function has an argument as props, whose value is object.assign ({}, the Object passed to the component (for example, bgColor in this case), attrs function argument Object)
// If in the style template string, all properties passed in (except for the props properties that are actually being used as style property values) are passed in as component properties
const CustomInput = styled.input.attrs({
  placeholder: 'Klaus'.color: 'red'
})`
  background-color: ${ props => props.bgColor || props.color };
`

export default class App extends PureComponent {
  render() {
    return (
      <>
        <CustomInput type="password" bgColor="yellow" />
      </>)}}Copy the code
import { PureComponent } from 'react'
import styled from 'styled-components'

// If the styles conflict, the attribute value set in the attrs function overrides the attribute value of the same name passed to the component
const CustomInput = styled.input.attrs({
  placeholder: 'Klaus'.color: 'red'
})`
  background-color: ${ props => props.color };
`

export default class App extends PureComponent {
  render() {
    return (
      <>
        <CustomInput type="password" color="yellow" />
      </>)}}Copy the code
Styles are set using values in state
import { PureComponent } from 'react'
import styled from 'styled-components'

const CustomInput = styled.input.attrs({
  placeholder: 'Klaus'.color: 'red'
})`
  background-color: ${ props => props['bg-color'] || props.color };
`

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      bgColor: 'yellow'}}render() {
    return (
      <>
        <CustomInput type="password" bg-color={ this.state.bgColor} / >
      </>)}}Copy the code
Style inheritance
import { PureComponent } from 'react'
import styled from 'styled-components'

const CustomButton = styled.button` outline: none; `

// The style of CustomPrimaryButton is inherited from CustomButton
const CustomPrimaryButton = styled(CustomButton)` background-color: green; color: #fff; `

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      bgColor: 'yellow'}}render() {
    return (
      <>
        <CustomButton>CustomButton</CustomButton>
        <CustomPrimaryButton>CustomPrimaryButton</CustomPrimaryButton>
      </>)}}Copy the code
Theme Style (global style)

App.js

import { PureComponent } from 'react'
import { ThemeProvider } from 'styled-components'

import Cpn from '.. /Cpn'

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      bgColor: 'yellow'}}render() {
    return (
      <ThemeProvider theme={{ bgColor: 'blue', fontSize: '20px', color: 'red' }}>{/* Theme style is passed to all components using this theme */}<Cpn />
      </ThemeProvider>)}}Copy the code

Cpn.js

import { PureComponent } from 'react'

import styled from 'styled-components'

// The styles set on the theme are mounted to the props. Theme object
const Div = styled.div`
  background-color: ${ props => props.theme.bgColor };
  font-size: ${ props => props.theme.fontSize };
  color: ${ props => props.theme.color };
`

export default class App extends PureComponent {
  render() {
    return (
      <Div>Use of inline styles</Div>)}}Copy the code

Class Style Settings

The native set
import { PureComponent } from 'react'

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      isActive: true}}render() {
    return(< > {/* Note: multiple styles must be separated by Spaces */}
        <h2 className="foo bar">title</h2>
        <h2 className={ "foo bar" }>title</h2>
        <h2 className={` fooThe ${this.state.isActive ? 'active' :"'} `} >title</h2>
        <h2 className={['foo',  this.state.isActive ? 'active' :"'].join(' ') }>title</h2>}} < / a >)Copy the code
classnames

As you can see, setting classnames in React natively can be cumbersome, especially compared to Vue. The React community provides a library called classnames to help with this problem

#The installation
$ yarn add classnames
Copy the code
import { PureComponent } from 'react'

import classNames from 'classnames'

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      isActive: true}}render() {
    return(< ><h2 className={classNames('foo bar baz')} >title</h2>
       <h2 className={classNames('foo', 'bar', 'baz')} >title</h2>
       <h2 className={classNames('foo', this.state.isActive ? 'active' :"')} >title</h2>
       <h2 className={classNames('foo'{active: this.state.isActive})} >title</h2>

       <h2 className={classNames(['foo', 'bar'])} >title</h2>
       <h2 className={classNames(['foo'{active: this.state.isActive }])}>title</h2>}} < / a >)Copy the code
import { PureComponent } from 'react'

import classNames from 'classnames'

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      isUndefined: undefined.isNull: null.isZero: 0.isEmptyStr: ' '.isNotZero: 10}}render() {
    const {
      isUndefined,
      isNull,
      isZero,
      isNotZero,
      isEmptyStr
    } = this.state

    return(< > {/* If the property value is not Boolean, the property value will be cast to Boolean. If the property value is false, the style name will not be added. So if the property value is undefined, null, or 0, The corresponding style name is not added but if the attribute value is converted to Boolean and the corresponding value is true, then the corresponding style name is converted to string and added as the style name so here isNotZero has a value of 10 and will end up with a style named '10' on the H2 element */}
       <h2 className={classNames('foo', isUndefined, isNull, isZero, isEmptyStr, isNotZero)}>title</h2>

       {/* The same goes for the rest */}
       <h2 className={ classNames({ active: isNull }) }>title</h2>
       <h2 className={ classNames({ active: isNotZero }) }>title</h2>}} < / a >)Copy the code
import { PureComponent } from 'react'

// import classNames from 'classnames'

export default class App extends PureComponent {
  constructor(props) {
    super(props)

    this.state = {
      isActive: true}}render() {
    return(< > {/* Unlike vue, the class of a variable cannot coexist with the class of the specified value. If both exist, the following className overwrites the value of the previous className}
       {/* <h2 className="baz" className={classNames(['foo', { active: this.state.isActive }])}>title</h2> */</>)}}Copy the code