Nested Brackets and Ampersand usage in Tailwind UI examples - css

Can somebody help translate bracket usage in Tailwind.css?
In Example 1: - what does [&_*] mean?
In Example 2: what does the nested bracket combined with _& mean?
Example 1:
document.documentElement.classList.add('[&_*]:!transition-none')
Example 2:
<LightIcon className="hidden h-4 w-4 fill-slate-400 [:not(.dark)[data-theme=system]_&]:block" />
The closest I can get is the [] refers to attribute selection (in general) for .css and the Ampersand in is used by PostCSS processing in "normal" SASS nesting rules (as defined by tailwind's default nesting declaration support provided by postcss-nested).

What you are seeing is the usage of Tailwind's arbitrary variants feature.
Inside the square brackets is a CSS selector (or media query, I won't be talking about that here), with the ampersand (&) a substitute for the element that the class is being applied to. The nested brackets are attribute selectors, like with standard CSS selectors, as you correctly inferred in your Stacked Overflow question. Underscore is used instead of spaces in a CSS selector.
To give a few examples:
<div class="foo">
<div class="[.foo_&]:text-white"></div>
</div>
is conceptually like:
<div class="foo">
<div class="bar"></div>
</div>
<style>
/**
* .foo .bar
* ↓
* .foo &
* ↓
* .foo_&
*/
.foo .bar {
color: white;
}
</style>
With .bar now &, since .bar is the element we are applying the class/style to.
Another example:
<div class="foo"></div><div class="[.foo+&]:text-white"></div>
is conceptually like:
<div class="foo"></div><div class="bar"></div>
<style>
/**
* .foo + .bar
* ↓
* .foo + &
* ↓
* .foo+&
*/
.foo + .bar {
color: white;
}
</style>
The + grammar in CSS selectors does not strictly need spaces around it, so we can remove them for a more concise arbitrary variant syntax.
<div data-foo class="[&[data-foo]]:text-white"></div>
is conceptually like:
<div data-foo class="bar"></div>
<style>
/**
* .bar[data-foo]
* ↓
* &[data-foo]
*/
.bar[data-foo] {
color: white;
}
</style>
Hopefully this example makes the nested brackets clear.

Related

Why does .b:not(#a>.b) not work?

I'm working with some CSS and wondering why the following piece doesn't work:
.container:not(#topic-title>.container)
Is there anyway else I can achieve the same thing? I'm open to JavaScript solutions.
You could use this selector :
:not(#topic-title) > .container
.container {
height:20px;
}
:not(#topic-title) > .container {
background:green;
}
<div id="topic-title">
<div class="container">parent #topic-title</div>
</div>
<div>
<div class="container"> parent not #topic-title</div>
</div>
Take a look at the spec for the :not pseudo class: (bold is mine)
The negation pseudo-class, :not(X), is a functional notation taking a
simple selector (excluding the negation pseudo-class itself) as an
argument.
where
A simple selector is either a type selector, universal selector,
attribute selector, class selector, ID selector, or pseudo-class.
Hence #a>.b is not a simple selector and that's why the selector .b:not(#a>.b) doesn't work.
Here's an example with background-color, a margin example would be analogous. The idea: set a default page-wide, then cancel for instances where you don't want it.
.container {
background-color: red;
}
#topic-title > .container {
background-color: inherit;
}
<div>
<div id="topic-title">
<div class="container">A</div>
</div>
<div class="container">B</div>
</div>
<div class="container">C</div>

CSS regex selector match one OR another condition?

I'd like to match when /(\sclassName|^className)/ is satisfied, but when selecting css. Hypothetically I would use like:
[class(^|\s)='className'] {
font-size: 5000px;
}
I've found this resource, which is very nice: The Skinny on CSS Attribute Selectors, but it doesn't mention this use case.
I just want to match "icon-" in the following 2 examples, but not the 3rd.
Here, this can be achieved with [class^='icon-]
<div class='icon-something another-class'>
Here, this can be achieved with [class~='icon-'], but this does not match when 'icon-' is at the very beginning of the class string:
<div class='another-class icon-something'>
I do not want to match this, with -icon in the middle of a string. I believe *= will match this one, as will |= :
<div class='another-icon-class another-class'>
You'll need to use two separate selectors with the same rule. CSS selectors don't really support alternation.
[class^='icon-'], [class*=' icon-'] {
/* ... */
}
div {
color: red;
}
[class^='icon-'], [class*=' icon-'] {
color: green;
}
<div class='icon-something another-class'>should match</div>
<div class='another-class icon-something'>should match</div>
<div class='another-icon-class another-class'>should not match</div>
You can use the following selectors to select any element whose class either starts with "icon-" or contains " icon-" (note the space at the start):
[class^="icon-"], [class*=" icon-"] { ... }
JSFiddle demo.

What does the character '>' and '&' mean in bootstrap less modules?

I am very new to bootstrap and I would like to customize it. I am confused when I see '>' and '&' character. What does that mean? Is that present in less documentation. Is that some sort of nesting? Please see sample code below.
.navbar-nav {
> .open > a {
&,
&:hover,
&:focus {
background-color: #navbar-inverse-link-active-bg;
color: #navbar-inverse-link-active-color;
}
}
This might be the easiest question, don't hate me for this. Thanks folks.
In CSS, the ">" character means that only "first nested" elements will be targeted ("direct child" elements).
that means in the following scenario:
<div id="a">
<div id="b">
<div id="c">
</div>
</div>
</div>
then in CSS #a > div would only target <div id="b"> and NOT <div id="c">
without the > character, #a div would target both "b" and "c".
As for the & character in LESS:
The ampersand selector is most commonly used when applying a modifying class or pseudo-class to an existing selector:
a {
color: blue;
&:hover {
color: green;
}
}
The inner selector in this example compiles to a:hover. Without the &, it would compile to a :hover (a descendant selector that matches hovered elements inside of tags).
Read more at http://blog.slaks.net/2013-09-29/less-css-secrets-of-the-ampersand/
The > character refers to the direct children of certain element.
The & character is used in SASS for reference of the parent selectors.

What's the difference between CSS classes .foo.bar (without space) and .foo .bar (with space)

Would you please explain me the difference between these two CSS classes syntax:
.element .symbol {}
and
.element.large .symbol {}
I don't understand the difference between the two. The first line indicates two different classes to which are applied the same styles. But about the second, what's the meaning of '.large' which is written attached to '.element'?
.element .symbol
means .symbol inside .element
.element.symbol
means .element that has the class symbol as well.
So,
.element.large .symbol
means .symbol inside .element that has the class large as well.
I think you got a slight misunderstanding what the first one means.
.element .symbol {}
Means that those CSS settings are applied to any HTML element with the class .symbol that is inside an element with the class .element.
<div class="element">
<div class="symbol" />
</div>
In this example your first CSS entry would affect the <div> tag in the middle.
Your second example means that the first class requires two classes to be affected. Other than that it's equal to the first one.
<div class="element large">
<div class="symbol" />
</div>
So if the HTML looks like this, the CSS values will be applied to the inner <div> tag as well.
If you want to set CSS tags that apply for multiple classes separately then you need to split them up using a comma. So it looks like this:
.element, .symbol {}
Edit: By request the link to the documentation of the CSS selectors.
Using
.element.large
refers to an element with both classes:
<div class="element large"></div>
rather than a descendant of an element:
.element .large
meaning that in:
<div class="element">
<div class="large"></div>
</div>
only
<div class="large"></div>
is 'receiving' the styles.
Basically, being separated by a space implies two elements with a descendant relationship.
You would use .element .symbol this where you have an element inside of another element. For example:
<div class="element">
<i class="symbol"></i>
</div>
If down the road you wanted to differentiate some divs, you could add an additional class to target only those that differ, and target it with .element.large .symbol. So, for example:
<div class="element large">
<i class="symbol"></i>
</div>
In your second example, the first part of the selector is simply an element with two classes, as in <span class="element large"> or <span class="large element">.
In general, each part of a selector applies to one HTML element.
table[border].clname means a table with a border attribute and a class of clname, while table [border] .clname means an element with class clname, in an element with a border attribute, in a table.
(Edit: well, I say "one HTML element", but of course you can have more than one table that this applies to. You understand.)
Without whitespace, you are simply more specific with the selector. Because classes can appear several times in the html dom. But two or more classes in one element is rarer and therefore more precise.
Selectors with a whitespace (.a1 .b2) say search for the class a1 and see if there is a child or child-child element with the class b2 in this element.
An even higher degree of accuracy can be achieved with the >selector (.a1 .b2 > span). This states that only span elements should be taken into account which are direct children of the class .b2 located within an element with the class a1.
.a1 .b1 {
color: green;
}
.a1.a2 .b1 {
color: red;
}
.a1.a2 .b2 {
font-style: italic;
font-weight: bold;
}
.a1.a2 .b2 > span {
color: orange;
}
<div class="a1">
<div class="b1">Hello France</div>
<div class="b1">Hello Spain</div>
<div class="b2">Hello Sweden</div>
</div>
<hr/>
<div class="a1 a2">
<div class="b1">Bye France</div>
<div class="b1">Bye Spain</div>
<div class="b2">
Bye
<span>World</span>
</div>
</div>

Append content via multiple CSS :after classes

Given the following HTML:
<div class="required">required only</div>
<div class="note">note only</div>
<div class="required note">required and note</div>
<div class="note required">note and required</div>
And CSS:
.required:after { content: " *"; color: red; }
.note:after { content: " +"; color: red; }
The result in Firefox 11 is:
required only *
note only +
required and note +
note and required +
Where more than one class is supplied (.required and .note) I would like to have both "*" and "+" appended to the element such that:
required and note *+
note and required +*
Is this possible using pure CSS, and if so, how?
Edit: Here's a link to jsfiddle for this example: http://jsfiddle.net/xpZST/
You'll need additional rules for this to work.
Given that the ordering of classes matters (when normally it shouldn't!), you'll need to use attribute selectors instead of class selectors, and you'll need to create two rules:
[class="required note"]:after { content: " *+"; color: red; }
[class="note required"]:after { content: " +*"; color: red; }
Simply add these rules after the ones you have and it should work, as attribute and class selectors are equally specific.
jsFiddle preview
By the way, if you have common styles you can keep your code DRY by isolating them in another rule. For example, you can select each class and give them both color: red:
.required:after, .note:after { color: red; }
jsFiddle preview

Resources