使用 javascript(或 jQuery)选择和操作 CSS 伪元素,例如 ::before 和 ::after

IT技术 javascript jquery css jquery-selectors pseudo-element
2021-01-02 23:16:58

有什么方法可以使用 jQuery选择/操作 CSS 伪元素,例如::before::after(以及带有一个分号的旧版本)?

例如,我的样式表具有以下规则:

.span::after{ content:'foo' }

如何使用 vanilla JS 或 jQuery 将 'foo' 更改为 'bar'?

6个回答

您还可以将内容传递给具有 data 属性的伪元素,然后使用 jQuery 来操作它:

在 HTML 中:

<span>foo</span>

在 jQuery 中:

$('span').hover(function(){
    $(this).attr('data-content','bar');
});

在 CSS 中:

span:after {
    content: attr(data-content) ' any other text you may want';
}

如果您想防止出现“其他文本”,您可以将其与 seucolega 的解决方案相结合,如下所示:

在 HTML 中:

<span>foo</span>

在 jQuery 中:

$('span').hover(function(){
    $(this).addClass('change').attr('data-content','bar');
});

在 CSS 中:

span.change:after {
    content: attr(data-content) ' any other text you may want';
}
+1 对于attr(),太糟糕了,我无法将它与content. 演示
2021-02-13 23:16:58
您在规范中是否有attr针对该content属性使用该函数的链接我很惊讶我从来没有听说过这个......
2021-02-16 23:16:58
那是因为目前还没有浏览器实现attr()了 CSS2 之外的功能,而在 CSS2 中本身attr()只为content属性定义了
2021-02-21 23:16:58
更新了属性参考链接:w3.org/TR/css3-values/#attr-notation
2021-03-01 23:16:58

您会认为这将是一个简单的问题,jQuery 可以做任何其他事情。不幸的是,问题归结为一个技术问题:css :after 和 :before 规则不是 DOM 的一部分,因此不能使用 jQuery 的 DOM 方法进行更改。

一些方法可以使用 JavaScript 和/或 CSS 变通方法来操作这些元素;您使用哪一种取决于您的确切要求。


我将从广泛认为的“最佳”方法开始:

1) 添加/删除预定的类

在这种方法中,你已经在用不同的你的CSS创建一个类:after:before样式。稍后将这个“新”类放在您的样式表中以确保它覆盖:

p:before {
    content: "foo";
}
p.special:before {
    content: "bar";
}

然后,您可以使用 jQuery(或 vanilla JavaScript)轻松添加或删除此类:

$('p').on('click', function() {
    $(this).toggleClass('special');
});

  • 优点:易于使用 jQuery 实现;一次快速改变多种风格;强制分离关注点(将 CSS 和 JS 与 HTML 隔离)
  • 缺点: CSS 必须预先编写,所以:before的内容:after不是完全动态的

2) 直接在文档的样式表中添加新样式

可以使用 JavaScript 将样式直接添加到文档样式表,包括:after:before样式。jQuery 没有提供方便的快捷方式,但幸运的是 JS 并没有那么复杂:

var str = "bar";
document.styleSheets[0].addRule('p.special:before','content: "'+str+'";');

.addRule()并且相关.insertRule()方法在今天得到了相当好的支持。

作为一种变体,您还可以使用 jQuery 向文档中添加一个全新的样式表,但所需的代码并不简洁:

var str = "bar";
$('<style>p.special:before{content:"'+str+'"}</style>').appendTo('head');

如果我们谈论的是“操作”值,而不仅仅是添加到它们,我们还可以:after:before使用不同的方法读取现有的样式

var str = window.getComputedStyle(document.querySelector('p'), ':before') 
           .getPropertyValue('content');

我们可以在使用 jQuery 时替换document.querySelector('p')$('p')[0],以获得稍短的代码。

  • 优点:任何字符串都可以动态插入到样式中
  • 缺点:原始样式不会改变,只是被覆盖;重复(ab)使用可以使 DOM 增长任意大

