13

How to write a CSS Selector selecting elements NOT having a certain attribute?

I have 2 <div> nodes as follows:

  • First:

    <div class="weEq5" style="will-change; width;">
        <button class="_35EW6">
    
  • Second:

    <div class="weEq5">
        <button class="_35EW6">
    

I need to select the <div> (with the similar class) and each of them which have a similar descending <button> but without the style attribute.

XPath seems working fine as:

//div[@class and not (@style)]/button

I am looking for an equivalent CssSelector.

Trials:

div[class :not(style)]>button (doesn't works).

I have been through the following discussion but they seem to be discarding the class attribute as :not([class]) as in:

I was looking in similar lines ending with :not(attribute).

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • You already have your answer - just substitute "style" where "class" appears in your example. – BoltClock Dec 26 '18 at 04:49
  • @BoltClock Tried but not getting resolved within the [Test](http://videlibri.sourceforge.net/cgi-bin/xidelcgi) template. – undetected Selenium Dec 26 '18 at 04:50
  • 1
    It's resolving for me using `div:not([style]) button` or `div[class]:not([style]) button`. – BoltClock Dec 26 '18 at 04:53
  • @BoltClock Thanks, with exactly the same css `div:not([style])` it still doesn't resolves at my end (shows default 1 Result) – undetected Selenium Dec 26 '18 at 04:56
  • @BoltClock Yeah, it does `div:not(style) button` but somehow can I include the class _attribute_? `div[class]:not(style) button` seems not acceptable. – undetected Selenium Dec 26 '18 at 04:56
  • `div.weEq5:not([style])` – yong Dec 26 '18 at 05:05
  • @yong `weEq5` is _dynamic_, so we can't take this value – undetected Selenium Dec 26 '18 at 05:10
  • 2
    @BoltClock `div[class]:not(style) button` seems working perfect. – undetected Selenium Dec 26 '18 at 05:14
  • *Without* the square brackets? Wow, that's... very confusing. Because :not(style) actually means "not a – BoltClock Dec 26 '18 at 05:16
  • Should use the square bracket round `style` like this: `div[class]:not([style])` – yong Dec 26 '18 at 05:17
  • @BoltClock That's where I was stuck. Isn't absence of _style_ attribute implies "not a – undetected Selenium Dec 26 '18 at 05:17
  • for css not selector `:not()`, the argument for `:not()` should be valid css selector, if you use `not(style)`, the `style` here mean any tag which tag name is `style`, but for `not([style])` , the `[style]` means any tag which has attribute `style`. One is match by tag name, one is match by tag attribute. There are different. – yong Dec 26 '18 at 05:22
  • @DebanjanB: No, because attributes and elements are two different things. It's the same reason why you prefix attributes with @ in XPath - in XPath, `style` and `@style` likewise mean different things. – BoltClock Dec 26 '18 at 05:22
  • @DebanjanB - Can you post the answer to this question with little explanation ? It will be helpful for all. Thanks – Amit Jain Dec 26 '18 at 05:30
  • @AmitJain See I got the _css-selectors_ working but BoltClock seems not agreeing with the solution pertaining to the functionality and best practices. Can we wait for the _css-selectors_ contributors to have a look at it please? – undetected Selenium Dec 26 '18 at 05:35
  • What about this one `div.weEq5:not([style]) button` ? – NarendraR Dec 26 '18 at 06:05
  • @NarendraR `weEq5` is dynamic, so we can't take this value into consideration – undetected Selenium Dec 26 '18 at 06:15
  • 2
    @DebanjanB, You are right it would be. the concern about excluding `style` attribute. `div:not([style]) button` this locate the second button. you can take other surrounding element to make this robust. – NarendraR Dec 26 '18 at 06:20
  • Please refer to this https://stackoverflow.com/questions/1533444/css-selector-to-match-an-element-without-attribute-x post – Yugansh Jan 04 '19 at 05:01

4 Answers4

17

I think more accurate CSS Selector is:

div[class]:not([style])>button

because the button element is a child of div element.

Hope it helps you!

Ratmir Asanov
  • 6,237
  • 5
  • 26
  • 40
12

That's the code you're looking for:

div:not([style]) button{
  background-color: red;
}

Now let's break it down. We have have four selectors in this example:

  1. div and button - these select html elements. We can replace it for example with a class selector like .weEq5.
  2. :not() - indicates that we want everything that does not qualify as the selector inside the brackets.
  3. [style] - an attribute selector which is very powerful. We can place inside the not any other css selector like html tag names (button or div), class names or ids.

The combination of div:not([style]) means that we want all divs that do not have a style attribute. After which we have a space and a button means that we want all the buttons that are inside the above selector.

Adding a > before the button div:not([style]) > button will only select button elements which are direct children of the selected div. It will exclude from selection buttons that are deeper inside the div.

Adam Genshaft
  • 756
  • 10
  • 22
4

Normally, you would write :not([style]) to match an element that does not have a style attribute, as described here which emphasizes the use of both () and [] brackets, in that order.

But if this isn't working in Selenium WebDriver, and worse still if :not(style) works exactly like how I would expect :not([style]) to, then that's a bug with its CSS selector parser, since :not(style) actually means "not a style element" which makes div:not(style) redundant as an element can only either be a div or a style but not both at the same time. Unless you absolutely require a selector, I strongly recommend using the XPath locator strategy instead of relying on quirks like this with Selenium WebDriver's CSS selector engine that force you to write selectors that are both incorrect and don't work anywhere else that accepts a selector.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 1
    Niche thoughts indeed. Can you help me to understand this phrase you have used _...an element can only either be a `div` or a `style` but not both at the same time..._ because when I was going through [HTML `
    ` Tag](https://www.w3schools.com/tags/tag_div.asp) the example was based on `
    ` i.e. a `
    ` tag with _style_ attribute.
    – undetected Selenium Dec 28 '18 at 15:30
  • 3
    @DebanjanB: The tag name is `div`. What `:not(style)` means is "tag name is not `style`". Since a `div` is a `div`, `:not(style)` will always be true for that element in much the same way that `:not(p)` or `:not(span)` would be true for that element. It has nothing to do with the style attribute. – BoltClock Dec 28 '18 at 15:32
  • 2
    Thanks. It got cleared now. ` – undetected Selenium Dec 28 '18 at 15:37
3

I do not understand how the situation developed in the first place, where the structure of the page necessitates the CSS rules to be aware of whether "style=..." exists in the document itself. Or even why style=... is being used.

The style attribute is old-school now, pre-CSS I believe. It also takes precedence over anything in the CSS. That attribute does not accept CSS class names. It accepts only native html style properties like "width","height","font" - old-school stuff - ultimately those are what your CSS resolves to, no matter how fancy or obfuscated it is through frameworks: font, width, left, top, float.. and so on.

By use of the class attribute (instead of style) in the document you get infinite control from which to write smart selectors in your CSS.

You can put 3 classes in the class attribute of your div for example, if you want, and have your selectors apply styling to it if 2 of the classes are present but not if all 3 are there. Tonnes of flexibility, no need to override or use "style=..." in the document at all.

John Fantastico
  • 332
  • 1
  • 7
  • The style attribute is post-CSS. Its syntax is derived *from* CSS, not the other way around. The "native html style properties" you've listed aren't the old-school presentational attributes you're thinking of, but modern (relatively speaking) CSS properties that participate in the same cascade as the rest of Cascading Style Sheets. In fact, these days the presentational attributes are implemented using CSS, though I'm not sure if it was ever implemented the other way around when the first browsers to support CSS emerged in 1996/97. – BoltClock Jan 04 '19 at 06:18
  • All said, the use case here is not styling elements with CSS, as can be gleaned from the tags, this is an automated testing use case using Selenium WebDriver, which doesn't involve applying or overriding CSS. – BoltClock Jan 04 '19 at 06:25