整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

MistCSS 火了!JS-from-CSS 才是前端未来?

家好,很高兴又见面了,我是"高级前端‬进阶‬",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发,您的支持是我不断创作的动力。

什么是 MistCSS

A new, better and faster way to write visual components. CSS-in-JS? Nope! JS-from-CSS

MistCSS 是一种新的、更好、更快的编写可视化组件的方法,其抛弃了传统的 CSS-in-JS 而采用 JS-from-CSS, 支持 Next.js、Remix 和 TailwindCSS 等等。

MistCSS 的典型特征包括:

  • 普适性:支持 Next.js、TailwindCSS、Remix 等等
  • 注重风格:不再需要使用 JS/TS 代码进行上下文切换,直接使用所有现代 CSS 功能。生成的代码降低了团队成员之间出现错误和实施不一致的风险。
  • 改进的代码库:自动类型安全,支持可视化、无状态组件和其他组件之间的清晰分离。自动类型安全,无需手动编写 TypeScript 类型并确保传递的所有 props 均有效。
  • 完美 DX:无需向 VScode 添加扩展,无需学习新的 API,零配置开箱即用。
  • ⚡ 运行速度快:无性能成本、零运行时间和本机浏览器支持

与 CSS-in-JS 工具不同,MistCSS 不需要代码编辑器扩展,没有 API 限制,也没有学习曲线,可以完全访问 CSS 的强大功能。

MistCSS 允许编写更简洁的代码,样式的作用域类似于 CSS Module,并且视觉行为位于同一位置,类似于 CSS-in-JS。同时,MistCSS 的运行时为零,不会给项目增加任何开销。

目前 MistCSS 在 Github 通过 MIT 协议开源,是一个值得关注的前端开源项目。

如何使用 MistCSS

通过示例可以更好地理解 MistCSS,以下代码创建一个接受两个 props 的经典 Button 组件:

  • size: 'lg' | 'sm'
  • danger: boolean
// src/Button.mist.css
@scope (.button) {
  button:scope {
    /* Default style */
    font-size: 1rem;
    border-radius: 0.25rem;
    &[data-size='lg'] {
      font-size: 1.5rem;
    }
    &[data-size='sm'] {
      font-size: 0.75rem;
    }
    &[data-danger] {
      background-color: red;
      color: white;
    }
  }
}

注意:@scope 中的类在项目中必须是唯一的,后续会添加自动检查功能

上面的 CSS 代码是 标准且有效的, MistCSS 没有引入任何专有语法。因此,代码编辑器本身就支持。然后执行下面的命令进行编译:

npx mistcss ./src
//  Button.mist.tsx will be created

此时编译器会自动生成如下图所示的代码,和往常自己写 Button 组件非常类似,但是思路却完全反过来,即通过写样式文件来反向生成组件

接着就可以像下面一样导入 Button 组件:

import {Button} from '.components/Button.mist'

export default const App = () => (
  <main>
    {/* 像普通组件一样使用 React component */}
    <Button size="lg">Submit</Button>
    <Button size="lg" danger>Delete</Button>
    <Button onClick={handleClick}>Cancel</Button>
    {/*  TypeScript will catch the wrong size here */}
    <Button size="foo">Oops</Button>
  </main>
)

通过上面的步骤,一个视觉和类型安全的 React 组件就完成了,无需任何额外 JS 代码✨。

由于 MistCSS 使用纯 CSS,因此开发者不受限制可以直接使用所有 CSS 功能:

  • 容器查询 @container 以根据组件大小调整样式
  • CSS 变量,例如 --primary-color,具有一致的样式
  • 媒体查询 @media (prefers-color-scheme: dark),处理暗模式

当然,也可以在 MistCSS 组件中使用 TailwindCSS 实用程序类。

参考资料

https://github.com/typicode/mistcss

https://typicode.github.io/mistcss/

https://twitter.com/argyleink/status/1769741521270583393/photo/4

React以其声明式编程范式和组件化架构,成为了构建用户界面的首选技术之一。然而,随着项目规模的扩大和设计需求的多样化,如何高效地管理 CSS 样式成为了每个React开发者都需要面对的挑战。

本文将从一下三个方面进行介绍,探讨如何在 React 中应用和管理样式,包括内联样式、CSS 类、CSS Modules 和 CSS-in-JS 技术,提升界面美观和开发效率。

常见的样式方案

在 React 中,组件样式指的是如何为每个独立的组件定义和管理视觉表现。组件样式的设计和应用是 React 开发中的关键部分,它决定了应用的外观和用户体验。

内联样式 (Inline Styles)

