Css Basics
Documentation for Developers
CSS Development Best Practices
Table of Contents
- Angular CSS Best Practices
- Performance Optimization
- SCSS Structure and Nesting
- CSS Custom Properties vs @Input()
- Anti-Patterns to Avoid
Angular CSS Best Practices
✅ Recommended Approaches
1. CSS Custom Properties (CSS Variables)
The modern, performant way to style child components:
// ✅ BEST PRACTICE: CSS Custom Properties
:host {
// Define custom properties for child components
--panel-bg: var(--theme-surface, #ffffff);
--panel-text: var(--theme-text, #000000);
--panel-border: 1px solid var(--theme-border, #e5e7eb);
}
// Child component automatically inherits these values
.child-component {
background: var(--panel-bg);
color: var(--panel-text);
border: var(--panel-border);
}
Benefits:
- 🚀 Performance: Browser-native processing (~0.1ms)
- 🔄 No change detection: Zero Angular overhead
- 🌐 SSR-friendly: Works before JavaScript hydration
- 🎨 Natural cascading: CSS inheritance works as intended
2. External Stylesheets Only
Always use separate .scss files:
// ✅ CORRECT: External stylesheet
@Component({
selector: 'app-component',
templateUrl: './component.html',
styleUrl: './component.scss' // External file only
})
// ❌ AVOID: Inline styles
@Component({
selector: 'app-component',
template: `...`,
styles: [`...`] // Avoid inline styles
})
❌ Anti-Patterns to Avoid
1. ::ng-deep (DEPRECATED)
// ❌ DEPRECATED: ::ng-deep breaks encapsulation
:host {
::ng-deep .child-component {
color: red; // Breaks style isolation
}
}
Problems with ::ng-deep:
- 🚫 Officially deprecated by Angular team
- 💥 Breaks encapsulation: Styles leak globally
- 🐛 Hard to debug: Style dependencies unclear
- 🔮 Future removal: May break in future Angular versions
- 🐌 Performance impact: Affects rendering performance
Modern Alternative:
// ✅ MODERN: CSS Custom Properties
:host {
--child-text-color: red;
}
// Child component consumes the variable
.child-component {
color: var(--child-text-color, #000);
}
2. ViewEncapsulation.None
// ❌ AVOID: Breaks style isolation
@Component({
encapsulation: ViewEncapsulation.None
})
Why it's problematic:
- 🌍 Global pollution: Styles affect entire application
- 🔄 Unpredictable: Style conflicts hard to track
- 🧪 Testing issues: Component isolation broken
Performance Optimization
CSS Variables vs @Input() Properties
| Approach | Performance | Change Detection | Bundle Size | SSR Support |
|---|---|---|---|---|
| CSS Variables | ✅ ~0.1ms | ✅ None | ✅ No impact | ✅ Immediate |
| @Input() Properties | ❌ ~2-5ms | ❌ Every change | ❌ Increases JS | ❌ Needs hydration |
When to Use Each:
// ✅ CSS Variables for: STYLING
:host {
--button-bg: #007bff;
--button-text: #ffffff;
--button-padding: 12px 24px;
--button-radius: 6px;
}
// ✅ @Input() Properties for: LOGIC
@Component({...})
export class ButtonComponent {
@Input() disabled = false; // Logic/behavior
@Input() type: 'button' | 'submit' = 'button'; // Functionality
@Input() loading = false; // State management
@Input() size: 'sm' | 'md' | 'lg' = 'md'; // Affects CSS classes
}
Performance Tips:
- Minimize CSS Custom Property Changes:
// ✅ GOOD: Few, semantic variables
:host {
--theme-primary: #007bff;
--theme-surface: #ffffff;
}
// ❌ AVOID: Too many specific variables
:host {
--button-top-padding: 12px;
--button-right-padding: 24px;
--button-bottom-padding: 12px;
--button-left-padding: 24px;
}
- Use CSS Custom Properties for Theming:
// ✅ Efficient theme switching
:host {
&.theme-dark {
--surface: #1f2937;
--text: #f9fafb;
}
&.theme-light {
--surface: #ffffff;
--text: #111827;
}
}
SCSS Structure and Nesting
Proper Nesting Hierarchy
Always nest child selectors inside their parents:
// ✅ CORRECT: Proper nesting structure
.page-details {
padding: 20px;
background: var(--surface);
&__section {
margin-bottom: 24px;
border-radius: 8px;
&-title {
font-size: 16px;
font-weight: 600;
&::before {
content: '';
background: var(--accent);
}
}
}
&__field {
margin-bottom: 16px;
label {
display: block;
font-weight: 500;
&.required::after {
content: '*';
color: var(--danger);
}
}
.form-control {
width: 100%;
padding: 8px 12px;
&:focus {
border-color: var(--primary);
& + .form-hint {
color: var(--primary);
}
}
&:disabled {
opacity: 0.6;
cursor: not-allowed;
}
}
}
}
Benefits of Proper Nesting:
- 🔍 Clear Hierarchy: Visual structure matches DOM
- 📦 Better Organization: Related styles grouped together
- 🔧 Easier Maintenance: Find and modify styles quickly
- 🎯 Specificity Control: Natural CSS specificity progression
Nesting Guidelines:
// ✅ GOOD: Logical nesting (max 3-4 levels)
.component {
.header {
.title {
.icon {
// Max recommended depth
}
}
}
}
// ❌ AVOID: Too deep nesting (hard to maintain)
.component {
.wrapper {
.container {
.content {
.section {
.item {
.text {
// Too deep!
}
}
}
}
}
}
}
Component Styling Architecture
File Organization:
component/
├── component.ts # Logic only
├── component.html # Template only
├── component.scss # Styles only
└── component.spec.ts # Tests
SCSS File Structure:
// 1. Host styles
:host {
display: block;
--component-bg: var(--theme-surface);
}
// 2. Main component styles
.component {
background: var(--component-bg);
// 3. Nested elements
&__header {
padding: 1rem;
&-title {
font-weight: 600;
}
}
&__body {
padding: 1rem;
}
&__footer {
padding: 1rem;
border-top: 1px solid var(--border);
}
}
// 4. State modifiers
.component {
&--loading {
opacity: 0.6;
}
&--error {
border-color: var(--danger);
}
}
// 5. Responsive styles
@media (max-width: 768px) {
.component {
&__header {
padding: 0.75rem;
}
}
}
Migration Guide
From ::ng-deep to CSS Custom Properties:
// ❌ OLD: Using ::ng-deep
:host {
::ng-deep .child-component {
background: #f0f0f0;
color: #333;
}
}
// ✅ NEW: Using CSS Custom Properties
:host {
--child-bg: #f0f0f0;
--child-text: #333;
}
// In child component:
.child-component {
background: var(--child-bg, #fff);
color: var(--child-text, #000);
}
Migration Steps:
- Identify ::ng-deep usage in your components
- Define CSS custom properties in parent component
- Update child component to consume variables
- Test thoroughly to ensure styling works
- Remove ::ng-deep from parent component
Common SCSS Import Issues
Path Resolution Errors
When you encounter "Can't find stylesheet to import" errors, the issue is typically incorrect relative paths:
// ❌ COMMON ERROR: Wrong path depth
@use '../../../theme-system/theme-styles/src/lib/styles/index' as *;
How to Fix:
- Count directory levels: From your component to the target file
- Test the path: Use terminal to verify:
ls -la ../../path/to/file.scss - Apply the correct path:
// ✅ CORRECT: Proper relative path calculation
@use '../../../../../../theme-system/theme-styles/src/lib/styles/index' as *;
Path Calculation Examples:
// From: libs/ux-test-lib/src/lib/storage/components/storage-inspector/
// To: libs/theme-system/theme-styles/src/lib/styles/utilities/
// Path: ../../../../../../theme-system/theme-styles/src/lib/styles/utilities/
// From: libs/theme-system/theme-showcase/src/lib/components/theme-showcase/
// To: libs/theme-system/theme-styles/src/lib/styles/
// Path: ../../../../../theme-styles/src/lib/styles/
Debug Process:
- Navigate to your component directory in terminal
- Test the path:
cd /path/to/component && ls -la ../../../../../target/file.scss - Adjust
../count until the file is found - Update your
@usestatement with the working path
Best Practices Summary
✅ DO:
- Use CSS custom properties for styling child components
- Keep .ts, .html, and .scss files separate
- Follow proper SCSS nesting hierarchy
- Use semantic variable names
- Optimize for performance with CSS variables
- Test SCSS import paths via terminal before committing
❌ DON'T:
- Use ::ng-deep (deprecated)
- Mix inline styles with external stylesheets
- Nest SCSS more than 3-4 levels deep
- Use @Input() properties for purely visual styling
- Break Angular's style encapsulation
- Guess at relative import paths
Performance Benchmarks
| Technique | Processing Time | Memory Usage | Change Detection |
|---|---|---|---|
| CSS Variables | ~0.1ms | Minimal | None |
| @Input() Styling | ~2-5ms | Higher | Every change |
| ::ng-deep | ~1-3ms | Moderate | None (but deprecated) |
Conclusion: CSS Custom Properties are the fastest, most maintainable approach for component styling in modern Angular applications.