变量大家都再熟悉不过了,为啥要代码需要变量?因为相同的数值被多个地方引用,我们将其提取为变量,这样只需要修改该变量,那么所有引用的地方都会同步修改。
CSS自定义变量
一直以来CSS
只是简单的UI
描述语言,无法像js
那样使用更高级的特性,后期CSS
变量的诞生赋予CSS
更多的能力,让我可以实现“一次修改,多处生效”,不仅节省了开发时间,还可让我们将更多的UI
变量代码(全局context, state
等等)从js
挪到CSS
代码里,方便维护,主题换肤功能(暗色模式/深色模式/护眼模式也属于)就是CSS
变量的一个使用场景。
兼容问题
如果你还在硬性地兼容老旧的IE11,那么很遗憾IE11并未支持,因此应禁止使用该特性,尤其是你将其应用到布局样式,诸如margin, flex, position
等等,那会导致这些样式直接失效,从而使页面崩坏掉。
这个变量没有兼容性问题
不兼容的硬伤我们无法修复,不过好在下文所述的这个CSS
变量没有兼容性问题。
不要小看她,就算是仅存的一个变量,但是还是在很多使用场景都有所帮助!
初体验
很多地方都在用这个变量,只是你没察觉到,客官往下看:
让我们创建两个普通的超链接,为了让你更好理解,我们创建两个不同样式的下划线:
<a href="https://www.tuya.com">访问官网</a>
<a style="text-decoration-style: wavy;" href="https://developer.tuya.com/cn">
访问开发者
</a>
显示效果如下:
我们发现下划线和波浪线看起来和字体颜色一样,让我们继续做实验:
我们分别将两个超链接的字体颜色改为主题色涂鸦橙:rgb(255 72 0)
,官网活力蓝:rgb(78 133 254)
<a style="color: rgb(255 72 0);" href="https://www.tuya.com">
访问官网
</a>
<a style="color: rgb(78 133 254);text-decoration-style: wavy;" href="https://developer.tuya.com/cn">
访问开发者
</a>
我们惊喜的发现,不管是下划线还是波浪线,都在视觉上与字体颜色同步,但这些线可能并不是用字体画出来的。
我们甚至可以通过js
获取计算样式的真实颜色值来验证:
getComputedStyle(firstLink).textDecorationColor
最终应用的色值就是字体颜色本身,验证了我们的猜测。其实textDecorationColor
的默认值正是currentColor
,现在主角登场~
currentColor
该CSS
变量值顾名思义就是当前color
值,你可以这样理解:currentColot = color
,该属性值用于读取和同步字体颜色,用以其他地方,比如上述波浪颜色,而我们熟知的border-color
的默认值也是currentColor
。
由于color
可以继承父元素或者祖先元素的变量,因此对父元素只需设置一次颜色,即可穿透至底部元素。
完整真实案例
让我们制作这样的彩色按钮,默认是镂空按钮,hover
变为实心按钮。
这对你来说没有一点难度,让我们按照旧思路来写:
<button class="btn">
<span class="btn-txt">访问官网</span>
<span class="btn-icon">
<!-- 图标(如果需要) -->
</span>
</button>
button {
margin: 0;
padding: 0;
outline: none;
border: none;
background: none;
} /* reset css用于清除button自带样式 */
.btn {
color: rgb(78 133 254); /* 默认颜色 */
height: 30px;
line-height: 30px; /* 高度 */
padding: 0 8px;
border-radius: 6px; /* 圆角 */
border-style: solid;
border-width: 1px; /* 边框 */
cursor: pointer;
}
/* hover时变实心 */
.btn:hover {
background-color: rgb(78 133 254);
}
.btn:active {
opacity: .8;
}
.btn:hover > .btn-txt {
color: white;
}
这对你来说没有任何难度,别高兴太早,往下看:
需求增加
现我们需要增加额外两种颜色主题,表示成功的绿色,和警示性的红色。
这也是小菜一碟,我们在基础样式上,增加两个特性样式去覆盖字体颜色和hover背景色即可:
/* 保持源代码不动,增加如下代码 */
/* 成功色 */
.btn.btn-success {
color: #7cb305;
}
.btn.btn-success:hover {
background-color: #7cb305;
}
/* 警示色 */
.btn.btn-warning {
color: #ff4d4f;
}
.btn.btn-warning:hover {
background-color: #ff4d4f;
}
然后我们在需要使用的地方添加新增样式即可:
<!-- 应用警告色 -->
<button class="btn btn-warning">
<span class="btn-txt">访问官网</span>
<span class="btn-icon">
<!-- 图标(如果需要) -->
</span>
</button>
封装组件
我们需要将其封装为React
组件,下面写个伪代码示范下:
const colorTheme = {
success: 'btn-success',
warning: 'btn-warning',
}
// 出于时间原因,代码全程省略非空控判断,请自觉添加;请自觉forwardRef.
const Button = (props) => {
const { children, theme, className: customerClassName, ...restAsHTMLAttr } = props
const themeClassName = colorTheme[theme] || ''
const classNames = ['btn', themeClassName, customerClassName].join(' ')
return (
<button className={classNames} {...restAsHTMLAttr}>
<span className="btn-txt">{children}</span>
<span className="btn-icon">
{/* 图标,如果需要 */}
</span>
</button>
)
}
然后我们可以通过theme
属性来轻松切换我们想要的按钮:
<Button theme="success">登录</Button>
<Button theme="warning">注销账号</Button>
难度升级
现要求我们组件支持自定义颜色值,因为有可能我们用于不同项目,不同项目使用不同色系,就需要对该基础组件进行自定义颜色后再二次封装为业务组件。
由于我们无法预知未来有多少种颜色,因此在基础组件中,我们无法通过写样式来配置themeColor
,鬼知道未来有多少种颜色,因此我们需要使用者直接将颜色值通过props
传进来。
接受颜色属性
现在我们通过props
的color
获取自定义颜色值,然后将其应用到按钮的color
style
中:
const colorTheme = {
success: 'btn-success',
warning: 'btn-warning',
}
const Button = (props) => {
const {
children,
theme,
color,
className: customerClassName,
style: customerStyle,
...restAsHTMLAttr
} = props
const themeClassName = colorTheme[theme] || ''
const classNames = ['btn', themeClassName, customerClassName].join(' ')
const colorStyle = {
color, //接受自定义颜色
...customerStyle,
}
return (
<button style={colorStyle} className={classNames} {...restAsHTMLAttr}>
<span className="btn-txt">{children}</span>
<span className="btn-icon">
{/* 图标,如果需要 */}
</span>
</button>
)
}
支持hover
目前我们通过color
来修改了按钮颜色,但是我们需要处理hover态,但js
没有hover
事件,我们可以通过两个事件来模拟,比如mouseover
和mouseleave
,而且我们需要颜色改变,这里可以使用state
,思路如下:
//以下均为伪代码
const { color } = props
const normalStyle = { color }
const hoverStyle = {
backgroundStyle: color,
}
const [colorStyle, setColorStyle] = useState({
...normalStyle
//...用户传入的style这里略过,请自行处理
})
接下来在mouseover
事件中,将style改变为背景色:
//切换到背景色
onMouseOver = () => {
setColorStyle(hoverStyle)
//其他代码省略
}
最后在mouseleave
中切换为字体色:
//切换回字体色
onMouseLeave = () => {
setColorStyle(normalStyle)
//其他代码省略
}
当然如果你不想用state
,你可以在事件回调中直接拿到dom
,通过event.target.style.xxx = XXX
,修改样式,不过同样不友好。
因为写这么多事件竟然只是为了改个背景色,原本纯U组件变得不纯粹,这样做很恶心,我是非常讨厌写一堆这样的代码,要是能挪到css就好了。
使用currentColor优化
注意到了吗?上述背景色只是为了同步字体颜色,那么我们就使用currentColor
来优化,修改我们的CSS
如下:
.btn {
color: rgb(78 133 254);
height: 30px;
line-height: 30px;
padding: 0 8px;
border-radius: 6px;
border-style: solid;
border-width: 1px;
cursor: pointer;
}
.btn:hover {
background-color: currentColor; /* 同步color */
}
.btn:active {
opacity: .8;
}
.btn:hover > .btn-txt {
color: white;
}
那么接下来我们只需要操作color
就可以同步背景色了,所以我们要把以前无用的,操作背景的代码统统删掉!
/* 成功色 */
.btn.btn-success {
color: #7cb305;
}
/* 通通删掉 */
/* .btn.btn-success:hover {
background-color: #7cb305;
} */
/* 警示色 */
.btn.btn-warning {
color: #ff4d4f;
}
/* 通通删掉 */
/* .btn.btn-warning:hover {
background-color: #ff4d4f;
} */
最后只留下了两个颜色。接着修改我们的组件,将mouseover, mouseleave
和state
等一堆杂七杂八的东西全删掉,只留下修改color
的代码,最后代码精简到如下:
const colorTheme = {
success: 'btn-success',
warning: 'btn-warning',
}
const Button = (props) => {
const {
children,
theme,
color,
className: customerClassName,
style: customerStyle,
...restAsHTMLAttr
} = props
const themeClassName = colorTheme[theme] || ''
const classNames = ['btn', themeClassName, customerClassName].join(' ')
const colorStyle = {
color, //接受自定义颜色
...customerStyle,
}
return (
<button style={colorStyle} className={classNames} {...restAsHTMLAttr}>
<span className="btn-txt">{children}</span>
<span className="btn-icon">
{/* 图标,如果需要 */}
</span>
</button>
)
}
小技巧
借助color
可以继承的特性,如下的场景卡片,会有一个主题色(下图所示的黄色),并且需要根据配图来变化。
多个标题和按钮的颜色可以继承卡片,我们只需要将颜色设置在卡片最大容器上,然后将Button
颜色设置为inherit
即可继承至卡片的颜色,从而不需要在js
代码里将颜色层层往下传递或者使用context
。
更多场景
颜色还可以用于box-shadow
,甚至是svg
的fill
属性,做到svg icon
和字体颜色自动同步,以省去我们通过自定义样式层层修改颜色值的时间。antd的部分svg
图标也用到currentColot
:
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!