How to target only the first and the last match of a selector in CSS?
Example (This is only an example, general solution needed) to illustrate my requirement:
<style>
main>article p:first { /* to select the first p anywhere under article */ }
main>article p:last { /* to select the last p anywhere under article */ }
</style>
<main>
<article>
<section>
<p>SHOULD be selected as first element</p>
<p>SHOULD NOT be selected</p>
</section>
<ul>
<li><p>SHOULD NOT be selected</p></li>
<li><p>SHOULD NOT be selected</p></li>
</ul>
<p>SHOULD be selected as last element</p>
</article>
</main>
The DOM under <article> might have <p> as children. <p>s (including the first and the last ones) are not required to be direct children of <article> though and can have any set of parents. Are there any not-necessarily-elegant CSS rule to select only the first and the last <p>?
JavaScript as indicated by tags of this question is not allowed, but for means of demonstration purposes… following code does exactly what I want to achieve:
var els = document.querySelectorAll('main>article p'),
first = els[0],
last = els[els.length - 1];
Now what I've already tried using and what did not work out for me:
any selector combination with :first-child, :last-child
There's no guarantee of any structure which one could use to make a fail-proof selector which would select only the first and the last p which is a (not-necessarily-direct) chilren of <article>.
any selector combination with :first-of-type, :last-of-type
Because this would also select first/last article *>p
In particular I've tried main>article p:first-of-type and main>article p:first-of-type.
overriding with ~ and/or +
EDITS
The DOM will not necessarily will be the same as given in example – it's just an example after all.
Both first and last <p> is a children of article, but not always a direct children. That means there may be other elements between thne first/last <p> and parent <article>.
Just remembered jQuery. $('main>article p:first') and $('main>article p:last') from jQuery would do exactly what I want, but I'm restricted to CSS.
You can use the first-of-type/last-of type you can select the first/last child of a parent with an element type
p:first-of-type
or
p:last-of-type
That will select the first or last paragraph element of that is a child of the parent element
p:first-child
or
p:last-child
Similar to last-of-type
W3 schools has some good information on this also
http://www.w3schools.com/cssref/css_selectors.asp
Unfortunately it is not possible to do what you want without using JavaScript (as shown in your original question). There is currently no global nth-of-class selector available. I believe it is because the styles for elements are calculated in one pass. There's no real way for the selectors to be aware of elements in other branches of the DOM tree.
Much like how you can use the adjacent sibling (+) and general sibling (~) combinators to apply styles that come after a certain selector, but not before it.
this solve the issue:
article section > p:first-child {
color: red;
}
article > p:last-child{
color: red;
}
FIDDLE
or this:
main p:first-child {
color: red;
}
main article > p:last-child{
color: red;
}
article > ul p{color:black !important;}
FIDDLE
Related
I would like to apply margin-bottom, only if there is another paragraph directly after the other one. I know there is a way to select the first paragraph if the next one is also a paragraph, but I unfortunately forgot how.
I thought with the plus symbol: #blog .blog-post .entry p+p.
But this will result in add margin-bottom to the last paragraph.
You can use nth-child. For more details see here: https://css-tricks.com/how-nth-child-works/
To add more detail, badically you would do something like this:
p:nth-child(2) { }
Or apply it to a div if the 2nd p is a child of div. More details on child selection
When E+F selector used. The target is F. Just add margin-top instead of margin-buttom
I would use :first-child with the sibling selector +. Optionally use :not() if you want to prevent the last paragraph from being selected: :not(:last-child). Most of these CSS features fall under CSS3 Selectors, and the only browser that you might have issues with is IE8 (if you're even supporting it).
Here's an example:
<section>
<p>One</p>
<p>Two</p>
<p>Three</p>
</section>
section p:first-child + p {
background-color: lime;
}
https://jsfiddle.net/wo26k1vb/
Is it possible to write a CSS rule to select the first child of an element without a specific class?
example:
<div>
<span class="common-class ignore"></span>
<span class="common-class ignore"></span>
<span class="common-class"></span>
<span class="common-class"></span>
</div>
In this case I would like to select the first span without class ignore.
I tried this, but didn't seem to work:
.common-class:first-child:not(.ignore) {
...some rules...
}
UPDATE:
If I add a class to the parent div named parent-class, a modified version of the selector suggested by Jukka works except when the first span with class ignore comes after the first one without. The above-mentioned selector is the following:
.parent-class > .common-class.ignore + .common-class:not(.ignore) {
...some rules...
}
This question is similar to CSS selector for first element with class, except for the first element without a class. As mentioned, :first-child:not(.ignore) represents an element that is the first child of its parent and does not have the class "ignore", not the first child matching the rest of the selector.
You can use the overriding technique with a sibling combinator that I've described in my answer to the linked question, replacing the class selector with the :not() pseudo-class containing a class selector:
.common-class:not(.ignore) {
/* Every span without class .ignore, including the first */
}
.common-class:not(.ignore) ~ .common-class:not(.ignore) {
/* Revert above declarations for every such element after the first */
}
This selects all span with a .common-class and without an .ignore class.
span.common-class:not(.ignore) {
color: blue;
}
But, because we want to select only the first one, you can override the siblings that follow with the ~ selector.
span.common-class:not(.ignore) ~ span {
color: black; /* or color: inherit; */
}
jsBin demo
If you are already using jQuery, this can also be done with
$("span.common-class:not(.ignore):first").css('color', 'blue');
No, it is not possible. The selector :first-child:not(.ignore) selects an element that is the first child of its parent and does not belong to class ignore. There is no “first of class” selector and no “first not of class” selector either.
You could use the selector .ignore + :not(.ignore), but it matches any element that is not in class ignore and immediately follows an element in that class. But it matches too much, not just the first one of such elements. Depending on the markup structure, this selector might still be suitable in a particular situation, even though it is not an answer to the general question asked.
You don't have to select the div using a class. What about other css solutions like nth-child etc.? Of course, this requires the knowledge of a document structure.
Here is the official documentation for the CSS3 :not() pseudo-class:
http://www.w3.org/TR/css3-selectors/#negation
and the proposed CSS Selectors Level 4 enhancement:
http://dev.w3.org/csswg/selectors4/#negation
I've been searching the implementation and browser support for :not(), but the only examples I found were with a single element or with a direct child of an element, e.g.:
div *:not(p) { color: red; }
The example above works when <p> is a direct child of <div>, but it does not work when <p> is a more distant descendant of <div>.
div :not(p) {
color: red;
}
<div>
<ul>
<li>This is red</li>
</ul>
<p>This is NOT</p>
<blockquote><p>This is red but is not supposed to be!</p></blockquote>
</div>
If the answer is in the official documentation above, then I didn't find/understand it. As I said, I have searched this site and the web but couldn't find any discussion about the support or lack thereof of :not() as grand-children of another element.
Is this supposed to work like I think it should?
Is this supposed to work like I think it should?
No, the behavior you're seeing is correct.
In your last example, although the <blockquote> contains a <p>, it's the <blockquote> itself that's matching *:not(p), as well as the condition that it must be a descendant of the <div>, which it is. The style is applied only to the <blockquote>, but it is then inherited by the <p> inside it.
The <p> element itself still counts against the negation, so the <p> itself is still being excluded from your selector. It's just inheriting the text color from its parent, the <blockquote> element.
Even if none of its relatively close ancestors matched the selector, you have elements like html and body to worry about as well — although you could probably just tack on a body selector in the very beginning:
body div...
This is why I often strongly advise against using the :not() selector for filtering descendants, especially when not qualified with a type selector (like div in your example). It doesn't work the way most people expect it to, and the use of inherited properties like color only serves to compound the problem, on top of making it even more confusing for authors. See my answers to these other questions for more examples:
Why doesn't this CSS :not() declaration filter down?
CSS negation pseudo-class :not() for parent/ancestor elements
The solution to the problem described is to simply apply a different color to <p> elements. You won't be able to simply exclude them with a selector because of inheritance:
/* Apply to div and let all its descendants inherit */
div {
color: red;
}
/* Remove it from div p */
div p {
color: black;
}
On Selectors Level 4: yes, :not() has indeed been enhanced to accept full complex selectors that contain combinators. Essentially, this means (once browsers begin implementing it) you will be able to write the following selector and have it do exactly what you want:
p:not(div p) {
color: red;
}
In case anyone is interested, this works in jQuery today.
The color is assigned to the blockquote, and is then inherited by the p.
:not(p) just makes it so that the styles are not directly applied. They are still inherited though.
I have a HTML structure:
<div class="home-view">
<div class="view-header">Header</div>
<div class="view-content">Content</div>
</div>
And I would like to style the first item of home-view. In this case, it's view-header, but sometimes there is no header and the view-content will be the first item in home-view.
The first item in home-view should get some styles.
I've been trying with .home-view:first-child, but no luck there since it's children have different class-names (I think). Any advice?
.home-view > *:first-child { background-color:red; }
...will select the first sub element of any type that is a first child.
Since both elements are divs you could specify the first div within .home-view
.home-view div:first-child{
background: red;
}
Working Example: http://jsfiddle.net/7cNZS/
.home-view > div:first-of-type{ background-color:red; }
The :first-of-type selector matches every element that is the first child, of a particular type, of its parent.
More....
You responded to the previous answers that you only wanted the direct child elements to be styled, and not child elements below them.
So I'll adapt those answers and give you an answer that meets that requirement:
.home-view>div:first-child{
background: red;
}
The difference here is the > selector between .home-view and div instead of a space. This forces it to only select immediate children of .home-view, and not divs that are further down the tree, whereas a space between them would tell it to select any matching child elements down the tree.
Hope that helps.
Try this:
$('.home-view').children().eq(0);
I have a table with some rows:
<table>
<tr class="even"><td>tr0</td></tr>
<tr><td>tr1</td></tr>
<tr class="even"><td>tr2</td></tr>
</table>
I have a CSS rule (rule1) for even rows:
.even{
background-color: blue;
}
I have another rule (rule2) for override the bgcolor of any row:
.override, .override.even{
background-color: green;
}
The weird thing is in IE9 all even rows (with no override class) are green!
Developer tools shows this for even rows:
In these two conditions IE do the job correctly:
If I rewrite rule2 like this:
.override, .override .even{ ... }
If I move rule2 above rule1:
.override, .override.even{ ... }
.even { ... }
Question is what's the difference between .override.even and .override .even?
EDIT:
Thanks for replies. Another question which I forgot to ask is why IE shows the even rows green?
Spacing in between class specifiers means a ascendant -> descendant relationship.
The rule:
.test .heading { font-weight: bold; }
Would apply to the <p> element here:
<span class="test"><p class="heading">Something</p></span>
The lack of space means that the element must have both classes for the rule to apply.
The rule:
.heading.major { color: blue; }
Would apply to the <p> element here:
<p class="heading major">Major heading</p>
Both answers are right, but they don't explain, why IE shows both rows green.
It's because IE has "standard" and "quirks" mode. To make multiple classes selectors work, you need to use proper DOCTYPE at the beginning of the file.
You are in "quirks" mode now and IE don't support multiple selectors, it sees only latest class. So it sees this and rows are green:
.even {
background-color: blue;
}
.override, .even {
background-color: green;
}
Put
<!DOCTYPE html>
(or another DOCTYPE) at the beginning of the file and both rows are going to be blue as expected.
See the W3C [CSS] Selector (Level 3) "Recommendation":
.override .even is two simple selectors separated by a space (which is the descendant combinator, CSS is whitespace-sensitive):
At times, authors may want selectors to describe an element that is the descendant of another element in the document tree (e.g., "an EM element that is contained within an H1 element"). Descendant combinators express such a relationship. A descendant combinator is whitespace that separates two sequences of simple selectors. A selector of the form "A B" represents an element B that is an arbitrary descendant of some ancestor element A.
This selector will match elements that have the class even if and only if there exists an ancestor -- not necessarily the parent! -- element with the class override. (Unlike characters in some movies, an element is never it's own ancestor ;-)
.override.even is a simple selector sequence:
A sequence of simple selectors is a chain of simple selectors that are not separated by a combinator. It always begins with a type selector or a universal selector. No other type selector or universal selector is allowed in the sequence.
A simple selector sequence is evaluated as the conjunction of the individual simple selectors applied to the same element: that is, it will only match elements with both the override and even classes applied.
Happy coding.
.override .even is interpreted as "some element with an 'override' class, with another element with a .even class nested within. It's basically the same as ul li, but applying to CSS classes.
override.even is interpreted as "some single element with BOTH override AND even classes".
<div class="class1">
<div class="class2">
<p>test1</p>
</div>
</div>
If this type coded added than use space between to class like .class1 .class2
<div class="class1 class2">
<p>test2</p>
</div>
If this type coded added than don't use space between to class like .class1.class2