Belirli metin içeren öğeler için bir CSS seçici var mı?


512

Aşağıdaki tablo için bir CSS seçici arıyorum:

Peter    | male    | 34
Susanne  | female  | 12

"Erkek" içeren tüm tank avcılarına uyan herhangi bir seçici var mı?


1
Sorun şu ki, bu performansın uygulanması çok zor olacaktır.
Ms2ger

7
XPath seçici bunu .text () yöntemiyle yapabilir (JavaScript yürütücüsünü kullanmamayı tercih ediyorsanız).
djangofan

11
İşte xpath: // h1 [text () = 'Session'] kullanarak bunu nasıl yapabileceğinize dair bir örnek ve $ x ("// h1 [text () = 'Session']" yazarak Chrome'da xpath'i test edebilirsiniz ) konsolda
VinnyG

1
Bu çok uygun olurdu. Örneğin, bir onay işareti veya "Evet", "Başarılı", "Tamam" vb. Dizeyi içeren bir tablo hücresi yeşil olabilir.
Andreas Rejbrand

$xsoruya cevap verir. orijinal soru için, $x("//td[text()='male']")hile yapar
Xiao

Yanıtlar:


394

Ben okursanız şartname hayır, doğru.

Bir öğeyle, öğedeki özniteliğin adıyla ve öğedeki adlandırılmış özniteliğin değeriyle eşleşebilirsiniz. Yine de, bir öğedeki içeriği eşleştirmek için hiçbir şey göremiyorum.


228
Bir kenar durum vardır: :empty.
Ciro Santilli 法轮功 10: 病 六四 事件 法轮功

34
Kendi sorumu cevaplamak için: Evet, bugün için hala geçerli! İçerik seçiciler kullanımdan kaldırıldı! CSS3'ten beri başka içerik seçici yok. ( W3.org/TR/css3-selectors/#selectors )
wlad

158

JQuery kullanma:

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

7
Bunun tersini gerektiren sona erdi, yani: jQuery (element) .not (": içerir ('string')")
Jazzy

311
Bunun dışında CSS değil, JavaScript.
Synetech

9
Kabul etti - bu yüzden cevabım CSS yerine jQuery kullandığımı söyledi. Ama cevabımın o kısmı düzenlendi. =)
Moettinger

18
ama erkek fe kelimesinin kendisi de 'erkek' kelimesini içerir. ilk önce mi çalışıyor çünkü ilk önce erkek mi? Hata yeniden sipariş edilirse gerçekleşmesini bekliyor?
Michael Durrant

5
@Michael Durrant: Sen jest, ancak çapraz eleman dize eşleme (aynı eleman içindeki normal alt dize eşleşmelerinden daha büyük bir problemdir) aslında en büyük nedenlerden biridir: içerir () bırakıldı.
BoltClock

158

Görünüşe göre CSS3 spec için düşünüyorlardı ama kesmedi .

:contains()CSS3 seçici 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.Ve iyi bir nedenden dolayı, stil, içerik, yapı ve davranışı ayırma öncülünü ihlal edecektir.
Synetech

56
@Synetech Stilin içerikten ayrılmasına yardımcı olabilir, çünkü içeriğin müşterisi hakkında bilmesi gerekmez, stilin temeli temel almak için önemli olduğunu düşünecektir. Şu anda html içeriğimiz tipik olarak şekillendiricinin umurunda olduğumuz sınıfları ekleyerek css ile sıkı bir şekilde eşleştirilmiştir. CSS3'teki özellik değeri seçicileri tarafından kanıtlandığı gibi, içerikte CSS'ye izin vermeye zaten kayıyorlar.
DannyMeister

8
@Synetech ve tam olarak nasıl "davranış"? Bana göre bu bir sunum meselesi. O değil yapmak bir şey - bu sunar belirli bir şekilde belirli içerik türlerini.
BarbaraKwarc

4
@DannyMeister, oh beni ikna etmek zorunda değilsin. Birkaç yıl sonra, tam olarak bu işlevselliği aramaya çalışırken kendimi burada buluyorum ve sadece var olmakla kalmayıp aynı zamanda reddedildiğini de üzdüm. 😒 eBay, kullanıcı arayüzünü değiştirdi ve sitelerinin kullanımını çok zorlaştırdı. Bir kullanıcı stil sayfası ile düzeltmek için çalışıyorum, ancak onların işaretleme açık artırmalar ve BIN listeleri arasında ayrım yapmaz, bu nedenle bir listede teklif sayısını vurgulamak için tek yolu öğeyi metinsel içeriğiyle eşleştirmektir. Birini ikna etmek için gereken tek şey bir kullanım senaryosu ilk elden deneyimlemek.
Synetech

8
İçeriğin ve stilin iyi bir şekilde ayrılmasını sağlamak için: include () seçicimiz olmayacaktır. Dolayısıyla, bir hücreyi içeriğine göre biçimlendirmek yerine (ör. "Aç" veya "Çözülmüş" ifadesinin "durum" sütunu), içeriği hem ekrandaki hem de sınıf özniteliklerinde çoğaltırız ve ardından . Mükemmel!
Jon Kloske

