First draft of Honeycomb case study, improved nav handling, css cleanup
This commit is contained in:
parent
5393fa5f49
commit
1b0e097818
@ -14,14 +14,8 @@
|
||||
--red-body: #de342a;
|
||||
--blue: #0070C0;
|
||||
--black: #272727;
|
||||
--bg1: #E5DAD2;
|
||||
--green: #03A653;
|
||||
|
||||
--darkcyan: #008694;
|
||||
|
||||
--lightblue: #e6f3fe;
|
||||
--lightcyan: #e2ffff;
|
||||
/*--line: rgba(23, 23, 23, 0.12);*/
|
||||
--line: #272727;
|
||||
--light: #dfdfdf;
|
||||
--white: #f7f7f7;
|
||||
@ -56,7 +50,7 @@ a {
|
||||
&:hover {
|
||||
color: var(--hover);
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 1.5px;
|
||||
text-decoration-thickness: 2.5px;
|
||||
text-underline-offset: 0.2rem;
|
||||
}
|
||||
|
||||
@ -74,7 +68,7 @@ h1 {
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: clamp(1.75rem, 2.25dvw, 2.375rem);
|
||||
font-size: clamp(1.75rem, 2.5dvw, 2.375rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.1;
|
||||
margin: 0 0 1.5rem;
|
||||
@ -84,7 +78,7 @@ h2 {
|
||||
|
||||
h3 {
|
||||
color: var(--text);
|
||||
font-size: clamp(1.33rem, 3vw, 1.625rem);
|
||||
font-size: clamp(1.33rem, 1.75dvw, 1.625rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.3;
|
||||
margin-top: 2rem;
|
||||
@ -103,6 +97,13 @@ h4 {
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875rem;
|
||||
background: var(--light);
|
||||
border-radius: 3px;
|
||||
padding: 0.125rem 0.25rem;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
@ -249,6 +250,10 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--light);
|
||||
}
|
||||
|
||||
#end
|
||||
{
|
||||
.text p:first-child {
|
||||
@ -328,7 +333,8 @@ main {
|
||||
hgroup {
|
||||
align-content: end;
|
||||
display: grid;
|
||||
padding: 3rem 0 0;
|
||||
margin-top: 3rem;
|
||||
padding: 0;
|
||||
|
||||
.lede {
|
||||
margin: 1rem 0 0;
|
||||
@ -361,8 +367,8 @@ main {
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
justify-content: flex-start;
|
||||
padding-bottom: 2rem;
|
||||
padding-top: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
margin-top: 2rem;
|
||||
|
||||
figure {
|
||||
display: grid;
|
||||
@ -425,6 +431,12 @@ main {
|
||||
#content {
|
||||
display: grid;
|
||||
gap: 0;
|
||||
|
||||
ul {
|
||||
li {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
@ -477,12 +489,6 @@ main {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
li {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -504,22 +510,13 @@ nav {
|
||||
margin: 0;
|
||||
overflow-x: auto;
|
||||
padding: 0;
|
||||
|
||||
a {
|
||||
color: var(--muted);
|
||||
text-decoration: none;
|
||||
transition: padding 125ms ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
background: var(--white);
|
||||
border-bottom: 1px solid var(--faded);
|
||||
height: 3rem;
|
||||
padding: 0.6rem 1.5rem 0.5rem;
|
||||
padding: 0.7rem 1.5rem 0.5rem;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
|
||||
@ -527,10 +524,6 @@ nav {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
/*border: none;*/
|
||||
}
|
||||
|
||||
&.active
|
||||
{
|
||||
&::after {
|
||||
@ -549,12 +542,66 @@ nav {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
&.group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 0;
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
padding: 0.7rem 0 0.5rem;
|
||||
}
|
||||
|
||||
/* direct child link needs manual marker */
|
||||
> a {
|
||||
padding: 0.7rem 1.5rem 0.5rem 3rem;
|
||||
|
||||
&::before {
|
||||
color: var(--muted);
|
||||
content: attr(data-id);
|
||||
font-weight: 400;
|
||||
left: 1.25rem;
|
||||
position: absolute;
|
||||
text-align: right;
|
||||
width: 1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* sub lists */
|
||||
ul {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
list-style: disc;
|
||||
list-style-position: inside;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
padding: 0 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* links and text */
|
||||
a,
|
||||
span {
|
||||
color: var(--muted);
|
||||
text-decoration: none;
|
||||
transition: padding 125ms ease;
|
||||
}
|
||||
|
||||
a {
|
||||
&:hover {
|
||||
color: var(--text);
|
||||
text-decoration-thickness: 1.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* study elements
|
||||
* case study elements
|
||||
*/
|
||||
|
||||
.icon {
|
||||
@ -739,6 +786,7 @@ body#default
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
|
||||
/* css shapes art */
|
||||
#circle,
|
||||
#rectangle,
|
||||
#semicircle,
|
||||
@ -747,7 +795,6 @@ body#default
|
||||
position: absolute;
|
||||
transition: transform 2000ms ease-in-out;
|
||||
}
|
||||
|
||||
#semicircle {
|
||||
background: var(--green);
|
||||
bottom: 12dvw;
|
||||
@ -756,7 +803,6 @@ body#default
|
||||
left: 60dvw;
|
||||
width: 20dvw;
|
||||
}
|
||||
|
||||
#square {
|
||||
background: var(--black);
|
||||
height: 12dvw;
|
||||
@ -764,7 +810,6 @@ body#default
|
||||
bottom: 0;
|
||||
left: 54dvw;
|
||||
}
|
||||
|
||||
#circle {
|
||||
background: var(--blue);
|
||||
border-radius: 50%;
|
||||
@ -777,7 +822,6 @@ body#default
|
||||
transform: translateX(1rem);
|
||||
}
|
||||
}
|
||||
|
||||
#rectangle {
|
||||
background: var(--yellow);
|
||||
height: 3dvh;
|
||||
@ -786,7 +830,6 @@ body#default
|
||||
bottom: 0;
|
||||
transform-origin: 38%;
|
||||
}
|
||||
|
||||
#triangle {
|
||||
background: var(--red);
|
||||
height: 32dvw;
|
||||
@ -811,23 +854,29 @@ body#default
|
||||
section#studies {
|
||||
background: var(--black);
|
||||
display: grid;
|
||||
gap: 3rem;
|
||||
justify-items: center;
|
||||
padding: 5rem 0;
|
||||
|
||||
h1 {
|
||||
border-bottom: 0.25rem solid var(--white);
|
||||
color: #fff;
|
||||
margin-bottom: 0;
|
||||
max-width: var(--column-width);
|
||||
padding-bottom: 1rem;
|
||||
width: var(--column-width);
|
||||
}
|
||||
|
||||
> p {
|
||||
> div {
|
||||
color: var(--white);
|
||||
padding-right: 1rem;
|
||||
margin-bottom: 0;
|
||||
max-width: var(--column-width);
|
||||
|
||||
p:first-child {
|
||||
margin-top: -1rem;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:active {
|
||||
color: #fff;
|
||||
@ -836,18 +885,13 @@ section#studies {
|
||||
}
|
||||
|
||||
article {
|
||||
background-color: var(--blue);
|
||||
background-color: var(--card-color);
|
||||
background-image: var(--card-bg);
|
||||
background-position: bottom -16rem right -1rem; /* mobile position */
|
||||
background-repeat: no-repeat;
|
||||
background-size: auto 30rem; /* mobile size */
|
||||
border: none;
|
||||
color: #fff;
|
||||
transition: transform 150ms ease-in, background-position 150ms ease-in;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
--card-color: var(--blue);
|
||||
|
||||
> a {
|
||||
color: inherit;
|
||||
@ -866,7 +910,6 @@ section#studies {
|
||||
}
|
||||
|
||||
p:first-of-type {
|
||||
color: #fff;
|
||||
font-size: 1.35rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
@ -878,11 +921,6 @@ section#studies {
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-position: bottom -15.5 right -1rem;
|
||||
transform: translateY(-0.5rem);
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -891,9 +929,10 @@ section#studies {
|
||||
|
||||
> figure {
|
||||
margin: 0;
|
||||
max-width: 50%;
|
||||
|
||||
.icon {
|
||||
color: color-mix(in srgb, var(--icon-color), #fff 50%);
|
||||
color: var(--icon-color);
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
@ -905,6 +944,27 @@ section#studies {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[color="blue"] {
|
||||
color: var(--white);
|
||||
|
||||
&:hover {
|
||||
filter: brightness(95%);
|
||||
}
|
||||
|
||||
div > figure .icon {
|
||||
color: color-mix(in srgb, var(--icon-color), #fff 50%);
|
||||
}
|
||||
}
|
||||
|
||||
&[color="yellow"] {
|
||||
--card-color: var(--yellow);
|
||||
color: var(--black);
|
||||
|
||||
&:hover {
|
||||
filter: brightness(105%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -928,6 +988,173 @@ body#legacy
|
||||
}
|
||||
}
|
||||
|
||||
/* honeycomb case study */
|
||||
body#honeycomb
|
||||
{
|
||||
main > header {
|
||||
overflow: hidden;
|
||||
padding-bottom: 4rem;
|
||||
--inspector-line: rgba(163, 88, 242, 1);
|
||||
--angled-line: rgba(163, 88, 242, 0.33);
|
||||
|
||||
/* inspector lines are the same on all screen sizes */
|
||||
hgroup {
|
||||
position: relative;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
background: linear-gradient(to bottom, var(--inspector-line) 0 50%, transparent 50% 100%);
|
||||
background-repeat: repeat-y;
|
||||
background-size: 1px 0.5rem;
|
||||
content: '';
|
||||
display: block;
|
||||
height: 150lvh;
|
||||
position: absolute;
|
||||
top: -25lvh;
|
||||
width: 1px;
|
||||
}
|
||||
&::before {
|
||||
left: 0;
|
||||
}
|
||||
&::after {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
> h1,
|
||||
> p {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
aside {
|
||||
position: relative;
|
||||
margin-bottom: 8dvh;
|
||||
}
|
||||
|
||||
hgroup > h1::before,
|
||||
hgroup > p::after,
|
||||
aside::before,
|
||||
aside::after {
|
||||
background: linear-gradient(to right, var(--inspector-line) 0 50%, transparent 50% 100%);
|
||||
background-repeat: repeat-x;
|
||||
background-size: 0.5rem 1px;
|
||||
content: '';
|
||||
display: block;
|
||||
height: 1px;
|
||||
left: -25dvw;
|
||||
position: absolute;
|
||||
width: 150dvw;
|
||||
}
|
||||
hgroup > h1::before,
|
||||
aside::before {
|
||||
top: 0;
|
||||
}
|
||||
hgroup > h1::after,
|
||||
aside::after {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/* shapes grid */
|
||||
#grid {
|
||||
height: var(--shape-size);
|
||||
max-width: 100dvw;
|
||||
position: relative;
|
||||
width: 100dvw;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr var(--column-width) 1fr;
|
||||
grid-template-rows: 1px 1fr 1px;
|
||||
--shape-size: min(6dvh, 3rem);
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
background: linear-gradient(to right, var(--inspector-line) 0 50%, transparent 50% 100%);
|
||||
background-repeat: repeat-x;
|
||||
background-size: 0.5rem 1px;
|
||||
content: '';
|
||||
display: block;
|
||||
grid-column: 1 / 4;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
#shapes {
|
||||
display: grid;
|
||||
gap: 1.5rem;
|
||||
grid-column: 2 / 4;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
width: var(--column-width);
|
||||
}
|
||||
|
||||
#square {
|
||||
height: var(--shape-size);
|
||||
max-height: var(--shape-size);
|
||||
max-width: var(--shape-size);
|
||||
width: var(--shape-size);
|
||||
background-color: var(--blue);
|
||||
}
|
||||
|
||||
#circle {
|
||||
background-color: var(--red);
|
||||
border-radius: 50%;
|
||||
height: var(--shape-size);
|
||||
max-height: var(--shape-size);
|
||||
max-width: var(--shape-size);
|
||||
position: relative;
|
||||
width: var(--shape-size);
|
||||
}
|
||||
|
||||
#triangle {
|
||||
aspect-ratio: 1/cos(30deg);
|
||||
background-color: var(--green);
|
||||
clip-path: polygon(50% 0,100% 100%,0 100%);
|
||||
height: var(--shape-size);
|
||||
max-height: var(--shape-size);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#rectangle {
|
||||
background-color: var(--yellow);
|
||||
height: var(--shape-size);
|
||||
max-height: var(--shape-size);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#circle::before,
|
||||
#rectangle::before,
|
||||
#rectangle::after {
|
||||
background-image:
|
||||
repeating-linear-gradient(
|
||||
to bottom,
|
||||
var(--inspector-line) 0 1px,
|
||||
transparent 0.25rem 0.5rem
|
||||
),
|
||||
repeating-linear-gradient(
|
||||
to bottom,
|
||||
var(--inspector-line) 0 1px,
|
||||
transparent 0.25rem 0.5rem
|
||||
),
|
||||
repeating-linear-gradient(
|
||||
45deg,
|
||||
var(--angled-line) 0 1px,
|
||||
transparent 1px 0.5rem
|
||||
);
|
||||
background-position: top left, top right, top left;
|
||||
background-repeat: repeat-y, repeat-y, repeat;
|
||||
background-size: 1px 0.4rem, 1px 0.4rem, auto;
|
||||
content: '';
|
||||
display: block;
|
||||
height: 100%;
|
||||
left: -1.5rem;
|
||||
position: absolute;
|
||||
width: 1.5rem;
|
||||
}
|
||||
#rectangle::after {
|
||||
left: auto;
|
||||
right: -1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* single page documents */
|
||||
body#values {
|
||||
grid-template-rows: 5rem auto auto;
|
||||
@ -990,7 +1217,8 @@ body#values {
|
||||
}
|
||||
|
||||
/**
|
||||
* display queries */
|
||||
* media queries
|
||||
**/
|
||||
|
||||
.tablet-show,
|
||||
.laptop-show,
|
||||
@ -1028,6 +1256,7 @@ body#values {
|
||||
/* tablets */
|
||||
@media (min-width: 640px)
|
||||
{
|
||||
/* site header sizing/display */
|
||||
body > header {
|
||||
padding: 0 2rem;
|
||||
|
||||
@ -1043,6 +1272,7 @@ body#values {
|
||||
}
|
||||
}
|
||||
|
||||
/* main header is now full pane */
|
||||
main {
|
||||
grid-template-rows: max(800px, calc(100lvh - 5rem)) auto;
|
||||
|
||||
@ -1050,7 +1280,7 @@ body#values {
|
||||
min-height: calc(800px - 5rem);
|
||||
|
||||
> hgroup {
|
||||
padding-top: 4rem;
|
||||
margin-top: 4rem;
|
||||
|
||||
.lede {
|
||||
font-size: 1.6rem;
|
||||
@ -1060,8 +1290,8 @@ body#values {
|
||||
|
||||
> aside {
|
||||
flex-direction: row;
|
||||
padding-bottom: 0;
|
||||
padding-top: 3rem;
|
||||
margin-bottom: 0;
|
||||
margin-top: 3rem;
|
||||
|
||||
figure {
|
||||
grid-template-columns: auto;
|
||||
@ -1086,6 +1316,7 @@ body#values {
|
||||
}
|
||||
}
|
||||
|
||||
/* case studies list has more room */
|
||||
section#studies
|
||||
{
|
||||
article
|
||||
@ -1100,6 +1331,20 @@ body#values {
|
||||
}
|
||||
}
|
||||
|
||||
/* honeycomb case study art changes */
|
||||
body#honeycomb main > header #grid {
|
||||
--shape-size: 10dvh;
|
||||
|
||||
#shapes {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
|
||||
#triangle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* media query utilities */
|
||||
.tablet-show {
|
||||
display: block;
|
||||
}
|
||||
@ -1111,16 +1356,15 @@ body#values {
|
||||
/* landscape tablets */
|
||||
@media (min-width: 768px)
|
||||
{
|
||||
/* case study background handling */
|
||||
section#studies
|
||||
{
|
||||
article {
|
||||
background-position: top 2rem right 2rem;
|
||||
background-size: 20% auto;
|
||||
width: var(--column-width);
|
||||
|
||||
&:hover {
|
||||
background-position: top 1.5rem right 2rem;
|
||||
}
|
||||
border: 2px solid var(--hover);
|
||||
box-shadow: 0.5rem 0.5rem 0 0 var(--hover);
|
||||
width: calc(var(--column-width) + 6px);
|
||||
|
||||
a {
|
||||
padding: 2rem;
|
||||
@ -1134,10 +1378,21 @@ body#values {
|
||||
flex-direction: row;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
/* inset the article when clicking the link */
|
||||
&:has(a:active) {
|
||||
box-shadow: none;
|
||||
margin: 0.5rem -0.5rem -0.5rem 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* honeycomb case study art */
|
||||
body#honeycomb main > header #grid {
|
||||
--shape-size: 14dvh;
|
||||
}
|
||||
}
|
||||
|
||||
/* laptops (nav/article move to columns now) */
|
||||
@media (min-width: 1024px)
|
||||
{
|
||||
@ -1151,6 +1406,7 @@ body#values {
|
||||
max-width: 75%;
|
||||
}
|
||||
|
||||
/* site footer follows content columns now */
|
||||
body > footer
|
||||
{
|
||||
section {
|
||||
@ -1184,6 +1440,7 @@ body#values {
|
||||
}
|
||||
}
|
||||
|
||||
/* cap the width of the main header ledes */
|
||||
main > header {
|
||||
> hgroup {
|
||||
.lede {
|
||||
@ -1192,6 +1449,7 @@ body#values {
|
||||
}
|
||||
}
|
||||
|
||||
/* table of contents is now on the left of the article */
|
||||
nav {
|
||||
margin-left: 0;
|
||||
top: var(--article-top);
|
||||
@ -1202,11 +1460,62 @@ body#values {
|
||||
flex-direction: column;
|
||||
margin-top: 0.75rem;
|
||||
overflow-x: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
flex-direction: column;
|
||||
|
||||
> li {
|
||||
padding: 0.4rem 0 0 0.5rem;
|
||||
|
||||
a {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top: 1px solid var(--faded);
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
height: 2.5rem;
|
||||
padding: 0.4rem 0.25rem 0;
|
||||
padding: 0.4rem 0 0;
|
||||
text-indent: 0.25rem;
|
||||
|
||||
/* group <li> is a list item again */
|
||||
&.group {
|
||||
height: auto;
|
||||
display: list-item;
|
||||
padding: 0.4rem 0 0;
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
> a {
|
||||
padding: 0 0 0.5rem;
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:has(li.active) {
|
||||
> a {
|
||||
color: var(--text);
|
||||
padding-left: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* active item */
|
||||
&.active
|
||||
{
|
||||
&::after {
|
||||
@ -1219,8 +1528,8 @@ body#values {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* homepage artwork moves to the right as a stack */
|
||||
body#default
|
||||
{
|
||||
main
|
||||
@ -1229,7 +1538,8 @@ body#values {
|
||||
padding: 0 1.5rem;
|
||||
|
||||
hgroup {
|
||||
padding: 10dvh 0 0;
|
||||
margin-top: 10dvh;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#semicircle {
|
||||
@ -1309,16 +1619,51 @@ body#values {
|
||||
}
|
||||
}
|
||||
|
||||
/* single page docs */
|
||||
body#values main > article {
|
||||
padding: 10dvh 0 0;
|
||||
padding: 10dvh 0 5dvh;
|
||||
|
||||
> header {
|
||||
padding: 0 10dvw 0 0;
|
||||
padding: 0 5dvw 0 5dvw; /* make this 0 10dvw 0 0 to use same left position as rest of site */
|
||||
}
|
||||
> section {
|
||||
grid-column-start: 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* honeycomb case study artwork now includes the triangle */
|
||||
body#honeycomb
|
||||
{
|
||||
main > header
|
||||
{
|
||||
aside {
|
||||
margin-bottom: 12dvh;
|
||||
}
|
||||
#grid {
|
||||
--shape-size: max(16dvh, 6rem);
|
||||
|
||||
#shapes {
|
||||
gap: 4rem;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
|
||||
#triangle {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
#circle::before,
|
||||
#rectangle::before,
|
||||
#rectangle::after {
|
||||
left: -4rem;
|
||||
width: 4rem;
|
||||
}
|
||||
#rectangle::after {
|
||||
left: auto;
|
||||
right: -4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* desktops */
|
||||
@ -1336,13 +1681,15 @@ body#values {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
/* move the page title down */
|
||||
main > header
|
||||
{
|
||||
> hgroup {
|
||||
padding-top: 6rem;
|
||||
margin-top: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* homepage footer alignment */
|
||||
body#default
|
||||
{
|
||||
> footer {
|
||||
@ -1355,6 +1702,7 @@ body#values {
|
||||
}
|
||||
}
|
||||
|
||||
/* single page docs */
|
||||
body#values main > article
|
||||
{
|
||||
> header {
|
||||
@ -1380,6 +1728,7 @@ body#values {
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* more room on the top pane and figures */
|
||||
main
|
||||
{
|
||||
> header > aside {
|
||||
@ -1415,10 +1764,11 @@ body#values {
|
||||
}
|
||||
}
|
||||
|
||||
/* case studies cards move beyond the edges */
|
||||
section#studies
|
||||
{
|
||||
article {
|
||||
width: calc(var(--column-width) + 4rem);
|
||||
width: calc(var(--column-width) + 4rem + 8px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
324
content/studies/honeycomb/index.md
Normal file
324
content/studies/honeycomb/index.md
Normal file
@ -0,0 +1,324 @@
|
||||
---
|
||||
title: "Accessible design system"
|
||||
layout: "study"
|
||||
slug: "honeycomb"
|
||||
summary: "Building a native-first, accessible design system that could actually be adopted across six very different education products."
|
||||
draft: false
|
||||
|
||||
hero:
|
||||
title: "Accessible design system"
|
||||
deck: "Building a **native-first, accessible design system** to support six different products, tech stacks, and development timelines."
|
||||
html: '<div id="grid"><div id="shapes"><div id="square"></div><div id="circle"></div><div id="rectangle"></div><div id="triangle"></div></div></div>'
|
||||
list:
|
||||
more: "My company needed a design system to unify six very different products as one new edtech platform. We did that while managing very different frontends and skill levels, urgent accessibility needs, and no single framework that everyone could share."
|
||||
color: yellow
|
||||
facts:
|
||||
- key: Role
|
||||
color: blue
|
||||
- key: tools
|
||||
color: red
|
||||
- key: industry
|
||||
color: green
|
||||
study:
|
||||
facts:
|
||||
- label: "Role"
|
||||
value: "<span>Principal designer,</span> frontend architect"
|
||||
icon: "hat"
|
||||
class: "min"
|
||||
- label: "Timeline"
|
||||
value: "Ongoing production system"
|
||||
icon: "calendar"
|
||||
- label: "Tools"
|
||||
value: "HTML, CSS, JS, Typescript, Figma"
|
||||
icon: "pen"
|
||||
- label: "Industry"
|
||||
value: "K-12 education SaaS"
|
||||
icon: "briefcase"
|
||||
- label: "Scope"
|
||||
value: "6 products, many stacks"
|
||||
icon: "users"
|
||||
toc:
|
||||
- id: "intro"
|
||||
label: "Introduction"
|
||||
- id: "overview"
|
||||
label: "Project overview"
|
||||
- id: "constraints"
|
||||
label: "Adoption constraints"
|
||||
- id: highlights
|
||||
label: "Highlights"
|
||||
num: "04."
|
||||
children:
|
||||
- id: "native"
|
||||
label: "Browser-native"
|
||||
- id: "layout"
|
||||
label: "Unified layout"
|
||||
- id: "updates"
|
||||
label: "Stable updates"
|
||||
- id: "docs"
|
||||
label: "Documentation"
|
||||
- id: "impact"
|
||||
label: "Impact"
|
||||
- id: "reflection"
|
||||
label: "Reflection"
|
||||
footnotes:
|
||||
- symbol: "†"
|
||||
note: "The naming here is intentionally a little in flux. Honeycomb is the public design-system name; Schooltastic is the anonymized company/product framing used elsewhere in this portfolio. I may replace this with SchoolStatus where it makes sense, since that connection is easy to infer."
|
||||
- symbol: "‡"
|
||||
note: "The DOJ's Title II web and mobile accessibility rule set WCAG 2.1 Level AA as the technical standard for state and local government web content and mobile apps. The original 2026 and 2027 compliance dates were later extended in 2026, but the rule's substance and procurement pressure remained important for education vendors."
|
||||
---
|
||||
|
||||
{{< intro id="intro" title="A design system is only valuable if teams can actually use it" >}}
|
||||
|
||||
Honeycomb was a large, foundational design-system effort: a **unified design language and implemented component library for _six acquired products_** that all looked, felt, and behaved differently. We designed and built 40+ components, plus the supporting patterns, layout scaffolds, utilities, documentation, and [connected](https://github.com/figma/code-connect) Figma components needed to make those products feel like they belonged to the same company.
|
||||
|
||||
But this case study is not primarily about the mechanics of building a design system. Many systems define tokens, document components, and create a composable UI. The more interesting problem was **how we designed Honeycomb from the start _to be used_ inside our particular set of constraints**: different products, different codebases, different teams, different levels of frontend skill, and very different modernization timelines.
|
||||
|
||||
That shaped both the earliest decisions and the later priorities: browser-native web technologies, a small JavaScript footprint, CSS variables for theming, progressive adoption, and [unusually thorough documentation](https://honeycomb.style). The system had to meet teams where they were, so the central design and engineering constraint became: <mark>make the right thing, but make it easy to adopt before the organization was technically uniform enough</mark> to deserve a perfect system.
|
||||
|
||||
{{< /intro >}}
|
||||
|
||||
{{< overview
|
||||
id="overview"
|
||||
title="Project overview"
|
||||
>}}
|
||||
|
||||
Honeycomb was built to support six education products with different histories, product roadmaps, engineering teams, and frontend maturity. We had products that ran the gamut from "we manually copy `jquery.min.js` and cannot install npm" to "everything is React." The system also existed in two connected places: a Figma component library for design work, and an implemented HTML/CSS package documented through a hand-built site.
|
||||
|
||||
The package was intentionally native-first. Most components shipped as documented **HTML plus compiled CSS, with minimal JavaScript reserved for interactions that could not be handled reliably** with browser behavior alone. That meant product teams could drop in the CSS, copy the documented markup into whatever view file or component system they were using, and get a large amount of visual consistency and accessibility handling without committing to React, installing Tailwind, or rebuilding their app shell.
|
||||
|
||||
This was also a design strategy. Our products needed to feel like one company without erasing their existing workflows overnight. The system provided shared foundations: header, left navigation, layout scaffolding, form controls, tables, buttons, alerts, theming, icons, and more complex components like datepickers and drawers. From there, each product could adopt progressively.
|
||||
|
||||
{{< /overview >}}
|
||||
|
||||
{{< problems id="constraints" title="Adoption constraints" >}}
|
||||
|
||||
The first major decision was accepting that adoption mattered more than technical purity. While many were pushing React aggressively, our reality was that we could not pick a fashionable component model and tell every product team to catch up.
|
||||
|
||||
{{< problem
|
||||
title="Six products had <mark>six different technical realities</mark>"
|
||||
>}}
|
||||
|
||||
The system had to support product teams with very different stacks and skill levels. Some could add one more npm package easily. Some were entirely React-based and would eventually wrap Honeycomb in React components. Others needed a more basic path: copy a CSS file, include a font folder, and use documented HTML in server-rendered views.
|
||||
|
||||
That ruled out a React-only system as the first deliverable. It also ruled out a system that assumed every team wanted to learn Tailwind, Sass, or a new build pipeline. The adoption path had to be boring in the best possible way 😏.
|
||||
|
||||
{{< /problem >}}
|
||||
|
||||
{{< problem
|
||||
title="<mark>Adoption had to be progressive</mark> with no massive rewrites"
|
||||
>}}
|
||||
|
||||
There was no appetite for a synchronized redesign across every product. Each app had its own customer expectations and roadmap pressure, so **Honeycomb had to support progressive adoption**: a new header now, tables and form controls there, updated buttons and modals in the next feature area, then deeper layout changes when a team was ready.
|
||||
|
||||
Components therefore needed stable class names that were prefixed to avoid any collisions, predictable HTML that would ideally never change, and compatibility with existing application markup. Our goal was that if a team adopted a component once, **future Honeycomb updates should only change presentation through CSS** and never require an underlying HTML update.
|
||||
|
||||
{{< /problem >}}
|
||||
|
||||
{{< problem
|
||||
title="The system had to cover <mark>patterns, not just components</mark>"
|
||||
>}}
|
||||
|
||||
The most valuable work was often not a button or alert, it was the repeatable and difficult stuff product teams kept rebuilding inconsistently: app shells, responsive layouts, table controls, drawer-based filters, form sections, empty states, and primary/secondary navigation.
|
||||
|
||||
By documenting those patterns, the design team handled decisions that would otherwise be made inconsistently across teams. Honeycomb became a shared product language, not just a visual toolkit. **Our design team became a shared product support team as well.**
|
||||
|
||||
{{< /problem >}}
|
||||
|
||||
{{< problem
|
||||
title="<mark>Federal accessibility requirements</mark> created real urgency"
|
||||
>}}
|
||||
|
||||
Accessibility was not just a quality goal or a design value—it had become a business requirement. Most Schooltastic customers are public school districts, and the [DOJ's Title II web and mobile accessibility rule](https://www.ada.gov/resources/2024-03-08-web-rule/) created a concrete expectation that public entities would bring web content and mobile apps into [WCAG 2.1 Level AA](https://www.w3.org/TR/WCAG21/) conformance‡.
|
||||
|
||||
For an edtech platform this meant we could lose some of our largest districts (and theoretically almost all of our customers) if we didn't meet these requirements. It also meant that the the product teams could not just treat accessibility as something to "handle whenever we feel like it," and we could not rely on every team independently interpreting the WCAG, writing accessible markup, handling keyboard behavior, and testing every interaction with a screen reader. **The company needed accessibility that product teams could pick up off the shelf** as part of normal feature work.
|
||||
|
||||
Honeycomb had to absorb as much of that responsibility as possible and we took it very seriously.
|
||||
|
||||
* Everyone on the team got accessibility training.
|
||||
* Documentation included implementation rules and accessible attributes in every component, and distilled down requirements to plain English.
|
||||
* Our team tested everything with screen readers and ran through various disability simulators.
|
||||
* We also leveraged browser-native elements that brought accessibility in for free as much as possible.
|
||||
|
||||
{{< /problem >}}
|
||||
|
||||
{{< /problems >}}
|
||||
|
||||
<div id="highlights"></div>
|
||||
|
||||
{{< section id="native" title="Browser-native by default" >}}
|
||||
|
||||
The most important implementation decision was that Honeycomb would not belong to any single product stack or require any kind of upgrade. We decided to be as out-of-the-way as possible and belong primarily to the browser.
|
||||
|
||||
Despite the extended discussion, this pretty quickly ruled out a React-first design system early on. Some products would eventually wrap Honeycomb in React components (which was great!) but React could not be the system's lowest common denominator. **If the baseline required a modern JavaScript framework, two products would be locked out for too long** and the design system would fail at the thing it most needed to do: create consistency across the company before every app was modernized.
|
||||
|
||||
So Honeycomb's first-class output was HTML and CSS. <mark color="yellow">Each product team could import a compiled CSS file, copy documented markup, and start using components without changing their build process.</mark> That made adoption possible for older apps while still leaving a better path for teams with more modern tooling.
|
||||
|
||||
### Sass on top of Tailwind
|
||||
|
||||
Under the hood, **we authored Honeycomb as Sass-based components on top of Tailwind**. Tailwind helped us write and maintain the system faster, and the decision was also practical: two products already used Tailwind, so they could compile Honeycomb alongside their own Tailwind configuration and benefit from the same tree-shaking and build process. Other products were encouraged to move in that direction (and one did), but they were not blocked if they could not get there immediately.
|
||||
|
||||
JavaScript followed the same model. We exported small vanilla JS modules, and later added a few framework-agnostic web components for interactions that needed more behavior. Teams could include those individually or as a bundle, but static components did not require JavaScript just to look and behave correctly. This included interactive components like dropdowns too!
|
||||
|
||||
[ interactive dropdown example ]
|
||||
|
||||
### Native elements whenever possible
|
||||
|
||||
We were also strict about using real browser controls wherever possible. A checkbox was an `<input type="checkbox">`, not a div managed by a JavaScript checkbox library. A button was a `<button>`. When the browser already provided semantics, keyboard behavior, form behavior, and accessibility expectations, Honeycomb leaned into that instead of replacing it.
|
||||
|
||||
In some products, this did mean that **we asked teams to remove older UI libraries that had recreated native controls in JavaScript**. That was one of the places where adoption did require change, but it was an intentional one: Honeycomb could only provide a reliable accessibility and interaction baseline if the underlying elements were honest.
|
||||
|
||||
[ screenshot of form controls ]
|
||||
|
||||
The result was a "tiered" model of sorts: every product could start with compiled CSS and documented HTML, and products with stronger tooling could compile the package themselves. Teams could opt into Tailwind, JavaScript modules, or web components as needed. **The system got more powerful at each layer, but the first layer still worked (really well).**
|
||||
|
||||
{{< /section >}}
|
||||
|
||||
{{< section id="layout" title="Unifying six app layouts" >}}
|
||||
|
||||
The biggest initial design challenge was trying to come up with an **app layout that could plausibly belong to six products that had a lot of unique history**. There was little visual overlap and we had at least three different navigation models to work with. Coming up with a modern layout and UI in isolation would've been a dream, but we had to consider legacy interfaces with longtime customers.
|
||||
|
||||
[ screenshot of the old layouts stacked? ]
|
||||
|
||||
We needed the products to feel meaningfully refreshed and part of the same portfolio, but not so different that each product team would have to significantly retrain users or redesign large workflows before adopting Honeycomb. That pushed us toward a familiar structure: a top app header, a collapsible left nav, a secondary left nav that could sit alongside this when needed, and a main content area that could support everything from dense admin tables to simpler card-based designs.
|
||||
|
||||
This seems super obvious in retrospect, but the bigger point is the restraint. The design team (and org as a whole) was excited about the possibility of a more novel layout as we now had the opportunity to introduce something fresh. And we did, in fact, try out a ton of different directions—they just all would have made adoption feel riskier and forced too many product-specific exceptions. **The shared layout gave us a stable frame where every product was recognizable, while still creating a clearer, more modern, and professional baseline** across the portfolio.
|
||||
|
||||
[ screenshot of left nav and header ]
|
||||
|
||||
### Neutral by default, themed by product
|
||||
|
||||
The visual direction followed the same logic. Honeycomb components were intentionally restrained: mostly monochromatic, solid borders, plenty of spacing, strong typography, and color used only where it carried meaning. This kept components from competing with each product's identity and helped the system work in very different product contexts.
|
||||
|
||||
**Product personality came through the specific color palettes instead.** Each app had its own palette exposed through CSS variables, so a product could feel distinct without owning a separate component library. These themes could even be applied with simple `data` attributes to allow for various fledgling integrations where one app feature was embedded in another. This all let us bring six products closer together without flattening them into a single generic interface.
|
||||
|
||||
[ Theme screenshot ]
|
||||
|
||||
This also helped Honeycomb provide patterns, not just components. A themed button or alert was (very) useful, but another win was that <mark color="green">we solved recurring questions each team had about layout patterns, what utilities to include in the header, how navigation should work, etc</mark>. Not only did they no longer have to reinvent these things every time in inconsistent ways, we took the decisionmaking chore away as well.
|
||||
|
||||
The neutral components also gave those patterns enough consistency to feel shared, while the product themes gave them enough flexibility to work in different app contexts.
|
||||
|
||||
### App header as an example
|
||||
|
||||
The header was one of the most important examples of this balancing act. Each product had account controls and would need to update their product name and logo to the new Schooltastic-branded one. Beyond that, though, each one used this space for a lot of different things. Two had complex group switching, one had super buttons for users to create different types of content, one used it for their app's entire navigation, and one didn't use it at all.
|
||||
|
||||
We used the header to standardize these things cross-product, while also solving some usability issues on both ends of the spectrum. The company plus product logo and the user account controls were the same and now in consistent places. A help button was introduced in those that didn't have it, and put in a predictable place as well. Finally, space was reserved for the two functions the header would be limited to: context switching and high-level app functions.
|
||||
|
||||
[ all 6 headers on top of each other ]
|
||||
|
||||
The design stayed intentionally simple so it could work across products without becoming a custom negotiation every time, and we took away the ability to jam other random things into this space. This decision made the header less expressive than some early explorations, but more useful as infrastructure. <mark color="red">The header became one of the easiest ways for a product to start feeling like part of the portfolio too</mark>, and because it sat above the rest of the app, it could introduce Honeycomb without forcing every screen underneath it to change at once.
|
||||
|
||||
{{< /section >}}
|
||||
|
||||
{{< section id="updates" title="Built for stable updates" >}}
|
||||
|
||||
Choosing HTML and CSS as Honeycomb's baseline solved the adoption problem, but it introduced a different kind of risk: once product teams copied component markup into their apps, that markup became a "public contract"! **We could not casually change markup later without creating work across every product.**
|
||||
|
||||
A JS component system would have given us total control over the rendered DOM, but that path had already been ruled out for adoption reasons. <mark color="yellow">So we treated the HTML itself with the same seriousness a library team would give to an API.</mark> The goal was to make the markup simple enough to adopt, stable enough to last, and flexible enough that most future improvements could ship through CSS, variables, and package updates.
|
||||
|
||||
That meant thinking through every component's structure up front before it appeared in the documentation. **We used prefixed class names to avoid collisions**, kept markup as browser-native as possible, and avoided fragile CSS selectors that depended on exact element relationships. Instead of styling something like `button > span`, we were always explicit with `.hc-button .hc-label`.
|
||||
|
||||
This is mundane but it was one of the most important parts of making Honeycomb usable at scale. In fact, many of the apps _were_ styling things by targeting the raw element and this let us make Honeycomb truly opt-in. **The kicker is a particular point of pride: over roughly 2.5 years, we only had to make _one_ breaking HTML change.** For a system used across multiple products with nearly 40 components and tons of interaction, this created immense trust in our team and what we were building.
|
||||
|
||||
### Central changes without product rewrites
|
||||
|
||||
Once the HTML for any given component was set, in most cases **we could improve the component just by asking the teams to update the library**. Anything visual was easy—spacing adjustments, font sizes, color changes, theme updates, etc. could usually ship through the package without asking anyone to rewrite their templates or components. We could even add or adjust interaction at times, and anything that did require a markup change was explicitly to _add_ functionality, never correct.
|
||||
|
||||
**CSS variables were a major part of that model.** Anything theme-related, all primitives, things like our custom shadows and opacities—really anything visual—was accessible and could be adjusted at the system layer easily. One of the biggest wins this introduced was the ability for product teams to access the same style attributes Honeycomb used when they weren't able to use a Honeycomb component.
|
||||
|
||||
[ screenshot of variables or theme controls ]
|
||||
|
||||
### Icons as an example
|
||||
|
||||
We decided to roll our own icon set—not just because [I love making icon fonts](https://keyrune.andrewgioia.com) but because it gave us control over a pretty important component to Honeycomb's personality. We looked at open source libraries like [Iconoir](https://iconoir.com) and [Lucide](https://lucide.dev) but 3 problems led to us making our own:
|
||||
|
||||
* No single library was complete enough for us
|
||||
* I hated the idea of loading massive font files when we only needed a fraction of the icons
|
||||
* We needed to make custom icons for things like product logos or education-specific items anyway
|
||||
|
||||
We also needed icons to remain centrally maintainable; if every product inlined SVG paths, then changing an icon later would require teams to touch app code in six different places, often on different timelines. **So an icon font was born!**
|
||||
|
||||
We combined open source icons and drew others to fill the gaps, and **shipped outline and solid sets as font files within the Honeycomb package**. One of the cool aspects is that we made the icon font work as one family with two weights: regular for outline icons and bold for filled icons. You could switch between variants using the same name just by changing the elements font weight.
|
||||
|
||||
We also added ligatures for every icon as well, so that teams could write readable names like `arrow-left` as text instead of the normal `<i class="hc-icon hc-icon--arow-left></i>`. This was partly an implementation convenience but mostly a response to a real product request: one team specifically wanted to place icons using words, as they were doing it that way in their app currently. <mark color="red">Supporting this request was just one more way we drove adoption.</mark>
|
||||
|
||||
[ screenshot of icon font variants ]
|
||||
|
||||
Icons are a great example of how Honeycomb needed to be easy for product teams to use, but still governable by the design system. Stable implementation gave product teams confidence, while centrally owned assets let the system keep getting better after adoption.
|
||||
|
||||
{{< /section >}}
|
||||
|
||||
{{< section id="docs" title="Documentation as support" >}}
|
||||
|
||||
The documentation site became one of the most important parts of Honeycomb because it turned the design system from a library into something teams could actually understand and use. Every product team had different frontend experience, and several did not have dedicated frontend developers at all. **The docs had to do more than list components—they had to explain how to build with Honeycomb in practical terms.**
|
||||
|
||||
Each component page included examples, available attributes, expected markup, accessibility notes, and implementation guidance. We documented not only what a component looked like, but when to use it, what options it supported, and what developers still needed to handle correctly in their own product context. <mark color="red">That level of detail made the docs a huge time investment, but it also made them one of the strongest adoption tools we had.</mark>
|
||||
|
||||
[ screenshot of component docs ]
|
||||
|
||||
**Writing the docs also improved the system itself.** If I had trouble explaining a component clearly, or if an example required too many caveats, or if the classnames were inconsistent with other components, that was usually a sign that the component/markup needed more work. It also let me test the designs in real time, which often improved our components on the Figma/design side.
|
||||
|
||||
The docs forced us to be honest about what we were shipping. They were not a layer added after the design system was done, they were part of how the design system got better.
|
||||
|
||||
### Accessibility in plain English
|
||||
|
||||
The docs were especially important for accessibility. The DOJ requirement created real urgency, but "make this WCAG compliant" is not useful guidance for a product developer trying to finish a sprint. <mark color="blue">We used the docs to translate accessibility requirements into practical implementation rules</mark>—when a label was required, what attributes mattered, how keyboard behavior should work, and where Honeycomb handled something versus where the product still had responsibility.
|
||||
|
||||
That helped teams get accessibility benefits from Honeycomb without needing every developer to become an accessibility specialist overnight. Components started from a stronger baseline, and the docs explained the remaining responsibilities clearly enough that teams could act on them.
|
||||
|
||||
[ screenshot of accessibility notes ]
|
||||
|
||||
### A playground for real markup
|
||||
|
||||
We also built a small HTML playground into the documentation site so developers could test markup live, like a mini CodePen. Since Honeycomb was HTML-first, developers needed to see how attributes, classes, themes, and component states worked together, and they needed a safe place to experiment before copying markup into a product.
|
||||
|
||||
The playground also made support conversations easier. If someone had an issue or came to us with an inconsistency, having a live editor running the latest version could quickly rule out what was our fault and what was theirs.
|
||||
|
||||
### Figma and docs stayed connected
|
||||
|
||||
[Figma Code Connect](https://github.com/figma/code-connect) added another entry point for developers. In Dev Mode, they could select a Honeycomb component and see the code directly in the design file. This somewhat competed with the documentation site, as a developer might get the code from Figma without checking the docs now.
|
||||
|
||||
That was OK because we kept both sources connected through the Honeycomb repo. **The same implementation examples that powered the docs also informed the Figma code connections**, so the code that developers saw in Dev Mode matched what they would find on the docs site. Figma became the quick path from design to code, while the docs remained the deeper source for examples, attributes, accessibility details, and usage guidance.
|
||||
|
||||
[ screenshot of Figma Dev Mode / Code Connect ]
|
||||
|
||||
### Design became a frontend resource
|
||||
|
||||
**The result was that the design team became a shared frontend resource for the company.** Product teams came to us with Honeycomb questions, but also with layout issues, CSS problems, accessibility concerns, and implementation details that were adjacent to the design system.
|
||||
|
||||
This really changed the design team's role quite a bit, particularly at a time when we were just beginning to work with certain product teams. Not only were we creating Figma files and static designs, we were now helping teams build better interfaces in the browser, answering frontend and accessibility questions, and taking recurring UI decisions off their plates.
|
||||
|
||||
{{< /section >}}
|
||||
|
||||
{{< section id="impact" title="Impact" >}}
|
||||
|
||||
Honeycomb has had a profound impact on Schooltastic as a whole. At the most basic level, it's a shared library of frontend components and patterns that have moved all six products so much closer to a truly unified experience. From accessibility to standardized patterns, it's taken so much off the plates of frontend developers that they're shipping noticeably faster. The design team too is able to create high fidelity designs much quicker and easier.
|
||||
|
||||
These are really table stakes for any design system, though, and I want to highlight two major and somewhat unexpected impacts that our specific design system created.
|
||||
|
||||
### Accessibility became a core competency
|
||||
|
||||
Accessibility is often an afterthought at most orgs, and even here where it was considerably more than that, knowledge was still very uneven. One team in particular baked it into their development processes, but most either never considered it or had no consistent way to translate accessibility requirements into everyday product work.
|
||||
|
||||
<mark color="blue">Honeycomb gave us a way to turn accessibility from a "compliance scramble" into a shared competency.</mark> The design team led the way in translating requirements into functional code. Components started from accessible markup and interaction patterns, the documentation explained requirements in practical language, and our team became a place product teams could go with real questions: focus behavior, labels, keyboard interactions, screen-reader expectations, color contrast, and when ARIA was actually needed.
|
||||
|
||||
The business value was significant too. For a company obviously selling into education, accessibility is not a nice-to-have feature. Accessibility affects trust, procurement, renewals, and risk, and Honeycomb gave Schooltastic a much stronger answer to that pressure because it was built into the system teams were already adopting.
|
||||
|
||||
### The design team elevated to a true cross-functional team
|
||||
|
||||
Honeycomb also changed how the design team was perceived and used across the company. We were no longer only producing screens in Figma or reviewing implementation after the fact. **Because _we_ owned the design system, documentation, and a lot of the frontend guidance around it, product teams started treating us as a practical resource** for building the interface itself.
|
||||
|
||||
That was especially valuable for teams without dedicated frontend developers. A layout issue, CSS bug, accessibility question, or component adoption problem that might have slowed a team down for hours could often be resolved quickly by someone on the design team. Slack support and the docs site made those conversations easier because we had a welcome place for questions and resources to point people to.
|
||||
|
||||
<mark color="yellow">This created a healthier relationship between design and engineering.</mark> Designers were closer to production realities, engineers had more support for difficult UI work, and product teams could move faster without re-solving the same interface decisions over and over. Honeycomb made the design team more than a service that handed off mockups, it made us a connective frontend group across the product organization.
|
||||
|
||||
{{< /section >}}
|
||||
|
||||
{{< section id="reflection" title="Reflection" >}}
|
||||
|
||||
The design team's shift to cross-functional team may be the impact I'm proudest of. Not only has it given us a lot of credibility, it eased our relationship-building with brand new teams at a critical point for the company. Design _can_ own the details of browser implementation, accessibility, documentation, and product consistency in a way that makes every team stronger.
|
||||
|
||||
Beyond the two unexpected impacts, though, this project has also really driven home for me that **technical details do matter, and the "state of the art" isn't always the correct choice**. Choosing native HTML over custom JavaScript mattered because it changed who could adopt the system. Choosing CSS-first components mattered because it changed bundle cost and maintenance. Writing exhaustive docs mattered because it shifted implementation work out of meetings and into examples. Connecting code to Figma mattered because it further enabled actual implementation.
|
||||
|
||||
The system looks simple from the outside: 1990s-style classes, markup, static docs site, and some web components. Underneath that simplicity, though, is a powerful, standards-compliant system that's prioritized "people are actually using it" over framework fashion or ceremony.
|
||||
|
||||
{{< /section >}}
|
||||
@ -12,6 +12,7 @@ hero:
|
||||
list:
|
||||
more: "Wallabyte supports schools and families through critical paperwork, but was woefully unusable. This case study covers how I approached that challenge—from identifying the highest impact issues to shaping a more coherent forms experience."
|
||||
img: card-legacy.png
|
||||
color: blue
|
||||
facts:
|
||||
- key: Role
|
||||
color: yellow
|
||||
|
||||
@ -16,7 +16,7 @@ footnotes:
|
||||
|
||||
<em>I design for the browser first.</em> This is true even in an age of mobile-first and push-them-to-the-app-at-all-costs. I think the web browser is a great equalizer and perhaps the greatest preserver of the open internet.
|
||||
|
||||
<em>I care deeply about how something looks, but aesthetics are never the point on their own.</em> Good design should feel thoughtful, trustworthy, and calm; it should reduce cognitive load, never add to it. The goal is to make software more useful and easier to use. If a visual choice, interaction, or animation doesn't improve the experience, it probably doesn't belong there. **Dark patterns are an abomination.** Delight matters and it should come primarily from responsiveness, care, playfulness, and personality.
|
||||
<em>I care deeply about how something looks, but aesthetics are never the point on their own.</em> Good design should feel thoughtfuland calm; it should build trust and reduce cognitive load, never add to it. The goal is to make software more useful and easier to use. If a visual choice, interaction, or animation doesn't improve the experience, it probably doesn't belong there. **Dark patterns are an abomination.** Delight matters and it should come primarily from responsiveness, care, playfulness, and personality.
|
||||
|
||||
<em>Good interfaces should respect the user and their device.</em> The browser, HTML, and CSS are already an extraordinarily capable platform, and I try to stay as close to browser-native as possible. If something can be done well with HTML and CSS, I will always do that rather than rely on JavaScript as a crutch.
|
||||
|
||||
|
||||
@ -9,6 +9,10 @@
|
||||
{{- $svg = .Content -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- $html := "" -}}
|
||||
{{- with .Params.hero.html -}}
|
||||
{{- $html = . -}}
|
||||
{{- end -}}
|
||||
|
||||
<header>
|
||||
<hgroup>
|
||||
@ -38,15 +42,31 @@
|
||||
{{- with $svg -}}
|
||||
{{ . | safeHTML }}
|
||||
{{- end -}}
|
||||
{{- with $html -}}
|
||||
{{ . | safeHTML }}
|
||||
{{- end -}}
|
||||
</header>
|
||||
|
||||
<article>
|
||||
{{- with .Params.study.toc -}}
|
||||
<nav aria-label="Table of contents">
|
||||
<ol>
|
||||
{{- range . -}}
|
||||
<li{{ with .children }} class="group"{{ end }}>
|
||||
{{- if .id -}}
|
||||
<a href="#{{ .id }}" {{- if .num -}}data-id="{{ .num }}"{{- end -}}>{{ .label }}</a>
|
||||
{{- else -}}
|
||||
<span>{{ .label }}</span>
|
||||
{{- end -}}
|
||||
{{- with .children -}}
|
||||
<ul>
|
||||
{{- range . -}}
|
||||
<li><a href="#{{ .id }}">{{ .label }}</a></li>
|
||||
{{- end -}}
|
||||
</ul>
|
||||
{{- end -}}
|
||||
</li>
|
||||
{{- end -}}
|
||||
</ol>
|
||||
</nav>
|
||||
{{- end -}}
|
||||
|
||||
@ -19,25 +19,31 @@
|
||||
</header>
|
||||
<section id="studies">
|
||||
<h1>Case studies</h1>
|
||||
<p class="tablet-hide">
|
||||
<div class="tablet-hide">
|
||||
<p>
|
||||
These longer format stories each highlight different aspects of my design process, thinking, collaboration style, and skills.
|
||||
</p>
|
||||
<p class="tablet-hide">
|
||||
You can also read about my <a href="/values">design philosophy and values</a> specifically.
|
||||
<p>
|
||||
You can also read about my <a href="/values">design philosophy and values</a> in more detail.
|
||||
</p>
|
||||
</div>
|
||||
{{ range where .Site.RegularPages "Section" "studies" }}
|
||||
{{- $page := . -}}
|
||||
{{- $cardImage := "" -}}
|
||||
{{- $image := "" -}}
|
||||
{{- $color := "" -}}
|
||||
{{- with .Params.list.img -}}
|
||||
{{- $match := $page.Resources.GetMatch . -}}
|
||||
{{- if not $match -}}
|
||||
{{- $match = $page.Resources.GetMatch (printf "img/%s" .) -}}
|
||||
{{- end -}}
|
||||
{{- with $match -}}
|
||||
{{- $cardImage = .RelPermalink -}}
|
||||
{{- $image = .RelPermalink -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
<article{{ with $cardImage }} style="--card-bg: url('{{ . }}');"{{ end }}>
|
||||
{{- with .Params.list.color -}}
|
||||
{{- $color = . -}}
|
||||
{{- end -}}
|
||||
<article{{ with $color }} color="{{ . }}"{{ end }}{{ with $image }} style="--card-bg: url('{{ . }}');"{{ end }}>
|
||||
<a href="{{ .RelPermalink }}">
|
||||
<h2>{{ .Title }}</h2>
|
||||
<p>{{ .Summary }}</p>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user