是否为包含某些文本的元素提供CSS选择器?


510

我正在寻找下表的CSS选择器:

Peter    | male    | 34
Susanne  | female  | 12

是否有任何选择器来匹配所有包含“ male”的TD?


1
问题在于这将很难以高性能的方式实现。
Ms2ger

7
XPath选择器可以使用.text()方法(如果您不想使用JavaScript执行程序)来完成此操作。
djangofan 2013年

11
这是一个使用xpath的示例:// h1 [text()='Session'],您可以在Chrome中输入$ x(“ // h1 [text()='Session']”来测试xpath )在控制台中
VinnyG,2013年

1
这样会很方便。例如,包含复选标记或字符串“是”,“通过”,“确定”等的表格单元可以是绿色。
Andreas Rejbrand 2014年

$x回答这个问题。对于最初的问题,$x("//td[text()='male']")这个窍门

Answers:



159

使用jQuery:

$('td:contains("male")')

7
最终需要与此相反的东西,即:jQuery(element).not(“:contains('string')”)
Jazzy 2013年

307
除非不是CSS,否则就是JavaScript。
Synetech

9
同意-这就是为什么我的回答说我使用的是jQuery,而不是CSS。但是我的答案的那一部分已被删除。=)
moettinger

17
但是“ fe male ”一词本身也包含“ male”一词,不是吗?“ cos男是第一位吗?如果重新订购它们,是否会等待发生错误?
Michael Durrant

5
@Michael Durrant:开个玩笑,但是跨元素字符串匹配(这比同一个元素中的常规子字符串匹配还要大),实际上是最大的原因之一:contains()被删除了。
BoltClock

158

看起来他们在考虑CSS3规范的问题,但是并没有成功

:contains()CSS3选择器http://www.w3.org/TR/css3-selectors/#content-selectors


9
Looks like they were thinking about it for the CSS3 spec but it didn't make the cut.并且有充分的理由,它将违反将样式,内容,结构和行为分开的整个前提。
Synetech

56
@Synetech它实际上可以帮助将样式与内容分离,因为这意味着不需要了解其客户的内容将被认为是基于样式的重要内容。现在,我们的html内容通常通过包含我们知道样式器关心的类而与css紧密配对。正如CSS3中的属性值选择器所证明的那样,它们已经朝着让CSS包含内容的方向发展。
DannyMeister

8
@Synetech,它的“行为”到底如何?对我来说,这只是一个介绍问题。它什么也没 -它以某种方式呈现某些类型的内容。
BarbaraKwarc

4
@DannyMeister,哦,您不必说服我。几年后,我发现自己回到这里,试图寻找确切的功能,但不但不知道它不存在,而且被拒绝了。Bay eBay刚刚更改了用户界面,并使其网站非常难以使用。我正在尝试使用用户样式表进行修复,但其标记无法区分拍卖和BIN列表,因此,突出显示列表中的出价数量的唯一方法是通过元素的文本内容进行匹配。说服某人是让他们亲身体验用例场景所需要的。
Synetech

8
为了确保内容和样式之间的良好分离,我们将没有:contains()选择器。因此,我们将不根据其内容为单元格样式(例如,“打开”或“已解决”的“状态”列),而是在显示属性和类属性中复制内容,然后在该属性上进行选择。优秀的!
乔恩·克洛斯凯

122

您必须将数据属性添加到data-gendermalefemale值调用的行中,并使用属性选择器:

HTML:

<td data-gender="male">...</td>

CSS:

td[data-gender="male"] { ... }

10
可以将自定义数据属性与Javascript和CSS一起使用是完全可以的。参见MDN使用数据属性
Michael Benjamin 2015年

1
我同意data属性是应该如何处理的,但是,像td.male这样的CSS规则通常更容易设置,尤其是在带有角度的情况下,它看起来像这样:<td class =“ {{person.gender}} “>
DJDaveMark

性别当然是班上课的典型例子。但是,如果数据的多样性不仅仅只是malefemale呢?class不能保证充斥其他类,它们的顺序的事实,可能与其他类名发生冲突等,使得class这种情况变得更糟。专用data-*属性会将您的数据与所有内容隔离开来,并使使用属性选择器对其进行部分匹配等操作变得更加容易。
Stijn de Witt

还有一个工作代码片段的答案,该代码片段以类似的方式使用数据属性。
乔什·哈布达斯

65

实际上,有一个非常概念性的基础来说明为什么尚未实现这一点。它基本上是三个方面的组合:

  1. 元素的文本内容实际上是该元素的子元素
  2. 您不能直接定位文本内容
  3. CSS不允许使用选择器提升

这3个共同意味着,当您拥有文本内容时,您将无法返回到包含元素,也无法为当前文本设置样式。这可能很重要,因为降序仅允许上下文的单一跟踪和SAX样式解析。升序或涉及其他轴的其他选择器引入了对更复杂的遍历或类似解决方案的需求,这将使CSS在DOM中的应用极大地复杂化。


