Functions & Mixins
This is the SCSS-authoring reference for Sulphuris. Everything here is callable from your own stylesheets once you import the relevant partial.
Importing
@use "sulphuris/core/utils/helpers" as helpers;
@use "sulphuris/core/utils/generators" as gen;
The utils/index.scss re-forwards both fixes and generators (which itself imports helpers), so @use "sulphuris/core/utils" gives you both.
Unit conversion
toRem($value)
Converts a px value to rem relative to config.$base-font-size. If the value has no px unit it is returned unchanged.
// _config.scss: $base-font-size: 16px
font-size: helpers.toRem(24px); // โ 1.5rem
margin: helpers.toRem(0); // โ 0
toEm($value, $unit: 'em', $base: config.$base-font-size)
Same conversion but returns em by default. toRem delegates to this internally with $unit: 'rem'. $base is what one unit is worth โ override it when the reference is not the document baseline, as the two functions below do.
padding: helpers.toEm(8px); // โ 0.5em
padding: helpers.toEm(8px, 'em', 32px); // โ 0.25em
emit-length($value)
A px length as it should be written into the document: converted under $rem-units, passed straight through when it is off. This is what the generators call, and what your own overrides should call โ keep sources in px and convert once at the point of emission, because gutter halves and offset arithmetic have to happen in one unit and mixing px with a relative unit is a hard Sass error.
padding: helpers.emit-length(32px); // โ 2rem, or 32px with $rem-units off
query-width($value)
Converts a px width for use inside a media query, dividing by a literal 16px rather than $base-font-size. Returns the value unchanged when $rem-units is off.
A media query resolves rem against the browser's font-size setting and never sees the percentage $base-font-size writes onto html, so the two references have to be kept apart โ otherwise a non-default baseline fires the breakpoint at a different width than the layout it switches. Use this for anything that lands in a @media condition, and emit-length() for anything that lands in the document.
// _config.scss: $base-font-size: 20px
@media (min-width: helpers.query-width(1024px)) { โฆ } // โ 64rem, still 1024px
max-width: helpers.emit-length(1024px); // โ 51.2rem, still 1024px
tracking($value, $font-size)
Converts a px letter-spacing to em against the font-size it sits on, not the root โ tracking corrects a size, so it has to move when the size does. Both arguments must be px; anything else passes through, since a relative unit is already a ratio the author chose.
letter-spacing: helpers.tracking(2px, 14px); // โ 0.1428571429em
Fluid sizing
fluid($min, $max, $min-vw: 420px, $max-vw: 1680px)
Returns a clamp() expression that scales a px value linearly with the viewport between $min-vw and $max-vw, clamped at both ends. px in, rem out.
font-size: helpers.fluid(16px, 24px);
// โ clamp(1rem, 0.8333333333rem + 0.6349206349vw, 1.5rem)
Color
color($name)
Returns a CSS custom property reference for a named color. If the name is in config.$colors it emits var(--color-<name>); otherwise it falls back to var(--color-<name>, <name>) so raw values still work.
background: helpers.color(primary); // โ var(--color-primary)
border-color: helpers.color(#ff0000); // โ var(--color-#ff0000, #ff0000)
get-color($name, $mode: '')
Pulls the raw SCSS value from config.$colors (or a named color mode map) at compile time. Use when you need the actual value, not a CSS variable reference.
$brand: helpers.get-color(primary); // raw value from $colors
$dark: helpers.get-color(primary, 'dark'); // raw value from $color-modes.dark
z($name)
Returns a named stacking level from the config.$z-layers map. Warns and returns auto for an unknown name.
z-index: helpers.z(modal); // โ 40
The map ships as: behind -1, base 0, dropdown 10, sticky 20, overlay 30, modal 40, popover 50, toast 60, tooltip 70.
behind is for decorative pseudo-elements that sit under their own content:
&::before { z-index: helpers.z(behind); } // โ -1
Breakpoints
breakpoint($size, $explicit: false) mixin
Wraps @content in a @media query built from the configured breakpoint map. Named sizes match your config.$breakpoints keys (e.g. sm, md, lg, xl, xxl).
$size |
$explicit |
Result |
|---|---|---|
'' |
false |
no media query โ content emitted directly |
md |
false |
min-width only |
md |
true |
min-width and max-width (explicit range) |
min / minimal |
โ | forces $size: '' + $explicit: true (smallest range) |
@include gen.breakpoint(md) {
.sidebar { display: block; }
}
// โ @media only screen and (min-width: 768px) { .sidebar { display: block; } }
@include gen.breakpoint(sm, true) {
.mobile-only { display: flex; }
}
// โ @media only screen and (min-width: 420px) and (max-width: 767px) { ... }
@include gen.breakpoint(min) {
.tiny { font-size: 12px; }
}
// โ @media only screen and (max-width: 419px) { ... }
Transitions
transition($properties, $durations, $easings) mixin
Generates a transition declaration. All parameters accept a single value or a list (one entry per property). $durations and $easings default to config.$default-transition-duration and config.$default-transition-easing. Easing names from config.$custom-easings are resolved automatically.
@include gen.transition(opacity);
// โ transition: opacity 250ms cubic-bezier(0.86, 0, 0.07, 1);
// (defaults: 250ms + the 'ease-in-out-quint' custom easing)
@include gen.transition((opacity, transform), (200ms, 400ms), (ease-in, ease-out));
// โ transition: opacity 200ms ease-in, transform 400ms ease-out;
Selection & form helpers
selection($color: primary) mixin
Sets ::selection background to the named color (resolved via color()).
@include helpers.selection(accent);
// โ ::selection { background: var(--color-accent); }
placeholder($color) mixin
Sets placeholder text color via the standard ::placeholder selector.
input {
@include helpers.placeholder(muted);
}
String & map helpers
str-split($string, $separator)
Splits a string into a list on each occurrence of $separator.
helpers.str-split('a.b.c', '.'); // โ 'a' 'b' 'c' (list of length 3)
map-deep-get($map, $keys...)
Fetches a nested map value by a path of keys.
helpers.map-deep-get((a: (b: 42)), a, b); // โ 42
svg-uri($svg)
Wraps an inline SVG in a url() data URI, percent-encoding it on the way. Write the icon as SVG and read it back as SVG โ the escaped form is the same bytes either way, and only one of the two says what the icon is.
%, <, >, # and " are encoded; everything else survives a quoted url() intact, and encoding more only makes the declaration longer. # is not optional โ a hash colour left raw ends the URL and starts a fragment identifier.
.icon-check {
background: currentcolor;
mask: helpers.svg-uri("<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L1.72 9.28a.75.75 0 1 1 1.06-1.06L6 11.44l6.72-6.72a.75.75 0 0 1 1.06 0Z'/></svg>") center / contain no-repeat;
}
// โ mask: url("data:image/svg+xml,%3Csvg xmlns='http://โฆ'%3E%3Cpath d='M13.78โฆ'/%3E%3C/svg%3E") center / contain no-repeat;
Single quotes inside the SVG, double quotes around it โ the other way round works too, since " is encoded, but it costs six characters per attribute. Masked rather than painted is the usual reason to want this at all: a mask takes the element's own color, so one icon follows a colour mode instead of needing a second copy in another fill.
Markup only, never a path: Sass has no way to read a file, so an icon on disk needs a build step and this is not one.
Utility class generator
utility-class-generator($pref, $property, $values, $unit, $suff, $orientations, $responsive, $var) mixin
The engine behind Sulphuris's utility classes. Generates a set of classes for a CSS property across all configured breakpoints. Accepts either positional arguments or a single config map as $pref.
Positional signature:
| Param | Type | Description |
|---|---|---|
$pref |
string or map | Class name prefix (or full config map) |
$property |
string | CSS property (e.g. padding) |
$values |
list or map | Values to iterate |
$unit |
string | Unit appended to each value (e.g. px, rem) |
$suff |
string | Optional class name suffix |
$orientations |
bool | When true, also generates -top/-right/-bottom/-left variants using config.$orientations |
$responsive |
bool | When true (default), emits breakpoint-prefixed variants |
$var |
bool or string | Use CSS custom properties instead of raw values |
Example โ generate padding utilities:
@include gen.utility-class-generator(
$pref: 'p',
$property: 'padding',
$values: (0, 4, 8, 12, 16, 24, 32),
$unit: 'px',
$orientations: true,
$responsive: true
);
This emits classes like .p-0, .p-8, .pt-16, .pb-32, and breakpoint variants .p-md-8, .pt-lg-24, etc.
Map form (equivalent, all keys optional except prefix, property, values):
@include gen.utility-class-generator((
prefix: 'p',
property: 'padding',
values: (0, 4, 8, 12, 16, 24, 32),
unit: 'px',
orientations: true,
responsive: true
));
grid-track-map($n)
Returns a map keyed 1โฆ$n whose values are repeat(n, minmax(0, 1fr)). Not a
generator itself โ feed it to utility-class-generator, which is what emits the
classes and their breakpoint variants.
@include gen.utility-class-generator('grid-cols', 'grid-template-columns', gen.grid-track-map(4));
// โ .grid-cols-1 โฆ .grid-cols-4, plus .grid-cols-sm-1 โฆ .grid-cols-xxl-4
core/layout/_grid.scss calls it twice, with config.$columns and
config.$rows, to produce .grid-cols-* and .grid-rows-*. Overriding those
two config values is enough for the common case; call it directly only for a
third track family with a different count.
grid-span-map($n)
Returns a map keyed 1โฆ$n plus full, whose values are span n / span n and
1 / -1. Same shape of use โ pass it to utility-class-generator with
grid-column or grid-row.
@include gen.utility-class-generator('grid-column-span', 'grid-column', gen.grid-span-map(4));
// โ .grid-column-span-1 โฆ -4, .grid-column-span-full, plus breakpoint variants
Both are plain maps, so map.merge adds your own keys before generating โ
('screen': '1 / -1') or a named area โ without touching the generator.
See Grid for the classes themselves.
Browser fixes (_fixes.scss)
Two mixins for targeted rendering quirks. Include only where needed.
| Mixin | Effect |
|---|---|
animate-scale-fix() |
Prevents jank on transform: scale() animations by forcing GPU compositing layer (backface-visibility: hidden, transform-style: preserve-3d) |
clearfix() |
Classic ::after float-clearing pattern |
.card {
@include gen.animate-scale-fix();
}
clearfix() no longer backs a .clearfix class โ the float, clear and clearfix
utilities were dropped in 3.0.0. The mixin stays for the case it is still good
for: clearing a float you set yourself, in your own CSS. Sulphuris emits no
floats.
Normalize (_normalize.scss)
A verbatim copy of normalize.css v8.0.1 (MIT). Included automatically when you import the Sulphuris core. It corrects browser inconsistencies without stripping all defaults โ box model, font inheritance for form controls, display: block for main/details, sub/sup line-height, and more. No configuration; just let it load.