Skip to content

SCSS & Styles

At Terra, we write SCSS (Sassy CSS) using a structured approach that leverages utilities, foundation variables, and @extend to create maintainable, consistent stylesheets.


Component stylesheets live in organized folders within the src/scss/ directory:

src/scss/
├── framework/
│ ├── _var/
│ │ └── _vars.scss # Foundation variables
│ ├── components/
│ │ ├── cta/
│ │ │ └── _c--cta-a.scss # Your component
│ │ ├── card/
│ │ └── hero/
│ ├── foundation/
│ │ ├── background/
│ │ ├── color/
│ │ ├── font/ # Font utilities
│ │ ├── gap/
│ │ ├── grid/ # Grid system
│ │ ├── reset/
│ │ ├── spaces/ # Spacing utilities
│ │ └── _foundation.scss
│ ├── utilities/
│ │ └── _utilities.scss # Utility classes
│ └── global-components/ # Pre-built components
└── style.scss # Main entry file

Let’s build a CTA component (c—cta-a) step-by-step. This component will have:

  • 10-column grid centered with justify-center utility
  • Title, subtitle, and button
  • Background color and border
<section class="c--cta-a u--pt-10 u--pb-10">
<div class="f--container">
<div class="f--row u--justify-content-center">
<div class="f--col-10 f--col-tablets-12">
<div class="c--cta-a__wrapper">
<h2 class="c--cta-a__wrapper__title">
Ready to Transform Your Business?
</h2>
<p class="c--cta-a__wrapper__subtitle">
Join thousands of companies already using our platform.
</p>
<a href="/contact" class="c--cta-a__wrapper__button">
Get Started Today
</a>
</div>
</div>
</div>
</div>
</section>

Key elements:

  • .f--container - Centers the content
  • .f--row u--justify-content-center - Creates flex row with centered content
  • .f--col-10 - 10 columns wide (83.33%)
  • BEM naming - .c--cta-a__wrapper__title

Create the file: src/scss/framework/components/cta/_c--cta-a.scss

@use "sass:map";
@use "@scss/framework/_var/_vars.scss" as *;
@use "@scssUtilities/utilities.scss";
@use "@scssFoundation/foundation.scss";
.c--cta-a {
@extend .u--position-relative;
@extend .u--overflow-hidden;
background-color: map.get($color-options, a); // Navy background
border: 2px solid map.get($color-options, c); // Brand border
border-radius: $measure * 2; // 16px border radius
&__wrapper {
@extend .u--display-flex;
@extend .u--flex-direction-column;
@extend .u--align-items-center;
@extend .f--sp-e; // Bottom spacing
gap: $measure * 3; // 24px gap between items
padding: $measure * 8 $measure * 5; // 64px top/bottom, 40px left/right
@media all and ($viewport-type: $tablets) {
padding: $measure * 6 $measure * 4; // 48px / 32px on tablets
gap: $measure * 2; // 16px gap on tablets
}
&__title {
@extend .f--font-c; // Large font size
@extend .f--color-w;
@extend .u--font-semibold;
@extend .u--text-align-center;
@extend .u--margin-0;
}
&__subtitle {
@extend .f--font-f; // Base font size
@extend .f--color-w;
@extend .u--text-align-center;
@extend .u--margin-0;
opacity: 0.9;
}
&__button {
@extend .u--display-inline-block;
@extend .f--font-g;
@extend .u--font-semibold;
background-color: map.get($color-options, c); // Brand color
color: map.get($color-options, w); // White text
padding: $measure * 2 $measure * 4; // 16px / 32px
border-radius: $measure; // 8px
text-decoration: none;
transition: transform $time-a $ease-standard-a,
background-color $time-a $ease-standard-a;
@media all and (hover: hover) and (pointer: fine) {
&:hover {
transform: translateY(-2px);
background-color: map.get($color-options, d); // Darker on hover
}
}
}
}
}

@use "sass:map"; // Sass map utilities
@use "@scss/framework/_var/_vars.scss" as *; // Variables
@use "@scssUtilities/utilities.scss"; // Utility classes
@use "@scssFoundation/foundation.scss"; // Foundation systems

