elloimbrandon
This design is based off of Google Material UI. I've always liked the simplicity and modern design of their components.
@layer tokens, base, components;
@layer tokens {
:root {
color-scheme: light dark;
--mui-success: #2e7d32;
--mui-error: #d32f2f;
--mui-warning: #ed6c02;
--mui-info: #0288d1;
--mui-font: "Roboto", "Helvetica", "Arial", sans-serif;
--mui-radius: 4px;
--mui-shadow-6:
0 3px 5px -1px rgb(0 0 0 / 0.2),
0 6px 10px 0 rgb(0 0 0 / 0.14),
0 1px 18px 0 rgb(0 0 0 / 0.12);
--mui-z-snackbar: 1400;
--mui-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--mui-ease-out: cubic-bezier(0, 0, 0.2, 1);
--mui-ease-in: cubic-bezier(0.4, 0, 1, 1);
--mui-sharp: cubic-bezier(0.4, 0, 0.6, 1);
--mui-shortest: 150ms;
--mui-shorter: 200ms;
--mui-short: 250ms;
--mui-standard: 300ms;
--mui-complex: 375ms;
--mui-entering: 225ms;
--mui-leaving: 195ms;
--mui-ripple: 550ms;
--mui-pulsate: 2500ms;
--toast-gap: 0.5rem;
--toast-offset: clamp(0.5rem, 3vw, 1.5rem);
--toast-width: min(100vw - var(--toast-offset) * 2, 28rem);
--toast-icon-size: 22px;
--toast-icon-gap: 12px;
--icon-success: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4C12.76,4 13.5,4.11 14.2,4.31L15.77,2.74C14.61,2.26 13.34,2 12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12M7.91,10.08L6.5,11.5L11,16L21,6L19.59,4.58L11,13.17L7.91,10.08Z'/></svg>");
--icon-error: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z'/></svg>");
--icon-warning: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 5.99L19.53 19H4.47L12 5.99M12 2L1 21h22L12 2zm1 14h-2v2h2v-2zm0-6h-2v4h2v-4z'/></svg>");
--icon-info: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z'/></svg>");
}
@keyframes mui-ripple-enter {
from { scale: 0; opacity: 0.1; }
to { scale: 1; opacity: 0.3; }
}
@keyframes mui-pulsate {
0%, 100% { scale: 1; }
50% { scale: 0.92; }
}
}
@layer base {
.toasts :where(p) { margin: 0; }
.toasts :where(button) { font: inherit; color: inherit; }
}
@layer components {
.toasts {
position: fixed;
inset-block-end: var(--toast-offset);
inset-inline-start: var(--toast-offset);
z-index: var(--mui-z-snackbar);
inline-size: var(--toast-width);
display: flex;
flex-direction: column;
container: toasts / inline-size;
interpolate-size: allow-keywords;
}
.toast {
--tone: var(--mui-info);
--icon: var(--icon-info);
--toast-bg: light-dark(
color-mix(in oklch, var(--tone) 10%, white),
color-mix(in oklch, var(--tone) 16%, #121212)
);
--toast-fg: light-dark(
color-mix(in oklch, var(--tone) 40%, black),
color-mix(in oklch, var(--tone) 40%, white)
);
display: flex;
align-items: flex-start;
block-size: auto;
padding: 6px 16px;
border-radius: var(--mui-radius);
background: var(--toast-bg);
color: var(--toast-fg);
box-shadow: var(--mui-shadow-6);
font: 400 0.875rem / 1.43 var(--mui-font);
letter-spacing: 0.01071em;
& + & {
margin-block-start: var(--toast-gap);
}
transition:
opacity var(--mui-entering) var(--mui-ease-in-out),
scale calc(var(--mui-entering) * 0.666) var(--mui-ease-in-out);
@starting-style {
opacity: 0;
scale: 0.75 0.5625;
}
&[hidden] {
display: none;
opacity: 0;
scale: 0.75 0.5625;
block-size: 0;
padding-block: 0;
margin-block-start: 0;
overflow: clip;
transition:
opacity var(--mui-leaving) var(--mui-ease-in-out),
scale calc(var(--mui-leaving) * 0.666) var(--mui-ease-in-out) calc(var(--mui-leaving) * 0.333),
block-size var(--mui-standard) var(--mui-ease-in-out) var(--mui-leaving),
padding-block var(--mui-standard) var(--mui-ease-in-out) var(--mui-leaving),
margin-block-start var(--mui-standard) var(--mui-ease-in-out) var(--mui-leaving),
overflow 0s allow-discrete,
display calc(var(--mui-leaving) + var(--mui-standard)) allow-discrete;
}
&::before {
content: "";
flex: none;
inline-size: var(--toast-icon-size);
block-size: var(--toast-icon-size);
margin-block: 7px;
margin-inline-end: var(--toast-icon-gap);
background-color: var(--tone);
mask: var(--icon) center / contain no-repeat;
opacity: 0.9;
}
&[data-variant="success"] { --tone: var(--mui-success); --icon: var(--icon-success); }
&[data-variant="error"] { --tone: var(--mui-error); --icon: var(--icon-error); }
&[data-variant="warning"] { --tone: var(--mui-warning); --icon: var(--icon-warning); }
&[data-variant="info"] { --tone: var(--mui-info); --icon: var(--icon-info); }
}
.toast-content {
flex: 1 1 0;
min-inline-size: 0;
padding-block: 8px;
}
.toast-title {
margin-block: -2px 0.35em;
font-size: 1rem;
font-weight: 500;
line-height: 1.5;
letter-spacing: 0.00938em;
}
.toast-body {
text-wrap: pretty;
}
.toast-actions {
flex: none;
display: flex;
align-items: center;
gap: 4px;
margin-inline: auto -8px;
padding: 4px 0 0 16px;
}
:is(.toast-action, .toast-close) {
--state: 0%;
--ripple-size: 100%;
position: relative;
isolation: isolate;
overflow: hidden;
appearance: none;
border: 0;
outline: 0;
cursor: pointer;
background: color-mix(in oklch, currentColor var(--state), transparent);
-webkit-tap-highlight-color: transparent;
&:hover { --state: 4%; }
&:focus-visible { --state: 12%; }
&::after {
content: "";
position: absolute;
inset-block-start: 50%;
inset-inline-start: 50%;
z-index: -1;
inline-size: var(--ripple-size);
aspect-ratio: 1;
translate: -50% -50%;
border-radius: 50%;
background: currentColor;
pointer-events: none;
opacity: 0;
scale: 0;
transition:
opacity var(--mui-ripple) var(--mui-ease-in-out),
scale 0s var(--mui-ripple);
}
&:active::after {
opacity: 0.3;
scale: 1;
transition:
opacity var(--mui-ripple) var(--mui-ease-in-out),
scale var(--mui-ripple) var(--mui-ease-in-out);
}
&:focus-visible:not(:active)::after {
opacity: 0.3;
scale: 1;
animation:
mui-ripple-enter var(--mui-ripple) var(--mui-ease-in-out),
mui-pulsate var(--mui-pulsate) var(--mui-ease-in-out) var(--mui-ripple) infinite;
}
}
.toast-action {
--ripple-size: 150%;
padding: 4px 5px;
min-inline-size: 64px;
border-radius: var(--mui-radius);
font-size: 0.8125rem;
font-weight: 500;
line-height: 1.75;
letter-spacing: 0.02857em;
text-transform: uppercase;
transition:
background-color var(--mui-short) var(--mui-ease-in-out),
color var(--mui-short) var(--mui-ease-in-out);
}
.toast-close {
display: inline-flex;
align-items: center;
justify-content: center;
inline-size: 30px;
aspect-ratio: 1;
padding: 0;
border-radius: 50%;
font-size: 1.375rem;
line-height: 1;
transition: background-color var(--mui-shortest) var(--mui-ease-in-out);
}
@container toasts (inline-size < 22rem) {
.toast:has(.toast-action) {
flex-wrap: wrap;
}
.toast:has(.toast-action) .toast-actions {
flex-basis: 100%;
justify-content: flex-end;
padding: 0 0 4px calc(var(--toast-icon-size) + var(--toast-icon-gap));
}
}
@media (prefers-reduced-motion: reduce) {
.toast,
.toast[hidden],
:is(.toast-action, .toast-close),
:is(.toast-action, .toast-close)::after {
transition-duration: 0s;
transition-delay: 0s;
animation: none;
}
}
}Discussion 1
Sign in to join the discussion.
Nice...I was wondering if someone would add in some icons. 👍