Skip to content

Variables & Tokens

The Guppy theme uses a deliberate SCSS architecture on top of Bootstrap 5, complemented by custom functions, mixins, and token sets. This page is the full developer reference.

Directory layout

text
src/Resources/app/storefront/src/scss/
├── overrides.scss                 # theme hook, loads before @DmfGuppyTheme
├── base.scss                      # theme hook, loads after @DmfGuppyTheme
├── abstract/
│   ├── functions/
│   │   ├── boolean.scss
│   │   ├── px-to-rem.scss
│   │   └── strip-unit.scss
│   ├── mixins/
│   │   ├── button-adaptive-hover.scss
│   │   ├── focus-style.scss
│   │   └── rlh.scss
│   └── variables/
│       ├── bootstrap.scss
│       └── custom.scss
├── base/                          # accessibility, container, typography
├── components/                    # buttons, cards, forms, slider, …
├── elements/                      # skip-link, splide-slider
├── layout/                        # header, footer, USP, navigation, …
├── page/                          # account, checkout, detail, …
└── skin/shopware/                 # integration with the default Shopware storefront
    ├── abstract/variables/
    │   ├── bootstrap.scss
    │   ├── custom.scss
    │   └── theme.scss
    ├── base.scss
    ├── base/                      # base.scss, inter-fontface.scss
    └── component/                 # cms-block, cms-element, modal, …

Build order

theme.json defines the compile order:

json
{
  "style": [
    "app/storefront/src/scss/overrides.scss",
    "@StorefrontBootstrap",
    "@Plugins",
    "app/storefront/src/scss/skin/shopware/base.scss",
    "app/storefront/src/scss/base.scss"
  ]
}

Order matters: overrides.scss loads before Bootstrap, it's where early variable overrides go; base.scss loads after everything and contains the final selector styles.

Functions

px-to-rem($px, $base-font-size: 16px)

scss
@function px-to-rem($px, $base-font-size: 16px) {
    @return ($px / $base-font-size) * 1rem;
}

.element {
    font-size: px-to-rem(18px); // 1.125rem
    padding: px-to-rem(24px);   // 1.5rem
}

strip-unit($value)

scss
@function strip-unit($value) {
    @return ($value / ($value * 0 + 1));
}

$value: strip-unit(100px); // 100

Bootstrap color functions (available)

scss
shade-color($color, $weight)   // darker
tint-color($color, $weight)    // lighter
shift-color($color, $weight)   // automatic (based on lightness)

Mixins

rlh($value) and line-height($value)

Responsive line heights via Bootstrap RFS:

scss
h1 { @include line-height(1.2); }
.title { @include rlh(1.5, line-height); }

focus-style

Consistent focus styles for accessibility:

scss
@mixin focus-style {
    outline-offset: $focus-outline-offset;
    outline: $focus-outline-color solid $focus-outline-width;
    box-shadow: $focus-outline-box-shadow;
}

button:focus-visible { @include focus-style; }

button-adaptive-hover($base-color)

Hover effects only when the device truly supports hover:

scss
@mixin button-adaptive-hover($base-color) {
    &:hover {
        @media (hover: hover) {
            background-color: shade-color($base-color, 15%);
        }
    }
}

text-ellipsis and text-clamp($lines)

scss
@mixin text-ellipsis { /* single line */ }
@mixin text-clamp($lines: 2) { /* multi line */ }

visually-hidden

Screen-reader-only content:

scss
.sr-only { @include visually-hidden; }

Bootstrap variables (excerpt)

The most important token families from abstract/variables/bootstrap.scss. They bind to $sw-* tokens, which in turn are populated from the theme configuration.

scss
// Colors
$gray-100: $sw-color-gray-100 !default;
$gray-900: $sw-color-gray-900 !default;

// Typography
$font-size-base: $sw-font-size-base !default;
$h1-font-size:   $sw-h1-font-size !default;

// Container and grid
$container-max-widths: (xs: $guppy-container-width-default) !default;
$grid-gutter-width: 1.5rem !default;

// Buttons and inputs
$btn-font-size:     $sw-input-btn-font-size !default;
$btn-border-radius: $sw-input-btn-border-radius !default;
$btn-font-weight:   $sw-input-btn-font-weight !default;

Custom variables (excerpt)

Guppy-specific tokens in abstract/variables/custom.scss:

scss
// Icons
$icon-base-size:                  22px !default;
$icon-base-color:                 currentColor !default;
$icon-accessibility-touch-size:   44px !default;

// Product images
$product-image-height:            240px !default;
$product-image-aspect-ratio:      #{10/9} !default;
$product-image-background:        $sw-color-product-image !default;

// Accessibility
$focus-outline-width:             2px !default;
$focus-outline-color:             $sw-color-brand-primary !default;
$focus-outline-offset:            2px !default;
$focus-outline-box-shadow:        0 0 0 2px #fff;

