CSS Selectors - Difference Between and When to Use ">", "+" or " "

CSS Selectors - difference between and when to use , + or

In CSS these are called Combinators and means three different things:

  1. div > .class: is called Child selector and will select all elements that are direct children of a div and have the class .class.

  2. div .class: is called Descendant selectors and will select all elements inside a div and having the class .class.

  3. div + .class: is called Adjacent sibling selector and will match any element that immediately follows a div and have the class .class.

Example:

In the following example:

<div>
<p class="test">
<a href="#" class="test">
Testing link</a>
<img class="test"/>
</p>
<span class="test">A span</span>
</div>
<h4 class="test">A title</h4>
  • div > .test will match only <p> and <span> elements.
  • div .test will match <p>, <a>, <img> and <span> elements.
  • div + .test will match only <h4> element because it follows the <div> immediately.

Demo:

div .test {  background: yellow;}
div>.test { background: red;}
div+.test { background: green;}
<div>  <p class="test">    Pragraph    <a href="#" class="test">      link</a>    <img class="test" width="50px" height="50px" />  </p>  <span class="test">Span</span></div><h4 class="test">Title</h4>

What is difference between “+” and “~” selector in CSS?

+ will only select the first element that is immediately preceded by the former selector.

~ selector all the sibling preceded by the former selector.

.plusSelector + div {  background: red}.tiltSelector ~ div {  background: red}
<h3>+ Selector</h3><div class="example1">  <div class="plusSelector">test</div>  <div>test</div>  <div>test</div>  <div>test</div>  <div>test</div></div>
<h3>~ Selector</h3><div class="example1"> <div class="tiltSelector">test</div> <div>test</div> <div>test</div> <div>test</div> <div>test</div></div>

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.

CSS3 Selectors: + vs ~ and the opposite of ~?

Is my understanding of the difference correct?

Yes. Selectors L3 defines those two types of sibling combinators (emphasis mine):

  • Adjacent sibling combinator

    The adjacent sibling combinator is made of the "plus sign" (U+002B, +)
    character that separates two sequences of simple selectors. The
    elements represented by the two sequences share the same parent in the
    document tree and the element represented by the first sequence
    immediately precedes the element represented by the second one.

  • General sibling combinator

    The general sibling combinator is made of the "tilde" (U+007E, ~)
    character that separates two sequences of simple selectors. The
    elements represented by the two sequences share the same parent in the
    document tree and the element represented by the first sequence
    precedes (not necessarily immediately) the element represented by the second one.

How can I select every element placed before (or immediately before) another element?

As explained in Is there a previous sibling selector?, it's not possible to do that with Selectors L3. Selectors L4 may introduce some way to do it, but probably it will only be available in JS (e.g. through querySelector) but not in CSS stylesheets because of performance reasons.

In CSS what is the difference between . and # when declaring a set of styles?

Yes, they are different...

# is an id selector, used to target a single specific element with a unique id, but . is a class selector used to target multiple elements with a particular class. To put it another way:

  • #foo {} will style the single element declared with an attribute id="foo"
  • .foo {} will style all elements with an attribute class="foo" (you can have multiple classes assigned to an element too, just separate them with spaces, e.g. class="foo bar")

Typical uses

Generally speaking, you use # for styling something you know is only going to appear once, for example, things like high level layout divs such sidebars, banner areas etc.

Classes are used where the style is repeated, e.g. say you head a special form of header for error messages, you could create a style h1.error {} which would only apply to <h1 class="error">

Specificity

Another aspect where selectors differ is in their specificity - an id selector is deemed to be more specific than class selector. This means that where styles conflict on an element, the ones defined with the more specific selector will override less specific selectors. For example, given <div id="sidebar" class="box"> any rules for #sidebar with override conflicting rules for .box

Learn more about CSS selectors

See Selectutorial for more great primers on CSS selectors - they are incredibly powerful, and if your conception is simply that "# is used for DIVs" you'd do well to read up on exactly how to use CSS more effectively.

EDIT: Looks like Selectutorial might have gone to the big website in the sky, so try this archive link instead.

How is the greater than or character used in CSS?

It's a CSS child selector. P > SPAN means applying the style that follows to all SPAN tags that are children of a P tag.

Note that "child" means "immediate descendant", not just any descendant. P SPAN is a descendant selector, applying the style that follows to all SPAN tags that are children of a P tag or recursively children of any other tag that is a child/descendant of a P tag. P > SPAN only applies to SPAN tags that are children of a P tag.

CSS '' selector; what is it?

> selects immediate children

For example, if you have nested divs like such:

<div class='outer'>
<div class="middle">
<div class="inner">...</div>
</div>
<div class="middle">
<div class="inner">...</div>
</div>
</div>

and you declare a css rule in your stylesheet like such:

.outer > div {
...
}

your rules will apply only to those divs that have a class of "middle" since those divs are direct descendants (immediate children) of elements with class "outer" (unless, of course, you declare other, more specific rules overriding these rules). See fiddle.

div {  border: 1px solid black;  padding: 10px;}.outer > div {  border: 1px solid orange;}
<div class='outer'>  div.outer - This is the parent.  <div class="middle">    div.middle - This is an immediate child of "outer". This will receive the orange border.    <div class="inner">div.inner - This is an immediate child of "middle". This will not receive the orange border.</div>  </div>  <div class="middle">    div.middle - This is an immediate child of "outer". This will receive the orange border.    <div class="inner">div.inner - This is an immediate child of "middle". This will not receive the orange border.</div>  </div></div>
<p>Without Words</p>
<div class='outer'> <div class="middle"> <div class="inner">...</div> </div> <div class="middle"> <div class="inner">...</div> </div></div>

