FSCSS 1.2.5 adds property shorthands: compile-time rewrites that turn short property names into standard longhand CSS before the stylesheet ever reaches the browser. No runtime cost for these names in production, since a compiled build just ships plain CSS.
This is the reference version: every shorthand group, what it expands to, and the processing order the compiler applies. For the story behind the release.
npm install fscss@1.2.5
<script src="https://cdn.jsdelivr.net/npm/fscss@1.2.5/runtime.min.js" defer></script>
ESM build: https://cdn.jsdelivr.net/npm/fscss@1.2.5/esm.min.js
Everything below is optional helpers. Longhand CSS is always valid inside an FSCSS file, shorthands just save you from typing the same pair of properties over and over.
Processing order
The compiler expands shorthands in a fixed order, which matters when a name could be read two ways:
- Side-scoped blocks (
top| ... |) - Axis and size
- Aliases and layout helpers
- Border and radius
- Background
ratio-fit()
Longer, more specific names win over shorter ones. scroll-mx resolves before the plain mx, bg-size resolves before the plain size.
Quick example
FSCSS:
.card {
stack: 12px;
px: 16px;
py: 14px;
rounded: 12px;
bg: #12121a;
border-x: 1px solid rgba(255,255,255,.08);
shadow: 0 8px 24px rgba(0,0,0,.35);
max-w: 360px;
}
.card h3 {
fs: 1.1rem;
fw: 600;
m: 0;
}
Compiles to:
.card {
display: flex;
flex-direction: column;
gap: 12px;
padding-left: 16px;
padding-right: 16px;
padding-top: 14px;
padding-bottom: 14px;
border-radius: 12px;
background: #12121a;
border-left: 1px solid rgba(255,255,255,.08);
border-right: 1px solid rgba(255,255,255,.08);
box-shadow: 0 8px 24px rgba(0,0,0,.35);
max-width: 360px;
}
.card h3 {
font-size: 1.1rem;
font-weight: 600;
margin: 0;
}
One stack: plus a handful of two-letter properties replaces nine lines of longhand.
Axis & spacing
| Shorthand | Expands to |
|---|---|
inset-x / inset-y
|
left+right / top+bottom |
margin-x / mx
|
margin-left + margin-right |
margin-y / my
|
margin-top + margin-bottom |
padding-x / px
|
padding-left + padding-right |
padding-y / py
|
padding-top + padding-bottom |
gap-x / gap-y
|
column-gap / row-gap |
scroll-mx · scroll-my · scroll-px · scroll-py
|
scroll-margin / scroll-padding axes |
safe-x · safe-y · inset-safe
|
padding/inset using env(safe-area-inset-*)
|
.overlay-side {
pos: absolute;
inset-x: 45px; /* left + right only, top/bottom untouched */
top: 0;
h: 4px;
}
That last point is the reason inset-x exists at all: inset: auto 45px sets all four sides, there's no native shorthand that means "left and right only, leave the rest alone."
Size
| Shorthand | Expands to |
|---|---|
w / h
|
width / height |
min-w · max-w · min-h · max-h
|
min/max width/height |
size: A |
width: A; height: A |
size: A B |
width: A; height: B |
min-size / max-size
|
same one- or two-value pattern |
.icon { size: 24px; }
.panel { size: 100% 200px; max-w: 480px; }
.thumb { min-size: 48px; max-size: 120px 80px; }
.icon { width: 24px; height: 24px; }
.panel { width: 100%; height: 200px; max-width: 480px; }
.thumb { min-width: 48px; min-height: 48px; max-width: 120px; max-height: 80px; }
Property aliases
Single-property renames, not axis pairs:
m mt mb ml mr · p pt pb pl pr · fs fw ff lh ls · ta td tt ws tsh · ov ovx ovy · z op cur pe us pos · jc ai ac ji js as pi · fdir fwrap grow shrink basis · trans anim tf fil · shadow aspect obj-fit obj-pos
.title {
fs: 1.25rem;
fw: 700;
lh: 1.2;
ta: center;
}
Layout helpers
| Helper | Result |
|---|---|
center: x / y / other |
flex justify / align, or grid place-items center |
stack: G / hstack: G
|
column/row flex with that gap |
fill / fill: fixed
|
absolute or fixed, inset 0 |
abs-center |
absolute, inset 0, margin auto |
truncate / line-clamp: N
|
single-line ellipsis / multi-line clamp |
cols / rows
|
grid, a number becomes repeat(N, 1fr)
|
auto-fit: MIN |
repeat(auto-fit, minmax(MIN, 1fr)) |
glass: BLUR / ring: W
|
backdrop-filter blur / box-shadow ring |
Place, origin, object
-
place-xexpands to justify-content plus justify-items -
place-yexpands to align-content plus align-items -
origin-x/origin-yset an axis of transform-origin -
object-x/object-yset an axis of object-position
Side-scoped blocks
A side block rewrites every known property inside it (padding, margin, border, border-width/style/color, inset, offset, paired border-radius corners) to apply to just that side:
.card {
top| padding: 8px; border-width: 1px; |
left| margin: 12px; |
}
Supported sides: top, bottom, left, right, block-start, block-end, inline-start, inline-end.
Border & radius
-
border-x/border-yset a full border on left+right or top+bottom -
border-tborder-bborder-lborder-rfor a single side -
bw/bw-x/bw-t... for border-width -
bs-*for border-style,bc-*for border-color -
rounded/radiusfor border-radius -
rounded-t/b/l/r,rounded-tland the other corners,radius-topand friends
Background
-
bgexpands to background -
bg-x/bg-yexpand to background-position-x/y -
bg-size-x/bg-size-yset a partial background-size -
bg-colorbg-imagebg-repeatbg-posbg-attachmentbg-clipbg-originbg-sizemap straight to their longhand names
ratio-fit()
.media-frame > img {
inset: ratio-fit(16 / 9);
obj-fit: cover;
}
Expands into absolute positioning, inset: 0, margin: auto, aspect-ratio, and width/height caps that use container-query units, so the box holds its ratio while staying inside whatever it's placed in. The exact formula tracks the compiler implementation, so treat the expansion above as the shape rather than a byte-for-byte guarantee.
Seen in a real file
Template
body {
ff: 'Inter', system-ui, sans-serif;
bg: #e8eaf0;
min-h: 100vh;
center: both;
gap: 40px;
py: 40px;
px: 20px;
fwrap: wrap;
}
.icon-btn {
size: 32px;
rounded: 10px;
bg: rgba(255,255,255,0.06);
center: both;
}
.loan-card {
mx: 22px;
mb: 18px;
rounded: 16px;
px: 16px;
py: 14px;
hstack: 12px;
ai: center;
}
Full template: st-core.fscss / templates / budget-app.
Notes
- Shorthands are optional. Longhand CSS is always valid in the same file.
- Works through both the CLI and the browser runtime, but production should compile ahead of time rather than ship the runtime.
- Older value-multiplexing helpers like
%2()and%3()are unaffected and still work alongside 1.2.5 shorthands. - Full backward compatibility: nothing from pre-1.2.5 syntax breaks.
Tooling
The FSCSS VS Code extension highlights .fscss/.xfscss files, ships snippets for @define, @import, arrays and others, and adds an FSCSS: Compile command with compile-on-save. It needs the compiler installed separately (npm install -g fscss or as a project dependency), the extension itself just drives it.
Links
- Shorthands reference: fscss.devtem.org/shorthands
- Release notes: v1.2.5 on GitHub
- Original announcement: FSCSS 1.2.5: size, padding-x, inset-x, and ratio-fit
- VS Code extension: marketplace.visualstudio.com/items?itemName=Figsh.fscss
- npm: npmjs.com/package/fscss
- Playground: fscss.devtem.org/playground
Top comments (0)