Why these imports?

  • sass:map - Access color palettes with map.get()
  • _vars.scss - Contains spacing ($measure), colors ($color-options), timing ($time-a)
  • utilities.scss - Provides .u-- classes for common patterns
  • foundation.scss - Typography (.f--font-*), spacing (.f--sp-*)

Terra provides a comprehensive variable system for consistent design:

// Access colors from the color palette
background-color: map.get($color-options, a); // Navy
border-color: map.get($color-options, c); // Brand color
color: map.get($color-options, w); // White

Common color keys (random examples):

  • a - Primary navy
  • c - Brand accent color
  • w - White
  • f - Light gray (borders)
  • h - Text gray

All spacing uses the $measure unit (8px base):

padding: $measure * 8 $measure * 5; // 64px / 40px
gap: $measure * 3; // 24px
border-radius: $measure * 2; // 16px

Common multipliers:

  • $measure * 1 = 8px
  • $measure * 2 = 16px
  • $measure * 3 = 24px
  • $measure * 4 = 32px
  • $measure * 5 = 40px
  • $measure * 8 = 64px

Use foundation classes for consistent type (random examples):

@extend .f--font-a; // Largest (70px)
@extend .f--font-b; // Very large (60px)
@extend .f--font-c; // Large (48px)
@extend .f--font-d; // Medium-large (32px)
@extend .f--font-f; // Base (18px)
@extend .f--font-g; // Small (16px)

For smooth animations:

transition: transform $time-a $ease-standard-a;
// $time-a = 0.3s
// $ease-standard-a = cubic-bezier(0.4, 0.0, 0.2, 1)

Available timing:

  • $time-a - Standard (0.3s)
  • $time-b - Fast (0.2s)
  • $time-c - Slow (0.5s)

Instead of writing CSS from scratch, we @extend utility classes:

@extend .u--display-flex; // display: flex
@extend .u--flex-direction-column; // flex-direction: column
@extend .u--align-items-center; // align-items: center
@extend .u--position-relative; // position: relative
@extend .u--text-align-center; // text-align: center

Benefits:

  • ✅ Smaller CSS bundle (classes are reused)
  • ✅ Consistency across components
  • ✅ Less code to write
  • ✅ Centralized updates
.c--cta-a {
// Block-level styles
background-color: map.get($color-options, a);
&__wrapper {
// Element styles
padding: $measure * 8 $measure * 5;
&__title {
// Sub-element styles
@extend .f--font-c;
}
&__subtitle {
// Another sub-element
@extend .f--font-f;
}
&__button {
// Button element
padding: $measure * 2 $measure * 4;
}
}
}

Compiled output:

.c--cta-a { ... }
.c--cta-a__wrapper { ... }
.c--cta-a__wrapper__title { ... }
.c--cta-a__wrapper__subtitle { ... }
.c--cta-a__wrapper__button { ... }

Use breakpoint variables for media queries:

// Desktop first
padding: $measure * 8 $measure * 5;
// Tablets and below
@media all and ($viewport-type: $tablets) {
padding: $measure * 6 $measure * 4;
}
// Mobile
@media all and ($viewport-type: $mobile) {
padding: $measure * 5 $measure * 3;
}

Available breakpoints:

  • $tablets - 810px and below
  • $tabletm - 1024px and below
  • $mobile - 580px and below
  • $laptop - 1570px and below

Always wrap hover states to avoid issues on touch devices:

@media all and (hover: hover) and (pointer: fine) {
&:hover {
transform: translateY(-2px);
background-color: map.get($color-options, d);
}
}

Why this media query?

  • hover: hover - Device supports true hover
  • pointer: fine - Device has precise pointer (mouse)
  • Prevents sticky hover states on mobile/touch devices

Utility classes are pre-built, single-purpose classes that handle common CSS patterns.

Display:

@extend .u--display-block;
@extend .u--display-flex;
@extend .u--display-inline-block;
@extend .u--display-none;

Flexbox:

@extend .u--flex-direction-column;
@extend .u--flex-direction-row;
@extend .u--align-items-center;
@extend .u--justify-content-center;
@extend .u--justify-content-space-between;

Spacing:

