Stylus Basics — Complete Guide
In this tutorial, you will learn about Stylus Basics. We cover key concepts, practical examples, and best practices to help you master this topic.
Stylus is an expressive CSS preprocessor with optional braces, indentation-based syntax, and powerful built-in functions for concise stylesheets.
What You'll Learn
- Installing and compiling Stylus
- Indentation-based syntax (no braces, no semicolons)
- Variables without prefixes
- Mixins and functions
- Built-in functions
- Key differences from Sass and Less
Why It Matters
- Stylus offers the most concise syntax
- Used in some Node.js projects and frameworks
- Understanding multiple preprocessors is valuable
- Unique features like transparent mixins
Real-World Use
- A Node.js API project uses Stylus for its admin panel
- A developer prefers Stylus for its minimal syntax
- A legacy project uses Stylus with Express
- A framework uses Stylus for its component library
flowchart LR
A[Stylus] --> B[Indentation Syntax]
A --> C[Prefix-free Variables]
A --> D[Transparent Mixins]
A --> E[Property Lookup]
B --> F[No {} or ;]
C --> G[color = #0066CC]
D --> H[Mixin looks like property]
E --> I[@prop = 'blue']
Stylus Basics
Code Example: Installation and Syntax
# Install Stylus globally
npm install -g stylus
# Install as dev dependency
npm install --save-dev stylus
# Compile
stylus styles.styl styles.css
# Compile directory
stylus src/stylus/ dist/css/
# Watch mode
stylus --watch src/stylus/ dist/css/
# Compress output
stylus --compress styles.styl styles.min.css
// Stylus syntax - no braces, no semicolons, no colons
// Just indentation
// Variables (no prefix)
primary = #0066CC
secondary = #6c757d
font-stack = 'Inter', system-ui, sans-serif
spacing-unit = 8px
// Nesting (indentation-based)
.card
background #fff
border 1px solid #eee
border-radius 8px
padding 1.5rem
&__title
font-size 1.25rem
color primary
&__text
color secondary
line-height 1.6
&:hover
box-shadow 0 4px 12px rgba(primary, 0.15)
// Properties can use ":" or just space
// Both work:
.element
color: #333
padding 1rem
// Mix of CSS and Stylus syntax
.element
font-family font-stack
Expected output: Stylus uses indentation instead of braces. Variables have no prefix. Property values can be separated by spaces (no colon required). The syntax is the most minimal of the preprocessors.
Code Example: Variables and Interpolation
// Variables (no prefix, just name = value)
primary = #0066CC
secondary = #6c757d
base-font = 16px
border-radius = 4px
// Variable assignment with operators
double-spacing = spacing-unit * 2
half-spacing = spacing-unit / 2
// Interpolation (using {} syntax)
vendor = 'webkit'
property = 'margin'
size = 16px
.element
// Property interpolation
{property} size
{property}-left size
// Selector interpolation
.{vendor}-app
display flex
// Variable in values (no interpolation needed)
color primary
// Block-scoped variables
.card
card-padding = 24px // Local scope
padding card-padding
.other
// padding card-padding // Error: undefined
// Property lookup (access another property's value)
.element
width 200px
height @width // Uses the value of width (200px)
line-height @width // Not a reference, just a lookup
Expected output: Variables need no prefix. Interpolation uses {} syntax. Property lookup with @ accesses another property in the same block, which is a unique Stylus feature.
Code Example: Mixins and Functions
// Mixin (no keyword, just indentation)
button-base()
display inline-flex
align-items center
padding 8px 16px
border none
border-radius 4px
font-size 1rem
cursor pointer
min-height 44px
// Mixin with parameters
button-variant(bg, color = #fff)
button-base() // Include another mixin
background bg
color color
&:hover
background darken(bg, 10%)
// Transparent mixin (mixin has same name as property)
border-radius()
-webkit-border-radius arguments
-moz-border-radius arguments
border-radius arguments
.element
border-radius(4px)
// Function (returns a value)
fluid-type(min-size, max-size, min-vw = 320px, max-vw = 1200px)
slope = (max-size - min-size) / (max-vw - min-vw)
intercept = min-size - slope * min-vw
return 'clamp(%s, %s + %s, %s)' % (min-size intercept slope * 100vw max-size)
// Usage
h1
font-size fluid-type(2rem, 4rem)
// Conditional in mixin
button-size(size)
if size == 'small'
padding 4px 8px
font-size 0.75rem
else if size == 'large'
padding 12px 24px
font-size 1.25rem
else
padding 8px 16px
font-size 1rem
// Usage
.btn-small
button-size('small')
// Rest parameter
box-shadow(shadows...)
box-shadow shadows
.element
box-shadow(0 2px 4px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.05))
Expected output: Mixins and functions both use indentation. Transparent mixins have the same name as CSS properties. Functions use the return keyword to output a value.
Code Example: Built-in Functions
// Color functions
primary = #0066CC
.element
background darken(primary, 10%)
color lighten(primary, 60%)
border-color saturate(primary, 20%)
opacity alpha(primary)
background rgba(primary, 0.5)
color contrast(primary) // Auto text color
// Math functions
.element
width unit(33.33, '%') // 33.33%
width ceil(33.33%) // 34%
height floor(33.33%) // 33%
opacity round(0.555) // 1
z-index abs(-100) // 100
// Math operations
.element
width 100% / 3
padding 16px * 2
margin 16px + 8px
// Type checking
check(n)
if typeof(n) == 'unit'
n * 1px
else
error('Not a number')
.element
width check(100)
// String functions
.element
content 'Hello ' + 'World'
content s('Hello %s!', 'Stylus')
// JSON support
// Stylus can import JSON files
// json('data.json')
// Then access: json.primary-color
// Lookup
primary = #0066CC
.element
color lookup('primary') // Variable lookup by name
Expected output: Stylus has comprehensive built-in functions for color, math, strings, and Type Checking. The s() function creates format strings. lookup() accesses variables by name at runtime.
Common Mistakes
- Inconsistent indentation — Stylus relies on indentation. Mixing tabs and spaces causes compilation errors.
- Forgetting that functions need return — Functions must use the
returnkeyword. Without it, they output CSS instead of returning a value. - Confusing mixins and functions — Mixins output CSS rules. Functions return values. The syntax looks similar but behavior differs.
- Not understanding transparent mixins — A mixin named border-radius() overrides the CSS property. This is intentional for vendor prefixing.
- Missing parentheses for parameterless mixins — button-base calls the mixin, button-base without parens references the mixin object.
- Overusing property lookup — @property uses the current block's property value. It is not a CSS variable or reference.
- Smaller ecosystem — Stylus has fewer plugins and community resources than Sass. Check plugin availability before committing.
Practice Questions
- What is the variable syntax in Stylus? No prefix:
primary = #0066CC(just name = value). - How do you return a value from a Stylus function? Use the
returnkeyword inside the function body. - What is a transparent mixin? A mixin with the same name as a CSS property that intercepts property calls for vendor prefixing.
- How does property lookup work in Stylus?
@property-nameaccesses the value of another property in the same block.
FAQ
Mini Project
Set up a Stylus project and build a component library. Install Stylus, create a directory structure with components/, a main.styl entry point, and _variables.styl for design tokens. Build 3 components (button with variants using conditions, card with BEM-style nesting, nav with responsive breakpoints). Use transparent mixins for border-radius and vendor prefixes. Use property lookup for related dimensions. Compile with --compress. Compare the Stylus source size and syntax conciseness with the equivalent Sass code from earlier lessons.
What's Next
Continue with Lesson 25: PostCSS Introduction to learn the PostCSS ecosystem.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro