哪个JavaScript框架可以搜索CSS样式表规则并编辑它们的属性?

15

问题

哪个 JavaScript 框架(prototype、script.aculo.us、Mootools、MochiKit 等)有 良好的 CSS 规则编辑 支持?

这是关于更改样式规则的问题。我想要使用 动态 CSS 类 进行更改。例如:

<style>
#answer, .reveal { display: none; color: blue; }
#answer { /* additional stuff */ }
</style>
现在,我想通过JavaScript更改具有“display:none”规则的样式表。 - 我相信有时这是正确的方法; 当它不是正确的方法时,我不寻找替代方法。 有哪些框架可以轻松实现以下功能:
1.从所有规则中选择一个规则(例如“#answer,.reveal”) 2.所选规则的“display”属性值是什么? 3.删除规则的“display”属性
(只要我从框架中获取到CSS规则的句柄,DOM就能够很容易地处理第2步和第3步)
以下是不太合适的框架:
例如,YUI的StyleSheet一次只能搜索一个sheet中的规则(有限制,但对我来说足够了),但它无法显示、编辑或检索多选择器规则,如我的第一个示例(对我来说太有限了)。
YUI也无法获取单个属性(底层DOM可以,但你无法通过YUI获取该结构)。如果您使用YUI手段获得规则,则可以仅删除“display”属性。
Dojo有一些文档不完整的东西在dojox.html.styles下。
Ext JS有Ext.util.CSS。我检查了代码并发现了getRule()中的错误…否则它的选择器匹配非常松散(不良的IE影响),这使它对于多选择器规则非常糟糕。它也无法通过API删除属性,但可以为您提供CSSRule,以便您自己执行操作。 CSS树遍历非常原始:不下降媒体规则或导入。 $('.reveal').css(...任何内容...)不是答案,因为它根本不会触及CSS规则(而是触及某些元素的CSS属性)!

可能还想在列表中添加 Dojo Toolkit JavaScript 库。虽然我不确定它目前是否符合您的要求,但它具有一些非常好的 CSS 访问器/修改功能。曾经我会推荐 "behaviour-js",但创建者 Ben Nolan 表示它已经被您列举的框架广泛采用了。 - chamberlainpi
1
请参见:https://dev59.com/-XRB5IYBdhLWcg3wcm2d - Richard M
@Richard,我之前看过那个问题,但它甚至没有回答自己(如何在jQuery中编辑CSS规则),也没有回答我的问题(哪个框架有良好的CSS规则编辑支持)。- 我已经知道在JavaScript本身中有一种冗长的方法来做到这一点。 - Robert Siemer
这是一个非常好的问题,也是我正在努力解决的问题。应该有一种简单的方法来实现它。我可以想到很多用例。 - huyz
4个回答

3

没有,但请证明我错了...

一个良好的实现首先需要讨论/记录以下内容:

  • 如何遍历CSS树(包括@imports和@media)
  • 如何配置遍历(考虑哪些@media和哪些样式表)
  • 如何处理/规避跨域访问限制
  • 由于CSS本身没有规则ID:只有选择器可以作为良好的规则标识符
    • 由于IE8及以下版本分割了多个选择器,框架能够聪明地处理这种情况吗?
    • IE9更糟糕(参见quirksmode.org
  • 由于一个选择器可以选择多个规则,它们的顺序如何确定?
  • 如何从规则集中找到负责编辑我们想要的属性的规则?

在框架赶上之前,请考虑:

  • 获取包含所需规则的样式/link节点
  • 使用node.sheet直接进入CSSStyleSheet
  • 检查quirksmode.org以解决问题,特别是IE
  • 通过已知的选择器循环查找您的规则
  • DOM CSSStyleRule为您提供了对任何样式规则的所有控制权

是的,请有人编写这个库 :) - huyz
你在说什么“非标准节点.sheet”?我找不到它。 - huyz
1
我编辑了我的回答:node.sheet是DOM标准。一个包含样式规则(例如<style>...</style>)的DOM节点(“节点”)具有一个sheet属性(“node.sheet”),它指向CSSStyleSheet对象。 - Robert Siemer

1

正如您所指出的那样,YUI具有StyleSheet实用程序http://developer.yahoo.com/yui/3/stylesheet/

示例:

var sheet = new Y.StyleSheet(styleNode);
sheet.set('.hover, .foo:hover', {
    background: 'red',
    color: '#fff'
});

它还支持通过将构造函数传递一个包含CSS规则的字符串来从头开始创建样式表。

请注意,同源策略防止访问远程链接节点的规则。

它尚不支持将规则作为对象树或访问规则的特定属性。但是,它确实支持删除规则或规则属性。今天,您可以为使用规则作为对象而做的最好的事情是类似于

var style = sheet.getCssText('.foo'),
    tmp = document.createElement('div');

tmp.style.cssText = sheet.getCssText('.foo');
if (tmp.style.display) { // does the rule include a setting for display
    ...
}

由于在运行时搞乱样式表通常不是正确的解决方案,因此该实用程序并没有得到很多开发人员关注以添加功能。当然,欢迎提出功能请求。


2
我们已经进入了2011年,有着飞行汽车和宇宙飞船。但是没有办法动态更改样式表吗?- 不,至少不是使用您选择的框架。- 如果要将HTML的样式从蓝色更改为绿色,您会如何手动更改?逐个添加“style”以影响所有元素吗?当然不是。您会在样式表中进行单点编辑。但是如果您从脚本中执行此操作,则称其为“混乱”。为什么?- 在我看来,这是唯一正确的方法:在需要更改的位置进行更改,而不是在十个不同的位置上覆盖它并希望它不会中断... - Robert Siemer
元素样式的更改会触发浏览器尝试极力限制其范围的重绘或回流。它还会批量处理回流,因此如果正确执行,则更改十个元素样式只会触发一次回流或重绘,并且影响回流/重绘的页面部分将被最小化。对样式表的任何更改都将触发完整页面的回流,这是对响应式用户界面最糟糕的事情。应该构建支持使用类和级联规则将蓝色更改为绿色的应用程序。 - Luke
此外,跨浏览器样式表API的支持历史可以说是非常不稳定的,而元素样式和类修改则相当可靠。我理解您想要更方便的API来操作样式表,但这并不意味着它是正确的工具。顺便说一下,YUI的StyleSheet工具可以编辑多选择器规则。 - Luke
1
样式表的更改一定会导致重新排版。它是否更便宜取决于页面和浏览器。YUI的StyleSheet工具只根据IE规则进行多选择器,不能在Chrome等浏览器上选择或更改我的第一个例子。跨浏览器问题正是我寻找能够替我解决这个问题的框架的原因! - Robert Siemer

0

存在像postCSS这样的库,它允许您使用插件的模块化生态系统来以编程方式更改CSS样式。


0

Robert Siemer提出的问题是:

这是关于更改样式规则的问题。我想要动态CSS类别,可以随时更改。

我想给出一个更好地定义问题的答案,以便那些正在寻找类似解决方案的读者和那些将问题与更新元素样式混淆的作者们能够更好地理解。

核心问题

我认为核心问题的第一部分是要注意浏览器确实允许对现有样式表进行操作,正如此评论所暗示并在此答案中进行了分析。例如,以下行将在文档的第二个样式表中的第三个规则上修改padding-top值,从20px更改为300px

document.styleSheets[1].cssRules[2].style.paddingTop = '300px'

... 给定 index.html 文件:

<html>
<head>
  <link type="text/css" href="foo.css"
  <link type="text/css" href="style.css">
<head>
<body><h1>Bar</h1></body>
</html>

...和style.css

html, body { padding: 0; margin: 0 }
body { color: black; }
h1 { color: gray; padding-top: 20px; }

牛肉的第二部分是如何找到符合条件的规则。这两个部分都有与旧浏览器兼容性方面的挑战,正如答案所讨论的那样。 如果我们忽略兼容性问题,并专注于这样一个框架应该如何大致工作,这里是我在原生JavaScript中的最小实现。

微型框架

function forEachCSSRule (iteratee) {
  var i, j, crs
  for (i = 0; i < document.styleSheets.length; i += 1) {
    crs = document.styleSheets[i].cssRules
    for (j = 0; j < crs.lenght; j += 1) {
      iteratee(crs[j])
    }
  }
}

function getCSSRulesBySelector (selectorString) {
  var matched = []
  forEachCSSRule(function (cr) {
    if (cr.selectorText.includes(selectorString)) {
      matched.push(cr)
    }
  })
  return matched
}

function getCSSRulesByStyle (styleString) {
  var matched = []
  forEachCSSRule(function (cr) {
    if (cr.cssText.includes(styleString)) {
      matched.push(cr)
    }
  })
  return matched
}

使用这样的框架,您可以例如:

var rules = getCSSRulesByStyle('display: none')
rules.forEach(function (rule) {
  rule.style.display = 'block'
})

...这正是原始问题所要求的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接