├── public └── favicon.ico ├── .vscode └── extensions.json ├── src ├── main.js ├── views │ ├── JaKoView.vue │ ├── MonospaceView.vue │ ├── SerifView.vue │ ├── SansSerifView.vue │ ├── HomeView.vue │ └── CharacterSetView.vue ├── components │ ├── CJKCharacterDisplay.vue │ ├── FontComparisonDisplay.vue │ ├── FontMoreDisplay.vue │ └── CustomFontTestDisplay.vue ├── router │ └── index.js ├── App.vue └── assets │ ├── color.css │ └── main.css ├── vite.config.js ├── package.json ├── .gitignore ├── .github └── dependabot.yml ├── README.md ├── vercel.json ├── index.html └── LICENSE /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YuKongA/Font-Weight-Test/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import './assets/main.css' 2 | 3 | import { createApp } from 'vue' 4 | import App from './App.vue' 5 | import router from './router' 6 | 7 | const app = createApp(App) 8 | 9 | app.use(router) 10 | 11 | router.push('/') 12 | 13 | app.mount('#app') 14 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | base: './', 9 | plugins: [ 10 | vue(), 11 | ], 12 | resolve: { 13 | alias: { 14 | '@': fileURLToPath(new URL('./src', import.meta.url)) 15 | } 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "font_weight_test", 3 | "version": "1.1.1", 4 | "type": "module", 5 | "private": true, 6 | "scripts": { 7 | "dev": "vite --host", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "vue": "^3.5.26", 13 | "vue-router": "^4.6.4" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-vue": "^6.0.3", 17 | "vite": "npm:rolldown-vite@latest" 18 | } 19 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | package-lock.json 17 | 18 | /cypress/videos/ 19 | /cypress/screenshots/ 20 | 21 | # Editor directories and files 22 | .vscode/* 23 | !.vscode/extensions.json 24 | .idea 25 | *.suo 26 | *.ntvs* 27 | *.njsproj 28 | *.sln 29 | *.sw? 30 | *.lock 31 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "daily" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Font Weight Test 2 | 3 | 网址: https://font.yukonga.top/ 4 | 5 | 本仓库使用 [Vue](https://vuejs.org/) + [Vite](https://vitejs.dev/) 创建 6 | 7 | ``` 8 | 2025.09.08 9 | - CJK 添加扩展 J 区 10 | - 重新整理 CJK 节选 11 | 12 | 2024.10.14 13 | - 新增可变字体测试 14 | - 新增同字字形测试 15 | - 增补 CJK 节选 16 | 17 | 2024.06.29 18 | - 重构项目,提高代码复用 19 | - 取消对日韩文字单独指定语言类型 20 | 21 | 2023.11.29 22 | - 添加深色模式支持 23 | 24 | 2023.11.07 25 | - 切换到类 Material Design 3 样式 26 | - 切换到 Vue 框架 SPA 单页 Web 应用 27 | 28 | 2023.11.06 29 | - 切换到最新的 MiSans VF 作为参考字体 30 | 31 | 2023.10.26 32 | - 对日韩文字单独指定 lang 语言类型 33 | ``` 34 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "redirects": [ 3 | { 4 | "source": "/sans-serif", 5 | "destination": "./", 6 | "permanent": false 7 | }, 8 | { 9 | "source": "/serif", 10 | "destination": "./", 11 | "permanent": false 12 | }, 13 | { 14 | "source": "/monospace", 15 | "destination": "./", 16 | "permanent": false 17 | }, 18 | { 19 | "source": "/ja-ko", 20 | "destination": "./", 21 | "permanent": false 22 | }, 23 | { 24 | "source": "/character-set", 25 | "destination": "./", 26 | "permanent": false 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /src/views/JaKoView.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 字体字重测试 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/components/CJKCharacterDisplay.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | -------------------------------------------------------------------------------- /src/components/FontComparisonDisplay.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | import HomeView from '../views/HomeView.vue' 3 | 4 | const router = createRouter({ 5 | history: createWebHistory(import.meta.env.BASE_URL), 6 | routes: [ 7 | { 8 | path: '/', 9 | name: '首页', 10 | component: HomeView 11 | }, 12 | { 13 | path: '/sans-serif', 14 | name: '无衬线', 15 | component: () => import('../views/SansSerifView.vue') 16 | }, 17 | { 18 | path: '/serif', 19 | name: '衬线', 20 | component: () => import('../views/SerifView.vue') 21 | }, 22 | { 23 | path: '/monospace', 24 | name: '等宽', 25 | component: () => import('../views/MonospaceView.vue') 26 | }, 27 | { 28 | path: '/ja-ko', 29 | name: '日韩', 30 | component: () => import('../views/JaKoView.vue') 31 | }, 32 | { 33 | path: '/character-set', 34 | name: '编码', 35 | component: () => import('../views/CharacterSetView.vue') 36 | }, 37 | ] 38 | }) 39 | 40 | export default router -------------------------------------------------------------------------------- /src/views/MonospaceView.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 YuKongA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/views/SerifView.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | -------------------------------------------------------------------------------- /src/views/SansSerifView.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/FontMoreDisplay.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 43 | 44 | -------------------------------------------------------------------------------- /src/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | -------------------------------------------------------------------------------- /src/assets/color.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --vt-c-primary: 20, 184, 166; 3 | --vt-c-surface-1: 255, 255, 255; 4 | --vt-c-surface-2: 20, 20, 24; 5 | 6 | --vt-c-white: rgb(252, 252, 255); 7 | --vt-c-black: rgb(18, 18, 22); 8 | 9 | --vt-c-text-light-1: rgb(26, 26, 30); 10 | --vt-c-text-light-2: rgb(60, 60, 70); 11 | 12 | --vt-c-text-dark-1: rgb(240, 240, 245); 13 | --vt-c-text-dark-2: rgb(204, 204, 214); 14 | 15 | --vt-c-active-color: rgb(20, 184, 166); 16 | --vt-c-hover-color: rgb(45, 212, 191); 17 | 18 | --vt-c-footer-text-1: rgb(55, 50, 70); 19 | --vt-c-footer-text-2: rgb(225, 230, 250); 20 | 21 | --vt-c-footer-background: rgba(20, 184, 166, 0.16); 22 | --vt-c-footer-hover: rgba(20, 184, 166, 0.6); 23 | --vt-c-footer-link-hover: rgb(56, 189, 248); 24 | } 25 | 26 | :root { 27 | --color-background: var(--vt-c-white); 28 | --color-text: var(--vt-c-text-light-1); 29 | --color-active: var(--vt-c-active-color); 30 | --color-hover: var(--vt-c-hover-color); 31 | --color-footer-background: var(--vt-c-footer-background); 32 | --color-footer-text: var(--vt-c-footer-text-1); 33 | --color-footer-hover: var(--vt-c-footer-hover); 34 | --color-footer-link-hover: var(--vt-c-footer-link-hover); 35 | --color-glass-bg: rgba(var(--vt-c-surface-1), 0.55); 36 | --color-glass-border: rgba(160, 200, 190, 0.35); 37 | --color-gradient-1: linear-gradient(135deg, rgba(var(--vt-c-primary), 0.12), rgba(var(--vt-c-primary), 0.06)); 38 | } 39 | 40 | @media (prefers-color-scheme: dark) { 41 | :root { 42 | --color-background: var(--vt-c-black); 43 | --color-text: var(--vt-c-text-dark-2); 44 | --color-active: var(--vt-c-active-color); 45 | --color-hover: var(--vt-c-hover-color); 46 | --color-footer-background: var(--vt-c-footer-background); 47 | --color-footer-text: var(--vt-c-footer-text-2); 48 | --color-footer-hover: var(--vt-c-footer-hover); 49 | --color-footer-link-hover: var(--vt-c-footer-link-hover); 50 | --color-glass-bg: rgba(var(--vt-c-surface-2), 0.55); 51 | --color-glass-border: rgba(100, 130, 200, 0.35); 52 | --color-gradient-1: linear-gradient(135deg, rgba(var(--vt-c-primary), 0.16), rgba(var(--vt-c-primary), 0.10)); 53 | } 54 | } -------------------------------------------------------------------------------- /src/views/CharacterSetView.vue: -------------------------------------------------------------------------------- 1 | 81 | -------------------------------------------------------------------------------- /src/components/CustomFontTestDisplay.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 116 | 117 | -------------------------------------------------------------------------------- /src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import "color.css"; 2 | 3 | /* CSS 变量定义 4 | ----------------------------------------*/ 5 | :root { 6 | /* 基础尺寸 */ 7 | --base-font: clamp(14px, 1.7vw, 16px); 8 | --heading-font: clamp(20px, 2.3vw, 26px); 9 | --wrapper-font: clamp(26px, 3.3vw, 34px); 10 | --nav-font: clamp(15px, 1.8vw, 19px); 11 | 12 | /* 布局尺寸 */ 13 | --content-width: 90%; 14 | --card-padding: 0.4cm; 15 | --side-margin: 5%; 16 | --border-radius: 0.3cm; 17 | --border-color: rgba(150, 150, 200, 0.35); 18 | 19 | /* 间距 */ 20 | --title-margin-top: 0.4cm; 21 | --title-margin-bottom: 0.2cm; 22 | 23 | /* 页脚相关 */ 24 | --footer-height: 30px; 25 | --safe-area-max-inset-bottom: env(safe-area-max-inset-bottom, 36px); 26 | --content-bottom-margin: calc(var(--footer-height) + var(--footer-bottom-margin) + 20px); 27 | 28 | /* 动画 */ 29 | --transition-normal: all 0.28s ease; 30 | --transition-slow: all 0.6s ease; 31 | } 32 | 33 | /* 基础重置和通用样式 34 | ----------------------------------------*/ 35 | * { 36 | margin: 0; 37 | padding: 0; 38 | box-sizing: border-box; 39 | } 40 | 41 | body { 42 | background: var(--color-gradient-1), var(--color-background); 43 | color: var(--color-text); 44 | line-height: 1.45; 45 | min-height: 100vh; 46 | padding-bottom: calc(60px + var(--safe-area-max-inset-bottom)); 47 | } 48 | 49 | a { 50 | text-decoration: none; 51 | color: inherit; 52 | } 53 | 54 | #sans-serif { 55 | font-family: sans-serif; 56 | } 57 | 58 | #serif { 59 | font-family: serif; 60 | } 61 | 62 | #monospace { 63 | font-family: monospace; 64 | } 65 | 66 | /* 布局容器 67 | ----------------------------------------*/ 68 | #app { 69 | min-height: 100vh; 70 | padding-bottom: var(--content-bottom-margin); 71 | box-sizing: border-box; 72 | } 73 | 74 | /* 顶部导航(玻璃态) 75 | ----------------------------------------*/ 76 | .app-header.glass-nav { 77 | position: sticky; 78 | padding-top: 35px; 79 | z-index: 20; 80 | backdrop-filter: saturate(1.15) blur(12px); 81 | -webkit-backdrop-filter: saturate(1.15) blur(12px); 82 | } 83 | 84 | /* 顶部整体容器 */ 85 | .header-shell { 86 | margin-top: 10px; 87 | } 88 | 89 | /* 标题样式 90 | ----------------------------------------*/ 91 | h2 { 92 | color: var(--color-text); 93 | transition: var(--transition-normal); 94 | } 95 | 96 | h2 { 97 | font-size: var(--heading-font); 98 | margin: var(--title-margin-top) var(--side-margin) var(--title-margin-bottom); 99 | font-weight: 600; 100 | width: var(--content-width); 101 | letter-spacing: 0.2px; 102 | } 103 | 104 | /* 卡片组件 105 | ----------------------------------------*/ 106 | .round { 107 | width: var(--content-width); 108 | margin: 0 var(--side-margin); 109 | padding: var(--card-padding); 110 | border-radius: 18px; 111 | border: 1px solid var(--color-glass-border); 112 | font-size: var(--base-font); 113 | transition: var(--transition-slow); 114 | background: var(--color-glass-bg); 115 | box-shadow: 0 8px 24px rgba(20, 20, 40, 0.12); 116 | backdrop-filter: saturate(1.1) blur(10px); 117 | -webkit-backdrop-filter: saturate(1.1) blur(10px); 118 | animation: fadeUp 500ms ease both; 119 | } 120 | 121 | .round:not(:last-child) { 122 | margin-bottom: 0.5cm; 123 | } 124 | 125 | .round> :nth-child(2) { 126 | margin-bottom: 0.15cm; 127 | } 128 | 129 | .round:hover { 130 | transform: translateY(-2px); 131 | box-shadow: 0 12px 32px rgba(20, 20, 40, 0.18); 132 | } 133 | 134 | @keyframes fadeUp { 135 | from { 136 | opacity: 0; 137 | transform: translateY(8px); 138 | } 139 | 140 | to { 141 | opacity: 1; 142 | transform: translateY(0); 143 | } 144 | } 145 | 146 | /* 掠影动画关键帧 */ 147 | @keyframes sheen { 148 | 0% { 149 | transform: translateX(-120%); 150 | } 151 | 152 | 100% { 153 | transform: translateX(120%); 154 | } 155 | } 156 | 157 | /* 导航样式 158 | ----------------------------------------*/ 159 | .ul { 160 | width: var(--content-width); 161 | margin: 0 var(--side-margin); 162 | padding: 0; 163 | font-size: var(--base-font); 164 | border-radius: 18px; 165 | border: 1px solid var(--color-glass-border); 166 | box-shadow: 0 8px 24px rgba(20, 20, 40, 0.12); 167 | line-height: clamp(2.6, 2.6 + 1.5vw, 4.6); 168 | overflow: hidden; 169 | transition: var(--transition-normal); 170 | background: var(--color-glass-bg); 171 | backdrop-filter: saturate(1.1) blur(10px); 172 | -webkit-backdrop-filter: saturate(1.1) blur(10px); 173 | list-style: none; 174 | display: grid; 175 | grid-template-columns: repeat(6, 1fr); 176 | } 177 | 178 | .li { 179 | transition: var(--transition-normal); 180 | } 181 | 182 | .li:last-child { 183 | border-right: none; 184 | } 185 | 186 | .li a { 187 | display: block; 188 | text-align: center; 189 | font-size: var(--nav-font); 190 | padding: clamp(0.3em, 0.3em + 0.8vw, 0.6em) 0; 191 | transition: var(--transition-normal); 192 | color: var(--color-text); 193 | font-weight: 500; 194 | letter-spacing: 0.1px; 195 | } 196 | 197 | /* 交互状态 198 | ----------------------------------------*/ 199 | .nothing { 200 | position: relative; 201 | transition: var(--transition-normal); 202 | background-color: transparent; 203 | overflow: hidden; 204 | /* 让掠影在圆角内裁切 */ 205 | } 206 | 207 | .nothing:hover { 208 | background-color: var(--color-hover); 209 | color: var(--color-background); 210 | box-shadow: 0 8px 18px rgba(20, 20, 40, 0.12), inset 0 -2px 8px rgba(255, 255, 255, 0.08); 211 | } 212 | 213 | .nothing:active { 214 | background-color: var(--color-active); 215 | } 216 | 217 | .nothing.active { 218 | background-color: var(--color-active); 219 | font-weight: 600; 220 | color: var(--color-background); 221 | } 222 | 223 | /* 掠影(shine)效果:在 hover 时从左到右扫过 */ 224 | .nothing::before { 225 | content: ""; 226 | position: absolute; 227 | inset: 0; 228 | border-radius: inherit; 229 | pointer-events: none; 230 | background: linear-gradient(90deg, 231 | rgba(255, 255, 255, 0) 0%, 232 | rgba(255, 255, 255, 0.22) 45%, 233 | rgba(255, 255, 255, 0) 100%); 234 | transform: translateX(-120%); 235 | opacity: 0; 236 | } 237 | 238 | .nothing:hover::before { 239 | opacity: 0.85; 240 | animation: sheen 700ms ease forwards; 241 | } 242 | 243 | .nothing.active::before { 244 | opacity: 0; 245 | } 246 | 247 | /* 字符表格 248 | ----------------------------------------*/ 249 | .character-table { 250 | width: 100%; 251 | border-collapse: collapse; 252 | backdrop-filter: blur(4px); 253 | } 254 | 255 | .character-table th, 256 | .character-table td { 257 | border: 1px solid var(--color-glass-border); 258 | padding: 8px 12px; 259 | text-align: center; 260 | font-size: 16px; 261 | line-height: 1.5; 262 | } 263 | 264 | .character-table th { 265 | font-weight: 600; 266 | background-color: transparent; 267 | } 268 | 269 | /* 移除最外层边框 */ 270 | .character-table tr:first-child th { 271 | border-top: none; 272 | } 273 | 274 | .character-table tr:last-child td { 275 | border-bottom: none; 276 | } 277 | 278 | .character-table th:first-child, 279 | .character-table td:first-child { 280 | border-left: none; 281 | } 282 | 283 | .character-table th:last-child, 284 | .character-table td:last-child { 285 | border-right: none; 286 | } 287 | 288 | /* 页脚 289 | ----------------------------------------*/ 290 | #footer { 291 | font-family: "MiSans VF"; 292 | position: fixed; 293 | bottom: 0; 294 | height: var(--footer-height); 295 | bottom: calc(env(safe-area-inset-bottom, 0px) + 10px); 296 | left: 50%; 297 | transform: translate(-50%, 0); 298 | width: 260px; 299 | background-color: var(--color-footer-background); 300 | backdrop-filter: blur(10px); 301 | color: var(--color-footer-text); 302 | padding: 0; 303 | border-radius: 10px; 304 | text-align: center; 305 | display: flex; 306 | align-items: center; 307 | justify-content: center; 308 | border: 1px solid var(--color-glass-border); 309 | box-shadow: 0 6px 20px rgba(20, 20, 40, 0.12); 310 | } 311 | 312 | /* 页脚链接 313 | ----------------------------------------*/ 314 | a.footer-msg { 315 | color: var(--color-footer-text); 316 | transition: color 0.3s; 317 | } 318 | 319 | a.footer-msg:visited { 320 | color: var(--color-footer-text); 321 | } 322 | 323 | a.footer-msg:active { 324 | color: #FFCC7A; 325 | } 326 | 327 | #footer a.footer-msg { 328 | transition: color 0.5s ease; 329 | } 330 | 331 | #footer:hover a.footer-msg:hover { 332 | color: var(--color-footer-link-hover); 333 | } 334 | 335 | /* 响应式布局 336 | ----------------------------------------*/ 337 | @media screen and (min-width: 768px) { 338 | :root { 339 | --content-width: min(85%, 800px); 340 | --side-margin: auto; 341 | } 342 | 343 | .round { 344 | line-height: 1.6; 345 | } 346 | 347 | .ul { 348 | margin: 0 auto 0.5cm; 349 | max-width: 800px; 350 | } 351 | 352 | h2 { 353 | margin: var(--title-margin-top) auto var(--title-margin-bottom); 354 | text-align: left; 355 | max-width: 800px; 356 | } 357 | 358 | .wrapper { 359 | margin: 1cm auto 0.8cm; 360 | max-width: 800px; 361 | } 362 | } 363 | 364 | @media screen and (min-width: 1024px) { 365 | :root { 366 | --content-width: min(75%, 900px); 367 | } 368 | 369 | .ul, 370 | h2, 371 | .wrapper { 372 | max-width: 900px; 373 | } 374 | } 375 | 376 | @media screen and (min-width: 1200px) { 377 | :root { 378 | --content-width: min(70%, 1000px); 379 | } 380 | 381 | .ul, 382 | h2, 383 | .wrapper { 384 | max-width: 1000px; 385 | } 386 | } 387 | 388 | /* 包装器 389 | ----------------------------------------*/ 390 | .wrapper { 391 | color: var(--color-text); 392 | font-family: "MiSans VF"; 393 | font-weight: 600; 394 | text-align: center; 395 | font-size: var(--wrapper-font); 396 | margin: 0 auto; 397 | transition: var(--transition-normal); 398 | letter-spacing: 0.2px; 399 | } 400 | 401 | /* 统一强调色 */ 402 | .accent { 403 | color: var(--color-active); 404 | } 405 | 406 | /* 视图分组标题 */ 407 | .section-title { 408 | font-weight: 600; 409 | } 410 | 411 | /* CJK 分组网格 */ 412 | .cjk-columns { 413 | display: grid; 414 | grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); 415 | gap: 14px; 416 | } 417 | 418 | .cjk-item { 419 | break-inside: avoid; 420 | -webkit-column-break-inside: avoid; 421 | background: var(--color-glass-bg); 422 | border: 1px solid var(--color-glass-border); 423 | border-radius: 12px; 424 | padding: 12px; 425 | margin-bottom: 0; 426 | } 427 | 428 | .cjk-item .accent { 429 | display: block; 430 | margin-bottom: 6px; 431 | } 432 | 433 | .cjk-text { 434 | letter-spacing: 0.1px; 435 | } 436 | 437 | /* gb-block 单列 */ 438 | .gb-block { 439 | white-space: normal; 440 | word-break: keep-all; 441 | hyphens: none; 442 | line-height: 1.8; 443 | font-size: clamp(15px, 1.9vw, 18px); 444 | padding: 2px 0; 445 | } 446 | 447 | @media screen and (min-width: 1024px) { 448 | .cjk-columns { 449 | grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); 450 | gap: 14px; 451 | } 452 | } 453 | 454 | /* 标签文本(次级标题) */ 455 | .label { 456 | font-weight: 500; 457 | } 458 | 459 | /* 间距工具类(简短且常用) */ 460 | .mb-0 { 461 | margin-bottom: 0 !important; 462 | } 463 | 464 | .mb-sm { 465 | margin-bottom: 0.5em; 466 | } 467 | 468 | .mb-md { 469 | margin-bottom: 0.6rem; 470 | } 471 | 472 | .mb-xl { 473 | margin-bottom: 1.5em; 474 | } 475 | 476 | /* 页面路由切换动画 */ 477 | .page-enter-active, 478 | .page-leave-active { 479 | transition: opacity 250ms ease, transform 250ms ease; 480 | } 481 | 482 | .page-enter-from, 483 | .page-leave-to { 484 | opacity: 0; 485 | transform: translateY(8px); 486 | } 487 | --------------------------------------------------------------------------------