当前位置: 首页 > news >正文

Scoped CSS规范草案

原文链接:https://github.com/AlloyTeam/AlloyTouch/wiki/Scoped-CSS

写在前面

问:什么是Scoped CSS规范?

Scoped CSS规范是Web组件产生不污染其他组件,也不被其他组件污染的CSS规范。

面对组件化的普及,组件的复用很普遍的需求,然而CSS相互污染是经常遇见的问题,建立规范让开发者放心使用各种组件,甚至跨生态的组件是很有必要的一件事情。

目前业界的一些方案

方案一:
如果用webpack的话,可以参考css-loader的这个功能:

105416-20161226160741601-1648420713.png

一段hash + 组件名,这个可能兼顾了辨识度 + 命名污染的问题。

方案二:

用webpack和scss,less写成模块化css就可以一定程度避免CSS污染,不能完全避免

方案三:样式规范上,使用与组件同名的嵌套命名空间

如果只用自己的生态可以这么搞,但是有的时候会引入第三方生态,第三方和自己的命名空间一样还是很有可能,比如scroller插件,社区里也有很多scroller插件loading uplader插件等等。

现有方案的局限性

这里还是会有污染的情况,因为:

  • 模块化的粒度是大于等于组件化粒度,意思就是一个模块可能有多个组件
  • 非less和sass项目下的组件怎么保证
  • 难以保证不污染第三方组件
  • 难以保证不被第三方组件污染
  • 同名组件的问题
  • 组件在第三方项目使用的问题
  • 组件自身生态闭环的问题

所以得出:

用意念或者规范约定不然注入程序自动化避免冲突

好处:

  • 能保证不污染别的组件并且不被被的组件污染可以更放心的复用
  • Scoped CSS规范是运行时产生唯一id~~ 永远不会css碰撞
  • 返回的这个id那个指定给组件的顶层div就行,实施简单

如果把这个过程放在构建过程就是工程问题。但是组件单独抽离出来给第三方用,其实就是组件本身的问题。总之要保证:

  • 不污染第三方的项目或组件
  • 不被第三组件或项目污染(由于是层叠样式,这个无法完全保证)

Scoped CSS代码

;(function () {

    function scoper(css) {
        var id = generateID();
        var prefix = "#" + id;
        css = css.replace(/\/\*[\s\S]*?\*\//g, '');
        var re = new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)", "g");
        css = css.replace(re, function(g0, g1, g2) {

            if (g1.match(/^\s*(@media|@keyframes|to|from|@font-face)/)) {
                return g1 + g2;
            }

            if (g1.match(/:scope/)) {
                g1 = g1.replace(/([^\s]*):scope/, function(h0, h1) {
                    if (h1 === "") {
                        return "> *";
                    } else {
                        return "> " + h1;
                    }
                });
            }

            g1 = g1.replace(/^(\s*)/, "$1" + prefix + " ");

            return g1 + g2;
        });

        addStyle(css,id+"-style");
        return id;
    }

    function generateID() {

        var id =  ("scoped"+ Math.random()).replace("0.","");
        if(document.getElementById(id)){
            return generateID();
        }else {
            return id;
        }
    }

    var isIE = (function () {

        var undef,
            v = 3,
            div = document.createElement('div'),
            all = div.getElementsByTagName('i');

        while (
            div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
                all[0]
            );

        return v > 4 ? v : undef;

    }());

    function addStyle(cssText, id) {
        var d = document,
            someThingStyles = d.createElement('style');
        d.getElementsByTagName('head')[0].appendChild(someThingStyles);
        someThingStyles.setAttribute('type', 'text/css');
        someThingStyles.setAttribute('id', id);
        if (isIE) {
            someThingStyles.styleSheet.cssText = cssText;
        } else {
            someThingStyles.textContent = cssText;
        }
    }


    window.scoper = scoper;
})();

Scoped CSS实施

var id = scoper("h1 {\
               color:red;\
            /*color: #0079ff;*/\
                }\
        \
                /*  h2 {\
                color:green\
                }*/");

scoper返回的id,在组件的JS里面赋给包裹的DOM便可以。这里详细说下生成id的过程:

function generateID() {
    var id =  ("scoped"+ Math.random()).replace("0.","");
    if(document.getElementById(id)){
        return generateID();
    }else {
        return id;
    }
}

通过Math.random得到随机数并经过处理,然后通过document.getElementById去查询页面上有没有同名ID,有的话则继续重新生成,没有的话就使用当前id。这里需要特别注意的是,比如一些弹出层插件,display hide的时候有的组件是直接从body里面移除,所以这就带来了CSS碰撞的可能性,所以这里Scoped CSS 规范强行约定:后插入的HTML,一定要经过scoper过程重新生成唯一id。
最后,Scoped CSS规范已经在AlloyTouch插件里开始实施,并打算推广开来。

你有什么好的想法可以让跨生态跨项目跨技术栈的组件复用更加惬意,可以交流交流。

相关文章:

  • apk增量升级
  • win7下JDK环境变量设置方法
  • Python学习基础
  • java并行计算Fork和Join的使用
  • bootstrap html页面禁止放大缩小
  • dot函数
  • Java图片合成
  • Ubuntu安装Eclipse
  • 接口初探
  • 设计模式总结篇系列:原型模式(Prototype)
  • oracle开启/关闭archlog
  • java虚拟机所管理的内存包括的运行时数据区域
  • Chrome浏览器查看cookie
  • 生成树协议设置
  • Java 系列文章
  • Akka系列(七):Actor持久化之Akka persistence
  • Django 博客开发教程 16 - 统计文章阅读量
  • express + mock 让前后台并行开发
  • Laravel5.4 Queues队列学习
  • ReactNative开发常用的三方模块
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • VUE es6技巧写法(持续更新中~~~)
  • Vue全家桶实现一个Web App
  • 分布式任务队列Celery
  • 官方解决所有 npm 全局安装权限问题
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 微服务框架lagom
  • 我的面试准备过程--容器(更新中)
  • 小试R空间处理新库sf
  • 优化 Vue 项目编译文件大小
  • 在Mac OS X上安装 Ruby运行环境
  • 正则表达式小结
  • 阿里云ACE认证之理解CDN技术
  • # 20155222 2016-2017-2 《Java程序设计》第5周学习总结
  • # 飞书APP集成平台-数字化落地
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (企业 / 公司项目)前端使用pingyin-pro将汉字转成拼音
  • (三)Hyperledger Fabric 1.1安装部署-chaincode测试
  • (算法)前K大的和
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转)关于多人操作数据的处理策略
  • ******IT公司面试题汇总+优秀技术博客汇总
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .Net CoreRabbitMQ消息存储可靠机制
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .net 中viewstate的原理和使用