// sample-styles.less: a commented Less stylesheet. // Free sample from 99helpers.com/file-types/less // Compile it with: npx -y less sample-styles.less sample-styles.css // (the npm package is called "less"; the command it installs is lessc) // Comments that start with // are dropped from the CSS. /* Compiled from sample-styles.less, a free sample from 99helpers.com/file-types/less */ // 1. Variables start with @. They are lazy: the last definition in a // scope wins, even one that comes after the place it is used. @brand: #046eff; @radius: 12px; @space: 1rem; @prefix: ui; // 2. Operations keep their units. Since Less 4.0, division needs // parentheses: (@space / 2) is 0.5rem, @space / 2 stays as written. @gutter: (@space / 2); // 3. A mixin with a default parameter. The () after its name keeps the // mixin itself out of the CSS. .rounded(@r: @radius) { border-radius: @r; } // 4. Guards: each version of the mixin applies only when its condition // is true, like an if/else. .text-on(@bg) when (lightness(@bg) >= 60%) { color: #111; } .text-on(@bg) when (lightness(@bg) < 60%) { color: #fff; } // 5. Interpolation: @{prefix} writes a variable into a selector. // Nesting and & work as in Sass; the media query bubbles up. .@{prefix}-card { padding: (@space * 1.5); background: #fff; .rounded(); h2 { margin-top: 0; } &:hover { box-shadow: 0 4px 12px fade(#000, 16%); } &--featured { border: 2px solid @brand; } @media (min-width: 900px) { padding: (@space * 2); } } // 6. Colour functions run at compile time. .@{prefix}-button { display: inline-block; padding: @gutter @space; background: @brand; .rounded(6px); .text-on(@brand); &:hover { background: darken(@brand, 10%); } } // 7. :extend adds this selector to an existing rule instead of // copying its declarations. .focus-ring { outline: 3px solid fade(@brand, 40%); outline-offset: 2px; } .@{prefix}-button:focus-visible { &:extend(.focus-ring); } // 8. A map: a detached ruleset whose values are looked up with []. @tones: { info: @brand; success: #15803d; warning: #fde68a; } .@{prefix}-alert { border-left: 4px solid @tones[warning]; } // 9. each() loops over the map: @key and @value are set for each entry. each(@tones, { .@{prefix}-badge-@{key} { background: @value; .text-on(@value); } }); // 10. A recursive mixin with a guard makes a counted loop: .mt-1 to .mt-4. .mt-loop(@i) when (@i <= 4) { .mt-@{i} { margin-top: (@i * 0.5rem); } .mt-loop(@i + 1); } .mt-loop(1); // 11. Escaping: ~"..." outputs the text as it is, after filling in @{}. .@{prefix}-sidebar { width: ~"calc(100% - @{gutter})"; } // 12. CSS custom properties pass through untouched; Less variables don't // exist any more once the file is compiled. :root { --brand: @brand; }