122

data-genderBir maleveya femaledeğerle çağrılan satırlara bir veri özelliği eklemeniz ve özellik seçiciyi kullanmanız gerekir:

HTML:

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

CSS:

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

10
Javascript ve CSS ile özel veri özniteliklerini kullanmak mükemmeldir. Bkz . Veri Özelliklerini Kullanarak MDN
Michael Benjamin

1
Veri özniteliğinin nasıl ele alınması gerektiğine katılıyorum, AMA, td.male gibi bir CSS kuralı oluşturmak genellikle çok daha kolay, özellikle aşağıdaki gibi bir açıya sahip olabilir: <td class = "{{person.gender}} ">
DJDaveMark

Cinsiyet elbette sınıfların işe yarayacağı tipik bir örnektir. Peki ya veriler sadece daha farklıysa maleya da female? Aslında classdiğer sınıfları ile doludur, bunların sıralaması garanti edilmez, vb yapar diğer sınıf adları ile collissions olabilir classBu tür görevler için daha kötü bir yer. Özel bir data-*özellik, verilerinizi tüm bu öğelerden yalıtır ve özellik seçicileri kullanarak kısmi eşleme vb.
Stijn de Witt

Veri özniteliklerini benzer şekilde kullanan bir çalışma kodu snippet'inde başka bir yanıt daha var.
Josh Habdas

65

Aslında bunun neden uygulanmadığının çok kavramsal bir temeli vardır. Temel olarak 3 yönün bir kombinasyonudur:

  1. Bir öğenin metin içeriği etkili bir şekilde o öğenin alt öğesidir
  2. Metin içeriğini doğrudan hedefleyemezsiniz
  3. CSS seçicilerle yükselmeye izin vermiyor

Bu 3 birlikte metin içeriğine sahip olduğunuzda, içeren öğeye geri yükselemeyeceğiniz ve mevcut metni biçimlendiremeyeceğiniz anlamına gelir. Bu, büyük olasılıkla önemlidir, çünkü azalan içerik ve SAX stili ayrıştırmasının tekil olarak izlenmesine izin verir. Yükselen veya diğer eksenleri içeren diğer seçiciler, CSS'nin DOM'a uygulanmasını büyük ölçüde karmaşıklaştıracak daha karmaşık çaprazlama veya benzer çözümlere olan ihtiyacı ortaya çıkarır.


4
Bu doğru. XPath bunun içindir. Seçiciyi JS / jQuery'de veya bir ayrıştırma kitaplığında (yalnızca CSS'nin aksine) yürütebilirseniz, XPath text()işlevini kullanmak mümkün olacaktır .
Mark Thomas

Bu içerikle ilgili iyi bir nokta . Ama nasıl olmasını dilerdim :contains(<sub-selector>), başka belirli elementler içeren bir element seçmek için. Gibi div:contains(div[id~="bannerAd"])reklamdan kurtulmak ve 's konteyner almak.
Lawrence Dol

27

İçeriği veri özelliği olarak ayarlayabilir ve ardından burada gösterildiği gibi özellik seçicileri kullanabilirsiniz :

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

Veri içeriği özniteliklerini kolayca ayarlamak için jQuery'yi de kullanabilirsiniz:

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

3
notu .text()ve .textContentoldukça ağır olan mümkün olduğunda uzun listeleri veya büyük metinlerde bunları önlemek için deneyin. .html()ve .innerHTMLhızlı.
oriadam

@JoshHabdas Değişikliğiniz için bir jsbin / jsfiddle örneği yapabilir misiniz?
Buksy

1
JQuery kullanacaksanız, $("td:contains(male)")
içerme

İçerik kullanıcı tarafından düzenlenebilirse ( contenteditable='true'- benim durumum), data-contentsayfa oluşturulmadan önce özelliğin değerini ayarlamak yeterli değildir . Sürekli güncellenmesi gerekir. İşte ne kullanıyorum:<td onkeypress="event.target.setAttribute('data-content', event.target.textContent);">
caram

13

CSS'de bu özellik bulunmadığından, hücreleri içeriğe göre biçimlendirmek için JavaScript kullanmanız gerekir. Örneğin XPath'larda contains:

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

Sonra sonucu şöyle kullanın:

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

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


bu javascript, bu soru ile nasıl ilişkilidir?
rubo77

3
Css'deki içeriğe göre seçim yapamadığınız için bunu yapmak için js kullanmanız gerekecektir. Bunun css olmadığını belirttiğiniz yerde olsanız da, bir veri özelliğinin kullanımı içeriğe göre seçilmez. Okuyucu o tablo vb vb ne kadar büyük html, kaç kibrit, için sahip olduğu erişim tür içeriği ne hücreleri seçmek istiyor neden Biz sadece tahmin edebilirsiniz
user40521


