/** * AKSRT Extended Components — 时间轴 / 步骤向导 / 九宫格 / 定价卡片 / * Toggle 开关 / 自定义复选框 / 数字步进器 * ------------------------------------------------------------ * 全部使用 aksrt- 前缀,保持原生语义可访问性。 */ /* ============================================================ * 1. 时间轴 — .aksrt-timeline * ============================================================ */ .aksrt-timeline { position: relative; padding-left: 28px; margin: 0; list-style: none; } /* 竖线 */ .aksrt-timeline::before { content: ''; position: absolute; left: 8px; top: 4px; bottom: 4px; width: 2px; background: var(--color-line, rgba(50, 50, 50, 0.1)); border-radius: 1px; } .aksrt-timeline__item { position: relative; padding-bottom: 24px; } .aksrt-timeline__item:last-child { padding-bottom: 0; } /* 圆点 */ .aksrt-timeline__dot { position: absolute; left: -24px; top: 4px; width: 12px; height: 12px; border-radius: 50%; background: var(--color-primary); border: 2px solid var(--surface-1, #fff); box-shadow: 0 0 0 2px var(--color-primary-soft, rgba(240, 68, 148, 0.12)); z-index: 1; } /* 空心圆点变体 */ .aksrt-timeline__dot--outline { background: var(--surface-1, #fff); border: 2px solid var(--color-primary); box-shadow: none; } /* 灰色圆点 — 已完成/已过去 */ .aksrt-timeline__dot--muted { background: var(--color-ink-4, #999); box-shadow: 0 0 0 2px var(--surface-2, #eee); } .aksrt-timeline__time { display: block; font-size: 12px; color: var(--color-ink-4, #999); margin-bottom: 4px; } .aksrt-timeline__title { font-weight: 600; color: var(--color-ink, #333); margin-bottom: 4px; } .aksrt-timeline__content { font-size: 14px; color: var(--color-ink-3, #777); line-height: 1.6; } /* ============================================================ * 2. 步骤向导 — .aksrt-steps * ============================================================ */ .aksrt-steps { display: flex; align-items: flex-start; gap: 0; margin: 0; padding: 0; list-style: none; counter-reset: aksrt-step; } .aksrt-steps__item { flex: 1; position: relative; text-align: center; counter-increment: aksrt-step; } /* 连接线 */ .aksrt-steps__item:not(:last-child)::after { content: ''; position: absolute; top: 16px; left: calc(50% + 20px); right: calc(-50% + 20px); height: 2px; background: var(--color-line, rgba(50, 50, 50, 0.1)); } .aksrt-steps__icon { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 50%; background: var(--surface-2, #eee); color: var(--color-ink-3, #777); font-size: 14px; font-weight: 700; margin: 0 auto 8px; position: relative; z-index: 1; } .aksrt-steps__item--active .aksrt-steps__icon { background: var(--color-primary); color: var(--color-on-primary, #fff); } .aksrt-steps__item--done .aksrt-steps__icon { background: var(--color-success); color: #fff; } .aksrt-steps__item--done:not(:last-child)::after { background: var(--color-success); } .aksrt-steps__label { font-size: 13px; font-weight: 600; color: var(--color-ink-3, #777); } .aksrt-steps__item--active .aksrt-steps__label { color: var(--color-primary); } .aksrt-steps__item--done .aksrt-steps__label { color: var(--color-success); } /* 垂直模式 */ .aksrt-steps--vertical { flex-direction: column; gap: 0; padding-left: 20px; } .aksrt-steps--vertical .aksrt-steps__item { text-align: left; padding-left: 28px; padding-bottom: 20px; } .aksrt-steps--vertical .aksrt-steps__item:not(:last-child)::after { top: 34px; left: 36px; right: auto; width: 2px; height: calc(100% - 34px); } .aksrt-steps--vertical .aksrt-steps__icon { position: absolute; left: 0; margin: 0; } /* ============================================================ * 3. 九宫格 — .aksrt-img-grid * ============================================================ */ .aksrt-img-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; border-radius: var(--radius, 8px); overflow: hidden; } .aksrt-img-grid img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; cursor: pointer; transition: transform .2s ease; } .aksrt-img-grid img:hover { transform: scale(1.03); } /* 自适应列数 */ .aksrt-img-grid--2 { grid-template-columns: repeat(2, 1fr); } .aksrt-img-grid--4 { grid-template-columns: repeat(4, 1fr); } @media (max-width: 480px) { .aksrt-img-grid--4 { grid-template-columns: repeat(3, 1fr); } } /* ============================================================ * 5. Toggle 开关 — .aksrt-toggle (纯 CSS + :checked) * 保持原生 可访问性 * ============================================================ */ .aksrt-toggle { position: relative; display: inline-flex; align-items: center; cursor: pointer; user-select: none; gap: 8px; } .aksrt-toggle__input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; } .aksrt-toggle__track { position: relative; width: var(--aksrt-toggle-w, 44px); height: var(--aksrt-toggle-h, 24px); background: var(--surface-3, #e8e8e8); border-radius: var(--aksrt-toggle-h, 24px); transition: background .2s ease; flex-shrink: 0; } .aksrt-toggle__track::after { content: ''; position: absolute; top: 2px; left: 2px; width: calc(var(--aksrt-toggle-h, 24px) - 4px); height: calc(var(--aksrt-toggle-h, 24px) - 4px); background: #fff; border-radius: 50%; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); transition: transform .2s ease; } /* Checked */ .aksrt-toggle__input:checked + .aksrt-toggle__track { background: var(--color-primary); } .aksrt-toggle__input:checked + .aksrt-toggle__track::after { transform: translateX(calc(var(--aksrt-toggle-w, 44px) - var(--aksrt-toggle-h, 24px))); } /* Focus-visible */ .aksrt-toggle__input:focus-visible + .aksrt-toggle__track { box-shadow: var(--focus-ring, 0 0 2px 3px rgba(253, 83, 161, 0.4)); } /* Disabled */ .aksrt-toggle__input:disabled + .aksrt-toggle__track { opacity: 0.5; cursor: not-allowed; } .aksrt-toggle__label { font-size: 14px; color: var(--color-ink-2, #4e5358); } /* ============================================================ * 6. 自定义复选框 — .aksrt-checkbox (纯 CSS + :checked) * 保持原生 可访问性 * ============================================================ */ .aksrt-checkbox { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; } .aksrt-checkbox__input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; } .aksrt-checkbox__box { position: relative; width: 18px; height: 18px; border: 2px solid var(--color-line, rgba(50, 50, 50, 0.15)); border-radius: 4px; background: var(--surface-1, #fff); transition: background .15s ease, border-color .15s ease; flex-shrink: 0; } /* 打勾 SVG */ .aksrt-checkbox__box::after { content: ''; position: absolute; top: 2px; left: 5px; width: 5px; height: 9px; border: 2px solid #fff; border-top: none; border-left: none; transform: rotate(45deg) scale(0); transition: transform .15s ease; } .aksrt-checkbox__input:checked + .aksrt-checkbox__box { background: var(--color-primary); border-color: var(--color-primary); } .aksrt-checkbox__input:checked + .aksrt-checkbox__box::after { transform: rotate(45deg) scale(1); } .aksrt-checkbox__input:focus-visible + .aksrt-checkbox__box { box-shadow: var(--focus-ring, 0 0 2px 3px rgba(253, 83, 161, 0.4)); } .aksrt-checkbox__input:disabled + .aksrt-checkbox__box { opacity: 0.5; cursor: not-allowed; } .aksrt-checkbox__label { font-size: 14px; color: var(--color-ink-2, #4e5358); } /* ============================================================ * 7. 数字步进器 — .aksrt-stepper * ============================================================ */ .aksrt-stepper { display: inline-flex; align-items: center; border: 1px solid var(--color-line, rgba(50, 50, 50, 0.1)); border-radius: var(--radius, 8px); overflow: hidden; height: var(--aksrt-stepper-h, 36px); } .aksrt-stepper__btn { display: flex; align-items: center; justify-content: center; width: var(--aksrt-stepper-h, 36px); height: 100%; background: var(--surface-2, #eee); color: var(--color-ink-2, #4e5358); border: none; cursor: pointer; font-size: 16px; font-weight: 600; transition: background .15s ease, color .15s ease; user-select: none; } .aksrt-stepper__btn:hover { background: var(--surface-3, #e8e8e8); color: var(--color-ink, #333); } .aksrt-stepper__btn:disabled { opacity: 0.4; cursor: not-allowed; } .aksrt-stepper__input { width: 48px; height: 100%; border: none; text-align: center; font-size: 14px; font-weight: 600; color: var(--color-ink, #333); background: var(--surface-1, #fff); -moz-appearance: textfield; } .aksrt-stepper__input::-webkit-outer-spin-button, .aksrt-stepper__input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } .aksrt-stepper__input:focus { outline: none; background: var(--color-primary-softer, rgba(240, 68, 148, 0.05)); } /* ============================================================ * 8. 头像尺寸变量系统 — .aksrt-avatar--{size} * ============================================================ */ .aksrt-avatar--xs { width: var(--aksrt-avatar-size-xs); height: var(--aksrt-avatar-size-xs); } .aksrt-avatar--sm { width: var(--aksrt-avatar-size-sm); height: var(--aksrt-avatar-size-sm); } .aksrt-avatar { width: var(--aksrt-avatar-size); height: var(--aksrt-avatar-size); } .aksrt-avatar--lg { width: var(--aksrt-avatar-size-lg); height: var(--aksrt-avatar-size-lg); } .aksrt-avatar--xl { width: var(--aksrt-avatar-size-xl); height: var(--aksrt-avatar-size-xl); } /* ============================================================ * 9. 涟漪点击效果 — .aksrt-ripple * 容器加此类,点击时 JS 注入 span.aksrt-ripple__wave * ============================================================ */ .aksrt-ripple { position: relative; overflow: hidden; } .aksrt-ripple__wave { position: absolute; border-radius: 50%; background: rgba(255, 255, 255, 0.35); transform: scale(0); animation: aksrtRippleWave .6s ease-out forwards; pointer-events: none; } @keyframes aksrtRippleWave { to { transform: scale(4); opacity: 0; } } /* Runtime broad ripple (.aksrt-wave injected into .but/.btn). * MUST stay out of flow — missing absolute made header CTA grow on click. */ .aksrt-wave { position: absolute !important; border-radius: 50%; background: rgba(255, 255, 255, 0.35); pointer-events: none !important; z-index: 1; transform: scale(0); animation: aksrtWaveRipple 0.6s ease-out forwards; } @keyframes aksrtWaveRipple { to { transform: scale(1); opacity: 0; } } .nowave { overflow: hidden; } /* ============================================================ * 10. 模态框堆叠动画 — 父模态缩小 * ============================================================ */ .modal-stacked .modal-dialog { transition: transform .25s var(--ease, ease), filter .25s ease; } .modal-stacked .modal-dialog.modal-behind { transform: scale(0.92); filter: brightness(0.85); pointer-events: none; }