Using CSS selectors and combinators (*, ~, >, <, +) - css

I am working with CSS selector symbols to create complex element selectors. I am currently stuck with selector symbols which I cannot create combinations with.
For instance, I am trying to create: body and children elements of body that are not of #foo id using
body > *:not(#main-div) + body
but the combinations of the elements don't work. I have used each of the selectors individually at least once before, but never tried their combinations. This feature seemed very useful to me and so I wanted to know whether it is possible to create combinations of these selector symbols. If yes, what is the correct syntax to follow?

In order to apply styles to both the body and all immediate children of the body (excluding the #main-div) element, you should use the following selector list:
body,
body > *:not(#main-div) {
...
}
Commas should be used to group selectors into selector lists. The + is an adjacent sibling combinator.
The Mozilla Developer Docs has a great primer on forming CSS selectors and rulesets here: https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors

This feature seemed very useful to me and so I wanted to know whether it is possible to create combinations of these selector symbols. If yes, what is the correct syntax to follow?
Yes it is possible but i think the syntax you are using is incorrect instead you must use
body > :not(#main-div),body
And according to me there's no use of * and + because by even not mentioning * it will exclude all the id's that are #main-div and + is only used when the element is right after the current element.

Related

Why does putting comma selectors inside a space selector break the parent?

I am used to using descendant space selectors and comma selectors. I have ids around larger sets of elements in order to manipulate them easier in jquery and css.
So I tried something like this:
#parent_id input, textarea
{
width: 100px;
}
So when I do this, my expectation is that this effect will occur on input AND textarea inside the #parent_id. Instead, this disqualifies parent_id and just selects all input, textarea. Why? And how can I avoid this, aside from making them separate.
In CSS, rules have the form:
selector0 [, selectorN ]*
{
property0: value0[,
property1: value1]*
}
So the comma , is used to separate different selectors for the same property set. For example, if you wanted two radically different selectors for the same property set.
Selectors in CSS must be fully-qualified, there is no contextual-sensitivity - this is partly because CSS is designed to be forward-compatible: browsers are instructed to try each and every selector in a rule independently, so browsers gracefully-degrade when they encounter new selector syntax they don't support.
To get the effect you want just type more :)
#parent_id input,
#parent_id textarea {
width: 100px;
}
Note that there is a proposed/experimental :matches() selector function which works as a logical OR operator in selectors, it's in the CSS Level 4 Selectors specification (currently in a working-draft state, as of 2016-05-04: https://drafts.csswg.org/selectors-4/ ).
The matches-any pseudo-class, :matches(), is a functional pseudo-class taking a selector list as its argument. It represents an element that is represented by its argument.
So in your case it would be:
#parent_id :matches( input, textarea ) {
width: 100px;
}
But I don't think this usage is really that better, it's less obvious and requires greater knowledge of CSS.

Can the Universal selector * be replaced by :lang?

