Historicamente, tem sido difícil personalizar elementos de formulário HTML padrão, como caixas de seleção e botões de opção. Os desenvolvedores geralmente precisavam escolher entre usar os padrões do navegador ou criar componentes personalizados do zero. Criar controles personalizados é demorado e pode facilmente levar a problemas de acessibilidade ou estados ausentes (como o estado indeterminado para caixas de seleção).
A propriedade CSS accent-color oferece uma maneira simples de aplicar a cor da sua marca às entradas de formulário HTML integradas com uma única linha de CSS, sem sacrificar a acessibilidade ou os recursos integrados do navegador.
Como implementar
Para aplicar a cor da sua marca aos controles de formulário:
- Identifique a cor da sua marca: escolha uma cor que represente sua marca.
- Aplique a propriedade
accent-color: adicioneaccent-colorao elemento ou a um elemento de contêiner (comobodyou um formulário específico) no CSS. - Suporte ao modo escuro (opcional, mas recomendado): use
color-schemepara informar ao navegador que seu site é compatível com o modo escuro e ajuste oaccent-color, se necessário, para melhorar o contraste.
Exemplo de código: controles de formulário consistentes com a marca
:root {
--brand-color: #6200ee;
}
/* Apply accent-color to the body or a specific container */
body {
accent-color: var(--brand-color);
}
/* Optional: Adjust for dark mode if needed */
@media (prefers-color-scheme: dark) {
:root {
--brand-color: #bb86fc; /* A lighter shade for dark mode */
}
}
<form>
<!-- Checkbox -->
<label for="subscribe">
<input type="checkbox" id="subscribe" checked>
Subscribe to newsletter
</label>
<!-- Radio Buttons -->
<label for="plan-monthly">
<input type="radio" id="plan-monthly" name="plan" value="monthly">
Monthly
</label>
<label for="plan-yearly">
<input type="radio" id="plan-yearly" name="plan" value="yearly" checked>
Yearly
</label>
<!-- Range Slider -->
<label for="volume">Volume:</label>
<input type="range" id="volume" min="0" max="100" value="70">
<!-- Progress Bar -->
<label for="file">Upload Progress:</label>
<progress id="file" max="100" value="70">70%</progress>
</form>
Implementação estratégica e práticas recomendadas
- USE
accent-colorpara personalizar facilmente os controles de formulário de acordo com sua marca. - NÃO confie cegamente no navegador para lidar com o contraste. Embora os navegadores devam determinar automaticamente uma cor de contraste qualificada, bugs conhecidos em implementações como o Safari (bug 244233 do WebKit) e o Chrome para Android (bug 343503163 do Chromium) podem falhar ao inverter as cores da marca de seleção, resultando em controles invisíveis ou difíceis de ver ao usar cores que não têm contraste suficiente com o plano de fundo (por exemplo, cores claras no modo claro ou cores escuras no modo escuro).
- FAÇA a combinação de
accent-colorcomcolor-scheme: light darkpara garantir que os controles de formulário fiquem bons nos temas claro e escuro. - NÃO use uma cor muito próxima à do plano de fundo. Embora os navegadores tentem garantir o contraste, é melhor fornecer uma cor com um bom contraste de base.
- NÃO presuma que
accent-colorfunciona em todos os elementos de formulário. No momento, ele só colore os elementoscheckbox,radio,rangeeprogress.
Estratégia de fallback
Para navegadores que não oferecem suporte a accent-color, os controles de formulário voltam à aparência padrão do navegador. Para garantir a consistência total da marca e alta confiabilidade em todos os ambientes, você PRECISA implementar uma estratégia de substituição personalizada usando a técnica estabelecida de "entrada visualmente oculta".
Aprimoramento progressivo com @supports not
É OBRIGATÓRIO usar a regra @supports not para aplicar estilos substitutos personalizados somente quando accent-color não for compatível. Isso garante que você aproveite a simplicidade do accent-color para navegadores mais recentes, além de uma experiência de marca consistente para os mais antigos.
1. Estrutura HTML
Verifique se os rótulos envolvem o texto em um <span> para permitir seletores irmãos em CSS:
<label for="subscribe-fallback">
<input type="checkbox" id="subscribe-fallback" class="visually-hidden" checked>
<span>Subscribe to newsletter</span>
</label>
2. CSS substituto
Aplique estilos personalizados em um bloco @supports not:
/* Fallback for older browsers without accent-color */
@supports not (accent-color: var(--brand-color)) {
/* Visually hide the native input using the canonical accessible recipe */
form input[type="checkbox"].visually-hidden {
position: absolute !important;
clip-path: inset(50%) !important;
overflow: hidden !important;
width: 1px !important;
height: 1px !important;
margin: -1px !important;
padding: 0 !important;
border: 0 !important;
white-space: nowrap !important;
}
/* Style the wrapper label */
label {
position: relative;
padding-left: 2rem;
cursor: pointer;
display: inline-flex;
align-items: center;
}
/* Custom box for checkbox */
input[type="checkbox"] + span::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 1.2rem;
height: 1.2rem;
border: 2px solid #ccc;
background: white;
border-radius: 4px;
box-sizing: border-box;
transition: all 0.2s ease;
}
/* Ensure custom checkbox shows focus for keyboard users */
input[type="checkbox"]:focus-visible + span::before {
outline: 2px solid #000;
outline-offset: 2px;
}
/* Checked State */
input[type="checkbox"]:checked + span::before {
background-color: var(--brand-color, #6200ee);
border-color: var(--brand-color, #6200ee);
}
/* Checkmark (Unicode) */
input[type="checkbox"]:checked + span::after {
content: "✓";
position: absolute;
left: 0.25rem;
top: 50%;
transform: translateY(-50%);
color: white;
font-weight: bold;
font-size: 0.9rem;
}
/* Fallback for Range Slider */
input[type="range"] {
-webkit-appearance: none;
appearance: none;
background: transparent;
}
/* Webkit (Chrome, Safari, Edge) */
input[type="range"]::-webkit-slider-runnable-track {
width: 100%;
height: 8px;
/* Use gradient to show progress for a static value (e.g., 70%) or update with JS */
background: linear-gradient(to right, var(--brand-color, #6200ee) 70%, #ccc 70%);
border-radius: 4px;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
height: 16px;
width: 16px;
border-radius: 50%;
background: var(--brand-color, #6200ee);
cursor: pointer;
margin-top: -4px; /* Center vertically */
}
/* Firefox */
input[type="range"]::-moz-range-track {
width: 100%;
height: 8px;
background: #ccc;
border-radius: 4px;
}
input[type="range"]::-moz-range-thumb {
height: 16px;
width: 16px;
border-radius: 50%;
background: var(--brand-color, #6200ee);
cursor: pointer;
}
/* Firefox specific progress bar */
input[type="range"]::-moz-range-progress {
background-color: var(--brand-color, #6200ee);
height: 8px;
border-radius: 4px;
}
/* Fallback for Progress Bar */
progress {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border: none;
background: #ccc;
height: 8px;
border-radius: 4px;
}
progress::-webkit-progress-bar {
background-color: #ccc;
border-radius: 4px;
}
progress::-webkit-progress-value {
background-color: var(--brand-color, #6200ee);
border-radius: 4px;
}
progress::-moz-progress-bar {
background-color: var(--brand-color, #6200ee);
border-radius: 4px;
}
}
Progresso do intervalo dinâmico no substituto do Webkit
Para fazer com que o preenchimento de progresso se mova com o controle deslizante em um controle deslizante de intervalo em navegadores Webkit (sem accent-color), use uma variável CSS e uma pequena quantidade de JavaScript.
Atualize o CSS: use uma variável CSS para o ponto de gradiente:
input[type="range"]::-webkit-slider-runnable-track { background: linear-gradient(to right, var(--brand-color) var(--progress, 0%), #ccc var(--progress, 0%)); }Adicionar JavaScript: atualize a variável no evento
input:
if (!CSS.supports('accent-color')) {
const slider = document.getElementById('volume');
slider.addEventListener('input', (e) => {
e.target.style.setProperty('--progress', `${e.target.value}%`);
});
}