在现代React中,有很多方法可以用CSS来设计React应用程序。每当我为有抱负的React开发者举办React研讨会时,由于时间有限,我只展示其中的一种方法,用于完整的React研讨会。但往往这一种造型方式并不足以涵盖这个重要话题的全部内容。有许多不同的策略(如CSS-in-JS)和这些策略中的许多不同方法(如风格化组件)需要学习:
- CSS-in-CSS(例如:CSS、Sass、CSS模块或带Sass的CSS模块)
- CSS-in-JS(例如样式化组件、Emotion)。
- 实用至上的CSS(如Tailwind CSS)。
请跟随我的React之旅,了解更多关于CSS中这些不同的策略和方法,来设计你的React组件。对于所有不同的方式,我们将从相同的React组件开始:
import React from 'react';
function App() {
const [fruits, setFruits] = React.useState([
{ id: '1', name: 'Apple', isFavorite: false },
{ id: '2', name: 'Peach', isFavorite: true },
{ id: '3', name: 'Strawberry', isFavorite: false },
]);
function handleClick(item) {
const newFruits = fruits.map((fruit) => {
if (fruit.id === item.id) {
return {
id: fruit.id,
name: fruit.name,
isFavorite: !fruit.isFavorite,
};
} else {
return fruit;
}
});
setFruits(newFruits);
}
return (
<div>
<h3>with no styling</h3>
<Basket items={fruits} onClick={handleClick} />
</div>
);
}
function Basket({ items, onClick }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
<button type="button" onClick={() => onClick(item)}>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
export default App;
这个小的React应用只是用一个有状态的列表来渲染一个列表组件。列表的每个项目都有一个按钮,帮助我们通过按钮及其回调处理程序来喜欢或不喜欢一个列表项目。在接下来的步骤中,我们将用不同的CSS样式设计按钮和列表。只要有CSS样式文件,我们就会在React项目中使用一个流行的文件夹结构。
CSS-in-CSS:React中的CSS
最基本的方法是在React中使用普通的CSS与CSS文件。在每个组件或每组组件的旁边,你可以有一个扩展名为.css的文件。例如,下面这个CSS文件为一个按钮定义了一个CSS类。
.button {
cursor: pointer;
border: 1px solid #1a202c;
padding: 8px;
min-width: 64px;
background: transparent;
transition: all 0.1s ease-in;
}
.button:hover {
background: #1a202c;
color: #ffffff;
}
在React JavaScript文件中,我们可以从这个样式文件中导入CSS并隐含地使用它。
import React from 'react';
import './style.css';
function App() {
...
}
function Basket({ items, onClick }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
<button
type="button"
className="button"
onClick={() => onClick(item)}
>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
没有直接的连接--像一个变量--让我们在JSX中用className属性定义这个CSS类。相反,通过导入CSS文件,所有的CSS类都可以在这里使用。
让我们继续对列表进行样式设计。在CSS文件中,我们可以为列表和列表项再添加两个CSS类。
.unordered-list {
margin: 0;
padding: 0;
list-style-type: none;
}
.list-item {
display: flex;
justify-content: space-between;
padding: 8px 0;
}
然后我们又可以在React的JSX中用CSS className属性来使用它们。由于我们已经导入了CSS文件,我们可以直接使用CSS类。
function Basket({ items, onClick }) {
return (
<ul className="unordered-list">
{items.map((item) => (
<li key={item.id} className="list-item">
{item.name}
<button
type="button"
className="button"
onClick={() => onClick(item)}
>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
这种CSS在React中的使用有几个缺点。首先,这只是普通的CSS,我们错过了很多高级的CSS功能。我们将用下一个叫做Sass的方法来改善这种情况,它与CSS-in-CSS策略相同。
CSS-in-CSS、React中的Sass
如果你使用create-react-app,你可以在安装后使用Sass。相反,如果你使用的是带有Webpack设置的自定义React,你需要为它配置Webpack。
Sass(Syntactically Awesome Style Sheets)是一个CSS扩展,为你提供更强大的CSS。例如,你可以定义可重复使用的CSS变量,并且你能够嵌套你的CSS。我们将利用后者来实现按钮的悬停效果。
.button {
cursor: pointer;
border: 1px solid #1a202c;
padding: 8px;
min-width: 64px;
background: transparent;
transition: all 0.1s ease-in;
&:hover {
background: #1a202c;
color: #ffffff;
}
}
在vanilla CSS中,我们必须定义另一个按钮的伪悬停类。在Sass中,我们可以使用父选择器&,指的是外部选择器(这里是.button )。这样,我们就可以将CSS选择器整齐地嵌套在一起,并从这些嵌套的选择器中引用父选择器。
新的CSS文件有一个Sass文件扩展名。将你的样式文件重命名为style.scss,并将其导入你的React JavaScript文件以进一步使用。
import React from 'react';
import './style.scss';
...
所有其他的样式和用法都和以前一样--当我们使用vanilla CSS时--因为我们在这里没有使用任何其他的Sass功能。请记住,当你使用CSS-in-CSS策略时,一定要选择像Sass这样的CSS扩展,以便在使用CSS时给自己更多的功能(嵌套CSS、变量和特殊选择器,如父选择器)。
在React中以这种方式使用CSS--即使是使用Sass--还有一个缺点。所有的CSS在导入后都可以全局访问。在React项目的其他地方,你可以重复使用按钮、列表和列表项的CSS类。有时这可能是你想要的效果,但大多数情况下,你想把你的样式/CSS范围扩大到一个JavaScript文件或一个React组件。让我们进入CSS模块 ...
CSS-in-CSS、React中的CSS模块
如果你使用create-react-app,你就可以马上使用CSS Modules。但是,如果你使用的是带有Webpack设置的自定义React,你需要为它配置Webpack。
CSS模块可以用于普通的CSS,也可以用于像Sass这样的CSS扩展。让我们看看如何在style.module.css(vanilla CSS)或style.module.scss文件(Sass)中定义一个CSS模块。
.button {
cursor: pointer;
border: 1px solid #1a202c;
padding: 8px;
min-width: 64px;
background: transparent;
transition: all 0.1s ease-in;
}
.button:hover {
background: #1a202c;
color: #ffffff;
}
如果你使用Sass与CSS模块,你可以再次使用所有的Sass功能,如&父选择器:
.button {
cursor: pointer;
border: 1px solid #1a202c;
padding: 8px;
min-width: 64px;
background: transparent;
transition: all 0.1s ease-in;
&:hover {
background: #1a202c;
color: #ffffff;
}
}
在你的React JavaScript文件中,你可以再次导入style.module.css或style.module.scss文件,但这次是用JavaScript样式对象明确导入:
import React from 'react';
import styles from './style.module.css';
...
如果你使用Sass,使用*.scss而不是.css*文件扩展名。这个新的JavaScript样式对象,无非是一个普通的JavaScript对象,持有你的CSS文件中的所有样式。你可以在你的React组件的JSX中使用它。
function Basket({ items, onClick }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
<button
type="button"
className={styles.button}
onClick={() => onClick(item)}
>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
CSS类可以作为导入的样式对象的属性。我们可以为列表和列表项类做同样的事情。首先在你的CSS文件中定义它们。
.unordered-list {
margin: 0;
padding: 0;
list-style-type: none;
}
.list-item {
display: flex;
justify-content: space-between;
padding: 8px 0;
}
由于之前按钮的使用,这两个CSS类已经被导入,我们可以直接在React的JSX中使用它们。
function Basket({ items, onClick }) {
return (
<ul className={styles['unordered-list']}>
{items.map((item) => (
<li key={item.id} className={styles['list-item']}>
{item.name}
<button
type="button"
className={styles.button}
onClick={() => onClick(item)}
>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
CSS类通常以kebab大小写定义。如果是按钮样式,你可以用styles.button 。然而,对于其他带破折号的样式,你需要用字符串从对象中获取。
总之,如果你想使用CSS-in-CSS作为造型策略,CSS模块与Sass这样的扩展是现代React的现状。如果你想使用CSS-in-JS,你会选择像Styled Components这样的东西。
CSS-in-JS:React中的样式化组件
样式化组件需要进行CSS设置,因为一切都带有JavaScript。基本上,正如CSS-in-JS的策略已经说过的,我们将不需要任何CSS文件,因为所有的CSS都在JavaScript中定义。在使用风格化组件之前,你需要在命令行中安装它们。
npm install styled-components
Styled Components采取的方法是只用一个HTML标签和一个样式字符串来创建组件。让我们看看一个按钮元素在我们的JavaScript文件中是如何成为一个Button组件的。
import React from 'react';
import styled from 'styled-components';
const Button = styled.button`
cursor: pointer;
border: 1px solid #1a202c;
padding: 8px;
min-width: 64px;
background: transparent;
transition: all 0.1s ease-in;
&:hover {
background: #1a202c;
color: #ffffff;
}
`;
Button变量是一个有效的React组件,可以在JSX中使用。任何属性如onClick ,都会传递给真正的按钮HTML元素。此外,一个样式化组件已经有了一些功能(这里:带有父选择器的CSS嵌套),我们通常会从Sass这样的CSS扩展中获得。
function Basket({ items, onClick }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
<Button type="button" onClick={() => onClick(item)}>
{item.isFavorite ? 'Unlike' : 'Like'}
</Button>
</li>
))}
</ul>
);
}
对于许多React初学者来说,样式化组件的语法并不十分清楚。基本上,styled 对象为每个HTML元素(如按钮、ul、li)提供一个函数。这个函数可以用JavaScript模板字头调用,而你放在模板字头里的所有东西都会成为组件的样式。
const UnorderedList = styled.ul`
margin: 0;
padding: 0;
list-style-type: none;
`;
const ListItem = styled.li`
display: flex;
justify-content: space-between;
padding: 8px 0;
`;
风格化的组件可以定义在同一个文件或其他地方。毕竟,在你定义了它们之后,它们只是普通的React组件,这使得它们可以在你的JSX中导出或直接使用。
function Basket({ items, onClick }) {
return (
<UnorderedList>
{items.map((item) => (
<ListItem key={item.id}>
{item.name}
<Button type="button" onClick={() => onClick(item)}>
{item.isFavorite ? 'Unlike' : 'Like'}
</Button>
</ListItem>
))}
</UnorderedList>
);
}
使用像Styled Components这样的CSS-in-JS方法,你仍然需要写CSS,但你用JavaScript来写。此外,像Styled Components这样的库已经解决了许多我们之前必须用CSS Modules(范围)和Sass(CSS特性)解决的问题。
实用为先--CSS、React中的Tailwind CSS
最后但并非最不重要的是,在CSS-in-CSS和CSS-in-JS策略的旁边,存在着Utility-First-CSS。实用优先CSS的方法之一是Tailwind CSS。让我们看看在你设置了它之后是什么样子的。请注意,Tailwind CSS在使用前需要进行一些适当的设置(在React中)。请查看Tailwind CSS官方网站的说明。之后,你可以为你的React组件导入Tailwind CSS。
import React from 'react';
import '../tailwind.generated.css';
...
当使用像Tailwind CSS这样的实用优先CSS策略时,你不需要再定义你的CSS。Tailwind CSS为你提供了所有预先配置好的CSS,你可以在你的React的classNames中立即使用。让我们来看看我们的按钮例子是怎样的。
function Basket({ items, onClick }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
<button
type="button"
className="p-2 w-16 border border-solid border-gray-900 transition duration-100 ease-in hover:bg-gray-900 hover:text-white"
onClick={() => onClick(item)}
>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
Tailwind CSS带有预配置的CSS类。例如,p-2 类为我们提供了0.5rem的所有方向的padding,如果没有其他配置的话,通常翻译为8px。也可以直接在你的JSX className属性中使用伪类的选择器(这里是hover)。
关于Tailwind CSS的坏处是,你不能再直接应用你的CSS知识,因为你必须学习他们的语法来表达所有的CSS属性,如宽度(这里是w-16)或颜色(border-gray-900)。然而,一旦你学会了Tailwind CSS的可用属性(或者至少知道如何浏览它们的文档),你可能会发现自己用CSS开发React组件比以往任何时候都快。与其从CSS中了解所有可能的键/值对,你几乎可以直接在你的JSX中使用该值。此外,Tailwind CSS带有很多合理的默认值,如颜色或填充/边距,这将自动导致一个更好看的应用程序。
让我们来看看我们如何用Tailwind CSS对列表和列表项元素进行样式设计:
function Basket({ items, onClick }) {
return (
<ul>
{items.map((item) => (
<li key={item.id} className="flex justify-between py-2">
{item.name}
<button
type="button"
className="p-2 w-16 border border-solid border-gray-900 transition duration-100 ease-in hover:bg-gray-900 hover:text-white"
onClick={() => onClick(item)}
>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
列表项元素只是接收了用于其flexbox样式的CSS值,以及用于顶部和底部的垂直填充。列表本身没有接收任何CSS类,因为它已经在Tailwind CSS默认值中看起来很好了,它删除了CSS列表样式装饰和边距/填充。
Tailwind CSS对于那些愿意学习Tailwind CSS类的个人开发者或团队来说是非常好的,因为他们不需要再自己定义CSS。
React中的内联CSS
内联CSS(也叫内联样式)是上面的一个小奖励,因为它不应该取代任何其他显示的CSS方法。然而,有时了解它对快速原型设计或由JavaScript驱动的更多动态CSS是很有用的。例如,每个HTML元素都有一个style属性。你可以在React的JSX中使用style属性,向其传递一个style对象。
function Basket({ items, onClick }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
<button
type="button"
onClick={() => onClick(item)}
style={{
cursor: 'pointer',
border: '1px solid #1a202c',
padding: '8px',
minWidth: '64px',
background: 'transparent',
transition: 'all 0.1s ease-in',
}}
>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
我们不需要定义任何其他的样式组件或CSS文件,因为我们可以直接将所有的样式作为对象传递给JSX的HTML元素。这同样适用于列表和列表项元素。
function Basket({ items, onClick }) {
return (
<ul
style={{
margin: '0',
padding: '0',
listStyleType: 'none',
}}
>
{items.map((item) => (
<li
key={item.id}
style={{
display: 'flex',
justifyContent: 'space-between',
padding: '8px 0',
}}
>
{item.name}
<button
type="button"
onClick={() => onClick(item)}
style={{
cursor: 'pointer',
border: '1px solid #1a202c',
padding: '8px',
minWidth: '64px',
background: 'transparent',
transition: 'all 0.1s ease-in',
}}
>
{item.isFavorite ? 'Unlike' : 'Like'}
</button>
</li>
))}
</ul>
);
}
你已经可以看到这种方法的负面影响:你的JSX变得不可读,因为所有的样式都在你的HTML标签中杂乱不堪。这就是为什么你在常规的React项目中很少看到内联样式。然而,如前所述,它可以在原型设计或基于JavaScript条件的动态CSS中派上用场。
毕竟,个人的品味和特点会影响你和你的团队的React项目采取哪种样式策略和方法的决定。在现代React应用中,你会发现每一种策略都有最流行的方法。CSS模块、风格化组件和Tailwind CSS。你可以在这个GitHub资源库中找到造型策略中的所有不同方法。