3) 改变不同的 DOM 属性

您还可以在 CSS 中使用attr()来读取特定的 DOM 属性。如果浏览器支持:before,它支持attr()为好。)通过这种结合content:在一些精心准备的CSS,我们可以改变的内容(而不是其他属性,像保证金或颜色):before:after动态:

p:before {
    content: attr(data-before);
    color: red;
    cursor: pointer;
}

JS:

$('p').on('click', function () {
    $(this).attr('data-before','bar');
});

如果 CSS 不能提前准备,这可以与第二种技术结合使用:

var str = "bar";

document.styleSheets[0].addRule('p:before', 'content: attr(data-before);');

$('p').on('click', function () {
    $(this).attr('data-before', str);
});

  • 优点:不会创造无穷无尽的额外风格
  • 缺点: attr在 CSS 中只能应用于内容字符串,不能应用于 URL 或 RGB 颜色
我正在尝试在 ::after psedo 中动态设置字形值(即,通过它们的十六进制值)。内容:元素(例如,内容:“\e043”;)。它似乎对我不起作用,所以我假设它也不适用于字形的十六进制值?
2021-02-06 23:16:58
Blazemonger,感谢您的快速回复......不幸的是,代码相当多,剪下相关代码需要花费相当多的精力。我已经花了 12 多个小时试图完成这项工作,这是我为让它工作而付出的最后努力。我需要减少损失。我希望您能够在使用您在上面 #3 中描述的技术时(在代码片段之前)验证我的假设:十六进制值。我可以在内容元素中插入十六进制字符串,但它显示字形十六进制值的文本而不是实际的字形。没有看到所有代码的印象?
2021-02-06 23:16:58
关于解决方案 2. & 3. 实际上,如果您使用:document.styleSheets[0].insertRule(rule, index),您可以防止样式表(过度)增长,然后使用此索引您可以在不需要时删除规则:document. styleSheets[0].deleteRule(index)
2021-02-07 23:16:58
@ user2101068 你应该把它作为一个新问题发布。我必须查看您使用的所有代码。
2021-02-12 23:16:58
@user2101068 不要使用十六进制字符串;相反,将实际的 Unicode 字符复制并粘贴到 HTML 属性中。jsfiddle.net/mblase75/Lcsjkc5y
2021-02-19 23:16:58

虽然它们通过 CSS 被浏览器渲染,就好像它们就像其他真正的 DOM 元素一样,但伪元素本身并不是 DOM 的一部分,因为伪元素,顾名思义,不是真正的元素,因此你不能直接使用 jQuery(或任何JavaScript API,甚至不是Selectors API选择和操作它们这适用于您尝试使用脚本修改其样式的任何伪元素,而不仅仅是::before::after

您只能在运行时通过 CSSOM (think window.getComputedStyle())直接访问伪元素样式,它不会被 jQuery Beyond公开.css(),该方法也不支持伪元素。

不过,您总是可以找到其他方法来解决它,例如:

  • 将样式应用于一个或多个任意类的伪元素,然后在类之间切换(请参阅seucolega 的快速示例的答案)——这是惯用的方式,因为它使用简单的选择器(伪元素不是)来区分元素和元素状态,它们的使用方式

  • 通过更改文档样式表来操纵应用于所述伪元素的样式,这更像是一种黑客行为

您不能在 jQuery 中选择伪元素,因为它们不是 DOM 的一部分。但是你可以给父元素添加一个特定的类,并在 CSS 中控制它的伪元素。

例子

在 jQuery 中:

<script type="text/javascript">
    $('span').addClass('change');
</script>

在 CSS 中:

span.change:after { content: 'bar' }

我们还可以依靠自定义属性(又名 CSS 变量)来操作伪元素。我们可以在规范读到

自定义属性是普通属性,所以可以在任何元素上声明,用普通的继承级联 规则解析,可以用@media等条件规则设置条件,可以在HTML的样式属性中使用,可以读取或设置使用 CSSOM等。

考虑到这一点,想法是在元素内定义自定义属性,伪元素将简单地继承它;因此我们可以很容易地修改它。

1)使用内联样式

