开发预览 更新于 2026-05-10

AspectRatio 宽高比

锁定子元素宽高比的容器(基于 CSS aspect-ratio),常用于图片 / 视频 / 嵌入帧占位。

基础用法

ratio 是一个数字(宽 / 高)。容器宽度跟随父元素,高度由 CSS aspect-ratio 计算。

背景
16 / 9video cover
<script setup lang="ts">
import { CfAspectRatio } from '@chufix-design/vue';
</script>

<template>
  <div class="aspect-demo aspect-demo--basic">
    <CfAspectRatio :ratio="16 / 9">
      <div class="aspect-demo__hero">
        <span class="aspect-demo__ratio">16 / 9</span>
        <span class="aspect-demo__label">video cover</span>
      </div>
    </CfAspectRatio>
  </div>
</template>

<style scoped>
.aspect-demo {
  width: min(100%, 420px);
}

.aspect-demo__hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  border: 1px solid oklch(80% 0.08 230 / 45%);
  border-radius: var(--r-8);
  background:
    radial-gradient(circle at 18% 18%, oklch(85% 0.12 195 / 70%), transparent 32%),
    linear-gradient(135deg, oklch(66% 0.16 224), oklch(58% 0.18 284));
  color: white;
  box-shadow: inset 0 0 0 1px oklch(100% 0 0 / 18%);
}

.aspect-demo__ratio {
  font-family: var(--font-mono);
  font-size: 1.75rem;
  font-weight: var(--w-semibold);
  line-height: 1;
}

.aspect-demo__label {
  font-size: var(--t-12);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.78;
}
</style>
<script setup>
import { CfAspectRatio } from '@chufix-design/vue';
</script>

<template>
  <div class="aspect-demo aspect-demo--basic">
    <CfAspectRatio :ratio="16 / 9">
      <div class="aspect-demo__hero">
        <span class="aspect-demo__ratio">16 / 9</span>
        <span class="aspect-demo__label">video cover</span>
      </div>
    </CfAspectRatio>
  </div>
</template>

<style scoped>
.aspect-demo {
  width: min(100%, 420px);
}

.aspect-demo__hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  border: 1px solid oklch(80% 0.08 230 / 45%);
  border-radius: var(--r-8);
  background:
    radial-gradient(circle at 18% 18%, oklch(85% 0.12 195 / 70%), transparent 32%),
    linear-gradient(135deg, oklch(66% 0.16 224), oklch(58% 0.18 284));
  color: white;
  box-shadow: inset 0 0 0 1px oklch(100% 0 0 / 18%);
}

.aspect-demo__ratio {
  font-family: var(--font-mono);
  font-size: 1.75rem;
  font-weight: var(--w-semibold);
  line-height: 1;
}

.aspect-demo__label {
  font-size: var(--t-12);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  opacity: 0.78;
}
</style>
<CfAspectRatio ratio={16 / 9}>
<div>16 / 9 内容</div>
</CfAspectRatio>
<CfAspectRatio ratio={16 / 9}>
<div>16 / 9 内容</div>
</CfAspectRatio>

常用比例

视频、卡片缩略图、人像头像、短视频 … 比例的视觉对照。

背景
21 / 9影院
16 / 9视频
4 / 3旧屏
1 / 1方形
3 / 4人像
9 / 16短视频
<script setup lang="ts">
import { CfAspectRatio } from '@chufix-design/vue';

const ratios = [
  { ratio: 21 / 9, label: '21 / 9', hint: '影院', tone: 'blue' },
  { ratio: 16 / 9, label: '16 / 9', hint: '视频', tone: 'cyan' },
  { ratio: 4 / 3, label: '4 / 3', hint: '旧屏', tone: 'amber' },
  { ratio: 1, label: '1 / 1', hint: '方形', tone: 'green' },
  { ratio: 3 / 4, label: '3 / 4', hint: '人像', tone: 'pink' },
  { ratio: 9 / 16, label: '9 / 16', hint: '短视频', tone: 'orange' },
];
</script>

<template>
  <div class="aspect-ratios">
    <div v-for="r in ratios" :key="r.label" class="aspect-ratios__item">
      <CfAspectRatio :ratio="r.ratio">
        <div class="aspect-ratios__card" :data-tone="r.tone">
          <strong>{{ r.label }}</strong>
          <span>{{ r.hint }}</span>
        </div>
      </CfAspectRatio>
    </div>
  </div>
</template>

<style scoped>
.aspect-ratios {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  gap: 0.85rem;
  width: min(100%, 720px);
}

.aspect-ratios__item {
  min-width: 0;
}

.aspect-ratios__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  border: 1px solid var(--line-1);
  border-radius: var(--r-8);
  background: var(--bg-1);
  color: var(--fg-1);
  box-shadow: var(--shadow-1);
}

.aspect-ratios__card strong {
  font-family: var(--font-mono);
  font-size: var(--t-14);
  line-height: 1;
}

