Whitespace in CSS Selectors

Whitespace in CSS selectors

All of your conclusions are correct. There are nuances with regard to whitespace in attribute selectors, covered in my answer to this question.

All the exact rules of where whitespace may or may not appear are covered in the grammar. For the purposes of the grammar, the "contextual characters (such as + and >)" that you refer to are officially known as combinators. (The term "contextual selector" was first used in CSS1 but hasn't appeared since.)

Remember in addition that any number of contiguous whitespace characters that separate two simple selectors is considered a descendant combinator, which is in fact one reason why whitespace isn't "allowed" around the delimiters for pseudo-elements, pseudo-classes, attribute selectors, class selectors and ID selectors — because it has significance and therefore its presence alters the meaning of the selector.

CSS selector for empty or whitespace

Lots of people missing the point of this question, which I've addressed in the following exposition, but for those just looking for the answer, I'm mirroring the last paragraph here:

Selectors 4 now redefines :empty to include elements that contain only whitespace. This was originally proposed as a separate pseudo-class :blank but was recently retconned into :empty after it was determined that it was safe to do so without too many sites depending on the original behavior. Browsers will need to update their implementations of :empty in order to conform to Selectors 4. If you need to support older browsers, you will have to go through the hassle of marking elements containing only whitespace or pruning the whitespace before or after the fact.


While the question depicts a <p> element containing a handful of regular space characters, which seems like an oversight, it is far more common to see markup where elements contain only whitespace in the form of indentation and blank lines, such as:

<ul class="items">
<li class="item">
<div>
<!-- Some complex structure of elements -->
</div>
</li>
<li class="item">
</li> <!-- Empty, except for a single line break and
indentation preceding the end tag -->
</ul>

Some elements, like <li> in the above example as well as <p>, have optional end tags, which can cause unintended side effects in DOM processing as well in the presence of inter-element whitespace. For example, the following two <ul> elements don't produce equivalent node trees, in particular the first one does not result in a li:empty in Selectors level 3:

li:empty::before { content: '(empty)'; font-style: italic; color: #999; }
<ul>  <li></ul><ul>  <li></li></ul>

White space and selectors

For this cases I prefer using css selectors because of its minimalistic syntax:

response.css("p.text-nowrap.hidden-xs::text")

Also google chrome developer tools displays css selectors when you observing html code
This makes scraper development much easier
google developer tools

What are the rules around whitespace in attribute selectors?

The rules on whitespace in attribute selectors are stated in the grammar. Here's the Selectors 3 production for attribute selectors (some tokens substituted with their string equivalents for illustration; S* represents 0 or more whitespace characters):

attrib
: '[' S* [ namespace_prefix ]? IDENT S*
[ [ '^=' |
'$=' |
'*=' |
'=' |
'~=' |
'|=' ] S* [ IDENT | STRING ] S*
]? ']'
;

Of course, the grammar isn't terribly useful to someone looking to understand how to write attribute selectors, as it's intended for someone who's implementing a selector engine.

Here's a plain-English explanation:

Whitespace before the attribute selector

This isn't covered in the above production, but the first obvious rule is that if you're attaching an attribute selector to another simple selector or a pseudo-element, don't use a space:

a[href]::after

If you do, the space is treated as a descendant combinator instead, with the universal selector implied on the attribute selector and anything that may follow it. In other words, these selectors are equivalent to each other, but different from the above:

a [href] ::after
a *[href] *::after

Whitespace inside the attribute selector

Whether you have any whitespace within the brackets and around the comparison operator doesn't matter; I find that browsers seem to treat them as if they weren't there (but I haven't tested extensively). These are all valid according to the grammar and, as far as I've seen, work in all modern browsers:

a[href]
a[ href ]
a[ href="http://stackoverflow.com" ]
a[href ^= "http://"]
a[ href ^= "http://" ]

Whitespace is not allowed between the ^ (or other symbol) and = as these are treated as a single token, and tokens cannot be broken apart.

If IE7 and IE8 implement the grammar correctly, they should be able to handle them all as well.

If a namespace prefix is used, whitespace is not allowed between the prefix and the attribute name.

These are incorrect:

unit[sh| quantity]
unit[ sh| quantity="200" ]
unit[sh| quantity = "200"]

These are correct:

unit[sh|quantity]
unit[ sh|quantity="200" ]
unit[sh|quantity = "200"]

Whitespace within the attribute value

But notice the quotes around the attribute values above; if you leave them out, and you try to select something whose attribute has spaces in its value you have a syntax error.

This is incorrect:

div[class=one two]

This is correct:

div[class="one two"]

This is because an unquoted attribute value is treated as an identifier, which doesn't include whitespace (for obvious reasons), whereas a quoted value is treated as a string. See this spec for more details.

To prevent such errors, I strongly recommend always quoting attribute values, whether in HTML, XHTML (required), XML (required), CSS or jQuery (once required).

Whitespace after the attribute value

As of Selectors 4 (following the original publication of this answer), attribute selectors can accept flags in the form of an identifier appearing after the attribute value. Two flags have been defined pertaining to character case, one for case-insensitive matching:

div[data-foo="bar" i]

And one for case-sensitive matching (whose addition I had a part in, albeit by proxy of the WHATWG):

ol[type="A" s]
ol[type="a" s]

The grammar has been updated thus:

attrib
: '[' S* attrib_name ']'
| '[' S* attrib_name attrib_match [ IDENT | STRING ] S* attrib_flags? ']'
;

attrib_name
: wqname_prefix? IDENT S*

attrib_match
: [ '=' |
PREFIX-MATCH |
SUFFIX-MATCH |
SUBSTRING-MATCH |
INCLUDE-MATCH |
DASH-MATCH
] S*

attrib_flags
: IDENT S*

In plain English: if the attribute value is not quoted (i.e. it is an identifier), whitespace between it and attrib_flags is required; otherwise, if the attribute value is quoted then whitespace is optional, but strongly recommended for the sake of readability. Whitespace between attrib_flags and the closing bracket is optional as always.

What is the difference between '' and a space in CSS selectors?

A > B will only select B that are direct children to A (that is, there are no other elements inbetween).

A B will select any B that are inside A, even if there are other elements between them.

Targeting a class value that begins with a space

Any leading or trailing spaces in the value of a class attribute are meaningless for targeting purposes. This: class=" example" is equivalent to this: class="example".

There is no need for a special selector that factors in the space.

From the HTML 5 spec:

2.4.7 Space-separated
tokens

A string containing a set of space-separated tokens may have leading
or trailing space characters.

Space characters are necessary, however, for separating multiple values in a class attribute.

3.2.5.7 The class
attribute

The attribute, if specified, must have a value that is a set of
space-separated tokens representing the various classes that the
element belongs to.

How to select classes with spaces

As Zepplock says, that's actually two classes in a single attribute: boolean and optional. The space is not part of a class name; it acts as the separator.

These three selectors will all match it:

.boolean
.optional
.boolean.optional

The last selector only picks up this element as it has both classes.

You never include a space when chaining class selectors, not even like this:

.boolean .optional

As that selects .optional elements that are contained within separate .boolean elements.

Use a space or greater than sign in CSS selector?

No they are completely different, using > selects a child element whereas using a space will select a nested element at any level.

For example…

Using /space in the selector…

<div class="welcome">
<section>
<div>This will be selected</div>
</section>
<div>This will be selected as well</div>
</div>

So here, the selector having space will target the div at any nested level of the parent element.

Demo (Using /space)

.welcome div {
font-size: 20px;
color: #f00;
}

Using >

<div class="welcome">
<section>
<div>This won't be selected</div>
</section>
<div>This will be selected</div>
</div>

Whereas here, the selector will target your div which is a child of the element having .welcome but it won't select the div which is nested inside section tag as it is a grandchild (but not a child) of the outer div.

Demo 2 (Using >)

.welcome > div {
font-size: 20px;
color: #f00;
}

From MDN : (For )

The combinator (that's meant to represent a space, or more
properly one or more whitespace characters) combines two selectors
such that the combined selector matches only those elements matching
the second selector for which there is an ancestor element matching
the first selector. Descendant selectors are similar to child
selectors, but they do not require that the relationship between
matched elements be strictly parent-child.

From MDN : (For >)

The > combinator separates two selectors and matches only those
elements matched by the second selector that are direct children of
elements matched by the first. By contrast, when two selectors are
combined with the descendant selector, the combined selector
expression matches those elements matched by the second selector for
which there exists an ancestor element matched by the first selector,
regardless of the number of "hops" up the DOM.



Related Topics



Leave a reply



Submit