What tool can I use to test the :contains() CSS3 pseudo-class in a browser?
jQuery's selector engine also implements the :contains()
pseudo-class. It is to my knowledge that jQuery and Selenium implement it the same way.
I'm not sure how you would be able to test it on sites that don't make use of jQuery, but on sites that do, it's just a matter of firing up your browser's JavaScript console, and running jQuery selectors in the console.
Here's an example with viewing this very Stack Overflow question on Chrome's JavaScript console (you may get different results depending on whether you're logged in or not):
> $("#mainbar div[id]:contains('selector')").get() /* DOM objects with .get() */
[<div class="question" id="question">…</div>, <div id="answers">…</div>, <div id="answer-9007154" class="answer">…</div>, <div id="answer-9008184" class="answer">…</div>]
Having some trouble understanding why the :contains() pseudo class in CSS selectors works the way it does?
The usual thing I do when I find myself in this kind of trouble is to look at the spec.
As you probably know, there's none for :contains()
in the current spec and therefore you rely on undocumented, unspeced features of a particular browser/parser. It should work, but it doesn't - obviously the implementation wasn't complete. And now the pseudo-class is gone.
Could you go for an XPath instead? Either by internal Selenium methods or JavaScript. This XPath is the same as your CSS selector number 2:
//div[contains(text(),'My Header Title')]/following-sibling::div//input[contains(@class,'my_button')]
EDIT
After your comment showed me that we're talking about Selenium RC and, therefore, Sizzle, I dug deeper.
I took your example HTML, stripped it from the hidden and (seemingly) needless elements, and was left with this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="sizzle.js" type="text/javascript"></script>
</head>
<body class="bp">
<div class="container">
<div id="nav_bar">
<div id="user_bar">
<div id="wrapper" style="border-radius: 10px 10px 10px 10px;">
<div class="content">
<div class="breadcrumb_trail">
<div class="organizer_widget root_organizer" title="WorkflowItem" style="">
<div class="object organizer">
<div class="interior">
<form method="POST" enctype="multipart/form-data">
<div class="organizer_header view_header"> My Header Title </div>
<div class="organizer_widget" title="Citation" style="">
<div id="citation" class="object organizer">
<div class="clear"></div>
<div class="interior">
<div id="Citation___id_widget" class="widget_row numeric">
<div id="Citation___title_widget" class="widget_row string">
<div id="Citation___abbreviated_title_widget" class="widget_row string">
<div id="Citation___authors_display_string_widget" class="widget_row string">
<div id="Citation___language_widget" class="widget_row choice">
<div id="Citation___link_widget" class="widget_row link">
<input id="ba_citation" class="my_button" type="button" value="Break Associations" name="break_assoc_5376dcc81102a5d76bf829513b096be8f67e560d" />
<div class="clear"></div>
</div></div></div></div></div></div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
I downloaded the latest Sizzle and I obtained the version of Sizzle that is actually used by Selenium in the current release.
Turns out those two are very different.
E.g. the contains
implementation of current Sizzle:
return ~( elem.textContent || elem.innerText || getText( elem ) ).indexOf( match[3] );
and the implementation Selenium uses:
return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
I tried both implementations on my test document, results can be seen here (click to enlarge):
Current Sizzle - matches all perfectly
Selenium's Sizzle - matches 1 out of 4
The results say it all. Selenium uses an old version of Sizzle that is somehow imperfect in handling of :contains()
pseudo-class. The current Sizzle version doesn't suffer from the bug and is able to find all elements well.
Now, you can do any of these:
- File a Selenium bug.
- Use XPath as a workaround.
- Switch the
sizzle.js
file in your Selenium package.
How can I inspect and tweak :before and :after pseudo-elements in-browser?
In Chrome's Dev tools, the styles of a pseudo-element are visible in the panel:
Otherwise, you can also input the following line in the JavaScript console, and inspect the returned CSSStyleDeclaration
object:
getComputedStyle(document.querySelector('html > body'), ':before');
window.getComputedStyle
document.querySelector
How do I test CSS selectors in JavaScript?
The simplest traditional way by far is to not use JavaScript at all, and just set up a test page by hand where you can test selectors to your heart's content. The test cases you see on the Web (like the well-known CSS3.info Selectors Test) are really just souped-up versions hosted online.
But if you're looking for a JavaScript method, you can try the Selectors API. It's available in modern DOM implementations (IE8+ and others) and it provides a JavaScript frontend for querying the DOM for element nodes using CSS selectors, as well as testing CSS selectors natively supported by a given browser.
(For browsers that don't implement the Selectors API, you'll have to rely on jQuery, but remember that it provides support for a different set of selectors than what a browser supports as well as its own non-standard extensions which aren't found in the Selectors spec. An example of using jQuery with Chrome's JavaScript console to test a selector can be found here.)
Call querySelector()
or querySelectorAll()
depending on what you want to test, and check the return value (preferably in your browser's developer tools since you're just testing):
If matches are found, the former method returns the first
Element
matched while the latter returns all elements matched as aNodeList
.If nothing is found, the former returns
null
while the latter returns an emptyNodeList
.If the selector is invalid, an exception will be thrown which you can catch.
Here are some examples with the command editor (multiline) in Firebug's console on Firefox 10, tested on this very question:
Finding the first
h1
inbody
:var h1 = document.body.querySelector('h1');
console.log(h1);<h1 itemprop="name">
Querying descendants of that
h1
element we just found:var subnodes = h1.querySelectorAll('*');
console.log(subnodes[0]);<a class="question-hyperlink" href="/questions/9165859/how-do-i-test-css-selectors-in-javascript">
Testing the
:-moz-any()
pseudo-class in Firefox (:-webkit-any()
in Safari/Chrome):// This selector works identically to h1 > a, li > a
var hyperlinks = document.querySelectorAll(':-moz-any(h1, li) > a');
console.log(hyperlinks);[a#nav-questions /questions, a#nav-tags /tags, a#nav-users /users, a#nav-badges /badges, a#nav-unanswered /unanswered, a#nav-askquestion /questions/ask, a.question-hyperlink /questio...vascript]
Testing a nonexistent selector (that perhaps many of us wish did exist):
// :first-of-class doesn't exist!
var selector = 'div.answer:first-of-class';
try {
var firstAnswer = document.querySelector(selector);
console.log(firstAnswer);
} catch (e) {
console.log('Invalid selector: ' + selector);
}Invalid selector: div.answer:first-of-class
How to know which CSS style is applied and from where (javascript)?
It's the chrome standard for outlining focussed input elements. These are so called "user agent styles" which might be hidden in the inspector - in that case you have to check "Show user agent styles" in the settings first. You can overwrite this with
input:focus{
outline:0;
}
But be aware, that for usability reasons, it is highly recommended to indicate to the user that a certain element is currently in focus! So you should apply some focus styles which suit your theme.
For example you could do some slight inset boxshadow (and perhaps remove the initial text or at least make it more opaque):
#yith-s:focus{
outline:0;
box-shadow:inset 0 0 2px 1px #ccc;
}
Is pseudo-class selector :checked supported in Chrome and Firefox?
Simply put yes they both do.
However the problem you're having stems from the way in which certain browsers render form elements such as checkboxes and radio buttons.
You're unable to see your background color change when the input is selected because the browser is overwriting your customization with it's own default behavior.
Luckily the fix is simple for Chrome, Safari (Webkit) you just need to set an 'appearance:none;' value to wipe out all default styles and then add your own special blend.
Firefox (Gecko) has a known bug associated with rendering checkboxes and radios so you'll get limited use out of the appearance value.
Here's a link to the fiddle http://jsfiddle.net/traxp/
Hope that helps :)
<!DOCTYPE html>
<html>
<head>
<style>
input {
-webkit-appearance:none;
-moz-appearance:none;
appearance:none;
background:white;
width:20px;
height:20px;
border:2px solid grey;
border-radius:10px;
}
input:checked {
background:red;
}
</style>
</head>
<body>
<input type="radio" checked />
<input type="radio"/>
<input type="checkbox" checked />
<input type="checkbox" />
</body>
</html>
Why doesn't the selector h3:nth-child(1):contains('a') work?
:contains()
is not was going to be a CSS3 selector (thanks T.J. Crowder for the link), but it didn't make it, most likely because the way it works tends to lead to severe performance and over-selection issues. For example, if an element E
matches :contains()
for a given string argument, then all of its ancestors would also match; using it with a universal selector would lead to unexpected results with certain style properties, on top of being slow for the browser.
There is no other CSS selector that serves a purpose like :contains()
. So you'll have to find some other way, either by modifying your HTML or even by using jQuery's :contains()
, to achieve the effect you want:
Select an
h3
element
if it is the first child of its parent
and its text contains the letter 'a'.
For jQuery and Selenium RC users: :contains()
is implemented in the Sizzle selector engine used by jQuery, which is also used in Selenium RC (but not Selenium WebDriver). It works as described in this decade-old revision of the CSS3 spec, but again, due to how the spec describes it, you need to use it with care or it may lead to unexpected selections.
On a final note, h3:nth-child(1)
can be replaced with h3:first-child
, which as a CSS2 selector has better browser support.
How do I add / insert a before or after pseudo element into Chrome's Inspector?
This is the easiest way and the way I do it:
Inspect the element you want to add the ::before or ::after to by right clicking it and going to "Inspect Element".
Now in the Developer Tools Console, click on the plus sign icon aka. "New Style Rule". See the image below, the plus sign is next to the "Toggle Element State" button.
Next, you will be able to edit the selector so add ::before / ::after to it:
Now edit the content to whatever you like, i.e.
Like so:
.grp-row::before {
content: '> ';
}
That's all there is to it :)
Related Topics
How to Make Border Radius in Popup Chrome Extension
Cant Edit CSS Style Properties (Grayed Out & Blocked) in Chrome
Using HTML Attributes as CSS Property Values
Turn Off Alt Tags on Links with CSS
How to Increase The Width of The Tooltip in Bootstrap-Vue
CSS Column-Count Not Respected
CSS Select Second Level Elements
CSS: Is Transition: Left/Top Gpu Accelerated
Aggressive Caching: Do All Browsers Support Url Parameter for Updating
How to Place a Badge in Lower Right Corner of a "Media" in Bootstrap
CSS Pseudo Element (Triangle Outside The Tr) Position Misaligned When Scrollbar Appears
Use Full Width Excluding Overflow Scrollbar with "Position: Absolute"
Can Someone Please Explain CSS Media Queries
Django 1.8 Static Files Doesnt Work
Chrome Print Preview Doesn't Load @Media Only Print Font-Face