在 React 中,内联样式是一种直接在元素上定义 CSS 样式的方式,类似于在 HTML 中使用 style 属性。不同的是,在 React 中,内联样式是通过一个 JavaScript 对象来定义的,而不是传统的 CSS 字符串。这使得内联样式在 React 中具有更强的动态性和灵活性。

基本语法

在 React 中,内联样式通过元素的 style 属性来设置,该属性接受一个 JavaScript 对象。对象的键是 CSS 属性名(使用驼峰命名法),值是对应的样式值;如下:

import React from 'react';

function InlineStyles() {
    const divStyle = {
        color: 'blue',
        backgroundColor: 'lightgray',
        padding: '10px',
    };

    return <div style={divStyle}>Hello, World!</div>;
}

export default InlineStyles;

在这个例子中,divStyle 是一个包含样式属性的 JavaScript 对象,并通过 style 属性应用到 div 元素上。

效果如下:

样式属性的命名

在 React 的内联样式中,CSS 属性名使用驼峰命名法(camelCase),而不是传统的 CSS 短横命名法(kebab-case)。例如:

  • background-color 在 React 中写成 backgroundColor
  • font-size 写成 fontSize
  • margin-top 写成 marginTop

动态样式

内联样式可以非常方便地实现动态样式。你可以根据组件的状态或属性来动态地改变样式。

import React, { useState } from 'react';

function DynamicStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    const divStyle = {
        color: isActive ? 'red' : 'blue',
        backgroundColor: 'lightgray',
        padding: '10px',
        cursor: 'pointer',
        userSelect: 'none',
    };

    return (
        <div style={divStyle} onClick={handleClick}>
            Click me to change color!
        </div>
    );
}

export default DynamicStyles;

在这个例子中,当点击 div 元素时会切换其文本颜色。效果图如下:

样式合并

React允许将多个样式对象合并为一个,这在需要应用多个条件样式时非常有用:

const baseStyle = { padding: '10px', margin: '5px' };
const activeStyle = { backgroundColor: 'green' };

// 合并样式
const finalStyle = { ...baseStyle, ...activeStyle };

// ...
<div style={finalStyle} />

内联样式的优缺点:

优点:

  • 局部作用域:内联样式只作用于当前的元素,不会影响其他元素,避免了样式冲突。
  • 动态性:可以很方便地根据组件的状态或属性来动态设置样式。
  • 简洁:对于简单的样式,可以减少代码量和文件数量。

缺点:

  • 可维护性:当样式变得复杂时,内联样式会使得组件代码变得难以维护。
  • 复用性差:内联样式无法复用,相同的样式需要在多个地方重复定义。
  • 缺少伪类和伪元素支持:内联样式无法直接使用 CSS 伪类和伪元素(如 :hover, ::after)。
  • 性能差:联样式对象包含大量的属性或者嵌套的对象,这可能会使得样式对象的创建和合并更加耗时。

CSS 类 (CSS Classes)

与内联样式相比,使用 CSS 类样式可以使代码更清晰、可维护性更高。

使用 CSS 类样式的基本方法

  • 创建 CSS 文件
  • 首先,你需要创建一个 CSS 文件,并在其中定义你的 CSS 类。例如,创建一个 common.css 文件:
/* common.css */
.container {
    color: blue;
    background-color: lightgray;
    padding: 10px;
}

.active {
    color: red;
}

在 React 组件中引入 CSS 文件 在你的 React 组件中,使用 import 语句引入刚刚创建的 CSS 文件:

import { useState } from 'react';
import '../assets/styles/common.css';

function ClassStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    return (
        <div
            className={`container ${isActive ? 'active' : ''}`}
            onClick={handleClick}>
            Click me to change color!
        </div>
    );
}

export default ClassStyles;
  • 在这个示例中,我们使用模板字符串(template literals)来动态添加或移除 CSS 类。效果如下:

动态添加或移除 CSS 类

可以使用条件渲染的方法动态添加或移除 CSS 类。例如,使用三元运算符或条件运算符:

<div
    className={`container ${isActive ? 'active' : ''}`}
    onClick={handleClick}>
    Click me to change color!
</div>

或者,使用 classnames、clsx 库来处理复杂的类名逻辑,下面用 classnames 做个演示:

import { useState } from 'react';
import classNames from 'classnames';

function ClassnamesStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    return (
        <div
            className={classNames('container', { active: isActive })}
            onClick={handleClick}>
            Click me to change color!
        </div>
    );
}

export default ClassnamesStyles;

