3

我需要知道一个元素是否具有 :first-letter 样式的样式,它应该是一个通用解决方案,因此我不会依赖类名或特殊样式属性。有什么办法吗?例子:

<p class="initial">First</p>
<p>Second</p>

.initial:first-letter {
float: left;
font-size: 1.5em;
font-weight: bold;
}

$('p').click(function(){
    // how to determine if :first-letter is applied to current paragraph?

});
4

3 回答 3

3

如果您的 CSS 是自托管的,您可以:

  1. 获取所有 CSS 块的列表
  2. 过滤掉不包含:first-letter在块选择器中的CSS 块
  3. 遍历剩余 CSS 块的列表,并matchesSelector()以目标元素作为接收器和当前 CSS 块的选择器作为参数运行。
    1. 如果matchesSelector()返回true,则当前 CSS 块的规则会影响目标元素的第一个字母。
    2. 否则移动到列表中的下一个 CSS 块

如果 CSS 不是自托管的并且 CDN 不发送 CORS 标头,那么由于隐私问题,您无法读取 CSS 文件源,并且无法做到这一点。

我也没有从算法中找出规则级联。道路上的另一个障碍是弄清楚伪选择器matchesSelector以错误的方式影响什么。

像考虑:

p.webkitMatchesSelector("p:first-letter") //false

因此,:first-letter在尝试匹配之前必须从字符串中删除伪类,因为这些是无关紧要的(但类伪类:nth-child并不是因为它们真正影响匹配)。

演示http://jsfiddle.net/PBuzb/5/(记住我提到的问题在这里没有很好地处理)(代码的基础最初由 Crush 提供)


为什么在跨域情况下不允许读取 CSS 源代码?

您只能从其他域显示图像、运行 css/js 等但绝对不能以任何方式访问其数据的原因是隐私。

这种情况下最容易制作图像。假设我已登录 facebook,并且 facebook 使用 url 作为私人照片,例如 http://facebook.com/myprofile.png。现在我去 evil.com,evil.com 可以加载图像,因为我登录到 facebook,facebook 会给他们那个图像。通常他们无法访问图像或以任何方式窃取图像,但如果我们启用跨域数据访问,他们现在可以访问我的私人照片并将其传播出去。

CSS 中也可能发生同样的情况,Facebook 服务器可能会生成特定于用户的 CSS,其中包含我私人朋友的用户 ID。如果我可以访问的任何网站都可以链接到该 CSS 并开始阅读,那么它们就不再那么私密了。

是的,主要问题是浏览器如何发送带有跨域请求的 cookie,如果浏览器在从 evil.com 请求 facebook 图像/css 时没有发送 cookie,那么 facebook 无法使用用户特定的 css 或我的私人照片进行响应因为cookies是识别我所必需的。

现在想象一下,如果浏览器没有发送 cookie。Evil.com 仍然可以通过这种方式访问​​任何 Intranet 数据,因为我的浏览器可以访问 Intranet。能够http://intranet/Myboss.jpg在 evil.com 网站上显示为图像不是问题,但 Evil.com 能够读取图像数据并因此能够复制和传播它是一个问题。

于 2013-07-31T12:30:58.940 回答
2

您可以遍历 cssRules,构建所有::first-letter规则的数组,然后检查元素是否具有这些规则之一。

工作演示(仅在 Chrome 中测试)

(function() {
    var firstLetterRules = [];

    var loadRules = function() {
        var stylesheets = document.styleSheets;

        for (var i = 0; i < stylesheets.length; i++) {
            var stylesheet = stylesheets[i];
            var rules = stylesheet.cssRules;

            for (var k = 0; k < rules.length; k++) {
                var rule = rules[k];

                if (rule.selectorText.indexOf("::first-letter") !== -1) {
                    //It is a ::first-letter selector. Add the rule to a list of ::first-letter rules.
                    firstLetterRules.push(rule.selectorText.toUpperCase());
                }
            }
        }
    };

    window.hasFirstLetterStyle = function(element) {
        var fullSelector = element.nodeName;

        if (element.className != '')
            fullSelector += '.' + element.className;

        fullSelector = fullSelector.toUpperCase() + "::FIRST-LETTER";

        for (var i = 0; i < firstLetterRules.length; i++) {
            if (fullSelector == firstLetterRules[i])
                return true;
        }

        return false;
    };

    loadRules();
})();

var element = document.getElementById("init");

if (hasFirstLetterStyle(element)) {
    console.log("Element has a first-letter style rule.");
}
于 2013-07-31T12:38:34.750 回答
1

你不能。

无法从您的 JS 代码访问伪选择器及其样式。

您可以做的最接近的事情是检查元素是否具有会触发样式的相关类first-letter,并在您的 JS 代码中假设如果该类存在,则first-letter必须已应用样式。

除了手动解析整个 CSS 文件之外,真的没有其他方法。

这也适用于其他伪选择器和伪元素(您会在此处找到许多类似的问题,询问关于:beforeand:after的类似问题,并给出类似的答案)

于 2013-07-31T12:23:58.367 回答