Selenium Tips: CSS Selectors

Posted Aug 20, 2020

Revised August 2020 by Matthew Heusser Matt@xndev.com

Learn about CSS rules and pseudo-classes to help you move your XPATH locators to CSS.

In order for Selenium or Appium to click on an element, type into it, or mouse in or out, the tool first needs to find the element. The WebDriver code library provides methods to do just that, such as findelement() or findelements(). These usually take a locator, which can be created by ID, XPATH Code, or Cascading Style Sheets (CSS). Getting the XPATH code can be as easy as selecting the element in developer tools or using something like Chropath. Fundamentally, XPATH is a query language for XML-like documents, such as web pages. It can be awkward to write, brittle, and even more awkward to reverse engineer. As a result, CSS has gained favor as the way to identify objects in WebDriver.

Like most powerful things, CSS has a bit of a learning curve. It's certainly a lot more challenging than cutting and pasting from a tool. Yet if you invest the time in learning CSS Selectors, you can have more powerful bindings that are easier to read, less brittle, and slightly more closely integrated into the browser platform.

Today we'll provide CSS rules, tips, and pseudo-classes to either get you out on the right foot, or, perhaps help you move your XPATH locators to CSS.

Getting Started with CSS Selectors

A CSS Selector is a combination of an element selector and a value which identifies the web element within a web page.  They are string representations of HTML tags, attributes, Id and Class.  As such they are patterns that match against elements in a tree and are one of several technologies that can be used to select nodes in an XML document. 

Today we'll cover simple CSS selectors, then more advanced, then pseudo-classes, which are essentially powerful, built-in matching functions that reduce a search to just what you are looking for.

I: Simple

Id

An element’s id in XPATH is defined using: “[@id='example']” and in CSS using: “#” - ID's must be unique within the DOM.

Examples:

XPath: //div[@id='example']
CSS: #example

Element Type

The previous example showed //div in the xpath. That is the element type, which could be input for a text box or button, img for an image, or "a" for a link. 

Xpath: //input or
Css: =input

Direct Child

HTML pages are structured like XML, with children nested inside of parents. If you can locate, for example, the first link within a div, you can construct a string to reach it. A direct child in XPATH is defined by the use of a “/“, while on CSS, it’s defined using “>”.  

Examples:

XPath: //div/a
CSS: div > a

Child or Sub-Child

Writing nested divs can get tiring - and result in code that is brittle. Sometimes you expect the code to change, or want to skip layers. If an element could be inside another or one of its children, it’s defined in XPATH using “//” and in CSS just by a whitespace.

Examples:

XPath: //div//a
CSS: div a

Class

For classes, things are pretty similar in XPATH: “[@class='example']” while in CSS it’s just “.”

Examples:

XPath: //div[@class='example']
CSS: .example

II: Advanced

Next Sibling

This is useful for navigating lists of elements, such as forms or ul items. The next sibling will tell selenium to find the next adjacent element on the page that’s inside the same parent. Let’s show an example using a form to select the field after username.

<form class = "form-signin" role = "form" action = "/index.php" method = "post">
<h4 class = "form-signin-heading"></h4> 
<input type = "text" class = "form-control" id = "username" name = "username" placeholder = "username" required autofocus></br> 
<input type = "password" class = "form-control" id = "password" name = "password" placeholder = "password" required> 
<p> 
<button class = "btn btn-lg btn-primary btn-block radius" type = "submit" name = "login">Login</button> 
</form> 

Let’s write an XPath and css selector that will choose the input field after “username”. This will select the “alias” input, or will select a different element if the form is reordered.

XPATH: //input[@id='username']/following-sibling:input[1]
CSS: #username + input

Attribute Values

If you don’t care about the ordering of child elements, you can use an attribute selector in selenium to choose elements based on any attribute value. A good example would be choosing the ‘username’ element of the form above without adding a class.

We can easily select the username element without adding a class or an id to the element.

XPATH: //input[@name='username']
CSS: input[name='username']

We can even chain filters to be more specific with our selectors.

XPATH: //input[@name='login'and @type='submit']
CSS: input[name='login'][type='submit']

Here Selenium will act on the input field with name="login" and type="submit"

Choosing a Specific Match

CSS selectors in Selenium allow us to navigate lists with more finesse than the above methods. If we have a ul and we want to select its fourth li element without regard to any other elements, we should use nth-child or nth-of-type. Nth-child is a pseudo-class. In straight CSS, that allows you to override behavior of certain elements; we can also use it to select those elements.

<ul id = "recordlist">
<li>Cat</li>
<li>Dog</li>
<li>Car</li>
<li>Goat</li>
</ul>

If we want to select the fourth li element (Goat) in this list, we can use the nth-of-type, which will find the fourth li in the list. Notice the two colons, a recent change to how CSS identifies pseudo-classes.

CSS: #recordlist li::nth-of-type(4)

On the other hand, if we want to get the fourth element only if it is a li element, we can use a filtered nth-child which will select (Car) in this case.

CSS: #recordlist li::nth-child(4)

Note, if you don’t specify a child type for nth-child it will allow you to select the fourth child without regard to type. This may be useful in testing css layout in selenium.

CSS: #recordlist *::nth-child(4)

In XPATH this would be similar to using [4].

Sub-String Matches

CSS in Selenium has an interesting feature of allowing partial string matches using ^=, $=, or *=. I’ll define them, then show an example of each:

^= Match a prefix
CSS: a[id^='id_prefix_']

A link with an “id” that starts with the text “id_prefix_”

$= Match a suffix
CSS: a[id$='_id_sufix']

A link with an “id” that ends with the text “_id_sufix”

*= Match a substring
CSS: a[id*='id_pattern']

A link with an “id” that contains the text “id_pattern”

Pseudo Class Compatibility

An earlier version of this article references :contains, a powerful way to match elements that had a desired inner text block. Sadly, that feature is deprecated and not supported any longer by the W3C Standard. The current CSS Selectors level 3 standard is implemented by all major browsers; level 4 is in working draft mode. That standard document has a detailed list of selectors and pseudo-classes. For a more manageable list, look at the Mozilla Documentation which has a wonderful, complete list of psuedo classes. Drill into any pseudo-class and scroll down for specific information on compatibility in different browsers, including this example from the nth-child() pseudo-class.

selenium css

Sauce Labs - Selenium Testing on the Cloud

Sauce Labs takes the tests that might run on a desktop or plugged-in device and runs them on the cloud. Our platform helps developers test native & hybrid mobile and web applications across 2400+ browser / OS platforms, including iOS, Android & Mac OS X. Sauce supports Selenium, Appium and popular JavaScript unit testing frameworks, and integrates with all of the top programming languages, test frameworks and CI systems. With built-in video recording and screenshots of every test case, debugging tools, and secure tunneling for local or firewalled testing, Sauce makes running, debugging and scaling test suites quick and easy.

Written by

Matthew Heusser

Topics

SeleniumProgramming languagesGet Started/Guide