<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>你适合在哪个城市居住?</title>
<style>
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body {
margin: 0; min-height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif;
background: linear-gradient(160deg, #f7f3ff 0%, #eef7ff 55%, #fff7ef 100%);
color: #2b2b2b; display: flex; justify-content: center; padding: 18px;
}
.app {
width: 100%; max-width: 480px; min-height: 90vh;
background: rgba(255,255,255,0.82); backdrop-filter: blur(10px);
border-radius: 28px; box-shadow: 0 18px 60px rgba(90, 80, 160, 0.14);
padding: 28px 22px 24px; display: flex; flex-direction: column;
}
h1 { font-size: 24px; line-height: 1.35; margin: 12px 0 10px; }
.sub { color: #777; font-size: 14px; line-height: 1.7; margin-bottom: 22px; }
.badge {
display: inline-block; font-size: 12px; color: #6b5bd2;
background: #efecff; padding: 5px 10px; border-radius: 999px; width: fit-content;
}
.btn {
border: none; width: 100%; padding: 15px; border-radius: 16px;
font-size: 16px; font-weight: 600; color: white;
background: linear-gradient(135deg, #7b6cf6, #5aa9ff);
cursor: pointer; margin-top: auto;
}
.btn:active { transform: scale(0.98); }
.progress-wrap { margin: 10px 0 18px; }
.progress-text { font-size: 13px; color: #888; margin-bottom: 8px; }
.progress-bar { height: 8px; background: #eceaf7; border-radius: 999px; overflow: hidden; }
.progress-inner {
height: 100%; width: 0%; border-radius: 999px;
background: linear-gradient(90deg, #7b6cf6, #5aa9ff); transition: width 0.25s ease;
}
.question { font-size: 19px; line-height: 1.55; font-weight: 650; margin: 8px 0 18px; }
.option {
width: 100%; text-align: left; border: 1.5px solid #e5e2f2; background: white;
border-radius: 16px; padding: 15px 16px; font-size: 15px; line-height: 1.5;
color: #333; margin-bottom: 11px; cursor: pointer; transition: all 0.15s ease;
}
.option:active { background: #f6f4ff; border-color: #b9b0ff; }
.result-card { text-align: center; padding: 8px 0 4px; }
.result-emoji { font-size: 54px; margin: 6px 0 4px; }
.result-city {
font-size: 30px; font-weight: 800; letter-spacing: 1px; margin: 6px 0 6px;
background: linear-gradient(135deg, #6f5cf1, #37a7ff);
-webkit-background-clip: text; background-clip: text; color: transparent;
}
.result-tag {
display: inline-block; background: #f1eeff; color: #6b5bd2;
border-radius: 999px; padding: 7px 14px; font-size: 13px; margin-bottom: 16px;
}
.result-desc {
text-align: left; font-size: 15px; line-height: 1.85; color: #555;
background: #faf9ff; border-radius: 18px; padding: 18px; margin: 10px 0 16px;
}
.disclaimer {
font-size: 11px; color: #aaa; line-height: 1.6; text-align: center; margin-top: 16px;
}
.hidden { display: none; }
.restart { background: #fff; color: #6b5bd2; border: 1.5px solid #dcd6ff; margin-top: 12px; }
.save-btn { margin-top: 12px; background: linear-gradient(135deg, #ff8a5c, #ff5f9e); }
.overlay {
position: fixed; inset: 0; background: rgba(20, 16, 40, 0.72);
display: flex; flex-direction: column; align-items: center; justify-content: center;
padding: 20px; z-index: 99; backdrop-filter: blur(4px);
}
.overlay img {
width: 100%; max-width: 340px; border-radius: 18px;
box-shadow: 0 20px 60px rgba(0,0,0,0.35);
}
.overlay-tip { color: #fff; font-size: 14px; margin-top: 16px; text-align: center; line-height: 1.6; }
.overlay-close {
margin-top: 18px; border: none; background: rgba(255,255,255,0.16);
color: #fff; padding: 12px 28px; border-radius: 999px; font-size: 15px; cursor: pointer;
}
</style>
</head>
<body>
<div class="app">
<section id="startScreen">
<span class="badge">趣味测试 · 仅供娱乐</span>
<h1>你适合在哪个城市居住?</h1>
<p class="sub">20道题,测测你的生活节奏、社交偏好和内心向往,看看哪座城市更像你的“精神老家”。</p>
<button class="btn" onclick="startTest()">开始测试</button>
<p class="disclaimer">本测试仅供娱乐参考,不构成任何专业评估或建议。</p>
</section>
<section id="quizScreen" class="hidden">
<div class="progress-wrap">
<div class="progress-text" id="progressText">第 1 / 20 题</div>
<div class="progress-bar"><div class="progress-inner" id="progressInner"></div></div>
</div>
<div class="question" id="questionText"></div>
<div id="optionsBox"></div>
<p class="disclaimer">请凭第一感觉选择,结果会更贴近你。</p>
</section>
<section id="resultScreen" class="hidden">
<div class="result-card">
<div class="result-emoji" id="resultEmoji">🏙️</div>
<div class="result-city" id="resultCity"></div>
<div class="result-tag" id="resultTag"></div>
<div class="result-desc" id="resultDesc"></div>
</div>
<button class="btn save-btn" onclick="generatePoster()">保存结果图片</button>
<button class="btn restart" onclick="restart()">再测一次</button>
<p class="disclaimer">本测试仅供娱乐参考,不构成任何专业评估或建议。</p>
</section>
</div>
<div id="overlay" class="overlay hidden">
<img id="posterImg" alt="测试结果海报" />
<div class="overlay-tip">长按图片保存到相册<br>或点击下方按钮关闭</div>
<button class="overlay-close" onclick="closeOverlay()">关闭</button>
</div>
<script>
const questions = [
{ q: "如果突然多出三天假,你的第一反应是?", options: [
{ text: "先把积压的待办清单清掉,不然玩不踏实", city: "深圳" },
{ text: "约朋友吃顿好的,再睡到自然醒", city: "成都" },
{ text: "找个海边民宿,什么都不干,就发呆", city: "厦门" },
{ text: "立刻查机票,去哪都行,先离开再说", city: "大理" }
]},
{ q: "你手机里最舍不得删的 App 类型是?", options: [
{ text: "效率工具/课程学习类,感觉留着就能变强", city: "深圳" },
{ text: "拍照修图/看展购票类,审美不能丢", city: "杭州" },
{ text: "美食探店/外卖类,活着就是为了吃", city: "成都" },
{ text: "旅行户外/冥想白噪音类,随时准备逃离", city: "大理" }
]},
{ q: "朋友对你的第一印象通常是?", options: [
{ text: "“你看起来好忙,是不是又在搞钱”", city: "深圳" },
{ text: "“你有点文艺,但又不完全文艺”", city: "杭州" },
{ text: "“你好会生活,跟你玩肯定不亏”", city: "成都" },
{ text: "“你身上有种松弛感,像在海边长大”", city: "厦门" }
]},
{ q: "下面哪种“崩溃”最让你受不了?", options: [
{ text: "计划被打乱,效率直接归零", city: "深圳" },
{ text: "城市太糙,找不到一家像样的咖啡馆", city: "杭州" },
{ text: "连续一周看不到天,窗外全是墙", city: "厦门" },
{ text: "被拉进一个 99+ 的群,还要挨个回复", city: "大理" }
]},
{ q: "你理想中的周末早晨是?", options: [
{ text: "冲杯咖啡,坐在窗边看书,顺便拍张照", city: "杭州" },
{ text: "睡到自然醒,下楼吃碗面,再逛个菜市场", city: "成都" },
{ text: "早起去海边/公园散步,吹吹风", city: "厦门" },
{ text: "没有早晨,睡到几点算几点", city: "大理" }
]},
{ q: "如果只能保留一种“奢侈”,你选?", options: [
{ text: "事业上有上升空间,累点也认", city: "深圳" },
{ text: "随时能约到人吃饭,永远不孤单", city: "成都" },
{ text: "住在有海/有山的地方,出门就是风景", city: "厦门" },
{ text: "时间完全自由,想干嘛干嘛", city: "大理" }
]},
{ q: "你更愿意为哪种“无用之美”花钱?", options: [
{ text: "一个能提升效率的会员/工具", city: "深圳" },
{ text: "一束花/一个好看的杯子/一张展票", city: "杭州" },
{ text: "一顿环境很好但有点贵的饭", city: "成都" },
{ text: "一张去山里的车票,什么都不带", city: "大理" }
]},
{ q: "别人在群里争论时,你通常?", options: [
{ text: "默默整理逻辑,最后甩一段总结", city: "深圳" },
{ text: "发个表情包缓和气氛,然后撤", city: "杭州" },
{ text: "忍不住接话,越聊越嗨,最后约饭", city: "成都" },
{ text: "看完就走,内心毫无波澜", city: "厦门" }
]},
{ q: "你对“排队”的忍耐度取决于?", options: [
{ text: "前面的人是不是在浪费时间", city: "深圳" },
{ text: "排队的地方好不好看,能不能拍照", city: "杭州" },
{ text: "排队的地方有没有海风/树荫", city: "厦门" },
{ text: "我根本不会去需要排队的地方", city: "大理" }
]},
{ q: "如果让你选一个城市住三年,你最看重?", options: [
{ text: "城市审美和文化氛围,日子要好看", city: "杭州" },
{ text: "生活成本和松弛感,舒服最重要", city: "成都" },
{ text: "气候和自然环境,每天像度假", city: "厦门" },
{ text: "能不能按自己的节奏活,不被卷", city: "大理" }
]},
{ q: "你更接近哪种“社交电量”?", options: [
{ text: "只跟固定几个人玩,边界清晰,不浪费时间", city: "深圳" },
{ text: "越聊越有劲,人越多越嗨,散场就空虚", city: "成都" },
{ text: "喜欢一对一的深度聊天,最好在海边", city: "厦门" },
{ text: "见完人需要独处三天回血,别找我", city: "大理" }
]},
{ q: "下面哪句话最像你的内心 OS?", options: [
{ text: "“搞钱要紧,别的以后再说”", city: "深圳" },
{ text: "“我想把日子过得好看一点”", city: "杭州" },
{ text: "“人生苦短,先吃顿好的”", city: "成都" },
{ text: "“我想去一个有风的地方”", city: "大理" }
]},
{ q: "你手机相册里最多的是?", options: [
{ text: "工作截图/学习笔记/待办清单", city: "深圳" },
{ text: "展、咖啡、街景、穿搭、天空", city: "杭州" },
{ text: "美食和聚餐合照,九宫格根本不够", city: "成都" },
{ text: "海、晚霞、树、花、猫", city: "厦门" }
]},
{ q: "如果明天开始远程办公,你最想搬去?", options: [
{ text: "不搬,远程也要待在机会最多的地方", city: "深圳" },
{ text: "气候舒服、生活精致的城市", city: "杭州" },
{ text: "海边城市,每天能看海", city: "厦门" },
{ text: "有山有水、房租便宜的小城", city: "大理" }
]},
{ q: "你对“成功”的第一反应是?", options: [
{ text: "被看见、被认可,做出有审美的东西", city: "杭州" },
{ text: "过上舒服自在的日子,想吃什么吃什么", city: "成都" },
{ text: "有一间能看海的房子,和喜欢的人", city: "厦门" },
{ text: "按自己的节奏活着,不被任何人定义", city: "大理" }
]},
{ q: "下面哪种天气最让你想出门?", options: [
{ text: "阴天,不晒,适合办事", city: "深圳" },
{ text: "晚上,凉快,适合吃宵夜", city: "成都" },
{ text: "晴天,海边有风", city: "厦门" },
{ text: "下雨天,适合一个人待着", city: "大理" }
]},
{ q: "你更受不了哪种“浪费”?", options: [
{ text: "浪费时间在无效社交上", city: "深圳" },
{ text: "浪费一个好天气没出门拍照", city: "杭州" },
{ text: "浪费一顿好吃的没好好吃", city: "成都" },
{ text: "浪费一个可以独处的下午", city: "大理" }
]},
{ q: "朋友说“你变了”,你第一反应是?", options: [
{ text: "“变强了还是变秃了?”", city: "深圳" },
{ text: "“变好看了还是变胖了?”", city: "杭州" },
{ text: "“变开朗了还是变宅了?”", city: "成都" },
{ text: "“变松弛了还是变黑了?”", city: "厦门" }
]},
{ q: "你理想中的“家”窗外是?", options: [
{ text: "高楼和城市灯光,越晚越亮", city: "深圳" },
{ text: "梧桐树和街道,有烟火也有距离", city: "杭州" },
{ text: "海和晚霞,每天不重样", city: "厦门" },
{ text: "山、云、田野,最好还有一只猫", city: "大理" }
]},
{ q: "最后,你更相信哪种生活哲学?", options: [
{ text: "在现实和理想之间找平衡", city: "杭州" },
{ text: "把日子过舒服最重要", city: "成都" },
{ text: "慢慢来,比较快", city: "厦门" },
{ text: "自由比稳定更珍贵", city: "大理" }
]}
];
const results = {
"深圳": { emoji: "🌃", tag: "效率型野心家", desc: "你适合深圳,不是因为你喜欢加班,而是你喜欢“事情能成”的感觉。你需要快节奏、多机会、边界清晰的环境,把精力放在真正重要的事上。但别忘了,偶尔浪费时间,也是一种能力。" },
"杭州": { emoji: "🌿", tag: "精致平衡派", desc: "你适合杭州,或者任何“既能搞事业、又能好好生活”的城市。你在意审美、细节和距离感,喜欢努力,但不想被努力吞掉。对你来说,最好的城市是能让你在效率和松弛之间来回切换的地方。" },
"成都": { emoji: "🍲", tag: "烟火气生活家", desc: "你适合成都,或者任何“人味很重”的城市。你需要朋友、美食、热闹和随时能出门的夜晚。你相信生活不是用来赶路的,而是用来过的。对你来说,城市再大,不如楼下那家好吃的店和随叫随到的人。" },
"厦门": { emoji: "🌊", tag: "海边治愈系", desc: "你适合厦门,或者任何能让你靠近海和风的地方。你需要空间呼吸,需要自然给你回血。你不排斥努力,但不愿意为了效率牺牲生活里的风景。对你来说,一座城市最好的样子,是傍晚散步时不用赶时间。" },
"大理": { emoji: "⛰️", tag: "自由慢生活者", desc: "你适合大理,或者任何允许你“按自己节奏来”的地方。你讨厌被比较、被催促、被塞进统一模板。你需要山、云、田野和足够的独处时间。对你来说,城市不必很大,但一定要能让你喘口气。" }
};
let current = 0;
let scores = {};
let finalCity = "";
function startTest() {
current = 0;
scores = { "深圳": 0, "杭州": 0, "成都": 0, "厦门": 0, "大理": 0 };
document.getElementById("startScreen").classList.add("hidden");
document.getElementById("resultScreen").classList.add("hidden");
document.getElementById("quizScreen").classList.remove("hidden");
renderQuestion();
}
function renderQuestion() {
const q = questions[current];
document.getElementById("progressText").textContent = `第 ${current + 1} / ${questions.length} 题`;
document.getElementById("progressInner").style.width = `${(current / questions.length) * 100}%`;
document.getElementById("questionText").textContent = q.q;
const box = document.getElementById("optionsBox");
box.innerHTML = "";
q.options.forEach(opt => {
const btn = document.createElement("button");
btn.className = "option";
btn.textContent = opt.text;
btn.onclick = () => choose(opt.city);
box.appendChild(btn);
});
}
function choose(city) {
scores[city] = (scores[city] || 0) + 1;
current++;
if (current < questions.length) renderQuestion();
else showResult();
}
function showResult() {
let topCity = "杭州", topScore = -1;
Object.keys(scores).forEach(city => {
if (scores[city] > topScore) { topScore = scores[city]; topCity = city; }
});
finalCity = topCity;
const r = results[topCity];
document.getElementById("resultEmoji").textContent = r.emoji;
document.getElementById("resultCity").textContent = topCity;
document.getElementById("resultTag").textContent = r.tag;
document.getElementById("resultDesc").textContent = r.desc;
document.getElementById("quizScreen").classList.add("hidden");
document.getElementById("resultScreen").classList.remove("hidden");
}
function restart() {
document.getElementById("resultScreen").classList.add("hidden");
document.getElementById("startScreen").classList.remove("hidden");
}
function generatePoster() {
const r = results[finalCity];
const W = 750, H = 1000;
const canvas = document.createElement("canvas");
canvas.width = W;
canvas.height = H;
const ctx = canvas.getContext("2d");
const bg = ctx.createLinearGradient(0, 0, W, H);
bg.addColorStop(0, "#f5f1ff");
bg.addColorStop(0.55, "#eaf5ff");
bg.addColorStop(1, "#fff4ea");
ctx.fillStyle = bg;
ctx.fillRect(0, 0, W, H);
roundRect(ctx, 45, 55, W - 90, H - 110, 42);
ctx.fillStyle = "rgba(255,255,255,0.88)";
ctx.fill();
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = '96px "Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",sans-serif';
ctx.fillText(r.emoji, W / 2, 190);
ctx.font = 'bold 76px "PingFang SC","Microsoft YaHei",sans-serif';
const cityGrad = ctx.createLinearGradient(W/2 - 160, 0, W/2 + 160, 0);
cityGrad.addColorStop(0, "#6f5cf1");
cityGrad.addColorStop(1, "#37a7ff");
ctx.fillStyle = cityGrad;
ctx.fillText(finalCity, W / 2, 320);
ctx.font = '30px "PingFang SC","Microsoft YaHei",sans-serif';
const tagText = r.tag;
const tagW = ctx.measureText(tagText).width + 56;
const tagH = 58;
const tagX = W / 2 - tagW / 2;
const tagY = 385;
roundRect(ctx, tagX, tagY, tagW, tagH, tagH / 2);
ctx.fillStyle = "#f1eeff";
ctx.fill();
ctx.fillStyle = "#6b5bd2";
ctx.fillText(tagText, W / 2, tagY + tagH / 2 + 1);
ctx.font = '30px "PingFang SC","Microsoft YaHei",sans-serif';
ctx.fillStyle = "#555";
ctx.textAlign = "left";
const maxWidth = W - 220;
const startX = 110;
let startY = 500;
const lineHeight = 52;
const lines = wrapText(ctx, r.desc, maxWidth);
lines.forEach((line, i) => {
ctx.fillText(line, startX, startY + i * lineHeight);
});
ctx.strokeStyle = "#eee";
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(110, 860);
ctx.lineTo(W - 110, 860);
ctx.stroke();
ctx.textAlign = "center";
ctx.font = '26px "PingFang SC","Microsoft YaHei",sans-serif';
ctx.fillStyle = "#8a7cf0";
ctx.fillText("截图分享,看看谁和你同城", W / 2, 900);
ctx.font = '20px "PingFang SC","Microsoft YaHei",sans-serif';
ctx.fillStyle = "#bbb";
ctx.fillText("本测试仅供娱乐参考,不构成专业评估", W / 2, 945);
const dataUrl = canvas.toDataURL("image/png");
const img = document.getElementById("posterImg");
img.src = dataUrl;
document.getElementById("overlay").classList.remove("hidden");
}
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
}
function wrapText(ctx, text, maxWidth) {
const lines = [];
let line = "";
for (const ch of text) {
const test = line + ch;
if (ctx.measureText(test).width > maxWidth && line) {
lines.push(line);
line = ch;
} else {
line = test;
}
}
if (line) lines.push(line);
return lines;
}
function closeOverlay() {
document.getElementById("overlay").classList.add("hidden");
}
</script>
</body>
</html>