然后在 App.jsx 中引入 ClassnamesStyles 组件;在这个示例中,classnames 库使得根据条件判断类名的处理更加简洁和易读。效果如下:

CSS Modules

为了避免全局样式冲突,React 推荐使用 CSS 模块(CSS Modules),它允许你将 CSS 类名限定在本地作用域内。

  • 创建 CSS 模块文件 首先,创建一个 CSS 模块文件,例如 page.module.css:
/* page.module.css */
.container {
    color: blue;
    background-color: lightgray;
    padding: 10px;
}

.active {
    color: red;
}

在 React 组件中引入和使用 CSS 模块

import { useState } from 'react';
import styles from '../assets/styles/page.module.css';

function CssModuleStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    return (
        <div
            className={`${styles.container} ${isActive ? styles.active : ''}`}
            onClick={handleClick}>
            Click me to change color!
        </div>
    );
}

export default CssModuleStyles;
  • 在这个示例中,CSS 类名是通过 styles 对象来引用的,这样可以确保类名在本地作用域内不发生冲突。

优缺点对比

优点:

  • 可维护性高:样式定义集中在一个地方,使得代码更清晰易读。
  • 复用性好:相同的样式可以在多个组件中复用。
  • 避免冲突:使用 CSS 模块可以避免全局命名冲突。

缺点:

  • 动态性较差:相比于内联样式,动态设置样式略显不便。
  • 额外的构建步骤:需要引入和配置 CSS 文件,增加了项目的构建复杂度。

Styled Components 和 CSS-in-JS

在 React 中,Styled Components 和 CSS-in-JS 是用于管理和应用样式的现代解决方案。它们旨在使样式更加模块化、可复用和动态化。

Styled Components

Styled Components 是一个流行的 CSS-in-JS 库,它使用 ES6 的模板字符串语法来定义组件级别的样式。通过使用 Styled Components,你可以将组件的样式与其逻辑紧密结合,使得样式更加模块化和可维护。

  • 安装 styled-components 库
$ npm install styled-components
  • 使用示例

以下是如何在 React 中使用 Styled Components:

import { useState } from 'react';
import styled from 'styled-components';

// 定义一个带有样式的容器组件
const Container = styled.div`
    /* 根据 props.isActive 设置颜色 */
    color: ${props => (props.isActive ? 'red' : 'blue')};
    background-color: lightgray;
    padding: 10px;
    cursor: pointer;
    transition: color 0.3s;
`;

const Button = styled.button`
    /* 根据 props.primary 设置按钮样式 */
    background: ${props => (props.$primary ? '#BF4F74' : 'white')};
    color: ${props => (props.$primary ? 'white' : '#BF4F74')};
    font-size: 1em;
    margin: 1em;
    padding: 0.25em 1em;
    border: 2px solid #bf4f74;
    border-radius: 3px;
`;

function StyledComponentsStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    return (
        <main>
            <Container isActive={isActive}>Click me to change color!</Container>
            <Button onClick={handleClick} $primary={isActive}>
                Primary
            </Button>
        </main>
    );
}

export default StyledComponentsStyles;

效果如下:

CSS-in-JS

CSS-in-JS 是一种将 CSS 样式直接写在 JavaScript 文件中的技术。Styled Components 是 CSS-in-JS 的实现之一,但还有其他库和方法可以实现 CSS-in-JS,例如 emotion、styled-jsx 等。

优点

  • 模块化:每个组件的样式都与组件本身紧密结合,避免了样式冲突。
  • 动态样式:可以方便地根据组件的状态或属性来动态调整样式。
  • 可维护性:将组件的样式和逻辑放在一起,使得代码更加内聚和可维护。
  • 自动前缀:自动添加浏览器前缀,使得样式兼容更多浏览器。

缺点

  • 性能:在某些情况下,CSS-in-JS 可能会对性能产生影响,因为样式是在运行时生成的。
  • 学习曲线:需要学习新的库和语法,可能增加项目的复杂性。

其他 CSS-in-JS 库

  • Emotion Emotion 是另一个流行的 CSS-in-JS 库,具有强大的动态样式和高性能的特点。
  1. 安装 Emotion
$ npm install @emotion/react
  1. 使用示例

在使用 emotion 方案的 jsx 文件开头加入一行 /** @jsxImportSource @emotion/react **/ 的 JSX Pragma(编译指示),告诉 JS 编译器使用 @emotion/react 包来替代 React 原生的jsx 运行时。

/* @jsxImportSource @emotion/react */
import React from 'react';
import { css } from '@emotion/react';

const color = 'white';

