原文連接:https://github.com/AlloyTeam/AlloyTouch/wiki/Scoped-CSScss
問:什麼是Scoped CSS規範?webpack
Scoped CSS規範是Web組件產生不污染其餘組件,也不被其餘組件污染的CSS規範。git
面對組件化的普及,組件的複用很廣泛的需求,然而CSS相互污染是常常碰見的問題,創建規範讓開發者放心使用各類組件,甚至跨生態的組件是頗有必要的一件事情。github
方案一:
若是用webpack的話,能夠參考css-loader的這個功能:web
一段hash + 組件名,這個可能兼顧了辨識度 + 命名污染的問題。sass
方案二:app
用webpack和scss,less寫成模塊化css就能夠必定程度避免CSS污染,不能徹底避免less
方案三:樣式規範上,使用與組件同名的嵌套命名空間dom
若是隻用本身的生態能夠這麼搞,可是有的時候會引入第三方生態,第三方和本身的命名空間同樣仍是頗有可能,好比scroller插件,社區裏也有不少scroller插件loading uplader插件等等。ide
這裏仍是會有污染的狀況,由於:
因此得出:
用意念或者規範約定否則注入程序自動化避免衝突
好處:
若是把這個過程放在構建過程就是工程問題。可是組件單獨抽離出來給第三方用,其實就是組件自己的問題。總之要保證:
;(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; })();
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插件裏開始實施,並打算推廣開來。
你有什麼好的想法可讓跨生態跨項目跨技術棧的組件複用更加愜意,能夠交流交流。