tailwind2-3 Exercise 2: Custom Variants and @variant ===================================================== Setup: a folder with Tailwind installed (npm install tailwindcss @tailwindcss/cli). Create the files below, then build each CSS file with: npx @tailwindcss/cli -i .css -o .out.css --- v.css --- @import "tailwindcss" source(none); @source "./tpl.html"; @custom-variant theme-midnight (&:where([data-theme="midnight"], [data-theme="midnight"] *)); @custom-variant hocus (&:is(:hover, :focus-visible)); @custom-variant any-hover { @media (any-hover: hover) { &:hover { @slot; } } } @custom-variant desktop-hover { @media (width >= 64rem) { @media (hover: hover) { &:hover { @slot; } } } } @custom-variant dark-hover { @variant dark { @variant hover { @slot; } } } --- v/tpl.html --- --- w.css --- @import "tailwindcss" source(none); @source "./tpl.html"; .btn { background: white; @variant hover { background: black; } @variant md { padding: 1rem; } @variant hover:focus { outline: 2px solid red; } @variant dark, print { color: gray; } } (w/tpl.html is just .) Output (selectors written to the utilities layer for v.css, nesting shown by indentation; then the .btn rule for w.css): exit 0 .group-hocus\:flex:is(:where(.group):is(:hover, :focus-visible) *) .theme-midnight\:bg-black:where([data-theme="midnight"], [data-theme="midnight"] *) @media (hover: hover) .theme-midnight\:hover\:text-white:where([data-theme="midnight"], [data-theme="midnight"] *):hover @media (width >= 48rem) .md\:theme-midnight\:p-2:where([data-theme="midnight"], [data-theme="midnight"] *) .hocus\:underline:is(:hover, :focus-visible) @media (any-hover: hover) .any-hover\:font-bold:hover @media (width >= 64rem) @media (hover: hover) .desktop-hover\:italic:hover @media (prefers-color-scheme: dark) @media (hover: hover) .dark-hover\:uppercase:hover --- w.css: .btn block .btn { background: white; &:hover { @media (hover: hover) { background: black; } } @media (width >= 48rem) { padding: 1rem; } &:hover { @media (hover: hover) { &:focus { outline: 2px solid red; } } } @media (prefers-color-scheme: dark) { color: gray; } @media print { color: gray; } } WHY THIS WORKS AS AN ANSWER --------------------------- @custom-variant with a selector in brackets is the short form: theme-midnight becomes :where([data-theme="midnight"], [data-theme="midnight"] *), and :where() keeps the specificity at zero so a plain utility is never made harder to override. hocus is the same idea with :is(:hover, :focus-visible). The block form wraps @slot in at-rules: any-hover puts :hover inside @media (any-hover: hover). desktop-hover nests two media queries (width >= 64rem and hover: hover), which is how you build a variant that needs two conditions at once. dark-hover composes two existing variants with @variant inside @custom-variant: the output has the dark media query around the hover media query. Stacking in the markup works as with built-ins: md:theme-midnight:p-2 gets the width media query, and theme-midnight:hover:text-white gets the hover media query. group-hocus: appeared without being defined: a custom variant automatically works with group- as well. In w.css, @variant is used inside your own CSS rule instead of a class. The hover and md blocks become nested rules, "hover:focus" stacks (the output nests focus inside hover), and a comma list (dark, print) repeats the same declarations for each. Note the .btn rule is outside every layer, so by the cascade rule from chapter 1 it beats utilities such as p-8; put it in @layer components if that is not what you want.