.aspect-ratios__card span {
  font-size: var(--t-12);
  color: var(--fg-2);
}

.aspect-ratios__card[data-tone='blue'] { background: linear-gradient(135deg, oklch(95% 0.03 225), oklch(88% 0.05 265)); }
.aspect-ratios__card[data-tone='cyan'] { background: linear-gradient(135deg, oklch(95% 0.04 195), oklch(89% 0.05 225)); }
.aspect-ratios__card[data-tone='amber'] { background: linear-gradient(135deg, oklch(96% 0.04 78), oklch(90% 0.06 52)); }
.aspect-ratios__card[data-tone='green'] { background: linear-gradient(135deg, oklch(95% 0.04 148), oklch(89% 0.05 176)); }
.aspect-ratios__card[data-tone='pink'] { background: linear-gradient(135deg, oklch(96% 0.04 340), oklch(90% 0.06 15)); }
.aspect-ratios__card[data-tone='orange'] { background: linear-gradient(135deg, oklch(96% 0.04 62), oklch(90% 0.06 36)); }
</style>
<script setup>
import { CfAspectRatio } from '@chufix-design/vue';

const ratios = [
  { ratio: 21 / 9, label: '21 / 9', hint: '影院', tone: 'blue' },
  { ratio: 16 / 9, label: '16 / 9', hint: '视频', tone: 'cyan' },
  { ratio: 4 / 3, label: '4 / 3', hint: '旧屏', tone: 'amber' },
  { ratio: 1, label: '1 / 1', hint: '方形', tone: 'green' },
  { ratio: 3 / 4, label: '3 / 4', hint: '人像', tone: 'pink' },
  { ratio: 9 / 16, label: '9 / 16', hint: '短视频', tone: 'orange' },
];
</script>

<template>
  <div class="aspect-ratios">
    <div v-for="r in ratios" :key="r.label" class="aspect-ratios__item">
      <CfAspectRatio :ratio="r.ratio">
        <div class="aspect-ratios__card" :data-tone="r.tone">
          <strong>{{ r.label }}</strong>
          <span>{{ r.hint }}</span>
        </div>
      </CfAspectRatio>
    </div>
  </div>
</template>

<style scoped>
.aspect-ratios {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  gap: 0.85rem;
  width: min(100%, 720px);
}

.aspect-ratios__item {
  min-width: 0;
}

.aspect-ratios__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  border: 1px solid var(--line-1);
  border-radius: var(--r-8);
  background: var(--bg-1);
  color: var(--fg-1);
  box-shadow: var(--shadow-1);
}

.aspect-ratios__card strong {
  font-family: var(--font-mono);
  font-size: var(--t-14);
  line-height: 1;
}

.aspect-ratios__card span {
  font-size: var(--t-12);
  color: var(--fg-2);
}

.aspect-ratios__card[data-tone='blue'] { background: linear-gradient(135deg, oklch(95% 0.03 225), oklch(88% 0.05 265)); }
.aspect-ratios__card[data-tone='cyan'] { background: linear-gradient(135deg, oklch(95% 0.04 195), oklch(89% 0.05 225)); }
.aspect-ratios__card[data-tone='amber'] { background: linear-gradient(135deg, oklch(96% 0.04 78), oklch(90% 0.06 52)); }
.aspect-ratios__card[data-tone='green'] { background: linear-gradient(135deg, oklch(95% 0.04 148), oklch(89% 0.05 176)); }
.aspect-ratios__card[data-tone='pink'] { background: linear-gradient(135deg, oklch(96% 0.04 340), oklch(90% 0.06 15)); }
.aspect-ratios__card[data-tone='orange'] { background: linear-gradient(135deg, oklch(96% 0.04 62), oklch(90% 0.06 36)); }
</style>
<CfAspectRatio ratio={21 / 9}>…</CfAspectRatio>
<CfAspectRatio ratio={16 / 9}>…</CfAspectRatio>
<CfAspectRatio ratio={4 / 3}>…</CfAspectRatio>
<CfAspectRatio ratio={1}>…</CfAspectRatio>
<CfAspectRatio ratio={3 / 4}>…</CfAspectRatio>
<CfAspectRatio ratio={9 / 16}>…</CfAspectRatio>
<CfAspectRatio ratio={21 / 9}>…</CfAspectRatio>
<CfAspectRatio ratio={16 / 9}>…</CfAspectRatio>
<CfAspectRatio ratio={4 / 3}>…</CfAspectRatio>
<CfAspectRatio ratio={1}>…</CfAspectRatio>
<CfAspectRatio ratio={3 / 4}>…</CfAspectRatio>
<CfAspectRatio ratio={9 / 16}>…</CfAspectRatio>

子元素自动撑满

子节点会被 position: absolute; inset: 0 撑满。常见的 <img> / <video> / <iframe> 默认 width: 100%; height: 100%; object-fit: cover,开箱即用。

