使用 javascript 为 css 规则添加前缀
Add prefix to css rules with javascript
我有一个包含以下 css 的字符串,我需要使用 javascript
进行处理
h1
{
color: red;
}
.info
{
border: 1px dotted blue;
padding: 10px;
}
#rect
{
background: pink;
}
h2,
h3,
h4
{
font-weight: bold;
}
table td:last td
{
background: gainsboro;
}
如何为每条规则添加前缀 .page
以使 css 不被破坏?
我想要这个结果
.page h1
{
color: red;
}
.page .info
{
border: 1px dotted blue;
padding: 10px;
}
...
现在,我通过查找缩进来解决它,但是代码在这种情况下失败了
h1
{
color: red;
}
然后以
结尾
.page h1
{
.page color: red;
}
我也可以查找只有方括号的行,但这种情况会失败
h1 { color: red; }
我不想构建自己的 css 解析器,我发现的解析器主要处理 css 应用于 DOM 中的元素,而不是 [=32= 的字符串].是否有好的解析器或可以通过其他方式实现?
如果你想使用sass,你可以简单地写成
.page {
h1 {
color: red;
}
h2 {
color: green;
}
}
这将被编译成你想要的。但如果这不是一个选项,您必须编写自己的解析器。
看看正则表达式
例如这样的事情:
/([^]*?)({[^]*?}|,)/g
应该在第一组中捕获 css 字符串中的所有选择器,在第二组中捕获规则。然后你做这样的事情来替换火柴
var str = "your css text here";
re = /([^]*?)({[^]*?}|,)/g;
var new_str = str.replace(re, ".prefix "); //prefixed css
console.log(new_str);
如果您不熟悉正则表达式,我建议您阅读 Eloquent Javascript
中的相关章节
一个解决方案,它循环遍历 CSS 规则并动态更新它们。
/* debug purpose */
var j = JSON.stringify;
var el = document.getElementById('el');
var log = function( val ){el.innerHTML+='<div>'+val+'</div>'}
var doIt = function(){
// you have to identify your stylesheet to get it
var ss = document.styleSheets[0];
// we get all the rules from this stylesheets
var rules = ss.cssRules;
// we loop over all rules
for( var i = 0 ; i < rules.length; i++){
var rule = rules[i];
var selector = rule.selectorText;
var def = rule.cssText.replace(selector , '');
// we update the selector
var selector2 = selector.replace(/([^,]+,?)/g , '.page ' );
// we modify the rules on the fly !
var def2 = def.replace('red' , 'green');
def2 = def2.replace('blue' , 'red');
def2 = def2.replace('pink' , 'lime');
log(i);
log( 'def : ' + def);
log( 'modified : ' + def2);
log( 'selector : ' + selector);
log( 'updated : ' + selector2);
log('----------');
ss.deleteRule(i);// we remove the old
ss.insertRule(selector2 + def2 , i);// we add the new
};
// we check the stylecheet !
log( ' checking the results');
for( var i = 0 ; i < rules.length; i++){
var rule = rules[i];
var curRule = rule.cssText;
log( i + ': curRule => ' + curRule);
};
};
h1
{
color: red;
}
.info
{
border: 1px dotted blue;
padding: 10px;
}
#rect
{
background: pink;
}
h2,
h3,
h4
{
font-weight: bold;
}
table td:last td
{
background: gainsboro;
}
<div class='page'>
<div id='rect'> RECT </div>
<div class='info'> INFO </div>
<div>
<button onclick='doIt()'>update it</button>
<div id='el'><div>
你提出了一个问题,即如何做你认为是解决实际问题的方法,这似乎是,我如何将一些 CSS 仅应用于文档的一部分?
最终,解决方案将是 <style scoped>
。在我们等待期间,您可以尝试使用 https://github.com/PM5544/scoped-polyfill, http://thomaspark.co/2015/07/polyfill-for-scoped-css/, https://github.com/thingsinjars/jQuery-Scoped-CSS-plugin, or https://github.com/thomaspark/scoper.
等 polyfill
如果你有一个 CSS 的字符串(你是从哪里得到的?),那么要使用这些 polyfills,你可以简单地在你的 [=26] 中插入一个 <style scoped>
元素=] 在 .page
元素下,包含字符串中的 CSS。
所有这些 polyfill 的主要优点是它们基于浏览器正确解析的 CSS,并且不会在出现问题的第一个迹象时中断,因为您不明智地接受了正则表达式解决方案,并且所有其他正则表达式解决方案,不可避免地会。
这是一个为所有选择器添加 class 名称前缀的函数。此函数正确处理@规则:
var prefixCssSelectors = function(rules, className) {
var classLen = className.length,
char, nextChar, isAt, isIn;
// makes sure the className will not concatenate the selector
className += ' ';
// removes comments
rules = rules.replace( /\/\*(?:(?!\*\/)[\s\S])*\*\/|[\r\n\t]+/g, '' );
// makes sure nextChar will not target a space
rules = rules.replace( /}(\s*)@/g, '}@' );
rules = rules.replace( /}(\s*)}/g, '}}' );
for (var i = 0; i < rules.length-2; i++) {
char = rules[i];
nextChar = rules[i+1];
if (char === '@' && nextChar !== 'f') isAt = true;
if (!isAt && char === '{') isIn = true;
if (isIn && char === '}') isIn = false;
if (
!isIn &&
nextChar !== '@' &&
nextChar !== '}' &&
(
char === '}' ||
char === ',' ||
((char === '{' || char === ';') && isAt)
)
) {
rules = rules.slice(0, i+1) + className + rules.slice(i+1);
i += classLen;
isAt = false;
}
};
// prefix the first select if it is not `@media` and if it is not yet prefixed
if (rules.indexOf(className) !== 0 && rules.indexOf('@') !== 0) rules = className+rules;
return rules;
}
// Some examples:
console.log(prefixCssSelectors('div { width: 100%; }', '.page'));
console.log(prefixCssSelectors('@charset "utf-8"; div { width: 100%; }', '.page'));
console.log(prefixCssSelectors('@media only screen { div { width: 100%; } p { size: 1.2rem; } } @media only print { p { size: 1.2rem; } } div { height: 100%; font-family: "Arial", Times; }', '.page'));
console.log(prefixCssSelectors('@font-face { font-family: "Open Sans"; src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"); } div { width: 100%; }', '.page'));
如果您只想为 html
和 body
选择器使用 class 名称,请添加:
rules = rules.replace(/( html| body)/g, '');
我有一个包含以下 css 的字符串,我需要使用 javascript
进行处理h1
{
color: red;
}
.info
{
border: 1px dotted blue;
padding: 10px;
}
#rect
{
background: pink;
}
h2,
h3,
h4
{
font-weight: bold;
}
table td:last td
{
background: gainsboro;
}
如何为每条规则添加前缀 .page
以使 css 不被破坏?
我想要这个结果
.page h1
{
color: red;
}
.page .info
{
border: 1px dotted blue;
padding: 10px;
}
...
现在,我通过查找缩进来解决它,但是代码在这种情况下失败了
h1
{
color: red;
}
然后以
结尾.page h1
{
.page color: red;
}
我也可以查找只有方括号的行,但这种情况会失败
h1 { color: red; }
我不想构建自己的 css 解析器,我发现的解析器主要处理 css 应用于 DOM 中的元素,而不是 [=32= 的字符串].是否有好的解析器或可以通过其他方式实现?
如果你想使用sass,你可以简单地写成
.page {
h1 {
color: red;
}
h2 {
color: green;
}
}
这将被编译成你想要的。但如果这不是一个选项,您必须编写自己的解析器。
看看正则表达式
例如这样的事情:
/([^]*?)({[^]*?}|,)/g
应该在第一组中捕获 css 字符串中的所有选择器,在第二组中捕获规则。然后你做这样的事情来替换火柴
var str = "your css text here";
re = /([^]*?)({[^]*?}|,)/g;
var new_str = str.replace(re, ".prefix "); //prefixed css
console.log(new_str);
如果您不熟悉正则表达式,我建议您阅读 Eloquent Javascript
中的相关章节一个解决方案,它循环遍历 CSS 规则并动态更新它们。
/* debug purpose */
var j = JSON.stringify;
var el = document.getElementById('el');
var log = function( val ){el.innerHTML+='<div>'+val+'</div>'}
var doIt = function(){
// you have to identify your stylesheet to get it
var ss = document.styleSheets[0];
// we get all the rules from this stylesheets
var rules = ss.cssRules;
// we loop over all rules
for( var i = 0 ; i < rules.length; i++){
var rule = rules[i];
var selector = rule.selectorText;
var def = rule.cssText.replace(selector , '');
// we update the selector
var selector2 = selector.replace(/([^,]+,?)/g , '.page ' );
// we modify the rules on the fly !
var def2 = def.replace('red' , 'green');
def2 = def2.replace('blue' , 'red');
def2 = def2.replace('pink' , 'lime');
log(i);
log( 'def : ' + def);
log( 'modified : ' + def2);
log( 'selector : ' + selector);
log( 'updated : ' + selector2);
log('----------');
ss.deleteRule(i);// we remove the old
ss.insertRule(selector2 + def2 , i);// we add the new
};
// we check the stylecheet !
log( ' checking the results');
for( var i = 0 ; i < rules.length; i++){
var rule = rules[i];
var curRule = rule.cssText;
log( i + ': curRule => ' + curRule);
};
};
h1
{
color: red;
}
.info
{
border: 1px dotted blue;
padding: 10px;
}
#rect
{
background: pink;
}
h2,
h3,
h4
{
font-weight: bold;
}
table td:last td
{
background: gainsboro;
}
<div class='page'>
<div id='rect'> RECT </div>
<div class='info'> INFO </div>
<div>
<button onclick='doIt()'>update it</button>
<div id='el'><div>
你提出了一个问题,即如何做你认为是解决实际问题的方法,这似乎是,我如何将一些 CSS 仅应用于文档的一部分?
最终,解决方案将是 <style scoped>
。在我们等待期间,您可以尝试使用 https://github.com/PM5544/scoped-polyfill, http://thomaspark.co/2015/07/polyfill-for-scoped-css/, https://github.com/thingsinjars/jQuery-Scoped-CSS-plugin, or https://github.com/thomaspark/scoper.
如果你有一个 CSS 的字符串(你是从哪里得到的?),那么要使用这些 polyfills,你可以简单地在你的 [=26] 中插入一个 <style scoped>
元素=] 在 .page
元素下,包含字符串中的 CSS。
所有这些 polyfill 的主要优点是它们基于浏览器正确解析的 CSS,并且不会在出现问题的第一个迹象时中断,因为您不明智地接受了正则表达式解决方案,并且所有其他正则表达式解决方案,不可避免地会。
这是一个为所有选择器添加 class 名称前缀的函数。此函数正确处理@规则:
var prefixCssSelectors = function(rules, className) {
var classLen = className.length,
char, nextChar, isAt, isIn;
// makes sure the className will not concatenate the selector
className += ' ';
// removes comments
rules = rules.replace( /\/\*(?:(?!\*\/)[\s\S])*\*\/|[\r\n\t]+/g, '' );
// makes sure nextChar will not target a space
rules = rules.replace( /}(\s*)@/g, '}@' );
rules = rules.replace( /}(\s*)}/g, '}}' );
for (var i = 0; i < rules.length-2; i++) {
char = rules[i];
nextChar = rules[i+1];
if (char === '@' && nextChar !== 'f') isAt = true;
if (!isAt && char === '{') isIn = true;
if (isIn && char === '}') isIn = false;
if (
!isIn &&
nextChar !== '@' &&
nextChar !== '}' &&
(
char === '}' ||
char === ',' ||
((char === '{' || char === ';') && isAt)
)
) {
rules = rules.slice(0, i+1) + className + rules.slice(i+1);
i += classLen;
isAt = false;
}
};
// prefix the first select if it is not `@media` and if it is not yet prefixed
if (rules.indexOf(className) !== 0 && rules.indexOf('@') !== 0) rules = className+rules;
return rules;
}
// Some examples:
console.log(prefixCssSelectors('div { width: 100%; }', '.page'));
console.log(prefixCssSelectors('@charset "utf-8"; div { width: 100%; }', '.page'));
console.log(prefixCssSelectors('@media only screen { div { width: 100%; } p { size: 1.2rem; } } @media only print { p { size: 1.2rem; } } div { height: 100%; font-family: "Arial", Times; }', '.page'));
console.log(prefixCssSelectors('@font-face { font-family: "Open Sans"; src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2"); } div { width: 100%; }', '.page'));
如果您只想为 html
和 body
选择器使用 class 名称,请添加:
rules = rules.replace(/( html| body)/g, '');