跳到主内容

示例 / 布局

布局

经典 CSS 布局案例 —— 3 个可调试 demo

协同头像叠放

beginner查看章节 →
协同头像叠放GitHub / Vercel / Figma 风格
ABCDE
+3
查看源码html
<div class="avatar-stack">
  <span class="avatar">A</span>
  <span class="avatar">B</span>
  <span class="avatar">C</span>
  <span class="avatar">D</span>
  <span class="avatar">E</span>
</div>
<span class="more">+3</span>

<style>
.avatar-stack { display: flex; }
.avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 2px solid var(--bg);  /* 与背景同色,营造"留白"分隔 */
  display: grid;
  place-items: center;
  color: white;
  font-weight: 600;
}
.avatar:not(:first-child) {
  margin-left: -10px;            /* 关键:负 margin 让头像叠起来 */
}
</style>

通知徽章

beginner查看章节 →
通知徽章红点 + 数字角标 + 99+ 三种形态
查看源码html
<button class="icon-btn" aria-label="通知(有新消息)">
  🔔
  <span class="dot" aria-hidden="true"></span>
</button>

<button class="icon-btn" aria-label="收件箱(12 条新消息)">
  ✉️
  <span class="num-badge" aria-hidden="true">12</span>
</button>

<button class="icon-btn" aria-label="收件箱(99+ 条新消息)">
  ✉️
  <span class="num-badge" aria-hidden="true">99+</span>
</button>

<style>
.icon-btn {
  position: relative;            /* 关键:作为徽章的包含块 */
  width: 40px; height: 40px;
}

/* 红点:纯装饰,固定 10×10,简单 */
.dot {
  position: absolute;
  top: 6px; right: 6px;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #ef4444;
  border: 2px solid var(--bg);   /* 留白让小红点边缘清晰 */
  box-sizing: border-box;        /* border 算入尺寸,不撑大 */
}

/* 数字角标:可变宽度("12" 圆,"99+" 长胶囊) */
.num-badge {
  position: absolute;
  top: -6px; right: -8px;        /* 露出图标边缘 */
  min-width: 20px; height: 20px; /* min-width 让短文本仍是圆 */
  padding: 0 6px;
  border-radius: 999px;          /* 大值=任意宽都成胶囊 */
  background: #ef4444;
  color: white;
  font-size: 11px;
  line-height: 1;
  border: 2px solid var(--bg);
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;            /* "99+" 不被换行切成两行 */
}
</style>

骨架屏

intermediate查看章节 →
骨架屏渐变 shimmer 动画 + reduced-motion 适配
查看源码html
<article class="card" aria-busy="true" aria-label="加载中">
  <div class="skeleton" style="height: 140px;"></div>
  <div class="skeleton" style="height: 14px; width: 70%;"></div>
  <div class="skeleton" style="height: 12px;"></div>
  <div class="skeleton" style="height: 12px; width: 85%;"></div>
</article>

<style>
/* 浅灰背景 + 略深的"亮带"扫过;亮 / 暗模式各给一组色值 */
:root {
  --skeleton-base: #f3f4f6;
  --skeleton-highlight: #e5e7eb;
}
@media (prefers-color-scheme: dark) {
  :root {
    --skeleton-base: #27272a;
    --skeleton-highlight: #3f3f46;
  }
}

.skeleton {
  border-radius: 6px;
  background: linear-gradient(
    90deg,
    var(--skeleton-base) 0%,
    var(--skeleton-highlight) 50%,
    var(--skeleton-base) 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}

@keyframes shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* 尊重用户 reduced-motion 偏好——闪烁动画对前庭功能障碍 / 偏头痛
   用户刺眼。关键:要保留可见的占位(背景仍渐变),只停动画 */
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
}
</style>