To generate a set of colors in the shed style, you can use this Sass mixin, which can be found in the core.
@import "shed-css/lib/generate-theme.scss";
$natural-black: #111111;
$darker-gray: #333333;
$dark-gray: #666666;
$gray: #999999;
$light-gray: #CCCCCC;
$lighter-gray: #F3F3F3;
$white: #FFFFFF;
$ted-red: #E62B1E;
// expects a map of colors like this:
$my_colors: (
black: $natural-black,
gray-dd: $darker-gray,
gray-d: $dark-gray,
gray: $gray,
gray-l: $light-gray,
gray-ll: $lighter-gray,
white: $white,
red: $ted-red
);
// expects a map of breakpoints like this:
$my_breakpoints: (
n: 'none',
xs: "min-width: 500px",
sm: "min-width: 700px",
md: "min-width: 900px",
lg: "min-width: 1100px",
xl: "min-width: 1300px"
);
// execute the mixin outside of a selector
@include generate-theme($my_breakpoints, $my_colors);
While there's no convenice for creating themes, you can use this code along with the necessary postcss plugins to generate your own theme:
:root {
--black: #111111;
--gray-dd: #333333;
--gray-d: #666666;
--gray: #999999;
--gray-l: #CCCCCC;
--gray-ll: #F3F3F3;
--white: #FFFFFF;
--red: #E62B1E;
--black-g: linear-gradient(to bottom, var(--gray-dd), var(--black));
--gray-d-g: linear-gradient(to bottom, var(--gray-d), var(--gray-dd));
}
@custom-media --mq-xs (min-width: 24em);
@custom-media --mq-sm (min-width: 30em);
@custom-media --mq-md (min-width: 40em);
@custom-media --mq-lg (min-width: 48em);
@custom-media --mq-xl (min-width: 54em);
@each $mq in n, xs, sm, md, lg, xl {
@if $mq == n {
@each $color in black, gray-dd, gray-d, gray, gray-l, gray-ll, white, red, black-g, gray-d-g {
.c\:$color {
color: var(--$color);
}
.bg\:$color,
.bg-c\:$color {
background: var(--$color);
}
.hover\/c\:$color:hover {
color: var(--$color);
}
.hover\/bg\:$color:hover,
.hover\/bg-c\:$color:hover {
background: var(--$color);
}
@for $i from 1 to 9 {
.bg\:$color\.$i {
background-color: color(var(--$color) alpha(calc($i / 10)));
}
.c\:$color\.$i {
color: color(var(--$color) alpha(calc($i / 10)));
}
.hover\/bg\:$color\.$i:hover {
background-color: color(var(--$color) alpha(calc($i / 10)));
}
.hover\/c\:$color\.$i:hover {
color: color(var(--$color) alpha(calc($i / 10)));
}
}
}
}
@else {
@media(--mq-$mq) {
@each $color in black, gray-dd, gray-d, gray, gray-l, gray-ll, white, red, black-g, gray-d-g {
.c\:$color\@$mq {
color: var(--$color);
}
.bg\:$color\@$mq,
.bg-c\:$color\@$mq {
background: var(--$color);
}
.hover\/c\:$color\@$mq:hover {
color: var(--$color);
}
.hover\/bg\:$color\@$mq:hover,
.hover\/bg-c\:$color\@$mq:hover {
background: var(--$color);
}
@for $i from 1 to 9 {
.bg\:$color\.$i\@$mq {
background-color: color(var(--$color) alpha(calc($i / 10)));
}
.c\:$color\.$i\@$mq {
color: color(var(--$color) alpha(calc($i / 10)));
}
.hover\/bg\:$color\.$i\@$mq:hover {
background-color: color(var(--$color) alpha(calc($i / 10)));
}
.hover\/c\:$color\.$i\@$mq:hover {
color: color(var(--$color) alpha(calc($i / 10)));
}
}
}
}
}
}
To eliminate distraction for developers and designers by creating a set of options rather than encouraging bikeshedding, where shed gets its name.
When classes serve a single purpose, the cascade becomes a non-issue. If I use
the class bg:black
, I can count on it only doing one thing - making the
background for this element black. Future developers can also count on that.
This is the core idea that makes atomic/functional css work. Classes are "immutable" and you can get the same output every time. They're predictable and reliable.
Because classes have a single purpose and you can count on them, they're easier
to use together. I can easily put bg:black c:white
and be assured that they
won't conflict. I can also add p:1
and know that I'm not going to impact
color or background color by adding padding.
Choosing sizes has been a never-ending battle. 12px? 13.333px? 14.5px? 15px? and so on. Shed solves this problem by using a modular scale to resolve these conflicts. Shed provides a root size (1rem, don't hijack the browser default) and (by default) 10 steps above and below it. These apply to font size, padding, margin, height, max-width, positioning, border-radius, etc. This removes the need to dwell on sizes and also makes it easy to combine properties in a meaningful ways. For example (decoration added for clarity):
<div class="pos:r">
<div
class="
pos:a
p:.5
top:-.5
left:-.5
"
>
I should be aligned w/ my parent, but my background outside of it on the top and left.
</div>
</div>
Shed.css is build with mobile-first responsive web design in mind. The media queries available by default are:
xxs
xs
sm
md
lg
xl
xxl
You can access them like this:
<div
class="
f:1
f:2@xxs
f:3@xs
f:2@sm
f:6@md
f:4@lg
f:5@xl
f:6@xxl
"
>I change sizes based on screen resolution</div>
That's great, but I wouldn't want to combine a load of classes every time I need a button. shed suggests solving this problem by moving all of your design language to the template layer. The reasons are multiple:
When you create a new UI component, you're creating an abstraction, and abstractions are hard. You represent an idea through design and interaction. When you couple this with many common approaches to CSS architecture, you can exacerbate the problem by not only reusing that abstraction in CSS, but by coupling it with additional abstractions (commonly called patterns or objects) like the media object, breadcrumbs, block-list, etc. Now you have multiple requirements on the markup that are associated with multiple abstractions. Having so many moving and dependant abstractions becomes confusing and overwhelming.
Because a special abstraction is created for every UI component, modifying them often involves extending that abstraction again. Now you have your primary abstraction, css-only pattern abstractions, and modifier abstractions. And you have to name all of these!
Give shed a shot - by embracing its constraints, you can get control of your codebase and develop faster.
How does it actually work? Let's start with a simple example:
<button
class="
d:i-b
f-w:700
p-x:3
p-y:.7
b-r:.4
f:2
c:white
bg:blue
t-t:u
hover/bg:blue.9
"
>
Log In
</button>
While this can be overwhelming at first glance, there is a simple set of rules at play. Let's break down this button into it's pieces:
d:i-b
: this is simply display: inline-block
. There are utilities for each
display type.f-w:700
: this equates to font-weight: 700
. Font weights are available
from 100 - 900. Number values map to named
values,
so this is "bold".p-x:3
equates to padding-left: var(--z3); padding-right: var(--z3);
. “x”
is used to specify both, like the the css property overflow-x
.p-y:.7
equates to padding-top: var(--z-dot7); padding-bottom: var(--z-dot7)
. The ".7" means it's 3 steps down from the root on the scale, whereas a plain old "7" means it's seven steps up!b-r:.4
means border-radius: var(--z-dot4)
.f:2
: Since one of the most common things you'll do with fonts is change
their size, f
does just that. This class sets font-size: var(--z2)
.c:white
: you should be able to guess this one. It was generated from our
theme. It sets color: var(--white)
.bg:blue
similarly sets background-color: var(--blue)
.t-t:u
: Staying with our pattern of mapping to css properties, this sets
text-transform: uppercase;
.hover/bg:blue.9
: While shed tries to remain entirely stateless, there are
some actions in css that can't be avoided. We handle them with the
<action>/class
syntax, currently only color and background color are
supported on hover.Once you get moving, these shorthands should feel natural.
What about RWD? shed was build with a mobile-first approach in mind.
While it may be unusual to use some of these characters, it is not invalid. As I understand section 4.1.3 of the CSS 2.1 spec on characters and case:
“Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). For instance, the identifier "B&W?" may be written as "B&W?" or "B\26 W\3F".”
I haven't seen classnames formatted in this way before, but many of the ideas inside of shed.css were inspired by tachyons, Basscss, More Meaningful Typography, Forcing Immutability in CSS, Functional Programming, CSS, and your sanity, Atomic CSS, and many conversations and bikeshedding sessions.
When writing class names that have weird characters in them, they must be
escaped with a backslash (\
). That means something like f:10
has to be
authored (in the stylesheet) is like this:
.f\:10 { font-size: var(--z-10); }