@extend .u--mb-3; // margin-bottom: $measure * 3
@extend .u--mt-5; // margin-top: $measure * 5
@extend .u--pt-10; // padding-top: $measure * 10
@extend .u--pb-7; // padding-bottom: $measure * 7

Typography:

@extend .u--text-align-center;
@extend .u--text-align-left;
@extend .u--font-bold;
@extend .u--font-semibold;

Position:

@extend .u--position-relative;
@extend .u--position-absolute;
@extend .u--overflow-hidden;

Foundation classes provide design system tokens:

// Font sizes
@extend .f--font-a; // h1 size
@extend .f--font-b; // h2 size
@extend .f--font-c; // h3 size
@extend .f--font-f; // body size
// Font colors
@extend .f--color-a; // Primary text color
@extend .f--color-w; // White text
@extend .f--color-h; // Gray text
// Bottom spacing (margin-bottom)
@extend .f--sp-a; // Small spacing
@extend .f--sp-c; // Medium spacing
@extend .f--sp-e; // Large spacing

After creating your component SCSS, register it in the main style.scss:

File: src/scss/style.scss

// ... other imports
@use "@scssComponents/cta/_c--cta-a.scss";
@use "@scssComponents/cta/_c--cta-b.scss";
// ... rest of imports

Import Order:

  1. Keep similar components grouped (all CTAs together)
  2. Maintain alphabetical order within groups
  3. Remove test components before production

Terra provides a pre-built HTML and SCSS framework called Global Components that offers readily usable components. You can easily integrate these components into your projects by simply copying and pasting the code. This framework streamlines the development process by offering a collection of pre-designed elements for increased efficiency and consistency.

📚 Global Components Documentation

Here’s how to use g--card-08 from the Global Components library:

HTML:

<div class="g--card-08">
<h3 class="g--card-08__item-primary">Investment Banking</h3>
<div class="g--card-08__list-group">
<p class="g--card-08__list-group__item">Learn More</p>
</div>
</div>

SCSS:

@use "sass:map";
@use "@scss/framework/_var/_vars.scss" as *;
@use "@scssGlobalComponents/_global-vars.scss" as *;
@use "@scssFoundation/_foundation.scss";
.g--card-08 {
@include make-card-08();
@include make-card-08-modifier(
$item-primary-options: (
"className": f--font-b f--color-c,
),
$list-group-item-options: (
"className": f--font-d f--color-h,
),
);
&--second {
@include make-card-08-modifier(
$list-group-item-options: (
"className": f--font-f,
"color": map.get($color-options, f)
),
);
}
}

Key features:

  • Uses @include mixins from Global Components
  • Leverages modifier patterns for variations
  • Integrates with Terra’s foundation variables
  • Allows customization through options

Use foundation variables:

// ✅ Good
padding: $measure * 5;
color: map.get($color-options, a);
// ❌ Bad
padding: 40px;
color: #1a1536;

Extend utilities when possible:

// ✅ Good
@extend .u--display-flex;
@extend .u--align-items-center;
// ❌ Bad - writing CSS that already exists
display: flex;
align-items: center;

Use responsive breakpoints:

// ✅ Good
padding: $measure * 8;
@media all and ($viewport-type: $tablets) {
padding: $measure * 6;
}
// ❌ Bad - hardcoded breakpoint
@media (max-width: 768px) {
padding: 48px;
}

Wrap hover states:

// ✅ Good
@media all and (hover: hover) and (pointer: fine) {
&:hover {
transform: scale(1.05);
}
}
// ❌ Bad - causes issues on touch devices
&:hover {
transform: scale(1.05);
}

Don’t hardcode values:

// ❌ Wrong
padding: 37px;
color: #ff5733;
font-size: 21px;

Don’t skip BEM nesting:

// ❌ Wrong
.c--card { }
.card__title { } // Doesn't follow block name
// ✅ Correct
.c--card { }
.c--card__title { }

Don’t create deep nesting:

// ❌ Wrong - too deep
.c--card__wrapper__content__inner__title { }
// ✅ Correct - flatter structure
.c--card__title { }

Now that you understand SCSS structure and styling, let’s learn how to add interactivity with JavaScript.

→ Continue to JavaScript

Knowledge Check

Test your understanding of this section

Loading questions...