What does the (greater-than sign) CSS selector mean?

> is the child combinator, sometimes mistakenly called the direct descendant combinator.1

That means the selector div > p.some_class only matches paragraphs of .some_class that are nested directly inside a div, and not any paragraphs that are nested further within. This implies that every element matching div > p.some_class necessarily also matches div p.some_class, with the descendant combinator (space), so the two are understandably often confused.

An illustration comparing the child combinator with the descendant combinator:

div > p.some_class { 
background: yellow;
}

div p.some_class {
color: red;
}
<div>
<p class="some_class">Some text here</p> <!-- [1] div > p.some_class, div p.some_class -->
<blockquote>
<p class="some_class">More text here</p> <!-- [2] div p.some_class -->
</blockquote>
</div>

CSS use of '' (greater than) and '*' (star)

Your understanding is correct for them individually. When combined, it means all elements under the specified element (.seq-canvas in your example).

Here is a test. Notice that * alone will change the font size for everything, while > * will only change the color of the children of .seq-canvas:

#sequence .seq-canvas > *  {color: blue;}
* { font-size: 10px; }
<p>I'm outside</p><div id="sequence"><ul class="seq-canvas">  <li>This must be blue</li>  <li>So is this</li>  <li>    <ul>      <li>But is this blue?</li>    </ul> <li>This must also be blue...</li> <li>How about <span>SPANS</span> - will they be blue as well?</li> <div>Or let's say that I put a div in here (even    though I know it's not right), does this then    mean that this is blue? </div></ul></div><p>I'm also outside</p>

Difference between Scrapy selectors a::text and a ::text

Interesting observation! I spent the past couple of hours investigating this and it turns out, there's a lot more to it than meets the eye.

If you're coming from CSS, you'd probably expect to write a::text in much the same way you'd write a::first-line, a::first-letter, a::before or a::after. No surprises there.

On the other hand, standard selector syntax would suggest that a ::text matches the ::text pseudo-element of a descendant of the a element, making it equivalent to a *::text. However, .product-list-product-wrapper .product-name a doesn't have any child elements, so by rights, a ::text is supposed to match nothing. The fact that it does match suggests that Scrapy is not following the grammar.

Scrapy uses Parsel (itself based on cssselect) to translate selectors into XPath, which is where ::text comes from. With that in mind, let's examine how Parsel implements ::text:

>>> from parsel import css2xpath
>>> css2xpath('a::text')
'descendant-or-self::a/text()'
>>> css2xpath('a ::text')
'descendant-or-self::a/descendant-or-self::text()'

So, like cssselect, anything that follows a descendant combinator is translated into a descendant-or-self axis, but because text nodes are proper children of element nodes in the DOM, ::text is treated as a standalone node and converted directly to text(), which, with the descendant-or-self axis, matches any text node that is a descendant of an a element, just as a/text() matches any text node child of an a element (a child is also a descendant).

Egregiously, this happens even when you add an explicit * to the selector:

>>> css2xpath('a *::text')
'descendant-or-self::a/descendant-or-self::text()'

However, the use of the descendant-or-self axis means that a ::text can match all text nodes in the a element, including those in other elements nested within the a. In the following example, a ::text will match two text nodes: 'Link ' followed by 'text':

<a href="https://example.com">Link <span>text</span></a>

So while Scrapy's implementation of ::text is an egregious violation of the Selectors grammar, it seems to have been done this way very much intentionally.

In fact, Scrapy's other pseudo-element ::attr()1 behaves similarly. The following selectors all match the id attribute node belonging to the div element when it does not have any descendant elements:

>>> css2xpath('div::attr(id)')
'descendant-or-self::div/@id'
>>> css2xpath('div ::attr(id)')
'descendant-or-self::div/descendant-or-self::*/@id'
>>> css2xpath('div *::attr(id)')
'descendant-or-self::div/descendant-or-self::*/@id'

... but div ::attr(id) and div *::attr(id) will match all id attribute nodes within the div's descendants along with its own id attribute, such as in the following example:

<div id="parent"><p id="child"></p></div>

This, of course, is a much less plausible use case, so one has to wonder if this was an unintentional side effect of the implementation of ::text.

Compare the pseudo-element selectors to one that substitutes any simple selector for the pseudo-element:

>>> css2xpath('a [href]')
'descendant-or-self::a/descendant-or-self::*/*[@href]'

This correctly translates the descendant combinator to descendant-or-self::*/* with an additional implicit child axis, ensuring that the [@href] predicate is never tested on the a element.

If you're new to XPath, Selectors, or even Scrapy, this may all seem very confusing and overwhelming. So here's a summary of when to use one selector over the other:

  • Use a::text if your a element contains only text, or if you're only interested in the top-level text nodes of this a element and not its nested elements.

  • Use a ::text if your a element contains nested elements and you want to extract all the text nodes within this a element.

    While you can use a ::text if your a element contains only text, its syntax is confusing, so for the sake of consistency, use a::text instead.


1 On an interesting note, ::attr() appears in the (abandoned as of 2021) Non-element Selectors spec, where as you'd expect it behaves consistently with the Selectors grammar, making its behavior in Scrapy inconsistent with the spec. ::text on the other hand is conspicuously missing from the spec; based on this answer, I think you can make a reasonable guess as to why.



Related Topics



Leave a reply



Submit