携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,[点击查看活动详情]
前言
前端boy都知道,css是前端开发的必备技能,js搭建起的内容像1,而css则是1后的0,css运用的越好,用户体验感越好,那么项目的价值越高。css作为一门标记语言,主要用于样式定义以及页面布局,但是原生的css具有很多问题:
- 全局污染,样式覆盖,命名冲突等常见问题。
- 缺乏变量,函数式、模块化等机制,使得开发效率降低,同时遇到一些动态样式变化,通过
:class='{}',:style='{}'这种方式并不能很好的满足。 - 样式难以复用,无法通过继承、组件等方式对css样式进行复用。
虽然Sass、Less帮助我们增添了变量、混入、继承等概念,但在一定程度上并不能更好的解决以上问题,个人认为特别是组件化,函数式的问题。特别是许多后端同学写后台时对于css这种标记语言非常讨厌,渴望有一套函数式或者组件式写法。
因此Css in JS的思想很久之前就已经提出,并且经过了长期的实践,虽然其存在编译的性能问题以及对于新手使用不友好等问题,但并不妨碍其成为css的新常态,同时也衍生出许多优秀的工具,比如较早的Styled-Components,当我还是前端小白阶段时(现在依然是菜鸡),其使用方式完全颠覆了我对于原生css的概念,今天给大家讲解一款最近使用的@emotion/styled,其使用方式个人认为与Styled-Components相差无几。
一、emotion有哪些优势?
- 无需关心className命名问题,其为样式生成了唯一的name,不用担心命名冲突等问题。
- 可以搭配TS自定义样式组件,并且根据props动态配置。
- 提供了增强
React.createElement方法jsx,添加了一个cssprop。
二、emotion如何使用?
1.安装
yarn add @emotion/react @emotion/styled
2.基础使用
styled.后一般会跟一个html标签名,例如div、h1、main、article等元素标签,styled.div调用后会返回一个React组件,emotion会自动生成一个HashName加到组件中,并且将``内的样式与组件关联。
import React from 'react'
import styled from '@emotion/styled'
export const AuthenticatedApp=()=>{
return <Container>
<Main>
main
</Main>
</Container>
}
// 可以使用自定义变量
const widthNum='20rem'
const Container= styled.div`
width:${widthNum};
height: 100vh;
`;
const Main= styled.main`
`;
3.搭配Ts,实现一个自定义组件Row,并能够通过props控制样式
(1)在components下新建lib.tsx
我们希望该组件可以接收三个参数gap,between,marginBottom,分别控制其子元素的marginRight、flex横向布局样式以及marginBottom,css样式名后可以使${(props)=>props.between?'spacebetween':undefined}; 获取组件传来的props,同时根据需求结合props动态返回样式。
import styled from '@emotion/styled';
export const Row=styled.div<{
gap?:number | boolean,
between?:boolean,
marginBottom?:number
}>`
display:flex ;
align-items: center;
justify-content:${(props)=>props.between?'space-between':undefined};
margin-bottom:${props=>props.marginBottom + 'rem'} ;
> * {
margin-top: 0 !important ;
margin-bottom: 0 !important ;
margin-right:${props=>typeof props.gap==='number'?props.gap + 'rem':props.gap?'2rem':undefined};
}
`
(2)组件中使用,Header上可以传入参数gap等。
import React from 'react'
import styled from '@emotion/styled'
import { Row } from 'components/lib';
export const AuthenticatedApp=()=>{
return <Container>
<Header gap={true}>
<h2>项目</h2>
<h2>用户</h2>
</Header>
<Main>
main
</Main>
</Container>
}
const Container= styled.div`
width:20rem;
height: 100vh;
`;
const Header = styled(Row)``;
const Main= styled.main``;
4.实现样式的继承
styled(样式组件名)的方式可以实现对样式的继承,并在其后做样式的拓展,如下,我们继承了自定义样式组件Row的样式,并且添加了宽度属性。
const Header = styled(Row)`
width:100rem
`;
基于此,我们在使用组件库如antdesign的组件时,常常会在组件上写内联样式,那么现在不再需要在内联上改变样式,只需如下即可:
import {Button} from 'antd'
const Header = styled(Button)`
width:100rem
`;
5.提供了增强 React.createElement 方法jsx,添加了一个 css prop。
在标签上写内联样式style是有许多限制的,如不能使用层级选择等,而@emotion/react提供了jsx,进一步拓展了style。
import {jsx} from '@emotion/react'
import React from 'react'
export const AuthenticatedApp=()=>{
return <div css={{
backgroundColor:'red',
'&:hover': {
backgroundColor: 'green'
}
}}></div>
}
写在最后
css的初级使用其实是非常简单的,但是随着前端技术的发展,不断有更多更复杂的需求接踵而至,Css in JS的思想也是css工程化进程中的一种解决思路,同时其他方向的技术也不断发展,比如Tailwindcss,其类似于bootstrap使用了很多引导程序的语义,定义了一套基本样式,但是它也存在className生成繁乱,不够简洁等问题,所以说不同的技术方案有不同的优缺点,但是我们可以根据实际需求来选择我们的技术方案,比如快速建立一个简单的单页面应用,完全可以使用比如Tailwind等,如果要建立一个复杂的系统,更推荐大家使用Css in JS的相关工具,其动态性、以及组件的可维护性确实非常实用。