Есть ли селектор CSS для элементов, содержащих определенный текст?
Я ищу селектор CSS для следующей таблицы:
Peter | male | 34
Susanne | female | 12
Есть ли какой-либо селектор для соответствия всем TD, содержащим "мужской"?
22 ответа
Если я правильно прочитал спецификацию, нет.
Вы можете сопоставить элемент, имя атрибута в элементе и значение именованного атрибута в элементе. Я не вижу ничего для сопоставления содержимого в элементе, хотя.
Похоже, они думали об этом для спецификации CSS3, но это не сработало.
:contains()
CSS3 селектор http://www.w3.org/TR/css3-selectors/
Вы должны добавить атрибут данных в строки с именем data-gender
с male
или же female
значение и использовать селектор атрибута:
HTML:
<td data-gender="male">...</td>
CSS:
td[data-gender="male"] { ... }
На самом деле есть очень концептуальная основа, почему это не было реализовано. Это сочетание в основном трех аспектов:
- Текстовое содержимое элемента фактически является потомком этого элемента
- Вы не можете ориентироваться на текстовое содержимое напрямую
- CSS не позволяет восхождение с селекторами
Эти 3 вместе означают, что к тому времени, когда у вас будет текстовое содержимое, вы не сможете вернуться к содержащемуся элементу и не сможете стилизовать текущий текст. Это, вероятно, важно, поскольку по убыванию допускается только отдельное отслеживание контекста и разбор в стиле SAX. Восходящие или другие селекторы, включающие другие оси, создают необходимость в более сложных обходных или аналогичных решениях, которые значительно усложнили бы применение CSS в DOM.
Вы можете установить контент как атрибут данных, а затем использовать селекторы атрибутов
/* 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());
});
});
Поскольку в CSS нет этой функции, вам придется использовать javascript для стилизации ячеек по содержимому. Например, с xpath содержит
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";
}
As of Jan 2021, there IS something that will do just this. :has() ... only one catch: this is not supported in any browser yet
Example: The following selector matches only elements that directly contain an child:
a:has(> img)
References:
Для тех, кто хочет делать выделение текста 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];
}
Это вернет первый элемент, если их больше одного, так как в моем случае это всегда один элемент.
Боюсь, что это невозможно, потому что контент не является атрибутом и не доступен через псевдокласс. Полный список селекторов CSS3 можно найти в спецификации CSS3.
Если вы не создаете 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
Отличные ответы со всех сторон, но я думаю, что могу добавить что-то, что сработало для меня в практическом сценарии: использование атрибута для CSS.
Для незнающих читателей:
Это делает его очень специфичным для веб-сайта, но если ваш элемент содержит это, довольно просто выбрать этот элемент, используя содержимое атрибута:
HTML:
<td aria-label="male">Male</td>
<td aria-label="female">Female</td>
CSS:
td[aria-label="male"] {
outline: 1px dotted green;
}
Технически это то же самое, что и использование решения data-attribute, но это сработает для вас, если вы не являетесь автором веб-сайта, плюс это не какое-то необычное решение, специально разработанное для поддержки этого вариант использования; это довольно распространено само по себе. Единственным недостатком этого является то, что на самом деле нет никакой гарантии, что ваш предполагаемый элемент будет иметь этот атрибут.
Если вы используете Chimp / http://webdriver.io/, они поддерживают намного больше селекторов CSS, чем спецификации CSS.
Это, например, нажмет на первый якорь, который содержит слова "Плохой медведь":
browser.click("a*=Bad Bear");
Я согласен с тем, что атрибут data (ответ voyager) таков, как он должен обрабатываться, НО, 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}}">
Большинство ответов здесь пытаются предложить альтернативу тому, как написать 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>
@voyager ответ об использовании data-*
атрибут (например, data-gender="female|male"
самый эффективный и соответствующий стандартам подход с 2017 года:
[data-gender='male'] {background-color: #000; color: #ccc;}
Практически большинство целей может быть достигнуто, поскольку есть некоторые, хотя и ограниченные селекторы, ориентированные на текст. :: first-letter является псевдоэлементом, который может применять ограниченную стилизацию к первой букве элемента. Существует также псевдоэлемент :: first-line, кроме того, что выбор первой строки элемента (например, абзаца) также подразумевает, что очевидно, что CSS можно использовать для расширения этой существующей возможности для стилизации определенных аспектов textNode.,
До тех пор, пока такая адвокация не будет успешной и не будет реализована, следующее лучшее, что я мог бы предложить, когда это применимо, это explode
/split
слова, используя разделитель пробелов, выводят каждое отдельное слово внутри span
элемент, а затем, если цель слова / стиля является предсказуемой, используйте в сочетании с : nth селекторами:
$p = explode(' ',$words);
foreach ($p as $key1 => $value1)
{
echo '<span>'.$value1.'</span>;
}
Иначе, если не предсказуемо, снова используйте ответ voyager об использовании data-*
приписывать. Пример использования PHP:
$p = explode(' ',$words);
foreach ($p as $key1 => $value1)
{
echo '<span data-word="'.$value1.'">'.$value1.'</span>;
}
Если вы хотите применить стиль к желаемому контенту. Легкая уловка.
Вы также можете использовать content
с attr()
и ячейки таблицы стилей, которые :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">​</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">​</td>
<td data-value="41"></td>
</tr>
</table>
ZeroWidthSpace
используется для изменения цвета и может быть добавлен с помощью ванильного JavaScript:
const hombres = document.querySelectorAll('td[data-value="male"]');
hombres.forEach(hombre => hombre.innerHTML = '​');
Хотя <td>
Конечный тег может быть опущен, что может привести к тому, что он будет рассматриваться как непустой.
Вы можете перенести содержимое в атрибут ячейки, а затем использовать CSS, чтобы скопировать его для отображения («Не повторяйтесь» — что-то, что другие подобные ответы проигнорировали). Это используетcontent
иattr()
Почему бы вам не использовать этот метод:
- невозможность выделить текст
- доступность: aria-label на самом деле не означает «контент»
Если это вызывает опасения, вы можете отказаться от требования DRY «хорошо иметь»; но в этом случае вы также можете добавить className;class="f"
илиclass="m"
к ТД и выбирайте на основе этого.
Я считаю, что вариант атрибута лучше всего подходит, если вы не хотите использовать javascript или jquery.
Например, чтобы стилизовать все ячейки таблицы со словом "готово", в HTML сделайте следующее:
<td status*="ready">Ready</td>
Затем в css:
td[status*="ready"] {
color: red;
}
Делать маленькие виджеты фильтра вот так:
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')
}
})
})
Синтаксис этого вопроса похож на синтаксис Robot Framework. В этом случае, хотя нет селектора css, который вы могли бы использовать для contains, есть ключевое слово SeleniumLibrary, которое вы можете использовать вместо него. Подождите, пока элемент содержит.
Пример:
Wait Until Element Contains | ${element} | ${contains}
Wait Until Element Contains | td | male