Steller CSS
Steller is a utility-first CSS framework that serves as the foundation of your application's design system. It includes built-in smart defaults for building responsive, accesible, and visually consistent user interfaces. Unlike other CSS frameworks, Steller has no opinion on the actual end appearance of your application, it is simply a bridge for your design system and your application's styling.
Open-source development of Steller is proudly sponsored by Snap! Raise.
Features
- Simple configuration & setup ⚙️
- Grid system built with CSS Grid 📏
- Sass based ✨
- Encourages mobile-first development 📱
- Extensible module system 🚀
- Zero dependencies 🙌
Installation
npm i steller-css
yarn add steller-css
Usage
In you index.scss
or equivilent, import steller-css
.
// Assuming you are using webpack ; // StellerCSS
Example Projects
Config
All config variables are optional to define as they already have default values. You can take a look at them here.
It is recommended to make a steller-config.scss
file to be the centralized configuration file. Feel free to name this anything.
; // Your config ; // StellerCSS
Check out this example theme configuration file and feel free to copy/paste it into yours. The values are the same as the defaults above, but this config is your application's design system so get in there make it your own!
Colors
;
Typogrpahy
; ; ; ; ;
Breakpoints
;
Container
;
;
Grid
; ; ;
Spacing
;
Borders
; ;
Motion
;
;
Effects
;
Gradients
;
Utility Classes
Container
Class | Properties |
---|---|
.container | margin: 0 auto; max-width: $container-width; position: relative; |
Grid
Class | Properties |
---|---|
.grid | display: grid; grid-template-columns: repeat($grid-columns, 1fr); |
.{$breakpont}:col-{$span} | grid-column: span $span; |
.{$breakpont}:row-{$span} | grid-row: span $span; |
.{$breakpont}:col-{$span}-start-{$grid-column-start} | grid-column: $grid-column-start / span $span; |
Typography
Class | Properties |
---|---|
.font-{$family} | font-family: $font-family |
.font-size-{$size} | font-size: $size |
.font-weight-{$weight} | font-size: $weight |
.leading-{$leading} | line-height: $leading |
.italic | font-style: italic; |
.underline | text-decoration: underline; |
.no-underline | text-decoration: none; |
.lowercase | text-transform: lowercase; |
.uppercase | text-transform: uppercase; |
.capitalize | text-transform: captialize; |
.letter-spacing-tight | letter-spacing: -0.05em; |
.letter-spacing-normal | letter-spacing: 0em; |
.letter-spacing-wide | letter-spacing: 0.05em; |
.list-reset | list-style: none; padding: 0; |
.whitespace-normal | white-space: normal; |
.whitespace-no-wrap | white-space: nowrap; |
.whitespace-pre | white-space: pre; |
.whitespace-pre-line | white-space: pre-line; |
.whitespace-pre-wrap | white-space: pre-wrap; |
.break-word | word-wrap: break-word; |
.break-word | word-wrap: normal; |
.truncate | overflow: hidden; text-overflow: ellipses; white-space: nowrap; |
<!-- font size --> <!-- font weight --> <!-- leading (line height) -->
Color
Class | Properties |
---|---|
.text-{$color} | color: $color; |
.bg-{$color} | background-color: $color; |
;
Layout
Class | Properties |
---|---|
.block | display: block; |
.inline-block | display: inline-block; |
.inline | display: inline; |
.hidden | display: none; |
.text-center | text-align: center; |
.text-left | text-align: left; |
.text-right | text-align: right; |
.text-justify | text-align: justify; |
.float-left | float: left; |
.float-right | float: right; |
.float-none | float: none; |
.static | position: static; |
.fixed | position: fixed; |
.absolute | position: absolute; |
.relative | position: relative; |
.sticky | position: sticky; |
.pin | top: 0; right: 0; bottom: 0; left: 0; |
.pin-t | top: 0; |
.pin-r | right: 0; |
.pin-b | bottom: 0; |
.pib-l | left: 0; |
.visible | visibility: visible; |
.invisible | visibility: hidden; |
.z-0 | z-index: 0; |
.z-1 | z-index: 1; |
.z-2 | z-index: 2; |
.z-10 | z-index: 10; |
.z-20 | z-index: 20; |
.z-max | z-index: 2147483647; |
.vertical-align-baseline | vertical-align: baseline; |
.vertical-align-top | vertical-align: top; |
.vertical-align-middle | vertical-align: middle; |
.vertical-align-bottom | vertical-align: bottom; |
.vertical-align-text-top | vertical-align: text-top; |
.vertical-align-text-bottom | vertical-align: text-bottom; |
Spacing
Class | Properties |
---|---|
.m-{$size} | margin: $size; |
.p-{$size} | padding: $size; |
.mx-{$size} | margin-left: $size; margin-right: $size; |
.px-{$size} | padding-left: $size; padding-right: $size; |
.my-{$size} | margin-top: $size; margin-bottom: $size; |
.py-{$size} | padding-top: $size; padding-bottom: $size; |
.mt-{$size} | margin-top: $size; |
.pt-{$size} | padding-top: $size; |
.mr-{$size} | margin-right: $size; |
.pr-{$size} | padding-right: $size; |
.mb-{$size} | margin-bottom: $size; |
.pb-{$size} | padding-bottom: $size; |
.ml-{$size} | margin-left: $size; |
.pl-{$size} | padding-left: $size; |
- Spacing Sizes: ('xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl')
<!-- margin all sides large --> <!-- padding top/bottom small --> <!-- margin top 2xl --> <!-- padding right extra small -->
Flexbox
Class | Properties |
---|---|
.flex | display: flex; |
.inline-flex | display: inline-flex; |
.flex-row | flex-direction: row; |
.flex-col | flex-direction: col; |
.flex-row-reverse | flex-direction: row-reverse; |
.flex-col-reverse | flex-direction: col-reverse; |
.flex-wrap | flex-wrap: wrap; |
.flex-no-wrap | flex-wrap: nowrap; |
.flex-wrap-reverse | flex-wrap: wrap-reverse; |
.items-strech | align-items: stretch; |
.items-start | align-items: flex-start; |
.items-center | align-items: center; |
.items-end | align-items: flex-end; |
.items-baseline | align-items: baseline; |
.content-start | align-content: flex-start; |
.content-center | align-content: center; |
.content-end | align-content: flex-end; |
.content-betwen | align-content: space-between; |
.content-around | align-content: space-around; |
.self-auto | align-self: auto; |
.self-start | align-self: flex-start; |
.self-center | align-self: center; |
.self-end | align-self: flex-end; |
.self-stretch | align-self: stretch; |
.justify-start | justify-content: flex-start; |
.justify-center | justify-content: center; |
.justify-end | justify-content: flex-end; |
.flex-initial | flex: initial; |
.flex-1 | flex: 1; |
.flex-2 | flex: 2; |
.flex-auto | flex: auto; |
.flex-none | flex: none; |
.flex-grow | flex-grow: 1; |
.flex-shrink | flex-shrink: 1; |
.flex-no-grow | flex-grow: 0; |
.flex-no-shrink | flex-shrink: 0; |
Sizing
Class | Properties |
---|---|
.w-auto | width: auto; |
.w-full | width: 100%; |
.w-screen | width: 100vw; |
.w-1px | width: 1px; |
.h-auto | height: auto; |
.h-full | height: 100%; |
.h-screen | height: 100vh; |
.h-1px | height: 1px; |
.min-w-auto | min-width: auto; |
.min-w-full | min-width: 100%; |
.min-w-screen | min-width: 100vw; |
.min-w-1px | min-width: 1px; |
.min-w-0 | min-width: 0; |
.min-h-auto | min-height: auto; |
.min-h-full | min-height: 100%; |
.min-h-screen | min-height: 100vh; |
.min-h-1px | min-height: 1px; |
.min-h-0 | min-height: 0; |
.max-w-auto | max-width: auto; |
.max-w-full | max-width: 100%; |
.max-w-screen | max-width: 100vw; |
.max-w-1px | max-width: 1px; |
.max-w-0 | max-width: 0; |
.max-h-auto | max-height: auto; |
.max-h-full | max-height: 100%; |
.max-h-screen | max-height: 100vh; |
.max-h-1px | max-height: 1px; |
.max-h-0 | max-height: 0; |
Borders
Class | Properties |
---|---|
.rounded-{$size} | border-radius: $size; |
.border-{$color} | border-color: auto; |
.border-{$corner}-{$radius} | border-{$corner}-radius: $radius; |
.border-{$width} | border-width: $width; |
.border-{$side}-{$width} | border-{$side}-width: $width; |
.border-solid | border-style: solid; |
.border-dashed | border-style: dashed; |
.border-dotted | border-style: dotted; |
.border-inset | border-style: inset; |
.border-outset | border-style: outset; |
- Border Radius Sizes: ('sm', 'md', 'lg', 'xl')
- Border Width Sizes: ('xs', 'sm', 'md', 'lg', 'xl')
;
<!-- border radius (all 4 corners) --> <!-- border top --> <!-- rounded bottom right corner only -->
Effects
Class | Properties |
---|---|
.shadow-{$size} | box-shadow: $size; |
.opacity-100 | opacity: 1; |
.opacity-75 | opacity: 0.75; |
.opacity-50 | opacity: 0.5; |
.opacity-25 | opacity: 0.25; |
.opacity-0 | opacity: 0; |
- Box Shadow Sizes: ('sm', 'md', 'lg')
Gradients
Class | Properties |
---|---|
.bg-gradient-{$gradient-name} | background-image: $gradient; |
;
Backgrounds
Class | Properties |
---|---|
.bg-attachment-fixed | background-attachment: fixed; |
.bg-attachment-local | background-attachment: local; |
.bg-attachment-scroll | background-attachment: scroll; |
.bg-position-bottom | background-position: bottom; |
.bg-position-center | background-position: center; |
.bg-position-left | background-position: left; |
.bg-position-left-bottom | background-position: left-bottom; |
.bg-position-left-top | background-position: left-top; |
.bg-position-right | background-position: right; |
.bg-position-right-bottom | background-position: right-bottom; |
.bg-position-right-top | background-position: right-top; |
.bg-position-top | background-position: top; |
.bg-repeat | background-repeat: repeat; |
.bg-no-repeat | background-repeat: no-repeat; |
.bg-repeat-x | background-repeat: repeat-x; |
.bg-repeat-y | background-repeat: repeat-y; |
.bg-size-auto | background-size: auto; |
.bg-size-cover | background-size: cover; |
.bg-size-contain | background-size: contain; |
Interactivity
Class | Properties |
---|---|
.appearance-none | appearance: none; |
.cursor-auto | cursor: auto; |
.cursor-default | cursor: default; |
.cursor-pointer | cursor: pointer; |
.cursor-wait | cursor: wait; |
.cursor-move | cursor: move; |
.cursor-not-allowed | cursor: not-allowed; |
.outline-none | outline: none; |
.pointer-events-none | pointer-events: none; |
.pointer-events-auto | pointer-events: auto; |
.resize-none | resize: none; |
.resizable | resize: both; |
.resizable-y | resize: vertical; |
.resizable-x | resize: horizontal; |
.user-select-text | user-select: text; |
.user-select-none | user-select: none; |
Table
Class | Properties |
---|---|
.table-auto | table-layout: auto; |
.table-fixed | table-layout: fixed; |
.border-collapse | border-collapse: collapse; |
.border-seperate | border-collapse: separate; |
SVG
Class | Properties |
---|---|
.fill-current | fill: currentColor; |
.stroke-current | stroke: currentColor; |
State Variants
Responsive
For breakpoint specific stylings, add the breakpoint label prefix to the beginning of the class.
I am naturally the success color, but I am the danger color above the medium breakpoint
Hover
To apply a style on hover, prefix the normal class with hover:
.
I am undelrined on hover!
Focus
To apply a style on focus, prefix the normal class with focus:
.
I am undelrined on focus!
Active
To apply a style on active, prefix the normal class with active:
.
I am undelrined on active!
Custom CSS
Within a functional CSS paradigm, you hopefully won't be writing that much custom styling in CSS/SCSS files, but you'll likely need to write some for the occasional complex component or feature. Steller recognizes this and exposes all of your theme config variables as CSS Custom Properties (CSS Variables) to help you.
Your config
; ;
Your feature
Optionally, you can just reference the Steller theme variables directly or use one of the helper sass functions Steller provides.
.foo
List of all built-in functions like the above color & font-family example:
- color()
- font-family()
- spacing()
- border-radius()
- border-width()
- box-shadow()
- breakpoint()
- column-gutter()
- row-gutter()
- gradient()
- speed()
Extending Steller / Custom Classes
Steller is extensible via first or third-party modules. Simply add a sass map to the $steller-modules
variable in your theme conifg (or anywhere before your steller-css import).
Example.
;
Your module variable should look something along these lines:
;
Custom classes! :tada:
Classes via steller modules automatically have all prefixed variants available.
Contributors
Roadmap
- Ship a stable, battle-tested 1.0 version
Steller Family
What is functional/atomic/utility-first CSS?
TailwindCSS vs StellerCSS
The most similar framework to Steller is without a doubt Tailwind CSS. Tailwind is awesome and it was half of the reason I first realized the true power of utility-first CSS to begin with. So why Steller then? At Snap! Raise, we had a couple of primary reasons to roll our own framework.
- The Grid System. Tailwind doesn't have a built-in grid system and you're kinda stuck with hacking together a flexbox/width percentage solution as shown in their docs. A 12-column grid system is really important to us from both a design and developement perspective. The Steller grid system, which is built on top of CSS Grid, offers a lot more here.
- Sass vs JS. Tailwind is written in PostCSS which is a tool for transforming styles via JavaScript plugins. Though a very powerfull tool, it is my opinion that it's benefits comes with the trade offs of a more complex setup and steeper learning curve. Our team was already familiar with and using Sass and we wanted to stay within that reliable paradigm. Jumping into a JavaScript file to change your base CSS configuration just seems like a context switch.
Other than that, Steller and Tailwind are pretty much very similar tools. Like previously mentioned, the initial development of Steller was done with Tailwind as a key inspiration.