Morten Sæther

← Blog

Episode 11: Custom Styling with CSS

16 March 2026

Transforming Your Portal’s Visual Identity with Advanced Styling Techniques

Introduction

While basic styling gets you started, truly professional portals require advanced CSS techniques that go beyond simple color changes. This episode teaches you how to create sophisticated visual designs, implement complex layouts, override Power Pages defaults effectively, and build responsive designs that work beautifully across all devices and screen sizes.

Key Concepts

Learning Objectives

By the end of this episode, you will be able to:

Why Advanced CSS Matters

Professional portals require more than basic theming—they need sophisticated design systems that enhance usability, reinforce brand identity, and create memorable user experiences. Advanced CSS techniques allow you to create unique interfaces while maintaining the robust functionality that Power Pages provides.

Step-by-Step Guide

1. Understanding Power Pages CSS Specificity and Inheritance

CSS Specificity in Power Pages Context:

/* Understanding specificity levels for effective overrides */

/* Low specificity - may not override Power Pages defaults */
.btn { background-color: blue; }  /* Specificity: 10 */

/* Medium specificity - good for component overrides */
.portal-form .btn { background-color: blue; }  /* Specificity: 20 */

/* High specificity - for specific overrides */
.entityform .form-group .btn-primary { background-color: blue; }  /* Specificity: 30 */

/* Highest specificity - use sparingly */
.custom-portal .entityform .form-group .btn-primary { background-color: blue !important; }  /* Specificity: 40 + !important */

Safe Override Patterns:

/* Best practices for overriding Power Pages styles */

/* 1. Use specific container classes to scope your changes */
.custom-portal-theme {
    /* All custom styles within this container */
}

.custom-portal-theme .btn-primary {
    background: linear-gradient(45deg, #007bff, #0056b3);
    border: none;
    box-shadow: 0 4px 15px rgba(0, 123, 255, 0.3);
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.custom-portal-theme .btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0, 123, 255, 0.4);
}

/* 2. Use data attributes for state-based styling */
.form-section[data-state="loading"] {
    opacity: 0.6;
    pointer-events: none;
}

.form-section[data-state="error"] .form-control {
    border-color: #dc3545;
    box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}

/* 3. Leverage CSS custom properties for theming */
.custom-portal-theme {
    --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
    --success-color: #10d876;
    --warning-color: #ffb400;
    --error-color: #ff4757;
}

2. Advanced Layout Techniques

CSS Grid for Complex Layouts:

/* Advanced grid layouts for portal pages */

.portal-dashboard {
    display: grid;
    grid-template-columns: 250px 1fr 300px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas: 
        "sidebar header header"
        "sidebar main widgets"
        "sidebar footer footer";
    min-height: 100vh;
    gap: 1.5rem;
}

.dashboard-sidebar { grid-area: sidebar; }
.dashboard-header { grid-area: header; }
.dashboard-main { grid-area: main; }
.dashboard-widgets { grid-area: widgets; }
.dashboard-footer { grid-area: footer; }

/* Responsive grid adjustments */
@media (max-width: 1024px) {
    .portal-dashboard {
        grid-template-columns: 1fr;
        grid-template-areas: 
            "header"
            "sidebar"
            "main"
            "widgets"
            "footer";
    }
    
    .dashboard-sidebar {
        order: -1;
    }
}

/* Advanced flexbox patterns */
.dynamic-card-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    align-items: stretch;
}

.dynamic-card-grid .card {
    flex: 1 1 calc(33.333% - 1rem);
    min-width: 280px;
    display: flex;
    flex-direction: column;
}

.dynamic-card-grid .card .card-content {
    flex-grow: 1;
}

Advanced Component Styling:

/* Sophisticated form styling */
.advanced-form-group {
    position: relative;
    margin-bottom: 2rem;
}

.floating-label-input {
    width: 100%;
    padding: 1rem 1rem 0.5rem;
    border: 2px solid #e1e5e9;
    border-radius: 8px;
    background: transparent;
    font-size: 1rem;
    transition: all 0.3s ease;
}

.floating-label {
    position: absolute;
    top: 1rem;
    left: 1rem;
    color: #6c757d;
    font-size: 1rem;
    transition: all 0.3s ease;
    pointer-events: none;
    background: white;
    padding: 0 0.5rem;
}

