工具介绍
零宽字符隐写工具原理就是利用零宽字符(Zero Width Characters,如 \u200B)不可见的特性,将秘密信息二进制化后隐藏在普通文本(宿主文本)中。复制出来的文本看起来很正常,但粘贴到解密区就能看到隐藏内容。整个工具封装在一个 HTML 文件中,使用了 Tailwind CSS 做 UI,支持自动跟随系统的暗黑模式。
工具特点:
- 纯本地运行:所有逻辑都在浏览器完成,不上传服务器,安全隐私。
- 单文件:HTML/CSS/JS 合一,双击即用,方便部署或收藏。
- UI 美观:适配移动端和桌面端,支持深色/浅色模式切换。
- 一键复制:交互体验优化,支持一键复制加密结果。
使用场景:
- 在公开论坛/群聊传递秘密信息。
- 给文字添加“数字水印”。
- 单纯觉得好玩,整蛊朋友(比如表面发一句“你好”,实际隐藏了“V我50”)。
目前测试情况: QQ全端支持,微信手机端不支持发送零宽,只接受和复制粘贴
源码:代码直接保存为 .html 文件,用浏览器打开即可
注意:该工具不是加密工具,只是将字变成了零宽大小,专业的零宽加密工具找风导的
![图片[1]-零宽字符隐写工具(可以定制字并隐藏任何字)-QQ沐编程](https://www.qqmu.com/wp-content/uploads/2026/01/zifujiami.webp)
源码如下
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zero Text - 零宽文本加密</title>
<!-- 引入 Tailwind CSS (CDN) -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- 配置 Tailwind 主题 -->
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
primary: '#3b82f6', // blue-500
primaryHover: '#2563eb', // blue-600
darkBg: '#0f172a', // slate-900
darkCard: '#1e293b', // slate-800
},
boxShadow: {
'glow': '0 0 15px rgba(59, 130, 246, 0.5)',
}
}
}
}
</script>
<style>
/* 自定义滚动条样式 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
}
.dark ::-webkit-scrollbar-thumb {
background: #475569;
}
::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
/* 动画过渡 */
.transition-all-300 {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 文本域聚焦样式 */
.input-group:focus-within label {
color: #3b82f6;
}
</style>
</head>
<body class="min-h-screen bg-gray-100 dark:bg-darkBg text-slate-800 dark:text-slate-200 transition-colors duration-300 flex flex-col items-center py-8 px-4 font-sans">
<!-- 顶部标题栏 -->
<header class="w-full max-w-5xl flex justify-between items-center mb-8">
<div class="flex items-center gap-3">
<div class="bg-blue-600 p-2 rounded-lg shadow-lg text-white">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
</div>
<div>
<h1 class="text-2xl font-bold tracking-tight text-slate-900 dark:text-white">Zero Text</h1>
<p class="text-xs text-slate-500 dark:text-slate-400">零宽字符隐写工具</p>
</div>
</div>
<div class="flex items-center gap-4">
<!-- GitHub Link -->
<a href="https://www.52pojie.cn/" target="_blank" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-slate-700 transition-colors text-slate-600 dark:text-slate-400" title="View on GitHub">
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
</a>
<!-- Theme Toggle -->
<button id="themeToggle" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-slate-700 transition-colors text-slate-600 dark:text-slate-400">
<svg id="iconSun" class="hidden w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>
<svg id="iconMoon" class="block w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path></svg>
</button>
</div>
</header>
<!-- 主容器 -->
<main class="w-full max-w-5xl grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- 左侧:加密卡片 -->
<section class="bg-white dark:bg-darkCard rounded-2xl shadow-xl overflow-hidden border border-gray-200 dark:border-slate-700 flex flex-col h-full transition-all-300 hover:shadow-2xl">
<div class="bg-gradient-to-r from-blue-500 to-blue-600 p-4">
<h2 class="text-white font-semibold flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path></svg>
加密 / 隐藏信息
</h2>
</div>
<div class="p-6 flex flex-col gap-5 flex-1">
<!-- 宿主文本 -->
<div class="input-group">
<label class="block text-sm font-medium text-slate-600 dark:text-slate-400 mb-1.5 transition-colors">
1. 宿主文本(表面显示的内容)
</label>
<textarea id="carrierText" class="w-full h-24 p-3 rounded-lg border border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all resize-none text-sm" placeholder="例如:今天天气真不错,要不要一起去喝咖啡?"></textarea>
</div>
<!-- 秘密文本 -->
<div class="input-group">
<label class="block text-sm font-medium text-slate-600 dark:text-slate-400 mb-1.5 transition-colors">
2. 秘密文本(要隐藏的内容)
</label>
<textarea id="secretText" class="w-full h-24 p-3 rounded-lg border border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all resize-none text-sm" placeholder="例如:你好鸭"></textarea>
</div>
<!-- 按钮区 -->
<button id="encryptBtn" class="w-full py-3 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-xl shadow-lg shadow-blue-500/30 transition-all active:scale-[0.98] flex items-center justify-center gap-2 group">
<span class="group-hover:scale-110 transition-transform">🔒</span>
生成加密文本
</button>
<!-- 结果区 -->
<div class="relative mt-2">
<label class="block text-xs font-semibold uppercase text-slate-400 dark:text-slate-500 mb-1 tracking-wider">
加密结果
</label>
<div class="relative group">
<div id="encryptResult" class="w-full h-28 p-3 pr-12 rounded-lg border-2 border-dashed border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 text-sm text-slate-500 dark:text-slate-400 break-all overflow-y-auto font-mono transition-colors group-hover:border-blue-300 dark:group-hover:border-slate-500">
(等待生成...)
</div>
<!-- 复制按钮 (悬浮) -->
<button id="copyEncryptBtn" disabled class="absolute top-2 right-2 p-2 bg-white dark:bg-slate-700 border border-gray-200 dark:border-slate-600 rounded-md shadow-sm text-slate-500 hover:text-blue-600 hover:border-blue-200 dark:hover:text-blue-400 transition-all disabled:opacity-50 disabled:cursor-not-allowed group-hover:opacity-100" title="复制结果">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
</button>
</div>
</div>
</div>
</section>
<!-- 右侧:解密卡片 -->
<section class="bg-white dark:bg-darkCard rounded-2xl shadow-xl overflow-hidden border border-gray-200 dark:border-slate-700 flex flex-col h-full transition-all-300 hover:shadow-2xl">
<div class="bg-gradient-to-r from-emerald-500 to-emerald-600 p-4">
<h2 class="text-white font-semibold flex items-center gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>
解密 / 提取信息
</h2>
</div>
<div class="p-6 flex flex-col gap-5 flex-1">
<!-- 解密输入 -->
<div class="input-group">
<label class="block text-sm font-medium text-slate-600 dark:text-slate-400 mb-1.5 transition-colors">
粘贴包含零宽字符的文本
</label>
<textarea id="decodeInput" class="w-full h-[220px] p-3 rounded-lg border border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 focus:ring-2 focus:ring-emerald-500 focus:border-transparent outline-none transition-all resize-none text-sm" placeholder="在此处粘贴..."></textarea>
</div>
<!-- 按钮区 -->
<button id="decryptBtn" class="w-full py-3 bg-emerald-600 hover:bg-emerald-700 text-white font-semibold rounded-xl shadow-lg shadow-emerald-500/30 transition-all active:scale-[0.98] flex items-center justify-center gap-2 group">
<span class="group-hover:scale-110 transition-transform">🔓</span>
解密提取内容
</button>
<!-- 结果区 -->
<div class="relative mt-2 flex-1 flex flex-col">
<label class="block text-xs font-semibold uppercase text-slate-400 dark:text-slate-500 mb-1 tracking-wider">
还原结果
</label>
<div class="relative group flex-1">
<div id="decryptResult" class="w-full h-full min-h-[112px] p-3 pr-12 rounded-lg border-2 border-dashed border-gray-300 dark:border-slate-600 bg-gray-50 dark:bg-slate-900/50 text-sm text-slate-500 dark:text-slate-400 break-all overflow-y-auto font-mono transition-colors group-hover:border-emerald-300 dark:group-hover:border-slate-500">
(等待解密...)
</div>
<!-- 复制按钮 (悬浮) -->
<button id="copyDecryptBtn" disabled class="absolute top-2 right-2 p-2 bg-white dark:bg-slate-700 border border-gray-200 dark:border-slate-600 rounded-md shadow-sm text-slate-500 hover:text-emerald-600 hover:border-emerald-200 dark:hover:text-emerald-400 transition-all disabled:opacity-50 disabled:cursor-not-allowed group-hover:opacity-100" title="复制结果">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
</button>
</div>
</div>
</div>
</section>
</main>
<footer class="mt-8 text-center text-xs text-slate-400 dark:text-slate-500">
<p>🔒 所有加密/解密均在本地浏览器完成,不会上传数据</p>
</footer>
<!-- JavaScript 逻辑 -->
<script>
// ==========================================
// 核心加密解密逻辑 (保持不变)
// ==========================================
const ZWC = { 0: '\u200B', 1: '\u200C' };
function textToBinary(text) {
const utf8 = new TextEncoder().encode(text);
return Array.from(utf8)
.map((b) => b.toString(2).padStart(8, '0'))
.join('');
}
function binaryToText(bin) {
const bytesMatch = bin.match(/.{8}/g);
if (!bytesMatch) return '';
const bytes = bytesMatch.map((b) => parseInt(b, 2));
return new TextDecoder().decode(new Uint8Array(bytes));
}
function binaryToZWC(bin) {
return bin.split('').map((b) => ZWC[Number(b)]).join('');
}
function zwcToBinary(zwcText) {
return [...zwcText]
.map((c) => (c === '\u200B' ? '0' : c === '\u200C' ? '1' : ''))
.join('');
}
function insertZWCIntoCarrier(carrier, zwc) {
if (!carrier) carrier = " ";
const mid = Math.floor(carrier.length / 2);
return carrier.slice(0, mid) + zwc + carrier.slice(mid);
}
// ==========================================
// DOM 操作
// ==========================================
document.addEventListener('DOMContentLoaded', () => {
const carrierInput = document.getElementById('carrierText');
const secretInput = document.getElementById('secretText');
const encryptBtn = document.getElementById('encryptBtn');
const encryptResultDiv = document.getElementById('encryptResult');
const copyEncryptBtn = document.getElementById('copyEncryptBtn');
const decodeInput = document.getElementById('decodeInput');
const decryptBtn = document.getElementById('decryptBtn');
const decryptResultDiv = document.getElementById('decryptResult');
const copyDecryptBtn = document.getElementById('copyDecryptBtn');
const themeToggle = document.getElementById('themeToggle');
const iconSun = document.getElementById('iconSun');
const iconMoon = document.getElementById('iconMoon');
let encryptedValue = '';
let decryptedValue = '';
// 辅助函数:更新结果框状态
function updateResultBox(element, text, isPlaceholder = false) {
element.innerText = text;
if (isPlaceholder) {
element.classList.add('text-slate-500', 'dark:text-slate-400');
element.classList.remove('text-slate-800', 'dark:text-slate-200');
} else {
element.classList.remove('text-slate-500', 'dark:text-slate-400');
element.classList.add('text-slate-800', 'dark:text-slate-200');
}
}
// --- 加密 ---
encryptBtn.addEventListener('click', () => {
const secret = secretInput.value;
const carrier = carrierInput.value;
if (!secret) {
// 简单的震动反馈或边框红色提示
secretInput.classList.add('ring-2', 'ring-red-500');
setTimeout(() => secretInput.classList.remove('ring-2', 'ring-red-500'), 500);
return;
}
try {
const binary = textToBinary(secret);
const zwcText = binaryToZWC(binary);
const final = insertZWCIntoCarrier(carrier || 'Processing...', zwcText);
encryptedValue = final;
updateResultBox(encryptResultDiv, final);
copyEncryptBtn.disabled = false;
// 视觉反馈:稍微闪烁一下结果框
encryptResultDiv.classList.add('bg-blue-50', 'dark:bg-blue-900/20');
setTimeout(() => encryptResultDiv.classList.remove('bg-blue-50', 'dark:bg-blue-900/20'), 300);
} catch (e) {
console.error(e);
alert('加密失败');
}
});
// --- 解密 ---
decryptBtn.addEventListener('click', () => {
const input = decodeInput.value;
if (!input) return;
try {
const zwcChars = [...input]
.filter((c) => c === '\u200B' || c === '\u200C')
.join('');
if (!zwcChars) {
updateResultBox(decryptResultDiv, "⚠️ 未检测到隐藏信息", true);
decryptedValue = "";
copyDecryptBtn.disabled = true;
return;
}
const binary = zwcToBinary(zwcChars);
const text = binaryToText(binary);
decryptedValue = text;
updateResultBox(decryptResultDiv, text);
copyDecryptBtn.disabled = false;
// 视觉反馈
decryptResultDiv.classList.add('bg-emerald-50', 'dark:bg-emerald-900/20');
setTimeout(() => decryptResultDiv.classList.remove('bg-emerald-50', 'dark:bg-emerald-900/20'), 300);
} catch (e) {
console.error(e);
updateResultBox(decryptResultDiv, "❌ 解密失败:数据损坏", true);
}
});
// --- 复制 ---
async function copyToClipboard(text, btnElement) {
if (!text) return;
try {
await navigator.clipboard.writeText(text);
const originalIcon = btnElement.innerHTML;
// 切换为打钩图标
btnElement.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-green-500"><polyline points="20 6 9 17 4 12"></polyline></svg>`;
setTimeout(() => {
btnElement.innerHTML = originalIcon;
}, 1500);
} catch (err) {
alert('复制失败');
}
}
copyEncryptBtn.addEventListener('click', () => {
copyToClipboard(encryptedValue, copyEncryptBtn);
});
copyDecryptBtn.addEventListener('click', () => {
copyToClipboard(decryptedValue, copyDecryptBtn);
});
// --- 深色模式 ---
function updateThemeIcon(isDark) {
if (isDark) {
iconSun.classList.remove('hidden');
iconMoon.classList.add('hidden');
} else {
iconSun.classList.add('hidden');
iconMoon.classList.remove('hidden');
}
}
function initTheme() {
const stored = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (stored === 'dark' || (!stored && prefersDark)) {
document.documentElement.classList.add('dark');
updateThemeIcon(true);
} else {
document.documentElement.classList.remove('dark');
updateThemeIcon(false);
}
}
themeToggle.addEventListener('click', () => {
const isDark = document.documentElement.classList.toggle('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
updateThemeIcon(isDark);
});
initTheme();
});
</script>
</body>
</html>
© 版权声明
本站资源来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!
THE END