function EmotionStyles() {
    return (
        <div
            css={css`
                padding: 32px;
                font-size: 16px;
                background-color: hotpink;
                font-size: 24px;
                border-radius: 4px;
                &:hover {
                    color: ${color};
                }
            `}>
            Hover to change color.
        </div>
    );
}

export default EmotionStyles;

效果如下:

emotion 也支持了 style-components 的方案,不过要安装一下依赖:npm i @emotion/styled,使用示例如下:

/* @jsxImportSource @emotion/react */
import { useState } from 'react';
import styled from '@emotion/styled';

const Container = styled.div`
    color: ${props => (props.isActive ? 'red' : 'blue')};
    background-color: lightgray;
    padding: 10px;
    cursor: pointer;
    transition: color 0.3s;
`;

function EmotionStyledStyles() {
    const [isActive, setIsActive] = useState(false);

    const handleClick = () => {
        setIsActive(!isActive);
    };

    return (
        <Container isActive={isActive} onClick={handleClick}>
            Click me to change color!
        </Container>
    );
}

export default EmotionStyledStyles;

效果如下:

Styled Components 和 CSS-in-JS 是现代 React 开发中非常流行的样式解决方案。它们提供了模块化、动态化和高可维护性的样式管理方式。根据项目需求选择合适的方案,可以显著提高开发效率和代码质量。

总结

在 React 项目中,有许多不同的样式管理工具和库可供选择。以下是一些常见的选择:

  • CSS-in-JS:Styled Components, Emotion
  • Utility-First CSS 框架:Tailwind CSS、unocss
  • 组件库:Bootstrap (react-bootstrap), Ant Design, Material-UI等
  • CSS 预处理器:Sass、less
  • CSS 模块:CSS Modules

选择合适的样式管理工具取决于你的项目需求、团队的熟悉度以及具体的使用场景。




原文转自:https://juejin.cn/post/7384992844191154214

SS(Cascading Style Sheets) ,层叠样式表(级联样式表),用于设置HTML页面中的文本内容的字体、大小、对齐方式等,图片的宽高、边框样式、边距等以及页面的布局排版等各种外观显示样式。

CSS以HTML为基础,可以针对不同的浏览器设置不同的样式。CSS的出现可以说拯救了我们的页面,让HTML 专注去做结构呈现, 而样式全部交给 CSS来美化。

CSS样式规则,具体格式如下:

CSS语法由两部分组成:选择器和声明。 声明包括:属性和属性值
选择符 {属性: 属性值 ; 属性:属性值}

规则:

  1. 每个CSS样式由两部分组成,即选择器和声明。选择器用于指定CSS样式作用的HTML对象,声明又分为属性和属性值;
  2. 属性是对选择器选定的对象设置的样式属性,例如字体大小、文本颜色等。必须放在花括号中,属性与属性值用英文冒号连接,以“键值对”的形式出现。
  3. 每条声明用英文分号结束。当一个属性有多个属性值的时候,属性值与属性值不分先后顺序。在书写样式过程中,空格、换行等操作不影响属性显示。

注释规则

  • 注释规则
  • /* 需要注释的内容 */
  • 示例
  • p { color: red; /* 所有段落标签字体颜色是红色*/ }

三、CSS样式表引入方法

CSS放到什么位置呢? 怎么让它跟我们的HTML文件关联起来呢?

内联样式(行内式)

内联样式,又称行内样式、行间样式、内嵌样式。是通过标签的style属性来设置元素的样式。

  • 语法
<标签名 style="属性1:属性值1; 属性2:属性值2; 属性3:属性值3;"> 内容 </标签名>

<h2 style="color:red;">
    红色标题
</h2>
  • 说明
  • (1)style是标签的属性,任何HTML标签都有style属性,用来设置行内样式。
  • (2)属性和值的书写规范与CSS样式规则相同。
  • 注意
  • 行内样式只对其所在的标签及嵌套在其中的子标签起作用。

内部样式表

