会眨眼的404页面:HTML+CSS+SVG实现,复制即用

鸡腿大王 2 阅读 Web前端干货分享

纯 HTML+CSS+SVG 实现的动画 404 报错页面,不需要 JavaScript。页面包含眨眼、眼球移动、口鼻入场等动画效果,同时适配移动端,复制源码即可部署到自己网站,给站点增加一个趣味小彩蛋。

预览效果

代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>404 - 页面不存在</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }

        .error-page {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            min-height: 70vh;
            padding: 40px 20px;
            color: #10B981;
        }

        .face-container {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 400px;
            background: transparent;
        }

        .face { width: 200px; }

        .face__eyes, .face__eye-lid, .face__mouth-left, .face__mouth-right, .face__nose, .face__pupil {
            animation: eyes 1s 0.3s forwards;
        }

        .face__eye-lid, .face__pupil {
            animation-duration: 4s;
            animation-delay: 1.3s;
            animation-iteration-count: infinite;
        }

        .face__eye-lid { animation-name: eye-lid; }
        .face__mouth-left { animation-name: mouth-left; }
        .face__mouth-right { animation-name: mouth-right; }
        .face__nose { animation-name: nose; }
        .face__pupil { animation-name: pupil; }

        @keyframes eye-lid {
            0%, 40%, 45%, 100% { transform: translateY(0); }
            42.5% { transform: translateY(17.5px); }
        }
        @keyframes eyes {
            from { transform: translateY(112.5px); }
            to { transform: translateY(15px); }
        }
        @keyframes pupil {
            0%, 37.5%, 40%, 45%, 87.5%, 100% { stroke-dashoffset: 0; transform: translate(0, 0); }
            12.5%, 25%, 62.5%, 75% { transform: translate(-35px, 0); }
            42.5% { stroke-dashoffset: 35; transform: translate(0, 17.5px); }
        }
        @keyframes mouth-left {
            from, 50% { stroke-dashoffset: -102; }
            to { stroke-dashoffset: 0; }
        }
        @keyframes mouth-right {
            from, 50% { stroke-dashoffset: 102; }
            to { stroke-dashoffset: 0; }
        }
        @keyframes nose {
            from { transform: translate(0, 0); }
            to { transform: translate(0, 22.5px); }
        }

        .error-code {
            font-size: 96px;
            font-weight: 900;
            letter-spacing: 4px;
            margin: 10px 0 20px;
            animation: fadeIn 1s ease-out 1.2s backwards;
        }

        .error-title {
            font-size: 20px;
            font-weight: 500;
            color: #666;
            margin-bottom: 40px;
            animation: fadeIn 1s ease-out 1.4s backwards;
        }

        .back-link {
            font-size: 15px;
            color: #10B981;
            text-decoration: none;
            border-bottom: 1px solid #6ee7b7;
            padding-bottom: 2px;
            transition: border-color 0.25s ease;
            animation: fadeIn 1s ease-out 1.6s backwards;
        }
        .back-link:hover { border-color: #10B981; }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(15px); }
            to   { opacity: 1; transform: translateY(0); }
        }

        @media (max-width: 768px) {
            .face-container { height: 300px; }
            .face { width: 150px; }
            .error-code { font-size: 72px; }
            .error-title { font-size: 17px; }
        }
    </style>
</head>
<body>
<main class="error-page">
    <div class="face-container">
        <svg class="face" viewBox="0 0 320 380">
            <g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="25">
                <g class="face__eyes" transform="translate(0,112.5)">
                    <g transform="translate(15,0)">
                        <polyline class="face__eye-lid" points="37,0 0,120 75,120"></polyline>
                        <polyline class="face__pupil" points="55,120 55,155" stroke-dasharray="35 35"></polyline>
                    </g>
                    <g transform="translate(230,0)">
                        <polyline class="face__eye-lid" points="37,0 0,120 75,120"></polyline>
                        <polyline class="face__pupil" points="55,120 55,155" stroke-dasharray="35 35"></polyline>
                    </g>
                </g>
                <rect class="face__nose" x="132.5" y="112.5" width="55" height="155" rx="4" ry="4"></rect>
                <g transform="translate(65,334)" stroke-dasharray="102 102">
                    <path class="face__mouth-left" d="M 0 30 C 0 30 40 0 95 0"></path>
                    <path class="face__mouth-right" d="M 95 0 C 150 0 190 30 190 30"></path>
                </g>
            </g>
        </svg>
    </div>
    <div class="error-code">404</div>
    <p class="error-title">抱歉,你访问的页面不存在</p>
    <a class="back-link" href="./">返回首页</a>
</main>
</body>
</html>