使用变量 currentColor 减少重复代码
需求描述
- 移到按钮上时,改变该元素的 border-color 、 color ,还有一个具有透明度的同色背景。
- 点击按钮之后,颜色更改为移入按钮时的同种颜色。
![9873c78e6f8f245688da90ac225f90b9.gif](https://i-blog.csdnimg.cn/blog_migrate/0b7103b2cad82f6ac22dcab072e2a636.gif)
尝试方案
我相信任何一个前端开发者都能很快实现这个需求,不知道大家怎么样的,我在之前一直都是以下代码快速实现:
index.html 文件 :
请给我点赞
复制代码
index.scss 文件 :
.good { padding: 3px 6px; color: #333; background: rgba(#333, 0.1); border: 1px solid #333; border-radius: 3px; cursor: pointer; &:hover { color: #0069ff; background: rgba(#0069ff, 0.1); border: 1px solid #0069ff; } &.good-click { color: #0069ff; background: rgba(#0069ff, 0.1); border: 1px solid #0069ff; }}复制代码
index.js 文件 :
const goodBtn = document.querySelector('.good')goodBtn.addEventListener('click', () => { if (goodBtn.classList.contains('good-click')) { goodBtn.classList.remove(['good-click']) return } goodBtn.classList.add(['good-click'])})复制代码
是的,就是那么朴实无华,缺点也暴露无遗:
- 相同的颜色我们使用了多次,比如 #333 和 #0069ff 。如果有一天产品说把这个那个颜色改一下,细心点的你多动动手指也没啥问题,改就改了,但是这种方式很不“程序员”。
针对这个问题我们直接使用预处理器(SASS/LESS)的变量就完事了:
index.scss 文件 :
$color: #333;$hoverColor: #0069ff;.good { padding: 3px 6px; color: $color; background: rgba($color, 0.1); border: 1px solid $color; border-radius: 3px; cursor: pointer; &:hover { color: $hoverColor; background: rgba($hoverColor, 0.1); border: 1px solid $hoverColor; } &.good-click { color: $hoverColor; background: rgba($hoverColor, 0.1); border-color: $hoverColor; }}复制代码
咋一看已经是很好的实现方式了,但是也有缺点:
- 有时候(比如我大多数时候)都不想为了某一个特殊的类下的 color 单独设置一个变量,仅仅只有它使用,我还要专门为其定义一个变量就显得代码很臃肿;
- 在我添加了 good-click 这个类名后,我要把 color 、 border-color 、 background 全都重新设置一遍;
这个时候,css 原生变量 currentColor 即可大显身手了。
改进方案
变量 currentColor 能拿到本元素的 color 属性的值,如果没有显示设置,拿的将会是父元素的 color 属性的值,由此类推。借助这个特性,我们即可优化上述代码:
index.scss 文件 :
.good { position: relative; padding: 3px 6px; color: #333; border: 1px solid currentColor; border-radius: 3px; cursor: pointer; &::before { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: currentColor; opacity: 0.1; content: ''; } &:hover { color: #0069ff; } &.good-click { color: #0069ff; }}复制代码
现在看起来是不是好多了,我每次要更改颜色,只需要将此元素的 color 属性更改即可,不需要再重新写一堆重复的属性,当然,原生的 css 以及功能强大的 sass/less 都还是无法支持 rgba(currentColor, 0.1) 这种写法,我还去官方提了个 issue ,官方也给了很好的回复,有兴趣的同学可以看看。
所以现在我只能添加一个 ::before 来模拟背景色块,真正做到只改 color 属性,即可改全部颜色。
现在大家就可以在 React 或 Vue 中通过状态来控制改变颜色的类名添加与否并设置 color 属性,以此来完美地进行颜色的快速变换了~
多说一句,如果我们直接使用 ele.style.color = '#fff' 这种操作 dom 的形式来改变字体颜色,在未使用 currentColor 的情况下,我们是没法操作伪元素的,也就改变不了伪元素的 background 、 border-color 等其他与字体颜色一致的属性,所以这时候 currentColor 的优势就更明显了~
在线演示
使用变量 currentColor 减少重复代码 - codepen(https://codepen.io/vortesnail/pen/MWyzerK)
完美的带小箭头的聊天框
需求描述
- 主体功能聊天气泡,需有有边框 border 、背景色 background 、阴影、带边框的小三角箭头。
- 小三角的边框颜色和阴影颜色与主体框的颜色要一致,小三角的边框有 border-radius 。
![309ef87c42f3af7473fefa0d1cd32ed3.png](https://i-blog.csdnimg.cn/blog_migrate/27c2f898e769bf61718ce1cb9e602e27.jpeg)
尝试方案
给该元素加个伪元素,背景色与聊天框背景色一致,再给该伪元素添加上、左同色边框,绝对定位调整位置,再来个 border-top-left-radius: 3px ,最后 transform: rotate(-45deg) 旋转一下,代码如下:
index.html 文件 :
大家好,我是 vortesnail,如果大家喜欢我的文章,对大家有所帮助,麻烦给个小小的赞支持一下,谢谢
复制代码
index.scss 文件 :
.chat-box { position: relative; max-width: 200px; padding: 10px; color: #faae43; background: #fff9ed; border: 1px solid #ffc16b; border-radius: 4px; box-shadow: 0 2px 6px rgba(250, 174, 67, 0.8);}.chat-box::before { position: absolute; top: 20px; left: -6px; width: 10px; height: 10px; background: #fff9ed; border-color: #ffc16b; border-style: solid; border-width: 1px 0 0 1px; transform: rotate(-45deg); content: ''; /* box-shadow: 0 2px 6px rgba(250, 174, 67, 0.8); */}复制代码
可以达到现在下面的效果:
![da4eccca647b8a2b45f2b66fce9e4289.png](https://i-blog.csdnimg.cn/blog_migrate/1255eeb042705429eca9ab0ac290b45b.jpeg)
细心的你一定发现了,这个小三角指示箭头是没有阴影的,如果我给其加上与主体元素一致的 box-shadow ,又因为这个属性不能像 border-color 一样分别给各边设置为透明,结果就会像下面这样:
![11713c2069ec2d651e14fac33e9e288c.png](https://i-blog.csdnimg.cn/blog_migrate/496e82dc33d4e384cde118b584faff87.jpeg)
这已经是无法满足具有相同阴影的要求了,而且大家如过想一下就知道,在我主体元素不设 padding 或设的很小的情况下,小三角的背景色会将我们的文字挡住,这种方案直接宣布失败!
改进方案
针对以上的问题,我们进行一步步改造。
首先,我们考虑到主体元素不设置 padding 的情况,为了防止内容被我们的小三角背景色覆盖,我们可通过加一个伪元素 ::before ,利用 border 来画成一个三角形,代码如下: