Esiste un selettore CSS per elementi contenenti determinati testi?


512

Sto cercando un selettore CSS per la seguente tabella:

Peter    | male    | 34
Susanne  | female  | 12

Esiste un selettore per abbinare tutti i TD contenenti "maschio"?


1
Il problema è che questo sarebbe molto difficile da implementare in modo performante.
Ms2ger,

7
Un selettore XPath può farlo con il metodo .text () (se si preferisce non utilizzare l'esecutore JavaScript).
Djangofan,

11
Ecco un esempio di come puoi farlo usando xpath: // h1 [text () = 'Session'] e puoi provare xpath in Chrome digitando $ x ("// h1 [text () = 'Session']" ) nella console
VinnyG l'

1
Questo sarebbe così conveniente. Ad esempio, una cella di tabella contenente un segno di spunta o la stringa "Sì", "Passa", "OK" ecc. Potrebbe essere verde.
Andreas Rejbrand,

le $xrisposte alla domanda. per la domanda originale, $x("//td[text()='male']")fa il trucco
Xiao

Risposte:


394

Se ho letto correttamente le specifiche , no.

È possibile abbinare un elemento, il nome di un attributo nell'elemento e il valore di un attributo denominato in un elemento. Tuttavia, non vedo nulla per la corrispondenza dei contenuti all'interno di un elemento.


228
C'è un caso limite: :empty.
Ciro Santilli 6 冠状 病 六四 事件 法轮功

34
Per rispondere alla mia domanda: Sì, è ancora vero per oggi! I selettori di contenuto sono stati deprecati! Niente più selettori di contenuti dal CSS3. ( w3.org/TR/css3-selectors/#selectors )
Wlad

158

Utilizzando jQuery:

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

7
Finì per aver bisogno del contrario di questo, che è: jQuery (element) .not (": Includes ('string')")
Jazzy,

311
Tranne che non è CSS, ovvero JavaScript.
Synetech,

9
D'accordo - ecco perché la mia risposta diceva che stavo usando jQuery, non CSS. Ma quella parte della mia risposta è stata eliminata. =)
moettinger

18
ma la parola fe maschio stesso contiene anche la parola "maschio" no? funziona solo perché il maschio è il primo? Bug in attesa di accadere se vengono riordinati?
Michael Durrant,

5
@Michael Durrant: Jest, ma la corrispondenza delle stringhe tra elementi (che è un problema ancora più grande delle normali corrispondenze di sottostringhe all'interno dello stesso elemento) è in effetti uno dei motivi principali: contiene () è stato eliminato.
BoltClock

158

Sembra che ci stessero pensando per le specifiche CSS3 ma non ha fatto il taglio .

:contains()Selettore 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.E per una buona ragione, violerebbe l'intera premessa di separare stile, contenuto, struttura e comportamento.
Synetech,

56
@Synetech Può effettivamente aiutare a separare lo stile dal contenuto, in quanto significa che il contenuto non ha bisogno di sapere del proprio cliente sarà considerato importante su cui basare lo stile. In questo momento il nostro contenuto html in genere è strettamente accoppiato al CSS includendo le classi che sappiamo che lo styler si preoccupa. Si stanno già spostando verso la diffusione del CSS nel contenuto, come evidenziato dai selettori del valore degli attributi in CSS3.
DannyMeister,

8
@Synetech e come è "comportamento", esattamente? Per me è una questione di presentazione. Non fa niente - si presenta certi tipi di contenuti in un certo modo.
BarbaraKwarc,

4
@DannyMeister, oh non devi convincermi. Un paio d'anni dopo e mi ritrovo qui mentre cerco esattamente questa funzionalità, e sconvolto che non solo non esiste, ma è stato respinto. 😒 eBay ha appena cambiato l'interfaccia utente e ha reso il sito molto difficile da usare. Sto cercando di risolverlo con un foglio di stile utente, ma il loro markup non distingue tra aste ed elenchi BIN, quindi l'unico modo per evidenziare il numero di offerte in un elenco è abbinando l'elemento al suo contenuto testuale. Tutto ciò che serve per convincere qualcuno è che provino in prima persona uno scenario d'uso.
Synetech,

8
Per garantire una buona separazione tra contenuto e stile, non avremo un selettore: Includes (). Quindi, invece di assegnare uno stile a una cella in base al suo contenuto (ad esempio, una colonna "status" di "Apri" o "Risolto"), dupliceremo il contenuto sia nella visualizzazione che negli attributi della classe, quindi selezioneremo quello . Eccellente!
Jon Kloske,

122

Dovresti aggiungere un attributo di dati alle righe chiamate data-gendercon un valore maleo femalee utilizzare il selettore di attributi:

HTML:

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

CSS:

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

10
Va benissimo usare attributi di dati personalizzati con Javascript e CSS. Vedi MDN utilizzando gli attributi dei dati
Michael Benjamin,

1
Sono d'accordo che l'attributo di dati è come dovrebbe essere gestito, MA una regola CSS come td.male è spesso molto più facile da impostare, specialmente con angolare che potrebbe assomigliare a: <td class = "{{person.gender}} ">
DJDaveMark il

Il genere è ovviamente un tipico esempio di funzionamento delle lezioni. Ma cosa succede se i dati sono più vari rispetto al solo maleo female? Il fatto che classsia pieno di altre classi, l'ordine di esse non è garantito, ci possono essere collisioni con altri nomi di classi ecc. Rende classun posto peggiore per questo tipo di cose. Un data-*attributo dedicato isola i tuoi dati da tutto ciò e semplifica la corrispondenza parziale, ecc. Utilizzando i selettori degli attributi.
Stijn de Witt,

C'è un'altra risposta con uno snippet di codice funzionante che utilizza gli attributi dei dati in modo simile.
Josh Habdas,

65

Esiste in realtà una base molto concettuale per cui questo non è stato implementato. È una combinazione sostanzialmente di 3 aspetti:

  1. Il contenuto testuale di un elemento è effettivamente figlio di quell'elemento
  2. Non puoi indirizzare direttamente il contenuto del testo
  3. CSS non consente l'ascensione con i selettori

Questi 3 insieme significano che quando hai il contenuto del testo non puoi risalire all'elemento contenitore e non puoi dare uno stile al testo attuale. Ciò è probabilmente significativo poiché la discesa consente solo un tracciamento singolare del contesto e l'analisi dello stile SAX. I selettori ascendenti o di altro tipo che coinvolgono altri assi introducono la necessità di attraversamenti più complessi o soluzioni simili che complicherebbero notevolmente l'applicazione del CSS al DOM.


4
Questo è vero. Ecco a cosa serve XPath. Se è possibile eseguire il selettore in JS / jQuery o una libreria di analisi (anziché solo CSS), sarebbe possibile utilizzare la text()funzione XPath .
Mark Thomas,

Questo è un buon punto sul contenuto . Ma come vorrei che tu potessi avere :contains(<sub-selector>)a selezionare un elemento che contiene altri elementi specifici. Ti piace div:contains(div[id~="bannerAd"])sbarazzarti dell'annuncio e del suo contenitore.
Lawrence Dol

27

È possibile impostare il contenuto come attributo di dati e quindi utilizzare i selettori di attributo , come mostrato qui:

/* 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>

Puoi anche usare jQuery per impostare facilmente gli attributi del contenuto dei dati:

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

3
nota che .text()e .textContentsono piuttosto pesanti, cerca di evitarli in lunghi elenchi o testi di grandi dimensioni quando possibile. .html()e .innerHTMLsono veloci.
Oriadam,

@JoshHabdas puoi fare un esempio jsbin / jsfiddle del tuo cambiamento?
Buksy

1
Se hai intenzione di usare jQuery, usa il selettore contiene:$("td:contains(male)")
huwiler

Se il contenuto è modificabile dall'utente ( contenteditable='true'- il mio caso), non è sufficiente impostare il valore data-contentdell'attributo prima del rendering della pagina. Deve essere aggiornato continuamente. Ecco cosa uso:<td onkeypress="event.target.setAttribute('data-content', event.target.textContent);">
caram

13

Poiché ai CSS manca questa funzione, dovrai utilizzare JavaScript per definire lo stile delle celle in base al contenuto. Ad esempio con XPath contains:

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

Quindi utilizzare il risultato in questo modo:

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

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


questo è javascript, come si collega alla domanda?
rubo77,

3
Dato che non puoi selezionare il contenuto in CSS, dovrai usare js per farlo. Mentre hai ragione nel sottolineare che questo non è CSS, l'uso di un attributo di dati non sta selezionando in base al contenuto. Possiamo solo indovinare perché il lettore vuole selezionare le celle in base al contenuto, che tipo di accesso ha all'html, quante partite, quanto è grande il tavolo ecc
Ecc

7

Temo che ciò non sia possibile, poiché il contenuto non è un attributo né è accessibile tramite una pseudo-classe. L'elenco completo dei selettori CSS3 è disponibile nella specifica CSS3 .


4

Per coloro che stanno cercando di fare selezioni di testo CSS Selenium, questo script potrebbe essere di qualche utilità.

Il trucco è selezionare il genitore dell'elemento che stai cercando, quindi cercare il figlio con il testo:

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];
}

Questo restituirà il primo elemento se ce n'è più di uno poiché è sempre un elemento, nel mio caso.


Puoi usare TD:contains('male')se stai usando Selenium: lo uso solo se non riesci ad aggiornare l'origine per aggiungere classi. ad es. se stai testando il codice legacy o la tua azienda non ti lascerà parlare con gli sviluppatori (eurgh!) perché i tuoi test saranno fragili e si romperanno se qualcuno cambierà il testo in seguito masculineo cambierà lingua. I documenti di SauceLabs ne mostrano l'uso contains( saucelabs.com/resources/articles/selenium-tips-css-selectors ) + cc @matas vaitkevicius mi sono perso qualcosa?
snowcode

3

Sono d'accordo che l'attributo di dati (risposta del viaggiatore) è come dovrebbe essere gestito, MA, regole CSS come:

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

spesso può essere molto più facile da configurare, specialmente con librerie lato client come angularjs che potrebbero essere semplici come:

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

Assicurati solo che il contenuto sia solo una parola! Oppure puoi anche mappare a diversi nomi di classi CSS con:

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

Per completezza, ecco l'approccio degli attributi di dati:

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

I binding dei modelli sono un'ottima soluzione. Ma è un po 'complicato creare nomi di classe basati sulla struttura del markup (anche se è praticamente ciò che fa BEM in pratica).
Josh Habdas,

2

La risposta di @ voyager sull'uso data-*dell'attributo (ad es. data-gender="female|male"è l' approccio più efficace e conforme agli standard a partire dal 2017:

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

Quasi tutti gli obiettivi possono essere raggiunti in quanto vi sono alcuni selettori, sebbene limitati, orientati al testo. Il :: first-letter è un elemento pseudo che può applicare stili limitata alla prima lettera di un elemento. C'è anche un :: prima linea pseudo-elemento oltre a selezionare ovviamente la prima riga di un elemento (come un paragrafo) implica anche che è ovvio che CSS potrebbe essere usato per estendere questa capacità esistente allo stile di aspetti specifici di un textNode .

Fino a quando tale patrocinio avrà successo e sarà implementata la prossima cosa migliore che potrei suggerire quando applicabile è explode/ splitparole usando un delimitatore di spazio, emettere ogni singola parola all'interno di un spanelemento e quindi se l'obiettivo di parola / stile è prevedibile, utilizzare in combinazione con : ennesimi selettori :

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

Altrimenti se non prevedibile , utilizzare nuovamente la risposta del viaggiatore sull'uso data-*dell'attributo. Un esempio usando PHP:

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


1

La maggior parte delle risposte qui cerca di offrire un'alternativa a come scrivere il codice HTML per includere più dati perché almeno fino a CSS3 non è possibile selezionare un elemento tramite testo interno parziale. Ma può essere fatto, devi solo aggiungere un po 'di JavaScript vaniglia, nota che anche la femmina contiene maschio sarà selezionata:

      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

Trovo l'opzione di attributo la migliore scommessa se non si desidera utilizzare javascript o jquery.

Ad esempio per dare uno stile a tutte le celle della tabella con la parola pronta, in HTML fare questo:

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

Quindi in CSS:

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

0

Si potrebbe anche usare contentcon attr()e celle di tabelle stile che sono ::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 ZeroWidthSpaceviene utilizzato per modificare il colore e può essere aggiunto utilizzando JavaScript vaniglia:

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

Sebbene il <td>tag s end possa essere omesso, ciò può comportare che non venga considerato vuoto.


0

Se non si crea il DOM da soli (ad es. In uno script utente) è possibile effettuare le seguenti operazioni con JS puro:

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>

Uscita console

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

-2

Fare piccoli widget di filtro come questo:

    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

La sintassi di questa domanda sembra la sintassi di Robot Framework. In questo caso, anche se non esiste un selettore CSS che è possibile utilizzare per contiene, esiste invece una parola chiave SeleniumLibrary che è possibile utilizzare. L' attesa fino a quando l'elemento contiene .

Esempio:

Wait Until Element Contains  | ${element} | ${contains}
Wait Until Element Contains  |  td | male
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.