// Delivery status
$guppy-delivery-shipping-free-color:      #023B5A;
$guppy-delivery-shipping-free-background: #CEEDFE;
$guppy-delivery-available-color:          #154634;
$guppy-delivery-available-background:     #D3F2E7;
$guppy-delivery-restock-color:            #5D3B00;
$guppy-delivery-restock-background:       #FFEFD4;
$guppy-delivery-soldout-color:            #303030;
$guppy-delivery-soldout-background:       #EEEEEE;

Token tables

Brand colors

VariableDefaultUse
$sw-color-brand-primary#215AFFPrimary
$sw-color-brand-secondary#0B1845Secondary
$sw-background-color#FFFFFFBackground
$sw-border-color#CFD1D7Borders
$sw-text-color#1B1F29Text color
$sw-headline-color#1B1F29Headlines

Greyscales

VariableDefaultUse
$sw-color-gray-100#F9F9F9Backgrounds, footer
$sw-color-gray-200#EEEEEEDisabled elements
$sw-color-gray-300#BCC1C7Borders, dividers
$sw-color-gray-400#CED4DAInput borders
$sw-color-gray-500#ADB5BDPlaceholders
$sw-color-gray-600#798490Secondary text
$sw-color-gray-700#495057Text
$sw-color-gray-800#4A545BHeadlines
$sw-color-gray-900#212529Body text

Typography

VariableDefaultUse
$sw-font-size-base1remBase font size
$sw-h1-font-size32pxH1
$sw-h2-font-size24pxH2
$sw-h3-font-size20pxH3
$sw-h4-font-size18pxH4
$sw-h5-font-size16pxH5
$sw-h6-font-size15pxH6
$sw-h1-line-height44pxH1 line height
$sw-h2-line-height36pxH2 line height
$sw-h3-line-height32pxH3 line height

Accessibility

VariableDefaultUse
$focus-outline-width2pxFocus outline width
$focus-outline-color$sw-color-brand-primaryFocus outline color
$focus-outline-offset2pxDistance from element
$focus-outline-box-shadow0 0 0 2px #fffAdditional shadow
$icon-accessibility-touch-size44pxMin. touch target

Container and breakpoints

Standard Bootstrap breakpoints:

BreakpointClass infixDimensionContainer max-width
Extra small< 576 px100 %
Smallsm≥ 576 px540 px
Mediummd≥ 768 px720 px
Largelg≥ 992 px960 px
Extra largexl≥ 1200 px1140 px
XXLxxl≥ 1400 px1320 px

Guppy container padding per breakpoint:

scss
$guppy-container-default-padding-x-mobile: 10px;
$guppy-container-default-padding-x-sm:     24px;
$guppy-container-default-padding-x-md:     48px;
$guppy-container-default-padding-x-lg:     48px;
$guppy-container-default-padding-x-xl:     48px;
$guppy-container-default-padding-x-xxl:    48px;

Breakpoint mixins:

scss
@include media-breakpoint-up(md)            { /* ≥ 768 px */ }
@include media-breakpoint-down(lg)          { /* < 992 px */ }
@include media-breakpoint-between(md, xl)   { /* 768–1199 px */ }
@include media-breakpoint-only(lg)          { /* 992–1199 px */ }

Child theme overrides

In a child theme:

scss
// overrides.scss, variable overrides
$guppy-usp-background-color: #f8f9fa !default;
$product-image-height:       300px !default;
$primary:                    #007bff !default;
scss
// base.scss, additional styles
.my-custom-component {
    background-color: $primary;
    .title { @include line-height(1.3); }
}

Don't break the order

Variables must be set in overrides.scss (loads before Bootstrap), in base.scss they apply too late.

Best practices

Theme variables instead of hardcodes

scss
// good
.custom-component {
    color: $sw-text-color;
    background-color: $sw-color-gray-100;
}

// bad
.custom-component {
    color: #333;
    background-color: #f9f9f9;
}

Bootstrap breakpoints instead of custom media queries

scss
// good
@include media-breakpoint-up(md) { display: flex; }

// bad
@media (min-width: 768px) { display: flex; }

Focus styles via mixin

scss
// good
.custom-button:focus-visible { @include focus-style; }

// bad
.custom-button:focus { outline: 2px solid blue; }

Debugging

scss
@debug "Container width: #{$guppy-container-width-default}";
@debug "Primary color: #{$sw-color-brand-primary}";

Practical example

scss
// _my-component.scss
.my-component {
    background-color: $sw-color-gray-100;
    border: 1px solid $sw-border-color;
    border-radius: $border-radius;
    padding: $spacer;

    .title {
        font-size: $sw-h3-font-size;
        @include line-height($h3-line-height);
        color: $sw-headline-color;
    }

    @include media-breakpoint-up(md) {
        display: flex;
        gap: $spacer * 2;
    }

    &:focus-visible { @include focus-style; }

    .action-button {
        @include button-reset;
        @include button-adaptive-hover($sw-color-brand-primary);
    }
}