tailwind2-4 Exercise 3: Child Variants, State Attributes and starting: ======================================================================= Setup: a folder with Tailwind installed (npm install tailwindcss @tailwindcss/cli). Save the two files below, then build and open the page in Chrome: npx @tailwindcss/cli -i ex3.css -o ex3.out.css To read a value by hand, use the console, for example: getComputedStyle(document.querySelector('#s_card')).color (The results below were measured with a scripted Chrome that used real mouse and click events; the same values appear when you hover and click yourself.) --- ex3.css --- @import "tailwindcss" source(none); @source "./ex3.html"; --- ex3.html ---
childgrandchild
own classes
Results (the J line is read inside the browser: opacity immediately after the element is inserted, two animation frames later, and after 800 ms): G. k1 (no own classes): padding 8px | bg yellow-500 | grandchild colour RED G. k2 (own p-8 bg-blue-500): padding 8px | bg yellow-500 | colour RED I. tab1: bg blue-500 weight 700 underline none || tab2: bg rgba(0, 0, 0, 0) weight 400 underline none I. after switching: tab1: bg rgba(0, 0, 0, 0) weight 400 underline none || tab2: bg blue-500 weight 700 underline underline I. chevron rotate: closed none I. chevron rotate: open 180deg J. opacity just after insertion 0 | two frames later 0.00247066 | after 800 ms 1 WHY THIS WORKS AS AN ANSWER --------------------------- *:p-2 on the parent compiles to :is(.\*\:p-2 > *), a rule that targets every direct child, and **:text-red-500 targets every descendant, so the grandchild and even the child that has its own classes turn red. The k2 result is the lesson: k2 has its own p-8 and bg-blue-500, but it measured padding 8px and the yellow background, because the parent's rule has the same specificity as .p-8 (one class) and comes later in the generated stylesheet (in my build .p-8 was written at line 188 and the *:p-2 rule at line 210). A parent's child variant therefore overrides the child's own utilities; use *: for plain children and do not mix it with per-child styling. The tabs show the data-attribute pattern: data-[state=active]:bg-blue-500 reads an attribute with a value, aria-selected: reads aria-selected="true", and data-active: reads the mere presence of the attribute. After the JavaScript changed three attributes, tab2 took over the styles and tab1 lost them, with no class changes at all. group-data-[state=open]/menu:rotate-180 lets a child react to its named ancestor's state: the chevron's rotate property went from none to 180deg. Finally starting:opacity-0 produces an @starting-style rule: the new element began at opacity 0, was already moving two frames later (0.0025) and was fully visible (1) after 800 ms, without any JavaScript timing code.