.box:before {
  content:var(--content,"I am a before element");
  color:var(--color, red);
  font-size:25px;
}
<div class="box"></div>
<div class="box" style="--color:blue;--content:'I am a blue element'"></div>
<div class="box" style="--color:black"></div>
<div class="box" style="--color:#f0f;--content:'another element'"></div>

2) 使用 CSS 和类

.box:before {
  content:var(--content,"I am a before element");
  color:var(--color, red);
  font-size:25px;
}

.blue {
  --color:blue;
  --content:'I am a blue element';
}
.black {
  --color:black;
}
<div class="box"></div>
<div class="box black" ></div>
<div class="box blue"></div>

3)使用javascript

document.querySelectorAll('.box')[0].style.setProperty("--color", "blue");
document.querySelectorAll('.box')[1].style.setProperty("--content", "'I am another element'");
.box:before {
  content:var(--content,"I am a before element");
  color:var(--color, red);
  font-size:25px;
}
<div class="box"></div>
<div class="box"></div>

4)使用jQuery

$('.box').eq(0).css("--color", "blue");
/* the css() function with custom properties works only with a jQuery vesion >= 3.x
   with older version we can use style attribute to set the value. Simply pay
   attention if you already have inline style defined! 
*/
$('.box').eq(1).attr("style","--color:#f0f");
.box:before {
  content:"I am a before element";
  color:var(--color, red);
  font-size:25px;
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>


它也可以用于复数值:

.box {
  --c:"content";
  --b:linear-gradient(red,blue);
  --s:20px;
  --p:0 15px;
}

.box:before {
  content: var(--c);
  background:var(--b);
  color:#fff;
  font-size: calc(2 * var(--s) + 5px);
  padding:var(--p);
}
<div class="box"></div>

您可能会注意到我正在考虑语法var(--c,value)wherevalue是默认值,也称为回退值。

从相同的规范我们可以读到:

可以使用 var() 函数将自定义属性的值替换为另一个属性的值。var() 的语法是:

var() = var( <custom-property-name> [, <declaration-value> ]? )

该函数的第一个参数是要替换的自定义属性的名称。函数的第二个参数(如果提供)是回退值,当引用的自定义属性无效时,该值用作替代值

然后:

要在属性值中替换 var():

  1. 如果由var()函数的第一个参数命名的自定义属性被动画污染,并且该var()函数正在动画属性或其一个常用属性中使用,则将该自定义属性视为具有此算法其余部分的初始值。
  2. 如果由var()函数的第一个参数命名的自定义属性的值不是初始值,则将var()函数替换为相应的自定义属性的值。
  3. 否则,如果var()函数将回退值作为其第二个参数,则用var()回退值替换该函数。如果var()回退中有任何引用,也请替换它们。
  4. 否则,包含该var()函数的属性在计算值时无效。

如果我们不设置自定义属性或将其设置为initialOR 它包含无效值,则将使用回退值。initial如果我们想将自定义属性重置为其默认值使用可能会有所帮助。

有关的

如何在 CSS 变量(又名自定义属性)中存储继承值?

盒子模型的 CSS 自定义属性(变量)

@connexo 喜欢任何好的和现代的功能.. 它不受支持,也不会工作caniuse.com/#feat=css-variables
2021-02-06 23:16:58
这个答案是使用 CSS 变量关联和修改 JavaScript 伪元素的深度教程。非常感谢您抽出宝贵时间和分享这种极其宝贵的技术。
2021-02-07 23:16:58
@akalata 是的,代码需要 jQuery 版本 3.x .. 我添加了更多细节和 jQuery 的另一种选择;)
2021-02-09 23:16:58
这将如何在 IE 11 中执行?
2021-02-20 23:16:58
Ofc 我知道,并且由于 IE 11 仍然非常相关,因此我在您的答案的介绍部分中错过了那条信息。
2021-03-05 23:16:58