Sass placeholder selectors start with %. They work like classes for @extend, but unused placeholders never appear in the CSS—perfect for optional library styles. Five compiled examples follow.
01
%name
Silent selector
02
@extend
Opt-in CSS
03
Omit rules
No clutter
04
Libraries
No forced HTML
05
vs class
When to choose
06
Practice
5 examples
Concept
What Are Placeholder Selectors?
A placeholder looks and acts a lot like a class selector, but it starts with % (for example %toolbelt) and is not included in the CSS output by itself.
Any complex selector (the parts between commas) that contains a placeholder is omitted.
A whole style rule is omitted when every selector in its list contains a placeholder.
Placeholders become useful when another selector @extends them.
Unlike extending a class, unused placeholders do not leave dead CSS behind.
💡
Beginner tip
Think of % as a “silent class”: styles live in Sass until a real selector opts in with @extend. Your HTML never needs a class="%toolbelt"—that is not valid CSS anyway.
Foundation
📝 Basic Syntax
styles.scss
.alert:hover, %strong-alert {
font-weight: bold;
}
%strong-alert:hover {
color: red;
}
// Only .alert:hover survives in CSS until something @extends %strong-alert
The second rule is dropped entirely because its only selector contains a placeholder. The first rule keeps .alert:hover and drops the %strong-alert branch.
Opt-In
🔗 Extending Placeholders
Placeholders exist to be extended. Library authors can ship reusable style chunks without requiring a fixed HTML class name. Consumers write their own classes and @extend %name.
Official guidance: for a stylesheet used only in your own app, extending an existing class is often fine. Prefer placeholders when styles may go unused, or when you do not want to dictate HTML class names.
Compare
⚖️ Placeholders vs Class Selectors
%placeholder
.class
Unused output
Omitted from CSS
Still emitted
HTML
Not used in markup
Can appear in HTML
Best for
Libraries / optional packs
App UI classes
Activation
@extend %name
Class in HTML or @extend .name
Cheat Sheet
⚡ Quick Reference
Goal
Code
Define a placeholder
%card { padding: 1rem; }
Opt in from a class
.tile { @extend %card; }
Nest states
%btn { &:hover { … } }
Chain placeholders
%card--lg { @extend %card; }
Leave unused styles out
Define %lib-x and never extend it
Hands-On
Examples Gallery
Each example is verified with Dart Sass. Open View Compiled CSS for output.
📚 Getting Started
See what gets omitted—and what @extend brings back.
Example 1 — Placeholders Are Omitted from CSS
Mixed selector lists drop only the placeholder branches.
Sass merges both classes into the placeholder’s selector list. Nested &:hover becomes .reset-buttons:hover, .action-buttons:hover. Extra color rules stay on each class.
📈 Utilities, Chains & Unused Code
Reusable silent helpers and dead-code-free libraries.
Example 3 — Silent Utility Placeholder
A flex-center helper with no HTML class of its own.
Silent utilities — shared layout helpers without utility class spam in HTML.
Design system tokens as rules — group borders, radii, and shadows under %.
Theme packs — include many placeholders; only extended ones cost CSS weight.
Avoiding API lock-in — let users choose their own class names in markup.
🧠 How Compilation Works
1
Collect % rules
Parse placeholder selectors like silent classes.
Parse
2
Apply @extend
Merge real selectors into placeholder selector lists.
Extend
3
Drop leftovers
Remove any complex selector that still contains %.
Omit
4
✓
Emit clean CSS
Only real selectors reach the stylesheet.
Watch Out
⚠️ Common Pitfalls
Expecting % in HTML — placeholders are Sass-only; use real classes in markup.
Overusing @extend — deep extend graphs can surprise you; mixins are often clearer for parameterized styles.
Forgetting nothing extends it — then zero CSS is emitted (usually good—unless you meant to include it).
Extending across media queries carelessly — @extend has limits across contexts; see the @extend page.
Using placeholders for every app class — if the class is already in your HTML, a normal class may be simpler.
Pro Tips
💡 Best Practices
✅ Do
Use % for optional / library style chunks
Pair placeholders with clear @extend at call sites
Nest &:hover (and friends) inside placeholders when needed
Prefer placeholders when unused CSS must stay out of the bundle
Document which placeholders a package expects consumers to extend
❌ Don’t
Put % names in HTML class attributes
Replace every mixin with @extend blindly
Force library users into rigid class names when a placeholder would do
Assume unused .classes are free—they still emit CSS
Build huge extend chains that are hard to reason about
Summary
Key Takeaways
🚫01
% is silent
no CSS alone
Core
🔗02
@extend %
opt-in styles
Extend
📚03
Libraries
no forced HTML
API
⚖️04
vs .class
app vs lib
Choose
🗑️05
Unused = 0
no dead CSS
Size
❓ Frequently Asked Questions
Selectors that start with % (for example %toolbelt). They look and behave much like class selectors, but they are not written to the CSS output unless another selector extends them.
Unused placeholders leave no CSS behind. Classes always emit. Placeholders also avoid forcing library users to put a specific class name in their HTML—they @extend the placeholder from their own selectors.
Define styles under %name { ... }, then write .my-class { @extend %name; }. Sass merges .my-class into the placeholder’s selector list in the compiled CSS.
Only the complex selectors that do not contain a placeholder are emitted. Example: .alert:hover, %strong-alert { } compiles to just .alert:hover { } unless something extends %strong-alert.
Official Sass guidance: if the stylesheet is only for your own app and a real class already exists in the HTML, extending that class is often simpler. Prefer placeholders when writing reusable libraries or optional style packs.
Yes. %toolbelt { &:hover { ... } } works. Extenders inherit those nested rules too, so .action-buttons:hover appears in the output when you @extend %toolbelt.
Did you know?
Placeholder selectors are sometimes called “silent classes.” The % syntax was designed so stylesheets can share rules through @extend without polluting the final CSS when a chunk goes unused—especially helpful in large Sass libraries.
Placeholder selectors give you extendable style chunks that stay out of CSS until something opts in. Use them for libraries and optional packs; use ordinary classes when your app already owns the HTML class names.