4
这是真的。这就是XPath的目的。如果您可以在JS / jQuery或解析库(与仅限CSS相对)中执行选择器,则可以使用XPath的text()功能。
马克·托马斯

关于内容,这是一个很好的观点。但是,我希望您能:contains(<sub-selector>)选择一个包含其他特定元素的元素。就像div:contains(div[id~="bannerAd"])摆脱广告和它的容器。
劳伦斯·多尔

27

您可以将内容设置为数据属性,然后使用属性选择器,如下所示:

/* Select every cell containing word "male" */
td[data-content="male"] {
  color: red;
}

/* Select every cell starting on "p" case insensitive */
td[data-content^="p" i] {
  color: blue;
}

/* Select every cell containing "4" */
td[data-content*="4"] {
  color: green;
}
<table>
  <tr>
    <td data-content="Peter">Peter</td>
    <td data-content="male">male</td>
    <td data-content="34">34</td>
  </tr>
  <tr>
    <td data-conten="Susanne">Susanne</td>
    <td data-content="female">female</td>
    <td data-content="14">14</td>
  </tr>
</table>

您还可以使用jQuery轻松设置数据内容属性:

$(function(){
  $("td").each(function(){
    var $this = $(this);
    $this.attr("data-content", $this.text());
  });
});

3
需要注意的是.text().textContent是相当沉重的,尽量避免他们在长的列表或大的文本可能的情况下。.html()而且.innerHTML很快。
oriadam '17年

@JoshHabdas您可以制作一个jsbin / jsfiddle更改示例吗?
Buksy

1
如果要使用jQuery,请使用contains选择器:$("td:contains(male)")
huwiler19年

如果内容可由用户编辑(contenteditable='true'-我的情况),则data-content在呈现页面之前设置属性值是不够的。它必须不断更新。这是我使用的:<td onkeypress="event.target.setAttribute('data-content', event.target.textContent);">
caram

13

由于CSS缺少此功能,因此您将不得不使用JavaScript来按内容设置单元格样式。例如,使用XPath contains

var elms = document.evaluate( "//td[contains(., 'male')]", node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null )

然后像这样使用结果:

for ( var i=0 ; i < elms.snapshotLength; i++ ){
   elms.snapshotItem(i).style.background = "pink";
}

https://jsfiddle.net/gaby_de_wilde/o7bka7Ls/9/


这是javascript,这与问题有什么关系?
rubo77 '16

3
由于您无法通过CSS中的内容进行选择,因此您将不得不使用js来做到这一点。当您指出这不是CSS时,就正确了,但data属性的使用并不是按内容选择。我们只能猜测为什么读者希望通过内容选择单元格,对html的访问方式,匹配项数,表格的大小等。等等
user40521


4

对于那些希望选择Selenium CSS文本的人,此脚本可能会有所用。

技巧是选择要查找的元素的父级,然后搜索具有文本的子级:

public static IWebElement FindByText(this IWebDriver driver, string text)
{
    var list = driver.FindElement(By.CssSelector("#RiskAddressList"));
    var element = ((IJavaScriptExecutor)driver).ExecuteScript(string.Format(" var x = $(arguments[0]).find(\":contains('{0}')\"); return x;", text), list);
    return ((System.Collections.ObjectModel.ReadOnlyCollection<IWebElement>)element)[0];
}

如果有多个元素,它将返回第一个元素,因为在我的情况下,它始终是一个元素。


如果使用的TD:contains('male')是Selenium,则可以使用:imho仅在无法更新源代码以添加类时才使用。例如,如果您正在测试遗留代码,或者您的公司不允许您与开发人员交谈(eurgh!),因为您的测试将很脆弱,并且如果有人稍后将文本masculine更改为或更改语言,则测试将失败。SauceLabs文档显示了contains此处的使用(ucelabs.com/resources/articles/selenium-tips-css-selectors)+ cc @matas vaitkevicius我错过了什么吗?
snowcode,

3

我同意数据属性(旅行者的回答)是应该如何处理,但应遵循以下CSS规则:

td.male { color: blue; }
td.female { color: pink; }

设置起来通常会容易得多,尤其是使用客户端库(例如angularjs)时,它可能很简单:

<td class="{{person.gender}}">

只要确保内容只有一个字!或者甚至可以通过以下方式映射到不同的CSS类名称:

<td ng-class="{'masculine': person.isMale(), 'feminine': person.isFemale()}">

为了完整起见,这是数据属性方法:

<td data-gender="{{person.gender}}">

模板绑定是一个很好的解决方案。但是,基于标记结构创建类名有点麻烦(尽管这实际上是BEM在实践中所做的事情)。
乔什·哈布达斯

2

@voyager关于使用data-*属性的答案(例如data-gender="female|male",截至2017年,这是最有效且符合标准的方法:

[data-gender='male'] {background-color: #000; color: #ccc;}

尽管有一些围绕文本的有限选择器,但几乎可以实现大多数目标。所述::第一字母是一个伪元件可应用于有限的造型到元件的第一个字母。还有一个:: first-line除了明显地选择元素(例如段落)的第一行之外,伪元素,这也意味着很明显,可以使用CSS来扩展此现有功能来为textNode的特定方面设置样式。

在这样的倡导获得成功实施之前,我可能建议的下一件最好的事情是使用空格分隔符explode/ split来输出/ 单词,在span元素内输出每个单词,然后将该单词/样式目标与#nth选择器组合使用是可预测的

$p = explode(' ',$words);
foreach ($p as $key1 => $value1)
{
 echo '<span>'.$value1.'</span>;
}

否则,即使无法预料,还是要使用航海家关于使用data-*属性的答案。使用PHP的示例:

$p = explode(' ',$words);
foreach ($p as $key1 => $value1)
{
 echo '<span data-word="'.$value1.'">'.$value1.'</span>;
}


1

这里的大多数答案都试图提供一种替代方法,以替代编写HTML代码以包含更多数据的方法,因为至少在CSS3中,您不能通过部分内部文本选择元素。但这是可以做到的,您只需要添加一些普通的JavaScript,请注意,因为女性也包含男性,因此将其选中:

      cells = document.querySelectorAll('td');
    	console.log(cells);
      [].forEach.call(cells, function (el) {
    	if(el.innerText.indexOf("male") !== -1){
    	//el.click(); click or any other option
    	console.log(el)
    	}
    });
 <table>
      <tr>
        <td>Peter</td>
        <td>male</td>
        <td>34</td>
      </tr>
      <tr>
        <td>Susanne</td>
        <td>female</td>
        <td>14</td>
      </tr>
    </table>

<table>
  <tr>
    <td data-content="Peter">Peter</td>
    <td data-content="male">male</td>
    <td data-content="34">34</td>
  </tr>
  <tr>
    <td data-conten="Susanne">Susanne</td>
    <td data-content="female">female</td>
    <td data-content="14">14</td>
  </tr>
</table>

1

如果您不想使用javascript或jquery,我发现attribute选项是最好的选择。

例如,用单词ready为所有表单元格设置样式,在HTML中执行以下操作:

 <td status*="ready">Ready</td>

然后在CSS中:

td[status*="ready"] {
        color: red;
    }

0

你也可以使用contentattr()那些和样式表格单元格::not :empty

th::after { content: attr(data-value) }
td::after { content: attr(data-value) }
td[data-value]:not(:empty) {
  color: fuchsia;
}
<table>
  <tr>
    <th data-value="Peter"></th>
    <td data-value="male">&#x0200B;</td>
    <td data-value="34"></td>
  </tr>
  <tr>
    <th data-value="Susanne"></th>
    <td data-value="female"></td>
    <td data-value="12"></td>
  </tr>
  <tr>
    <th data-value="Lucas"></th>
    <td data-value="male">&#x0200B;</td>
    <td data-value="41"></td>
  </tr>
</table>

A ZeroWidthSpace用于更改颜色,可以使用原始JavaScript添加:

const hombres = document.querySelectorAll('td[data-value="male"]');
hombres.forEach(hombre => hombre.innerHTML = '&#x0200B;');

尽管可以省略<td> s结束标签,这样做可能导致将其视为非空标签。


0

如果您不是自己创建DOM(例如在用户脚本中),则可以使用纯JS执行以下操作:

for ( td of document.querySelectorAll('td') ) {
  console.debug("text:", td, td.innerText)
  td.setAttribute('text', td.innerText)
}
for ( td of document.querySelectorAll('td[text="male"]') )
  console.debug("male:", td, td.innerText)
<table>
  <tr>
    <td>Peter</td>
    <td>male</td>
    <td>34</td>
  </tr>
  <tr>
    <td>Susanne</td>
    <td>female</td>
    <td>12</td>
  </tr>
</table>

控制台输出

text: <td> Peter
text: <td> male
text: <td> 34
text: <td> Susanne
text: <td> female
text: <td> 12
male: <td text="male"> male

-2

像这样做小的过滤器小部件:

    var searchField = document.querySelector('HOWEVER_YOU_MAY_FIND_IT')
    var faqEntries = document.querySelectorAll('WRAPPING_ELEMENT .entry')

    searchField.addEventListener('keyup', function (evt) {
        var testValue = evt.target.value.toLocaleLowerCase();
        var regExp = RegExp(testValue);

        faqEntries.forEach(function (entry) {
            var text = entry.textContent.toLocaleLowerCase();

            entry.classList.remove('show', 'hide');

            if (regExp.test(text)) {
                entry.classList.add('show')
            } else {
                entry.classList.add('hide')
            }
        })
    })

-2

该问题的语法类似于Robot Framework语法。在这种情况下,尽管没有可用于包含的css选择器,但可以使用SeleniumLibrary关键字来代替。该等到元素包含

例:

Wait Until Element Contains  | ${element} | ${contains}
Wait Until Element Contains  |  td | male
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.