The universal selector asterisk (*) is unique in that it matches a single element of any type.
So if I have different elements within a div and I want to select them all with one selector, I can either add a class to all the inner elements (something like .parent .class {}) or I can use the universal selector (.parent * {})
Then I saw the spec for the :lang pseudo element (particularly the end):
Note the difference between [lang|=xx] and :lang(xx). In this HTML
example, only the BODY matches [lang|=fr] (because it has a LANG
attribute) but both the BODY and the P match :lang(fr) (because both
are in French).
<body lang=fr>
<p>Je suis Français.</p>
</body>
Which means that all elements within an element targeted by :lang selector are also targeted. (Wow!)
So let's say I wanted to add a border to all the elements within a div - instead of the selector div * {} I could theoretically use :lang
Here's a demo
As far as I can tell, the only difference is that the :lang selector selects the parent as well as all the children (and of course there's the technical difference the :lang has greater specificity)....however
if the :lang selector was applied in a semantic way that it included the whole document - with the lang attribute on the html element - I don't think that the above difference would matter.
So basically my question is:
Assuming that my html element has the attribute lang="en":
Can I replace code which uses the universal selector such like:
* { box-sizing: border-box; }
with:
:lang(en) {
box-sizing: border-box;
}
The code seems to work (DEMO), and it seems to be semantic as well, but I'm wondering if there are certain reasons/cons to the above technique.
Can the Universal selector * be replaced by :lang?
No, because you cannot write a selector using :lang() that is guaranteed to match all elements unless you assume all elements in the document will always be in the same language.1
If you're going to assume that all elements are in the same language, then using the :lang() pseudo is pretty pointless, since the whole point of that pseudo-class is to be able to distinguish parts of the document that differ in their content language.
Also note that the compound selector :lang(en) (consisting of just that one simple selector) is equivalent to *:lang(en). It is essentially the * selector with an additional qualification of a pseudo-class. You are not avoiding the use * by replacing it with :lang().
1 Selectors 4 allows a selector like :lang('*') to be written that matches elements in any language (which, again, is pointless if you don't care what language an element is in!), but this assumes the document even has content language semantics built into it. It is not clear if :lang() will work at all in a document lacking such semantics.

Using CSS pseudo and attribute selectors together

Because of a bug in webkit browsers, you can't use attribute and :before/:after classes by default.
The fix doesn't seem to have any effect when using nth-last-of-type selector.
Here's what I'm doing:
.left[class^='col']:nth-last-of-type{
margin-right: 0 !important;
}
Just wanted to check and see if I'm not overlooking something simple.
Your :nth-last-of-type syntax is a bit off — it's either :last-of-type or functional :nth-last-of-type() with a formula an+b as an argument.
The pseudo-classes pertaining to "type" refer to the element type, represented by its tag name. It does not mean "the last element matching the rest of this selector".
If, for example, the last element matching .left[class^='col'] is not the last span element, then :last-of-type will not match. You'll have to modify your HTML to either segregate those span elements from others, or add a class to the last such element, before you can target it with a selector.
WebKit does not have any issues with pseudo-classes and attribute selectors that I'm aware of (or if it did, those issues have long been fixed). It does have issues with pseudo-elements, which I address here, where the fiddle link originates.

nesting inside css :not() selectors

Is it possible to have nested values inside the :not selector? For eg:
:not(div > div)
Whenever I tried it, it does not seem to work.
Perhaps you need to use it another way which I have not figured out?
So far, in all the examples I see, you can only use one value inside this selector.
:not() only accepts one simple selector at a time; this is mentioned in the Selectors 3 spec:
The negation pseudo-class, :not(X), is a functional notation taking a simple selector (excluding the negation pseudo-class itself) as an argument. It represents an element that is not represented by its argument.
The simple selectors in your example would be the two div tokens that you have. Other simple selectors include class selectors, ID selectors, attribute selectors and pseudo-classes. It does not accept more than one simple selector, nor does it accept combinators like > or space.
Depending on which elements you're trying to select exactly, there may not be a way to exclude div > div:
If you only want to select elements that are children of a div, that are themselves not div, use this instead:
div > :not(div)
If you only want to select div elements whose parent element is not a div, use this instead:
:not(div) > div
If you want to use this negation by itself, selecting all other elements, then there isn't a way using just a selector.
The only other viable workaround in CSS that I can think of is to apply styles to the elements you want without the :not() expression, then undo them for div > div. This works for any set of elements you're trying to target; the disadvantage is that not all properties can be easily reset.
Alternatively, if you're using jQuery, which does support :not(div > div) unlike the CSS version, you can place the selector in a script and, for instance, have jQuery apply a class name to those elements then target that class in your CSS.
It should work now thanks to Selectors Level 4 which allows :not() to take a list of complex selectors.
You can now also nest :not()... like :not(:not()) which wasn't allowed in Selectors Level 3. Not sure why you'd want to do that but you can.

IE8: what to use in place of nth-of-type(n)?

I've inherited the following CSS code to initially hide the latter elements of a series of paragraphs and a series of list items.
.profileSection p:nth-of-type(n+2) {
display: none;
}
.profileSection li:nth-of-type(n+6) {
display: none;
}
Obviously, this code does not work in IE8. What is an alternate way to hide these elements?
Here is a discussion on it:
http://www.thebrightlines.com/2010/01/04/alternative-for-nth-of-type-and-nth-child/
The writer mentions that you can reference specific children element by using
tagname + tagname + etc
Or get generic children by using
* + * + etc
I personally would just add a special class to those items.
+, the adjacent sibling selector, would allow you to select all siblings which are immediately adjacent. In your case: .profileSection p+p. (If you must do this, consider wrapping it in something to prevent other browsers from seeing it, like conditional comments.)
But + won't help if your markup contains something other than <p> elements right next to each other. For example:
<p>Alpha</p>
<h4>Header</h4>
<p>Beta</p>
If you don't already have some kind of shiv or moderizr functionality on the site (which would help with many other similar issues), it would be easiest to add a special class to the elements, and select using that class.
You can also try downloading and including selectivizr, which makes css3 selectors work in IE6-8

Resources