CSS 使用CSS变量自定义全新的CSS语法范例——keyword()

需求描述

自定义一个CSS函数keyword(),使颜色关键字也能设置透明度。
如,当下方代码生效时,文字为半透明的蓝色

    --keyword: keyword(blue, 50%);
    color: var(--keyword);

最终效果见 https://demo.cssworld.cn/new/8/4-1.php

在这里插入图片描述

实现原理

使用JavaScript获取使用了keyword()函数的元素,再将其转换成浏览器可识别的rgba()颜色函数。

其他想要的自定义函数效果,也可以使用类似的方法实现。

代码

可以直接引入

<script src="https://www.zhangxinxu.com/study/202008/keyword-color.js"></script>

完整代码为:

/**
 * @description CSS 自定义的keyword()方法的支持和使用
 * @author zhangxinxu(.com) 2020-08-11
 * @docs https://www.zhangxinxu.com/wordpress/?p=9537
 * @license MIT 作者和出处保留
 */

(function () {
    if (!window.CSS) {
        return;
    }

    if (!NodeList.prototype.forEach) {
        NodeList.prototype.forEach = Array.prototype.forEach;
    }


    // 获取页面中所有的CSS自定义属性
    var isSameDomain = function (styleSheet) {
        if (!styleSheet.href) {
            return true;
        }

        return styleSheet.href.indexOf(window.location.origin) === 0;
    };

    var isStyleRule = function (rule) {
        return rule.type === 1;
    };

    var arrCSSCustomProps = (function () {
        return [].slice.call(document.styleSheets).filter(isSameDomain).reduce(function (finalArr, sheet) {
            return finalArr.concat([].slice.call(sheet.cssRules).filter(isStyleRule).reduce(function (propValArr, rule) {
                var props = [].slice.call(rule.style).map(function (propName) {
                    return [
                        propName.trim(),
                        rule.style.getPropertyValue(propName).trim()
                    ];
                }).filter(function ([propName]) {
                    return propName.indexOf('--') === 0;
                });

                return [].concat(propValArr, props);
            }, []));
        }, []);
    })();

    // 使用了keyword()语法的CSS自定义属性名
    var arrCssPropsValueIsKeyword = arrCSSCustomProps.filter(function (arrPropVal) {
        return /keyword\([\w\W]+\)/i.test(arrPropVal[1]);
    });

    // 设置自定义属性值的方法
    var funKeywordColor2Rgba = function (node) {
        if (node.nodeType != 1 || ['script', 'style', 'meta', 'title', 'head'].includes(node.nodeName.toLowerCase())) {
            return;
        }

        // 当前节点的所有样式对象
        var objStyle = window.getComputedStyle(node);

        // 所有设置了keyword()的自定义属性的遍历处理
        arrCssPropsValueIsKeyword.forEach(function (arr) {
            var cssProp = arr[0];

            // 判断当前元素是否设置了当前自定义属性
            var cssVarValueKeyword = objStyle.getPropertyValue(cssProp);

            if (!cssVarValueKeyword || !cssVarValueKeyword.trim() || !/keyword\([\w\W]+\)/i.test(cssVarValueKeyword)) {
                return;
            }

            cssVarValueKeyword = arr[1];

            // 解析与处理
            var keyColorAndOpacity = cssVarValueKeyword.replace(/\w+\(([\w\W]+)\)/, '$1');

            var arrKeyColorAndOpacity = keyColorAndOpacity.split(/\s+/);

            if (/,/.test(keyColorAndOpacity)) {
                arrKeyColorAndOpacity = keyColorAndOpacity.split(',');
            } else if (/\//.test(keyColorAndOpacity)) {
                arrKeyColorAndOpacity = keyColorAndOpacity.split(',');
            }

            if (arrKeyColorAndOpacity.length != 2) {
                return;
            }

            // 分出颜色和透明度
            var keyColor = arrKeyColorAndOpacity[0].trim();
            var opacity = (arrKeyColorAndOpacity[1] || '1').trim();

            // keyColor转rgb
            document.head.style.backgroundColor = keyColor;
            var rgbColor = window.getComputedStyle(document.head).backgroundColor;

            // 应用的颜色
            var applyColor = '';
            // 透明度替换
            if (/^rgba/.test(rgbColor)) {
                applyColor = rgbColor.replace('1)', opacity + ')');
            } else {
                applyColor = rgbColor.replace(')', ', ' + opacity + ')');
            }

            node.style.setProperty(cssProp, applyColor);
        });
    };


    var funAutoInitAndWatching = function () {
        // DOM Insert自动初始化
        if (window.MutationObserver) {
            var observerSelect = new MutationObserver(function (mutationsList) {
                mutationsList.forEach(function (mutation) {
                    var nodeAdded = mutation.addedNodes;
                    // 新增元素
                    nodeAdded.forEach(function (eleAdd) {
                        funKeywordColor2Rgba(eleAdd);
                    });
                });
            });

            observerSelect.observe(document.body, {
                childList: true,
                subtree: true
            });
        }

        // 如果没有开启自动初始化,则返回
        document.querySelectorAll('*').forEach(function (ele) {
            funKeywordColor2Rgba(ele);
        });
    };

    if (document.readyState != 'loading') {
        funAutoInitAndWatching();
    } else {
        window.addEventListener('DOMContentLoaded', funAutoInitAndWatching);
    }
})();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值