背景
media fills the frameimg / video / iframe
<script setup lang="ts">
import { CfAspectRatio } from '@chufix-design/vue';
</script>

<template>
  <div class="aspect-media">
    <CfAspectRatio :ratio="16 / 9">
      <div class="aspect-media__frame">
        <div class="aspect-media__sky" />
        <div class="aspect-media__mountain aspect-media__mountain--back" />
        <div class="aspect-media__mountain aspect-media__mountain--front" />
        <div class="aspect-media__caption">
          <strong>media fills the frame</strong>
          <span>img / video / iframe</span>
        </div>
      </div>
    </CfAspectRatio>
  </div>
</template>

<style scoped>
.aspect-media {
  width: min(100%, 480px);
}

.aspect-media__frame {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--line-1);
  border-radius: var(--r-8);
  background: linear-gradient(180deg, oklch(92% 0.04 220), oklch(82% 0.06 190));
  box-shadow: var(--shadow-1);
}

.aspect-media__sky {
  position: absolute;
  top: 16%;
  left: 14%;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  background: oklch(98% 0.05 86 / 86%);
}

.aspect-media__mountain {
  position: absolute;
  right: -8%;
  bottom: -20%;
  width: 72%;
  height: 68%;
  border-radius: 22% 0 0 0;
  transform: rotate(35deg);
  transform-origin: bottom right;
}

.aspect-media__mountain--back {
  right: 12%;
  bottom: -28%;
  background: oklch(68% 0.09 205 / 78%);
}

.aspect-media__mountain--front {
  background: oklch(48% 0.12 214 / 88%);
}

.aspect-media__caption {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  display: inline-flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid oklch(100% 0 0 / 24%);
  border-radius: var(--r-6);
  background: oklch(20% 0.04 250 / 72%);
  color: white;
  backdrop-filter: blur(8px);
}

.aspect-media__caption strong {
  font-size: var(--t-13);
  line-height: 1.2;
}

.aspect-media__caption span {
  font-family: var(--font-mono);
  font-size: var(--t-11);
  opacity: 0.72;
}
</style>
<script setup>
import { CfAspectRatio } from '@chufix-design/vue';
</script>

<template>
  <div class="aspect-media">
    <CfAspectRatio :ratio="16 / 9">
      <div class="aspect-media__frame">
        <div class="aspect-media__sky" />
        <div class="aspect-media__mountain aspect-media__mountain--back" />
        <div class="aspect-media__mountain aspect-media__mountain--front" />
        <div class="aspect-media__caption">
          <strong>media fills the frame</strong>
          <span>img / video / iframe</span>
        </div>
      </div>
    </CfAspectRatio>
  </div>
</template>

<style scoped>
.aspect-media {
  width: min(100%, 480px);
}

.aspect-media__frame {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--line-1);
  border-radius: var(--r-8);
  background: linear-gradient(180deg, oklch(92% 0.04 220), oklch(82% 0.06 190));
  box-shadow: var(--shadow-1);
}

.aspect-media__sky {
  position: absolute;
  top: 16%;
  left: 14%;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  background: oklch(98% 0.05 86 / 86%);
}

.aspect-media__mountain {
  position: absolute;
  right: -8%;
  bottom: -20%;
  width: 72%;
  height: 68%;
  border-radius: 22% 0 0 0;
  transform: rotate(35deg);
  transform-origin: bottom right;
}

.aspect-media__mountain--back {
  right: 12%;
  bottom: -28%;
  background: oklch(68% 0.09 205 / 78%);
}

.aspect-media__mountain--front {
  background: oklch(48% 0.12 214 / 88%);
}

.aspect-media__caption {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  display: inline-flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.55rem 0.7rem;
  border: 1px solid oklch(100% 0 0 / 24%);
  border-radius: var(--r-6);
  background: oklch(20% 0.04 250 / 72%);
  color: white;
  backdrop-filter: blur(8px);
}

.aspect-media__caption strong {
  font-size: var(--t-13);
  line-height: 1.2;
}

.aspect-media__caption span {
  font-family: var(--font-mono);
  font-size: var(--t-11);
  opacity: 0.72;
}
</style>
<CfAspectRatio ratio={16 / 9}>
<img src="cover.jpg" alt="封面" />
</CfAspectRatio>

<CfAspectRatio ratio={16 / 9}>
<iframe src="https://www.youtube.com/embed/..." allowFullScreen />
</CfAspectRatio>
<CfAspectRatio ratio={16 / 9}>
<img src="cover.jpg" alt="封面" />
</CfAspectRatio>

<CfAspectRatio ratio={16 / 9}>
<iframe src="https://www.youtube.com/embed/..." allowFullScreen />
</CfAspectRatio>

API

属性类型默认值说明
rationumber16 / 9宽 / 高比。常用值:21/9 16/9 4/3 1 3/4 9/16

反馈与讨论

AspectRatio 宽高比 的讨论

0
0 / 600
一键发送
正在加载评论...