@pageloop/styles
v0.6.1
Published
Shared SCSS utilities — breakpoints, @media / @container responsive mixins, accessibility helpers. SCSS-only; no JS runtime.
Readme
@pageloop/styles
Shared SCSS utilities — breakpoints, responsive mixins, accessibility
helpers. SCSS-only: no JS runtime, no bundled CSS, nothing in
this package ends up in production output unless a consumer
@uses a specific file.
Why this exists
The PageLoop monorepo has three independent visual languages —
the drop-in widget (@pageloop/vanilla), the admin SPA
(apps/admin), the marketing site (apps/marketing). They keep
their own color palettes, type ramps, and component styles. But
their breakpoint values, responsive mixin shape, and
a11y media-query conventions should be identical, so a
developer moving between the three packages doesn't have to
relearn three slightly-different sets.
This package is the single source for those conventions.
What's NOT here
- Color tokens, spacing scales, typography ramps. Each surface keeps its own.
- Component styles (buttons, cards, glass effects). Each surface has its own visual language.
- JavaScript anything. Style-only.
Files
| Subpath | Provides |
|---|---|
| breakpoints | $bp-sm/$bp-md/$bp-lg/$bp-xl and the bp($name) lookup function |
| respond | Viewport @media mixins: below, above, between, only |
| container | @container query mixins for surfaces with container-type: inline-size |
| a11y | @media mixins: reduced-motion, forced-colors, coarse-pointer, hover-capable, prefers-dark, prefers-light |
Each file is independent — @use only what you need. There is
no convenience index intentionally; tree-shaking SCSS works by
importing exactly what you reach for.
Usage
The package uses subpath exports + Sass's pkg: URL importer (Sass
1.71+, Vite 5.4+ with the modern compiler API). All three consumer
apps already use Vite + Sass 1.85+, so no extra setup is required.
@use 'pkg:@pageloop/styles/respond' as r;
@use 'pkg:@pageloop/styles/a11y' as a11y;
.nav {
display: flex;
gap: 24px;
@include r.below(md) {
display: none; // hamburger takes over below tablet
}
}
.modal {
transition: opacity 200ms ease-out;
@include a11y.reduced-motion {
transition: none;
}
}For the widget bundle, use container instead of respond so the
mixins react to the widget's own size rather than the host
viewport (which lies when mounted inside iframes / narrow embedder
columns / shadow roots):
@use 'pkg:@pageloop/styles/container' as cq;
.pl-root {
container-type: inline-size;
container-name: pl-root;
}
.pl-sidebar {
width: 360px;
@include cq.below(md) { width: 100%; }
}Breakpoint values
| Name | Width | Class |
|---|---|---|
| (none) | 0 – 479px | phones (default state) |
| sm | 480 – 767px | large phones / phablets |
| md | 768 – 1023px | tablets |
| lg | 1024 – 1439px | desktop |
| xl | 1440+ | wide desktop |
Mobile-first: the name marks the lower bound. above(md) =
md, lg, xl. below(md) = xs + sm.
Adding a breakpoint
breakpoints.scss is authoritative. Add a $bp-foo: <px> and
include it in the $breakpoints map — respond and container
mixins pick it up automatically.