4

Selenium CSS metin seçimleri yapmak isteyenler için, bu komut dosyasının bir kısmı yararlı olabilir.

Hile, aradığınız öğenin üst öğesini seçmek ve ardından metni içeren alt öğeyi aramaktır:

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

Bu benim durumumda her zaman bir öğe olduğundan birden fazla varsa ilk öğeyi döndürür.


Sen kullanabilirsiniz TD:contains('male')sen selenyum kullanıyorsanız: Eğer sınıfları eklemek kaynağını güncelleştirmek olamaz imho sadece kullanın. Örneğin, eski kodu test ediyorsanız veya şirketiniz geliştiricilerle konuşmanıza izin vermiyorsa (eurgh!) çünkü testleriniz kırılgan olacak ve birisi metni daha sonra değiştirirse masculineveya dili değiştirirse kırılacaktır . SauceLabs dokümanları containsburada kullanımını gösterir ( saucelabs.com/resources/articles/selenium-tips-css-selectors ) + cc @matas vaitkevicius bir şey kaçırdım mı?
kar kodu

3

Veri özniteliğinin (voyager'ın cevabı) nasıl ele alınması gerektiğine katılıyorum , AMA, CSS kuralları gibi:

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

kurulumu genellikle çok daha kolay olabilir, özellikle de angularjs gibi müşteri tarafındaki kütüphaneler kadar basit olabilir:

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

İçeriğin yalnızca bir kelime olduğundan emin olun! Veya aşağıdakilerle farklı CSS sınıfı adlarıyla eşleştirebilirsiniz:

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

Tamlık için veri özniteliği yaklaşımı:

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

Şablon bağlama harika bir çözümdür. Ancak işaretleme yapısına dayalı sınıf adları oluşturmak biraz rahatsızlık verici olsa da ( BEM'in pratikte yaptığı şey budur ).
Josh Habdas

2

@ voyager'ın data-*özelliği kullanma konusundaki cevabı (örn . 2017 itibariyle data-gender="female|male"en etkili ve standartlara uygun yaklaşımdır:

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

Hemen hemen çoğu gol olabilir sınırlı seçicileri de olsa bazı metnin etrafında odaklı olduğu gibi elde edilebilir. :: İlk harfli bir olan sözde öğesi bir öğenin ilk harfine sınırlı stil uygulayabilirsiniz. Ayrıca bir :: first-line pseudo-element öğenin ilk satırını (paragraf gibi) seçmenin yanı sıra, CSS'nin bu mevcut yeteneği bir textNode'un belirli yönlerini şekillendirmek için kullanılabileceği de açıktır. .

Böyle bir savunuculuk başarılı oluncaya ve uygulanıncaya kadar önerebileceğim bir sonraki en iyi şey explode/ splitbir boşluk sınırlayıcı kullanarak / kelimeler olduğunda , her bir spanöğeyi bir öğenin içine çıkarın ve ardından kelime / stil hedefi öngörülebilir kullanımla birleştiğinde : n. Seçiciler :

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

Else , öngörülemezse , voyager'ın data-*özniteliği kullanma hakkındaki cevabını tekrar kullanın . PHP kullanan bir örnek:

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


1

Buradaki cevapların çoğu, daha fazla veri eklemek için HTML kodunun nasıl yazılacağına alternatif sunmaya çalışıyor çünkü en azından CSS3'e kadar bir öğeyi kısmi iç metne göre seçemezsiniz. Ama yapılabilir, sadece biraz vanilya JavaScript eklemeniz gerekir, çünkü kadın da erkek içerdiğinden haberdar olun:

      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 veya jquery kullanmak istemiyorsanız özellik seçeneğini en iyi bahsiniz olarak görüyorum.

Örneğin tüm tablo hücrelerini hazır sözcüğü ile biçimlendirmek için HTML'de şunu yapın:

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

Sonra css içinde:

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

0

Ayrıca kullanabilirsiniz contentile attr()olan stil tablo hücreleri ve ::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 ZeroWidthSpacerengi değiştirmek için kullanılır ve vanilya JavaScript kullanılarak eklenebilir:

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

Her ne kadar <td>s uç etiketi atlanmış olsa da, boş olarak kabul edilmesine neden olabilir.


0

DOM'yi kendiniz oluşturmazsanız (örneğin, bir kullanıcı metninde) salt JS ile aşağıdakileri yapabilirsiniz:

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>

Konsol çıkışı

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

-2

Bunun gibi küçük Filtre Widget'ları yapmak:

    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

Bu sorunun sözdizimi Robot Framework sözdizimine benziyor. Bu durumda, içerenler için kullanabileceğiniz bir css seçici olmasa da, bunun yerine kullanabileceğiniz bir SeleniumLibrary anahtar sözcüğü vardır. Eleman kadar bekleyin içerir .

Misal:

Wait Until Element Contains  | ${element} | ${contains}
Wait Until Element Contains  |  td | male
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.