Sass/SCSS#
CSS preprocessor with variables, nesting, mixins, and functions for Jac applications.
Overview#
Sass (Syntactically Awesome Style Sheets) extends CSS with powerful features like variables, nesting, mixins, and functions. This approach is perfect for: - Large projects with shared styles - DRY (Don't Repeat Yourself) principles - Complex styling logic - Maintainable CSS architecture
Example#
See the complete working example: examples/css-styling/sass-example/
Quick Start#
1. Install Sass#
Add to package.json:
2. Create SCSS File#
Create styles.scss:
$primary-color: #007bff;
$secondary-color: #6c757d;
.button {
background-color: $primary-color;
color: white;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
&:hover {
background-color: darken($primary-color, 10%);
}
}
3. Import in Jac#
# Pages
cl import from react {useState, useEffect}
cl import ".styles.scss";
cl {
def app() -> any {
return <div className="container">
<button className="button">Click Me</button>
</div>;
}
}
Vite automatically compiles SCSS to CSS during the build process.
Sass Features#
Variables#
Define reusable values:
$primary-gradient-start: #dbeafe;
$primary-gradient-end: #e0e7ff;
$white: #ffffff;
$gray-800: #1f2937;
$spacing-unit: 1rem;
Nesting#
Nest selectors for better organization:
.button {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
&:hover {
transform: scale(1.05);
}
&:active {
transform: scale(0.95);
}
&Decrement {
background-color: $red-500;
}
&Reset {
background-color: $gray-500;
}
}
Mixins#
Create reusable style blocks:
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin button-base {
color: $white;
font-weight: bold;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
border: none;
cursor: pointer;
&:hover {
transform: scale(1.05);
}
}
.container {
@include flex-center;
min-height: 100vh;
}
.button {
@include button-base;
background-color: $primary-color;
}
Functions#
Use built-in and custom functions:
.button {
background-color: $red-500;
&:hover {
background-color: darken($red-500, 10%);
}
}
.card {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
&:hover {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
}
Partials and Imports#
Organize styles across multiple files:
// _variables.scss
$primary: #007bff;
$secondary: #6c757d;
// _mixins.scss
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
// styles.scss
@import 'variables';
@import 'mixins';
.container {
@include flex-center;
background-color: $primary;
}
Best Practices#
1. Use Variables#
Define colors, spacing, and other values as variables:
$colors: (
primary: #007bff,
secondary: #6c757d,
success: #28a745,
danger: #dc3545,
);
.button {
background-color: map-get($colors, primary);
}
2. Create Mixins#
Extract common patterns into mixins:
@mixin respond-to($breakpoint) {
@media (min-width: $breakpoint) {
@content;
}
}
.container {
padding: 1rem;
@include respond-to(768px) {
padding: 2rem;
}
}
3. Organize with Partials#
Split large files into smaller modules:
4. Use Nesting Wisely#
Don't nest too deeply (max 3-4 levels):
// Good
.card {
padding: 1rem;
&__header {
font-weight: bold;
}
}
// Avoid
.card {
.header {
.title {
.text {
// Too deep!
}
}
}
}
5. Leverage Functions#
Use Sass functions for calculations:
Common Patterns#
BEM with Nesting#
.card {
padding: 1rem;
&__header {
padding: 1rem;
border-bottom: 1px solid #ddd;
}
&__body {
padding: 1.5rem;
}
&--highlighted {
border: 2px solid $primary;
}
}
Color Management#
$colors: (
primary: #007bff,
secondary: #6c757d,
success: #28a745,
danger: #dc3545,
);
@function color($name) {
@return map-get($colors, $name);
}
.button {
background-color: color(primary);
}
Responsive Mixins#
@mixin respond-to($breakpoint) {
@if $breakpoint == mobile {
@media (max-width: 767px) { @content; }
}
@else if $breakpoint == tablet {
@media (min-width: 768px) { @content; }
}
@else if $breakpoint == desktop {
@media (min-width: 1024px) { @content; }
}
}
.container {
padding: 1rem;
@include respond-to(tablet) {
padding: 2rem;
}
}
Advantages#
- Variables for maintainable theming
- Nesting for better organization
- Mixins for reusable code
- Functions for dynamic values
- Partials for modular CSS
- Compiles to standard CSS
- Large ecosystem and community
Limitations#
- Requires build step
- Learning curve for Sass syntax
- Can get complex with deep nesting
- Additional dependency
- Debugging can be harder (source maps help)
When to Use#
Choose Sass/SCSS when:
- You're working on large projects
- You need variables and mixins
- You want better CSS organization
- You prefer preprocessing over runtime CSS
- You need complex styling logic
- You want to share styles across components
Import Syntax#
SCSS files are imported using the cl import syntax:
This compiles to:
Vite automatically processes SCSS imports and compiles them to CSS.
Next Steps#
- Explore Sass Documentation
- Check out Less for similar preprocessing (coming soon)
- Learn about PostCSS for CSS transformations (coming soon)
- See Pure CSS for traditional CSS approach