You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tailwind CSS peer-checked样式在Chrome和Safari中无法正常生效

解决Svelte+Tailwind单选开关在Chrome/Safari中样式失效问题

问题描述

我使用Svelte开发了一个双选项单选开关,核心代码如下:

<div class="flex justify-center mt-3 mb-2">
    <div class="inline-flex outline outline-neutral-100 rounded-md">
        <div>
            <input
                type="radio"
                name="radio"
                id="internato"
                class="sr-only peer"
                checked
                on:click={() => {
                    $spotTypeBeforeAPICall = spotTypes.INTERNATO;
                }}
            />
            <label
                for="internato"
                class="cursor-pointer inline-flex items-center py-2 px-3 text-base sm:text-lg peer-checked:bg-neutral-100 peer-checked:text-cyan-900 peer-checked:font-bold hover:font-bold"
            >
                IFE
            </label>
        </div>
        <div>
            <input
                type="radio"
                name="radio"
                id="iac"
                class="sr-only peer"
                on:click={() => {
                    $spotTypeBeforeAPICall = spotTypes.IAC;
                }}
            />
            <label
                for="iac"
                class="cursor-pointer inline-flex items-center py-2 px-3 text-base sm:text-lg peer-checked:bg-neutral-100 peer-checked:text-cyan-900 peer-checked:font-bold hover:font-bold"
            >
                IAC
            </label>
        </div>
    </div>
</div>

该组件在Firefox中显示正常:选中的选项会呈现灰色背景、深蓝色加粗文字;但在Chrome和Safari中,选中后的peer-checked样式完全不生效。

相关配置文件如下:

tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./src/**/*.{html,js,svelte}"],
  theme: {
    extend: {},
  },
  plugins: [],
}

rollup.config.js

import { spawn } from 'child_process';
import svelte from 'rollup-plugin-svelte';
import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import css from 'rollup-plugin-css-only';

const production = !process.env.ROLLUP_WATCH;

function serve() {
    let server;

    function toExit() {
        if (server) server.kill(0);
    }

    return {
        writeBundle() {
            if (server) return;
            server = spawn('npm', ['run', 'start', '--', '--dev'], {
                stdio: ['ignore', 'inherit', 'inherit'],
                shell: true
            });

            process.on('SIGTERM', toExit);
            process.on('exit', toExit);
        }
    };
}

export default {
    input: 'public/main.js',
    output: {
        sourcemap: true,
        format: 'iife',
        name: 'app',
        file: 'public/build/bundle.js'
    },
    plugins: [
        svelte({
            compilerOptions: {
                // enable run-time checks when not in production
                dev: !production
            }
        }),
        // we'll extract any component CSS out into
        // a separate file - better for performance
        css({ output: 'bundle.css' }),

        // If you have external dependencies installed from
        // npm, you'll most likely need these plugins. In
        // some cases you'll need additional configuration -
        // consult the documentation for details:
        // https://github.com/rollup/plugins/tree/master/packages/commonjs
        resolve({
            browser: true,
            dedupe: ['svelte'],
            exportConditions: ['svelte']
        }),
        commonjs(),

        // In dev mode, call `npm run start` once
        // the bundle has been generated
        !production && serve(),

        // Watch the `public` directory and refresh the
        // browser on changes when not in production
        !production && livereload('public'),

        // If we're building for production (npm run build
        // instead of npm run dev), minify
        production && terser()
    ],
    watch: {
        clearScreen: false
    }
};

postcss.config.js

module.exports = () => ({
    plugins: [require("tailwindcss")],
})

解决方案

1. 绑定radio状态到Store(核心修复)

问题根源是radio的checked属性未与Svelte Store同步,导致DOM中的单选框状态与实际选择不一致,进而使Tailwind的peer-checked选择器无法正确触发。修改代码,使用bind:checked将单选框状态与Store值关联:

<div class="flex justify-center mt-3 mb-2">
    <div class="inline-flex outline outline-neutral-100 rounded-md">
        <div>
            <input
                type="radio"
                name="radio"
                id="internato"
                class="sr-only peer"
                bind:checked={$spotTypeBeforeAPICall === spotTypes.INTERNATO}
                on:click={() => {
                    $spotTypeBeforeAPICall = spotTypes.INTERNATO;
                }}
            />
            <label
                for="internato"
                class="cursor-pointer inline-flex items-center py-2 px-3 text-base sm:text-lg peer-checked:bg-neutral-100 peer-checked:text-cyan-900 peer-checked:font-bold hover:font-bold"
            >
                IFE
            </label>
        </div>
        <div>
            <input
                type="radio"
                name="radio"
                id="iac"
                class="sr-only peer"
                bind:checked={$spotTypeBeforeAPICall === spotTypes.IAC}
                on:click={() => {
                    $spotTypeBeforeAPICall = spotTypes.IAC;
                }}
            />
            <label
                for="iac"
                class="cursor-pointer inline-flex items-center py-2 px-3 text-base sm:text-lg peer-checked:bg-neutral-100 peer-checked:text-cyan-900 peer-checked:font-bold hover:font-bold"
            >
                IAC
            </label>
        </div>
    </div>
</div>

2. 优化DOM结构(可选)

将单选框直接嵌套在label内,减少DOM层级,避免浏览器对兄弟选择器的解析差异:

<div class="flex justify-center mt-3 mb-2">
    <div class="inline-flex outline outline-neutral-100 rounded-md">
        <label class="cursor-pointer inline-flex items-center py-2 px-3 text-base sm:text-lg">
            <input
                type="radio"
                name="radio"
                class="sr-only peer"
                bind:checked={$spotTypeBeforeAPICall === spotTypes.INTERNATO}
                on:click={() => $spotTypeBeforeAPICall = spotTypes.INTERNATO}
            />
            <span class="peer-checked:bg-neutral-100 peer-checked:text-cyan-900 peer-checked:font-bold hover:font-bold">IFE</span>
        </label>
        <label class="cursor-pointer inline-flex items-center py-2 px-3 text-base sm:text-lg">
            <input
                type="radio"
                name="radio"
                class="sr-only peer"
                bind:checked={$spotTypeBeforeAPICall === spotTypes.IAC}
                on:click={() => $spotTypeBeforeAPICall = spotTypes.IAC}
            />
            <span class="peer-checked:bg-neutral-100 peer-checked:text-cyan-900 peer-checked:font-bold hover:font-bold">IAC</span>
        </label>
    </div>
</div>

3. 完善PostCSS配置确保兼容性

添加autoprefixer插件,确保生成的CSS兼容所有现代浏览器:

module.exports = () => ({
    plugins: [
        require("tailwindcss"),
        require("autoprefixer")
    ],
})

同时确保安装了最新版本的Tailwind CSS和PostCSS依赖:

npm install tailwindcss@latest postcss@latest autoprefixer@latest

验证步骤

  1. 重启开发服务器
  2. 清除浏览器缓存后重新测试
  3. 确认Chrome和Safari中选中选项的样式正常生效

内容的提问来源于stack exchange,提问作者Gustavo Morais

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 10:44:58