.floating-label-input:focus,
.floating-label-input:not(:placeholder-shown) {
    border-color: #007bff;
    outline: none;
}

.floating-label-input:focus + .floating-label,
.floating-label-input:not(:placeholder-shown) + .floating-label {
    top: -0.5rem;
    left: 0.75rem;
    font-size: 0.875rem;
    color: #007bff;
}

/* Advanced table styling */
.advanced-data-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
    background: white;
}

.advanced-data-table thead th {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: white;
    padding: 1.5rem 1rem;
    text-align: left;
    font-weight: 600;
    position: relative;
    border: none;
}

.advanced-data-table thead th::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 2px;
    background: rgba(255, 255, 255, 0.3);
}

.advanced-data-table tbody td {
    padding: 1rem;
    border-bottom: 1px solid #f1f3f4;
    transition: background-color 0.2s ease;
}

.advanced-data-table tbody tr:hover td {
    background-color: #f8f9fa;
}

.advanced-data-table tbody tr:last-child td {
    border-bottom: none;
}

3. Advanced Animation and Micro-Interactions

CSS Animations for Enhanced UX:

/* Loading states and transitions */
@keyframes shimmer {
    0% { background-position: -200px 0; }
    100% { background-position: calc(200px + 100%) 0; }
}

.loading-shimmer {
    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
    background-size: 200px 100%;
    animation: shimmer 1.5s infinite;
}

.skeleton-loader {
    border-radius: 4px;
    display: inline-block;
}

.skeleton-text {
    height: 1rem;
    width: 100%;
    margin-bottom: 0.5rem;
}

.skeleton-text:last-child {
    width: 60%;
}

/* Advanced hover effects */
.interactive-card {
    position: relative;
    overflow: hidden;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    cursor: pointer;
}

.interactive-card::before {
    content: '';
    position: absolute;
    top: 0;
    left: -100%;
    width: 100%;
    height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
    transition: left 0.5s ease;
}

.interactive-card:hover::before {
    left: 100%;
}

.interactive-card:hover {
    transform: translateY(-8px) scale(1.02);
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}

/* Staggered animations */
.stagger-animation {
    opacity: 0;
    transform: translateY(30px);
    animation: fadeInUp 0.6s ease forwards;
}

.stagger-animation:nth-child(1) { animation-delay: 0.1s; }
.stagger-animation:nth-child(2) { animation-delay: 0.2s; }
.stagger-animation:nth-child(3) { animation-delay: 0.3s; }
.stagger-animation:nth-child(4) { animation-delay: 0.4s; }

