progress-tracker
Version:
Illustrate the steps in a multi step process like a form or a timeline.
352 lines (278 loc) • 9.29 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;
}
.progress-step:last-child:not(:has(.progress-text)) {
flex-grow: 0;
}
/* Marker shape */
.progress-step::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 */
.progress-step::after {
--bg: var(--path-bg);
}
.progress-step:not(:last-child)::after {
content: "";
display: block;
position: absolute;
order: -1;
top: var(--path-position-block);
left: 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;
}
.progress-text > * + * {
margin-top: 4px;
}
.progress-text:where(a, button) {
-webkit-text-decoration: none;
text-decoration: none;
text-align: inherit;
line-height: inherit;
color: inherit;
background: none;
border: none;
}
.progress-text:where(a, button):hover {
cursor: pointer;
color: var(--text-color-hover);
}
.progress-text:where(a, button):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);
}
.progress-step.is-active::after {
--bg: var(--path-bg-active);
}
.progress-step.is-complete::before {
--bg: var(--marker-bg-complete);
}
.progress-step.is-complete::after {
--bg: var(--path-bg-complete);
}
.progress-step:not(.is-active):has(.progress-text:where(a, button)):hover::before {
--bg: var(--marker-bg-hover);
}
.progress-step:not(.is-active):has(.progress-text:where(a, button)):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;
}
.progress-tracker--center:not(.progress-tracker--vertical) .progress-step::before {
margin-left: auto;
margin-right: auto;
}
.progress-tracker--center.progress-tracker--vertical {
max-width: 240px;
margin-left: auto;
margin-right: auto;
}
.progress-tracker--end {
--path-position-inline: calc(100% + var(--marker-spacing));
text-align: right;
}
.progress-tracker--end:not(.progress-tracker--vertical) .progress-step::before {
margin-left: auto;
}
.progress-tracker--end.progress-tracker--vertical .progress-step {
flex-direction: row-reverse;
}
.progress-tracker--end.progress-tracker--vertical .progress-step::after {
left: auto;
right: var(--path-position-block);
}
.progress-tracker--reverse:not(.progress-tracker--vertical) .progress-step::after {
top: auto;
bottom: var(--path-position-block);
}
.progress-tracker--reverse.progress-tracker--marker-square .progress-step::after {
top: auto;
bottom: 0;
}
.progress-tracker--reverse .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-tracker--dashed .progress-step:not(:last-child)::after, .progress-tracker--dashed-even .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--dashed.progress-tracker--vertical, .progress-tracker--dashed-even.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)) {
.progress-tracker--dashed-even {
--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-tracker--marker-square .progress-step::before {
border-radius: 0;
}
.progress-tracker--marker-square.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:not(:last-child)::after, .progress-tracker--anim .progress-step.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%;
}
.progress-tracker--anim .progress-step.is-complete:not(:last-child)::after {
background-position: -100% 100%;
}
.progress-tracker--anim.progress-tracker--vertical .progress-step.is-active:not(:last-child)::after, .progress-tracker--anim.progress-tracker--vertical .progress-step.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%;
}
.progress-tracker--anim.progress-tracker--vertical .progress-step.is-complete:not(:last-child)::after {
background-position: 100% -100%;
}
.progress-tracker--inline {
overflow: auto;
}
.progress-tracker--inline .progress-step {
align-items: center;
flex-direction: row;
min-width: -moz-fit-content;
min-width: fit-content;
}
.progress-tracker--inline .progress-step::before {
flex-shrink: 0;
order: 2;
}
.progress-tracker--inline .progress-step::after {
position: relative;
top: auto;
left: 0;
order: 3;
}
.progress-tracker--inline .progress-text {
flex: 0 0 auto;
padding: 8px 12px;
}
.progress-tracker--inline .progress-text:has(*:nth-child(2)) {
flex-basis: min-content;
}
.progress-tracker--inline:not(.progress-tracker--inline-text-end) .progress-step:first-child .progress-text {
padding-left: 0;
}
.progress-tracker--inline-text-end .progress-text {
order: 2;
}
.progress-tracker--vertical {
flex-direction: column;
}
.progress-tracker--vertical .progress-step {
flex-direction: row;
}
.progress-tracker--vertical .progress-step::after {
top: calc(var(--marker-size-block) + var(--marker-spacing));
left: var(--path-position-block);
width: var(--path-size-block);
height: var(--path-size-inline);
}
.progress-tracker--vertical .progress-text {
flex-grow: 1;
padding-top: 4px;
padding-bottom: 12px;
}