Estoy buscando un selector CSS para la siguiente tabla:
Peter | male | 34
Susanne | female | 12
¿Hay algún selector que coincida con todos los TD que contengan "masculino"?
fuente
Estoy buscando un selector CSS para la siguiente tabla:
Peter | male | 34
Susanne | female | 12
¿Hay algún selector que coincida con todos los TD que contengan "masculino"?
Si leo la especificación correctamente, no.
Puede coincidir en un elemento, el nombre de un atributo en el elemento y el valor de un atributo con nombre en un elemento. Sin embargo, no veo nada para hacer coincidir el contenido dentro de un elemento.
:empty
.
Usando jQuery:
$('td:contains("male")')
Parece que estaban pensando en ello para la especificación CSS3 pero no logró el corte .
:contains()
Selector CSS3 http://www.w3.org/TR/css3-selectors/#content-selectors
Looks like they were thinking about it for the CSS3 spec but it didn't make the cut.
Y por una buena razón, violaría toda la premisa de separar el estilo, el contenido, la estructura y el comportamiento.
Tendría que agregar un atributo de datos a las filas llamadas data-gender
con un valor male
o female
y usar el selector de atributos:
HTML:
<td data-gender="male">...</td>
CSS:
td[data-gender="male"] { ... }
male
o female
? El hecho de que class
esté lleno de otras clases, el orden de ellas no está garantizado, puede haber colisiones con otros nombres de clase, etc., hace class
que este lugar sea peor. Un data-*
atributo dedicado aísla sus datos de todas esas cosas y facilita la coincidencia parcial, etc., utilizando selectores de atributos.
En realidad, existe una base muy conceptual de por qué esto no se ha implementado. Es una combinación de básicamente 3 aspectos:
Estos 3 juntos significan que cuando tiene el contenido del texto, no puede ascender de nuevo al elemento contenedor y no puede darle estilo al texto actual. Esto es probablemente significativo ya que descender solo permite un seguimiento singular del contexto y el análisis de estilo SAX. Los selectores ascendentes u otros que involucran otros ejes introducen la necesidad de soluciones transversales más complejas o similares que complicarían en gran medida la aplicación de CSS al DOM.
text()
función XPath .
:contains(<sub-selector>)
seleccionar un elemento que contenga otros elementos específicos. Desea div:contains(div[id~="bannerAd"])
deshacerse del anuncio y su contenedor.
Puede configurar el contenido como atributo de datos y luego usar selectores de atributos , como se muestra aquí:
/* 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>
También puede usar jQuery para configurar fácilmente los atributos de contenido de datos:
$(function(){
$("td").each(function(){
var $this = $(this);
$this.attr("data-content", $this.text());
});
});
.text()
y .textContent
son bastante pesados, trate de evitarlos en listas largas o textos grandes cuando sea posible. .html()
Y .innerHTML
son rápidos.
$("td:contains(male)")
contenteditable='true'
- mi caso), no es suficiente establecer el valor del data-content
atributo antes de que se renderice la página. Tiene que ser actualizado continuamente. Aquí lo que uso:<td onkeypress="event.target.setAttribute('data-content', event.target.textContent);">
Como CSS carece de esta característica, tendrá que usar JavaScript para diseñar las celdas por contenido. Por ejemplo con XPath's contains
:
var elms = document.evaluate( "//td[contains(., 'male')]", node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null )
Luego usa el resultado así:
for ( var i=0 ; i < elms.snapshotLength; i++ ){
elms.snapshotItem(i).style.background = "pink";
}
Me temo que esto no es posible, porque el contenido no es un atributo ni es accesible a través de una pseudo clase. La lista completa de selectores CSS3 se puede encontrar en la especificación CSS3 .
Para aquellos que buscan hacer selecciones de texto Selenium CSS, este script podría ser de alguna utilidad.
El truco consiste en seleccionar el elemento primario del elemento que está buscando y luego buscar el elemento secundario que tiene el texto:
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];
}
Esto devolverá el primer elemento si hay más de uno, ya que siempre es un elemento, en mi caso.
TD:contains('male')
si estás usando Selenium: solo lo usaré si no puedes actualizar la fuente para agregar clases. por ejemplo, si está probando código heredado o su empresa no le permite hablar con los desarrolladores (¡eurgh!) porque sus pruebas serán frágiles y se romperán si alguien cambia el texto más adelante masculine
o cambia el idioma. Los documentos de SauceLabs muestran el uso de contains
aquí ( saucelabs.com/resources/articles/selenium-tips-css-selectors ) + cc @matas vaitkevicius ¿Me he perdido algo?
Estoy de acuerdo en que el atributo de datos (respuesta del viajero) es cómo debe manejarse, PERO, reglas CSS como:
td.male { color: blue; }
td.female { color: pink; }
a menudo puede ser mucho más fácil de configurar, especialmente con libs del lado del cliente como angularjs, que podría ser tan simple como:
<td class="{{person.gender}}">
¡Solo asegúrate de que el contenido sea solo una palabra! O incluso podría asignar a diferentes nombres de clase CSS con:
<td ng-class="{'masculine': person.isMale(), 'feminine': person.isFemale()}">
Para completar, aquí está el enfoque de atributos de datos:
<td data-gender="{{person.gender}}">
La respuesta de @ voyager sobre el uso de data-*
atributos (por ejemplo, data-gender="female|male"
es el enfoque más efectivo y compatible con los estándares a partir de 2017:
[data-gender='male'] {background-color: #000; color: #ccc;}
Casi la mayoría de los objetivos se pueden alcanzar ya que hay algunos selectores, aunque limitados, orientados alrededor del texto. La :: primera letra es un pseudo-elemento que puede aplicar un estilo limitado a la primera letra de un elemento. También hay una :: primera línea pseudo-elemento , además de seleccionar obviamente la primera línea de un elemento (como un párrafo) también implica que es obvio que CSS podría usarse para extender esta capacidad existente para diseñar aspectos específicos de un nodo de texto .
Hasta que dicha promoción tenga éxito y se implemente, lo mejor que podría sugerir cuando corresponda es a explode
/ split
palabras usando un deliminador de espacio, envíe cada palabra individual dentro de un span
elemento y luego, si el objetivo de palabra / estilo es predecible, use en combinación con : enésimo selectores :
$p = explode(' ',$words);
foreach ($p as $key1 => $value1)
{
echo '<span>'.$value1.'</span>;
}
De lo contrario, si no es predecible , nuevamente, use la respuesta del viajero sobre el uso del data-*
atributo. Un ejemplo usando PHP:
$p = explode(' ',$words);
foreach ($p as $key1 => $value1)
{
echo '<span data-word="'.$value1.'">'.$value1.'</span>;
}
Si está utilizando Chimp / Webdriver.io , admiten muchos más selectores CSS que la especificación CSS.
Esto, por ejemplo, hará clic en el primer ancla que contiene las palabras "Oso malo":
browser.click("a*=Bad Bear");
La mayoría de las respuestas aquí intentan ofrecer una alternativa a cómo escribir el código HTML para incluir más datos porque al menos hasta CSS3 no puede seleccionar un elemento por texto interno parcial. Pero se puede hacer, solo necesita agregar un poco de JavaScript vainilla, tenga en cuenta que ya que la hembra también contiene el macho, se seleccionará:
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>
Creo que la opción de atributo es su mejor opción si no desea usar javascript o jquery.
Por ejemplo, para diseñar todas las celdas de la tabla con la palabra lista, en HTML haga esto:
<td status*="ready">Ready</td>
Luego en css:
td[status*="ready"] {
color: red;
}
También puede usar content
con attr()
y las celdas de tabla de estilo que son ::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>
A ZeroWidthSpace
se usa para cambiar el color y se puede agregar usando JavaScript de vainilla:
const hombres = document.querySelectorAll('td[data-value="male"]');
hombres.forEach(hombre => hombre.innerHTML = '​');
Aunque se puede omitir la<td>
etiqueta de finalización s, al hacerlo puede tratarse como no vacía.
Si no crea el DOM usted mismo (por ejemplo, en un script de usuario), puede hacer lo siguiente 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>
Salida de la consola
text: <td> Peter
text: <td> male
text: <td> 34
text: <td> Susanne
text: <td> female
text: <td> 12
male: <td text="male"> male
Hacer pequeños widgets de filtro como este:
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')
}
})
})
La sintaxis de esta pregunta se parece a la sintaxis de Robot Framework. En este caso, aunque no hay un selector css que pueda usar para contiene, hay una palabra clave SeleniumLibrary que puede usar en su lugar. El elemento Esperar hasta que contenga .
Ejemplo:
Wait Until Element Contains | ${element} | ${contains}
Wait Until Element Contains | td | male
$x
respuestas a la pregunta. para la pregunta original,$x("//td[text()='male']")
¿el truco