@keyframes fadeInUp {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

Advanced State Management with CSS:

/* Complex state-based styling */
.multi-state-component {
    --state-color: #6c757d;
    --state-bg: #f8f9fa;
    --state-border: #dee2e6;
    
    border: 2px solid var(--state-border);
    background: var(--state-bg);
    color: var(--state-color);
    transition: all 0.3s ease;
}

.multi-state-component[data-state="success"] {
    --state-color: #ffffff;
    --state-bg: linear-gradient(135deg, #10d876 0%, #00b353 100%);
    --state-border: #10d876;
}

.multi-state-component[data-state="warning"] {
    --state-color: #ffffff;
    --state-bg: linear-gradient(135deg, #ffb400 0%, #ff8c00 100%);
    --state-border: #ffb400;
}

.multi-state-component[data-state="error"] {
    --state-color: #ffffff;
    --state-bg: linear-gradient(135deg, #ff4757 0%, #c44569 100%);
    --state-border: #ff4757;
}

/* Advanced form validation styling */
.form-field-wrapper {
    position: relative;
}

.form-field-wrapper .validation-icon {
    position: absolute;
    right: 1rem;
    top: 50%;
    transform: translateY(-50%);
    opacity: 0;
    transition: all 0.3s ease;
}

.form-field-wrapper[data-validation="valid"] .validation-icon.success {
    opacity: 1;
    color: #10d876;
}

.form-field-wrapper[data-validation="invalid"] .validation-icon.error {
    opacity: 1;
    color: #ff4757;
}

.form-field-wrapper[data-validation="invalid"] .form-control {
    border-color: #ff4757;
    background-color: rgba(255, 71, 87, 0.05);
}

4. Advanced Responsive Design Patterns

Container Queries and Modern Responsive Techniques:

/* Modern responsive design with container queries */
.responsive-card-container {
    container-type: inline-size;
}

.responsive-card {
    padding: 1rem;
    background: white;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

@container (min-width: 300px) {
    .responsive-card {
        padding: 1.5rem;
        display: flex;
        align-items: center;
        gap: 1rem;
    }
    
    .responsive-card .card-content {
        flex: 1;
    }
}

@container (min-width: 500px) {
    .responsive-card {
        padding: 2rem;
    }
    
    .responsive-card .card-actions {
        display: flex;
        gap: 0.5rem;
    }
}

/* Advanced responsive typography */
.responsive-heading {
    font-size: clamp(1.5rem, 4vw, 3rem);
    line-height: 1.2;
    font-weight: 700;
}

.responsive-text {
    font-size: clamp(1rem, 2.5vw, 1.125rem);
    line-height: 1.6;
}

/* Fluid spacing system */
.section-padding {
    padding: clamp(2rem, 8vw, 6rem) clamp(1rem, 4vw, 2rem);
}

.element-margin {
    margin-bottom: clamp(1rem, 3vw, 2rem);
}

Advanced Mobile Optimizations:

/* Touch-friendly interactions */
@media (hover: none) and (pointer: coarse) {
    .interactive-element {
        min-height: 44px;
        min-width: 44px;
        padding: 0.75rem;
    }
    
    .hover-effect:hover {
        /* Disable hover effects on touch devices */
        transform: none;
        box-shadow: none;
    }
    
    .touch-feedback:active {
        transform: scale(0.95);
        opacity: 0.8;
    }
}

/* Improved mobile forms */
@media (max-width: 768px) {
    .mobile-form-stack .form-row {
        flex-direction: column;
        gap: 1rem;
    }
    
    .mobile-form-stack .form-control {
        font-size: 16px; /* Prevents zoom on iOS */
        padding: 1rem;
    }
    
    .mobile-form-stack .btn {
        width: 100%;
        padding: 1rem;
        font-size: 1.1rem;
        margin-bottom: 0.5rem;
    }
    
    /* Improved mobile tables */
    .mobile-responsive-table {
        display: block;
        overflow-x: auto;
        white-space: nowrap;
    }
    
    .mobile-responsive-table table {
        min-width: 600px;
    }
}

5. Advanced CSS Architecture and Organization

Scalable CSS Architecture:

/* 1. CSS Custom Properties for Design System */
:root {
    /* Color System */
    --color-primary-50: #eff6ff;
    --color-primary-100: #dbeafe;
    --color-primary-500: #3b82f6;
    --color-primary-600: #2563eb;
    --color-primary-900: #1e3a8a;
    
    /* Typography Scale */
    --text-xs: 0.75rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.25rem;
    --text-2xl: 1.5rem;
    --text-3xl: 1.875rem;
    
    /* Spacing Scale */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-4: 1rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-12: 3rem;
    --space-16: 4rem;
    
    /* Border Radius Scale */
    --radius-sm: 0.25rem;
    --radius-md: 0.5rem;
    --radius-lg: 0.75rem;
    --radius-xl: 1rem;
    
    /* Shadow Scale */
    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
    --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}

/* 2. Component-Based Architecture */
.c-button {
    /* Base button component */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-2) var(--space-4);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
    line-height: 1.5;
    text-decoration: none;
    cursor: pointer;
    transition: all 0.2s ease;
}

.c-button--primary {
    background-color: var(--color-primary-500);
    color: white;
}

.c-button--primary:hover {
    background-color: var(--color-primary-600);
}

.c-button--large {
    padding: var(--space-4) var(--space-6);
    font-size: var(--text-base);
}

/* 3. Utility Classes */
.u-text-center { text-align: center; }
.u-text-left { text-align: left; }
.u-text-right { text-align: right; }

.u-mt-1 { margin-top: var(--space-1); }
.u-mt-2 { margin-top: var(--space-2); }
.u-mt-4 { margin-top: var(--space-4); }

.u-hidden { display: none; }
.u-sr-only { 
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
}

Practical Example: TechStart Solutions Advanced Styling

Let’s implement a sophisticated design system for TechStart Solutions:

Complete Design System Implementation:

/* TechStart Solutions Advanced Design System */
:root {
    /* Brand Color Palette */
    --ts-blue-50: #eff6ff;
    --ts-blue-100: #dbeafe;
    --ts-blue-500: #0066cc;
    --ts-blue-600: #0056b3;
    --ts-blue-900: #003d82;
    
    --ts-slate-50: #f8fafc;
    --ts-slate-100: #f1f5f9;
    --ts-slate-500: #64748b;
    --ts-slate-900: #0f172a;
    
    /* Semantic Colors */
    --ts-success: #10d876;
    --ts-warning: #ffb400;
    --ts-error: #ff4757;
    --ts-info: #17a2b8;
    
    /* Advanced Gradients */
    --ts-gradient-primary: linear-gradient(135deg, var(--ts-blue-500) 0%, var(--ts-blue-600) 100%);
    --ts-gradient-surface: linear-gradient(180deg, white 0%, var(--ts-slate-50) 100%);
    --ts-gradient-overlay: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.1) 100%);
}

/* Advanced Component System */
.ts-card-premium {
    background: var(--ts-gradient-surface);
    border: 1px solid var(--ts-slate-100);
    border-radius: 16px;
    padding: 2rem;
    position: relative;
    overflow: hidden;
    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.ts-card-premium::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: var(--ts-gradient-primary);
}

.ts-card-premium:hover {
    transform: translateY(-4px);
    box-shadow: 0 20px 40px rgba(0, 102, 204, 0.1);
}

/* Advanced Data Visualization */
.ts-metric-card {
    background: white;
    border-radius: 12px;
    padding: 1.5rem;
    box-shadow: var(--shadow-md);
    position: relative;
    overflow: hidden;
}

.ts-metric-value {
    font-size: 2.5rem;
    font-weight: 700;
    color: var(--ts-blue-600);
    line-height: 1;
    margin-bottom: 0.5rem;
}

.ts-metric-label {
    color: var(--ts-slate-500);
    font-size: 0.875rem;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.ts-metric-trend {
    position: absolute;
    top: 1rem;
    right: 1rem;
    display: flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.75rem;
    font-weight: 600;
}

.ts-metric-trend--up {
    color: var(--ts-success);
}

.ts-metric-trend--down {
    color: var(--ts-error);
}

6. Performance Optimization and Best Practices

CSS Performance Techniques:

/* Efficient selectors and containment */
.optimized-component {
    contain: layout style paint;
    will-change: transform;
}

/* Efficient animations */
.gpu-accelerated {
    transform: translateZ(0);
    backface-visibility: hidden;
}

/* Critical CSS inlining strategy */
.above-fold-critical {
    /* Only essential styles for initial viewport */
}

/* Non-critical styles loaded asynchronously */
.below-fold-enhanced {
    /* Enhanced styles loaded after page load */
}

Troubleshooting Advanced CSS Issues

Problem: Complex animations causing performance issues Solution: Use transform and opacity for animations, enable hardware acceleration with translateZ(0)

Problem: CSS Grid not working in older browsers Solution: Implement progressive enhancement with flexbox fallbacks

Problem: Custom properties not supported Solution: Use PostCSS or provide fallback values

Problem: High specificity conflicts Solution: Use CSS architecture patterns and avoid deep nesting

Summary

Advanced CSS techniques transform basic portals into sophisticated, professional applications. Focus on creating maintainable architecture, optimizing performance, and enhancing user experience through thoughtful design. Remember that advanced styling should enhance functionality, not replace it.

In the next episode, you’ll learn how to create complex, multi-step forms with advanced validation and conditional logic that guides users through sophisticated data collection processes.

4. Documentation and Maintenance

Set yourself up for long-term success:

Practical Example

Consider implementing this episode’s techniques for a customer portal where users need enhanced functionality beyond basic templates. The implementation should:

Apply the specific techniques from this episode while following the general principles of good portal development.

Common Implementation Patterns

Pattern When to Use Benefits Considerations
Progressive Enhancement Adding advanced features Ensures basic functionality always works Requires careful planning
Responsive Design Multi-device support Consistent experience across devices May increase complexity
Modular Development Complex customizations Easier maintenance and updates Requires good architecture
Performance Monitoring All implementations Early detection of issues Ongoing effort required

Troubleshooting Tips

Advanced Considerations

As you implement these intermediate techniques, consider:

Summary

Custom styling transforms a generic portal into a branded experience that users trust and enjoy. Start with small changes, test across devices, and build a style guide for consistency. Next, you’ll learn how to create more sophisticated forms with advanced configuration options.