内嵌式是将CSS代码集中写在HTML文档的head头部标签中,并且用style标签定义

  • 语法
  • <head> <style type="text/CSS"> 选择器 {属性1:属性值1; 属性2:属性值2; 属性3:属性值3;} p{ color:#000;font-size:14px;} </style> </head>
  • 说明
  • (1)style标签一般位于head标签中title标签之后,也可以把他放在HTML文档的任何地方。
  • (2)type=“text/CSS” 在html5中可以省略, 写上也比较符合规范, 所以这个地方可以写也可以省略。

外部样式表(外链式)

当我们页面比较复杂,大量的内部样式,会导致页面看上去不美观,而且不利于维护。这时我们通常将所有的样式放在一个或多个以 .CSS 为扩展名的外部样式表文件中,通过link标签将外部样式表文件链接到HTML文档中。

  • 格式
  • <head> <link rel="stylesheet" type="text/CSS" href="CSS文件的路径" /> </head>
  • 说明
  • (1)rel:用于定义文档关联(当前文档与被链接文档之间的关系),在这里需要指定为“stylesheet”,表示被链接的文档是一个样式表文件,表示关联样式表。
  • (2)type:用于定义文档类型,通常指定为“text/css”,表示链接的外部文件为CSS样式表。
  • (3)href:用于定义所链接外部样式表文件的URL,通常是相对路径。
  • 注意
  • link 是单标签哦 _!
  • 使用link元素导入外部样式表时,需将该元素写在文 档头部,即与之间。

三种样式表总结

样式表

特点

使用

控制范围

优先级

行内样式表

书写方便,权重高

较少

控制单个标签(小)

内部样式表

结构和样式部分分离

较多

控制一个页面(中)

与书写的顺序有关,后书写的高

外部样式表

结构和样式完全分离,需要引入

最多,推荐使用

控制整个网站(多)

与书写的顺序有关,后书写的高

四、标签的类型(显示模式)

网页中的标签很多,为了更好的完成我们的网页布局,我们需要在不同地方会放不同类型的标签。

根据标签在网页中的显示模式,可以将HTML标签一般分为块级标签和行内标签两种类型,即块元素和行内元素。

块级元素(block-level)

  • 说明
  • 每个块元素通常都会独自占据一行或多行,可以设置其宽度、高度、对齐方式等属性,常用于网页布局和网页结构的搭建。
  • 举例
  • 常见的块元素有:<h1>~<h6>、<p>、<div>、<ul>、<ol>、<li>等,其中<div>标签是最典型的块元素,非常适合布局,所以我们常称之为 “CSS+DIV布局”。
  • 特点
  1. 块元素总是从新行开始,宽度是容器的100%。
  2. 块状元素都可以定义自己的宽度、高度、外边距以及内边距。
  3. 两个相邻块元素不会出现并列显示的现象;默认,块元素会按自上而下顺序排列。
  4. 块级元素一般可以容纳内联元素和其他块元素,故将其比喻为一个盒子。
  • 注意
  • 文字类块级标签,里面不能放其他块级元素。比如,只有文字才能组成段落 因此 p 里面不能放块级元素,同理还有这些标签h1,h2,h3,h4,h5,h6,dt。

行内元素(inline-level 或内联元素)

  • 说明
  • 行内元素(内联元素)不占独立的区域,仅靠自身的字体大小和图像尺寸来支撑结构,一般不可以设置宽度、高度、对齐等属性,常用于控制页面中文本的样式。
  • 举例
  • 常见的行内元素有<a>、<b>、<span>、<strong>、<em>、<i>、<del>、<s>、<ins>、<u>等,其中<span>标签最典型的行内元素。
  • 特点
  1. 和相邻行内元素在一行上显示
  2. 设置宽、高无效,可设置水平方向的padding和margin,但垂直方向的无效。
  3. 默认宽度就是它本身内容的宽度。
  4. 行内元素只能容纳文本或其他行内元素。(a除外)
  • 注意

链接里面不能再放链接!

行内块元素(inline-block)

  • 说明
  • 在行内元素中有几个特殊的标签,比如<img />、<input />、<td>,可以设置它们的宽、高和对齐方式,故称之为行内块元素。
  • 特点
  • 可同相邻行内元素(行内块)显示在一行上,但之间会有空白缝隙
  • 默认宽度就是它本身内容的宽度
  • 可设置高度,行高、外边距以及内边距

元素显示模式转变(display)

通过设置display的值,改变元素的显示模式。

  • 属性值
  • block、inline、inline-block、none
  • 说明
  1. 行内转块:display:block;
  2. 将元素转为块状元素,使该元素拥有块状元素的特点;
  3. 显示:
  4. 类似在元素后面添加换行符,也就是说其他元素不能在其后面并列显示。
  5. 块转行内:display:inline;
  6. 将元素转换为内联元素,使该元素拥有行内元素的特点;
  7. 显示:
  8. 在元素后面删除换行符,多个元素可以在一行内并列显示。
  9. 块、行内元素转换为行内块: display: inline-block;
  10. 只有这一个元素类型支持vertical-align属性,img,input(行内块元素)。
  11. 显示:
  12. 元素的内容以块状显示,行内的其他元素显示在同一行。
  13. none 此元素不会被显示