progress-tracker
Version:
Illustrate the steps in a multi step process like a form or a timeline.
386 lines (313 loc) • 8.27 kB
CSS
.progress-tracker {
--marker-size: 32px;
--marker-size-block: 32px;
--marker-size-inline: var(--marker-size-block);
--marker-size-half: calc(var(--marker-size-block) * 0.5);
--marker-spacing: 0px;
--marker-bg: #999;
--marker-bg-active: #0034a3;
--marker-bg-complete: #0157ff;
--marker-bg-hover: #3f7eff;
--marker-color: #fff;
--path-size-block: 4px;
--path-size-inline: calc(100% - (var(--marker-size-inline) + (var(--marker-spacing) * 2)));
--path-position-block: calc(var(--marker-size-half) - (var(--path-size-block) * 0.5));
--path-position-inline: calc(var(--marker-size-inline) + var(--marker-spacing));
--path-bg: #999;
--path-bg-active: #999;
--path-bg-complete: #0157ff;
--text-color: #0034a3;
--text-color-hover: #0157ff;
--animation-duration: 0.3s;
display: flex;
margin: 0;
padding: 0;
list-style: none;
counter-reset: step;
}
.progress-step {
position: relative;
display: flex;
flex-direction: column;
flex: 1 1 0%;
margin: 0;
padding: 0;
&:last-child:not(:has(.progress-text)) {
flex-grow: 0;
}
/* Marker shape */
&::before {
--bg: var(--marker-bg);
--color: var(--marker-color);
content: "";
position: relative;
z-index: 20;
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
width: var(--marker-size-inline);
height: var(--marker-size-block);
border-radius: 50%;
color: var(--color);
background-color: var(--bg);
transition: background-color, border-color;
transition-duration: var(--animation-duration);
}
/* Marker path */
&::after {
--bg: var(--path-bg);
}
&:not(:last-child)::after {
content: "";
display: block;
position: absolute;
order: -1;
inset-block-start: var(--path-position-block);
inset-inline-start: var(--path-position-inline);
width: var(--path-size-inline);
height: var(--path-size-block);
background-color: var(--bg);
transition: background-color, background-position;
transition-duration: var(--animation-duration);
}
}
.progress-text {
padding: 8px;
overflow: hidden;
color: var(--text-color);
text-overflow: ellipsis;
> * + * {
margin-block-start: 4px;
}
&:where(a, button) {
text-decoration: none;
text-align: inherit;
line-height: inherit;
color: inherit;
background: none;
border: none;
&:is(:hover, :focus) {
cursor: pointer;
color: var(--text-color-hover);
}
}
}
.progress-title {
font-size: 1.5rem;
}
/* States */
.progress-step {
&.is-active {
&::before {
--bg: var(--marker-bg-active);
}
&::after {
--bg: var(--path-bg-active);
}
}
&.is-complete {
&::before {
--bg: var(--marker-bg-complete);
}
&::after {
--bg: var(--path-bg-complete);
}
}
&:not(.is-active):has(.progress-text:where(a, button)) {
&:is(:hover, :focus) {
&::before {
--bg: var(--marker-bg-hover);
}
}
}
}
/* Alignment */
.progress-tracker--center {
--path-position-inline: calc(50% + (var(--marker-size-inline) / 2) + var(--marker-spacing));
text-align: center;
&:not(.progress-tracker--vertical) .progress-step {
&::before {
margin-inline: auto;
}
}
&.progress-tracker--vertical {
max-width: 240px;
margin-inline: auto;
}
}
.progress-tracker--end {
--path-position-inline: calc(100% + var(--marker-spacing));
text-align: right;
&:not(.progress-tracker--vertical) .progress-step {
&::before {
margin-inline-start: auto;
}
}
&.progress-tracker--vertical .progress-step {
flex-direction: row-reverse;
&::after {
inset-inline-start: auto;
inset-inline-end: var(--path-position-block);
}
}
}
.progress-tracker--reverse {
&:not(.progress-tracker--vertical) .progress-step {
&::after {
inset-block-start: auto;
inset-block-end: var(--path-position-block);
}
}
&.progress-tracker--marker-square .progress-step {
&::after {
inset-block: auto 0;
}
}
.progress-text {
order: -1;
flex-grow: 1;
}
}
/* Variants */
.progress-tracker--marker-counter {
.progress-step {
&::before {
content: counter(step);
counter-increment: step;
}
}
}
.progress-tracker--marker-dataset {
.progress-step {
&::before {
content: attr(data-text);
content: attr(data-text, "");
}
}
}
.progress-tracker--dashed, .progress-tracker--dashed-even {
--path-dash-size: 8px;
--path-dash-count: 0;
--path-dash-calc: var(--path-dash-size);
--path-direction: right;
--marker-spacing: 8px;
.progress-step {
&:not(:last-child)::after {
background: repeating-linear-gradient(to var(--path-direction), var(--bg) 0px var(--path-dash-calc), transparent var(--path-dash-calc) calc(var(--path-dash-calc)*2));
}
}
&.progress-tracker--vertical {
--path-direction: bottom;
}
}
.progress-tracker--dashed-even {
--path-dash-size: 0px;
--path-dash-count: 4;
--path-dash-percent: calc(100% / (var(--path-dash-count) + (var(--path-dash-count) - 1)));
--path-dash-calc: calc(100% / (var(--path-dash-count) + (var(--path-dash-count) - 1)));
--path-dash-calc: var(--path-dash-percent);
--marker-spacing: 0px;
@supports (height: round(up, 100.1px, 1px)) {
--path-dash-calc: round(up, var(--path-dash-percent), .5px);
}
}
.progress-tracker--spaced {
--marker-spacing: 8px;
}
.progress-tracker--marker-square {
--marker-size-block: 24px;
--marker-size-inline: 4px;
--path-position-block: calc(var(--marker-size-block) - var(--path-size-block));
.progress-step {
&::before {
border-radius: 0;
}
}
&.progress-tracker--vertical {
--marker-size-inline: 24px;
--marker-size-block: 4px;
--path-size-inline: calc(100% - (var(--marker-spacing) * 2));
}
}
.progress-tracker--anim {
.progress-step {
&.is-active, &.is-complete {
&:not(:last-child)::after {
background-image: linear-gradient(to right, var(--path-bg-active) 50%, var(--path-bg-complete) 50%);
background-size: 200% 100%;
background-position: 0% 100%;
}
}
&.is-complete {
&:not(:last-child)::after {
background-position: -100% 100%;
}
}
}
&.progress-tracker--vertical .progress-step {
&.is-active, &.is-complete {
&:not(:last-child)::after {
background-image: linear-gradient(to bottom, var(--path-bg-active) 50%, var(--path-bg-complete) 50%);
background-size: 100% 200%;
background-position: 100% 0%;
}
}
&.is-complete {
&:not(:last-child)::after {
background-position: 100% -100%;
}
}
}
}
.progress-tracker--inline {
overflow: auto;
.progress-step {
align-items: center;
flex-direction: row;
min-width: fit-content;
&::before {
flex-shrink: 0;
order: 2;
}
&::after {
position: relative;
inset-block-start: auto;
inset-inline-start: 0;
order: 3;
}
}
.progress-text {
flex: 0 0 auto;
padding: 8px 12px;
&:has(*:nth-child(2)) {
flex-basis: min-content;
}
}
&:not(.progress-tracker--inline-text-end) .progress-step:first-child {
.progress-text {
padding-inline-start: 0;
}
}
}
.progress-tracker--inline-text-end {
.progress-text {
order: 2;
}
}
.progress-tracker--vertical {
flex-direction: column;
.progress-step {
flex-direction: row;
&::after {
inset-block-start: calc(var(--marker-size-block) + var(--marker-spacing));
inset-inline-start: var(--path-position-block);
width: var(--path-size-block);
height: var(--path-size-inline);
}
}
.progress-text {
flex-grow: 1;
padding-block: 4px 12px;
}
}