Uma visão geral básica de como estabelecer um esquema de cores dinâmico e configurável
Nesta postagem, quero compartilhar ideias sobre maneiras de gerenciar vários esquemas de cores no CSS. Teste a demonstração.
Se você preferir o vídeo, aqui está uma versão do YouTube desta postagem:
Visão geral
Vamos criar um sistema de cores acessível com propriedades personalizadas e calc()
para
crie uma página da Web que se adapte às preferências do usuário, mantendo a criação
experiência mínima. Começamos com uma cor de marca de base e criamos um sistema de
duas cores de texto, quatro cores de superfície e uma sombra correspondente.
Este guia começa com a definição de todas as cores para cada esquema de cores frente. Só no final é que eles são usados para mudar a página.
A marca
Muitas vezes, a cor de uma marca já foi estabelecida e é fornecida como
hex ou
rgb. Este desafio de GUI
tem uma cor de marca de base #0af
. Primeiro, para esse sistema de cores, o valor hexadecimal
precisa ser convertido em
hsl.
* {
--brand: #0af;
--brand: hsl(200 100% 50%);
}
Para ativar um conceito de escurecimento ou clareamento da cor da marca, digamos 20%, os três canais do valor de cor hsl precisam ser extraídos nas próprias propriedades personalizadas, como esta:
* {
--brand-hue: 200;
--brand-saturation: 100%;
--brand-lightness: 50%;
}
O CSS pode fazer cálculos matemáticos nessas propriedades de cor, por exemplo, calc(var(--brand-lightness) -
20%)
para diminuir o valor de brilho em 20%. Isso é fundamental para criar um
esquema de cores, já que o CSS pode manter todas as cores na mesma família de matiz ajustando a
saturação e a luminosidade do HSL.
Tema claro
Cada variante de cor será marcada com o esquema correspondente.
é anexado com -light
.
Marca
Começando com a cor da marca, ela é recriada envolvendo as propriedades personalizadas --brand-hue
, --brand-saturation
e --brand-lightness
dentro dos parênteses da função hsl ()
,
sem cálculos:
* {
--brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
}
Cores do texto
Em seguida, os elementos essenciais de um esquema de cores precisam de cores de texto. Em um tema claro, o texto deve ser muito escuro. Observe como o brilho das seguintes cores é baixo, bem abaixo de 50%.
* {
--text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
--text2-light: hsl(var(--brand-hue) 30% 30%);
}
--text1-light
, por ser muito escuro com 10% de luminosidade, mantém a saturação de 100%
para que a cor da marca ainda apareça no azul-marinho escuro.
--text2-light
, não é tão escura quanto a primeira cor, o que é bom, já que é
uma cor secundária e também é muito menos saturada.
Cores da superfície
As cores da superfície são os planos de fundo, bordas e outras superfícies decorativas que o texto fica sobre ou dentro dele. Em um tema claro, essas são as cores claras, em oposição às cores de texto, que eram escuras. Para criar cores claras com hsl, vamos usar valores percentuais mais altos no terceiro valor de iluminação. Também vamos diminuir a saturação para que os cinzas claros não fiquem muito saturados.
* {
--surface1-light: hsl(var(--brand-hue) 25% 90%);
--surface2-light: hsl(var(--brand-hue) 20% 99%);
--surface3-light: hsl(var(--brand-hue) 20% 92%);
--surface4-light: hsl(var(--brand-hue) 20% 85%);
}
Quatro cores de superfície foram criadas, já que cores decorativas tendem a precisar de mais
variantes, para momentos interativos como :focus
ou :hover
, ou para criar a
a aparência das camadas de papel. Nesses cenários, é bom fazer a transição
--surface2-light
ao passar o cursor para --surface3-light
, portanto, passar o cursor resulta em uma
aumento do contraste (99% de claridade para 92% de claridade, tornando-o mais escuro).
Sombras
Sombras dentro de um esquema de cores estão acima e além, mas adicionam uma natureza realista ao o efeito e ajudá-lo a se destacar de sombras pretas irrealistas. Para fazer isso, a cor da sombra vai usar a propriedade personalizada de matiz, ser levemente saturada com o matiz, mas ainda muito escura. Basicamente, criando uma sombra ligeiramente azul e muito escura.
* {
--surface-shadow-light: var(--brand-hue) 10% 20%;
--shadow-strength-light: .02;
}
--surface-shadow-light
não está encapsulado em uma função hsl. Isso ocorre porque o
O valor --shadow-strength
será combinado para criar alguma opacidade, e o CSS precisa
as peças para realizar cálculos. Vá direto para a sombra radical
para saber mais.
Cores claras todas juntas
Não é preciso procurar para descobrir como as cores claras são feitas. Elas estão todas em um só lugar no CSS.
* {
--brand-light: hsl(var(--brand-hue) var(--brand-saturation) var(--brand-lightness));
--text1-light: hsl(var(--brand-hue) var(--brand-saturation) 10%);
--text2-light: hsl(var(--brand-hue) 30% 30%);
--surface1-light: hsl(var(--brand-hue) 25% 90%);
--surface2-light: hsl(var(--brand-hue) 20% 99%);
--surface3-light: hsl(var(--brand-hue) 20% 92%);
--surface4-light: hsl(var(--brand-hue) 20% 85%);
--surface-shadow-light: var(--brand-hue) 10% calc(var(--brand-lightness) / 5);
--shadow-strength-light: .02;
}
Tema escuro
A maioria das marcas não começa com um tema escuro, é uma variante do tema principal, geralmente mais claro. Os usuários, por outro lado, geralmente escolhem um tema escuro para contextos diferentes, como a noite. Esses fatores me fizeram manter duas coisas em mente com os temas escuros:
- Os usuários geralmente ficam no escuro ao usar esse tema, então teste no escurecer.
- As cores precisam ser desaturadas para não vibrarem na tela por serem muito intensas.
Marca
O tema claro usou os 3 valores dos canais de cor HDR da marca sem alteração, o tema escuro não. A saturação é reduzida pela metade e o brilho, em cerca de 50%.
* {
--brand-dark: hsl(
var(--brand-hue)
calc(var(--brand-saturation) / 2)
calc(var(--brand-lightness) / 1.5)
);
}
Cores do texto
Em um tema escuro, as cores do texto precisam ser claras. As cores a seguir têm alto valores de claridade, colocando-os mais próximos do branco.
* {
--text1-dark: hsl(var(--brand-hue) 15% 85%);
--text2-dark: hsl(var(--brand-hue) 5% 65%);
}
Cores da superfície
Em um tema escuro, as cores da superfície precisam ser escuras. As cores a seguir têm pouca luminosidade e saturação, sendo que a 1a superfície é a mais escura a 10%.
* {
--surface1-dark: hsl(var(--brand-hue) 10% 10%);
--surface2-dark: hsl(var(--brand-hue) 10% 15%);
--surface3-dark: hsl(var(--brand-hue) 5% 20%);
--surface4-dark: hsl(var(--brand-hue) 5% 25%);
}
Sombras
Em um tema escuro, as sombras podem ser muito difíceis de ver. Faz sentido, já que é difícil
escurecer algo que já é bastante escuro. É aqui que
--shadow-strength-dark
é muito útil, porque permite escurecer as
sombras mudando uma variável.
* {
--surface-shadow-dark: var(--brand-hue) 50% 3%;
--shadow-strength-dark: .8;
}
Além disso, observe a saturação dessa sombra. Consegue notar a cor quando você está olhando para a interface? Tente remover a saturação do DevTools, qual você prefere?!
Cores escuras todas juntas
* {
--brand-dark: hsl(var(--brand-hue) calc(var(--brand-saturation) / 2) calc(var(--brand-lightness) / 1.5));
--text1-dark: hsl(var(--brand-hue) 15% 85%);
--text2-dark: hsl(var(--brand-hue) 5% 65%);
--surface1-dark: hsl(var(--brand-hue) 10% 10%);
--surface2-dark: hsl(var(--brand-hue) 10% 15%);
--surface3-dark: hsl(var(--brand-hue) 5% 20%);
--surface4-dark: hsl(var(--brand-hue) 5% 25%);
--surface-shadow-dark: var(--brand-hue) 50% 3%;
--shadow-strength-dark: .8;
}
Tema escuro
Esse esquema de cores é sobre orquestrar a luminosidade e a saturação. deve haver saturação suficiente para ainda ter uma matiz visível, mas também apenas passam as pontuações de contraste, já que é devem ser escuros e de baixo contraste.
Marca
* {
--brand-dim: hsl(
var(--brand-hue)
calc(var(--brand-saturation) / 1.25)
calc(var(--brand-lightness) / 1.25)
);
}
Cores do texto
* {
--text1-dim: hsl(var(--brand-hue) 15% 75%);
--text2-dim: hsl(var(--brand-hue) 10% 61%);
}
Cores da superfície
* {
--surface1-dim: hsl(var(--brand-hue) 10% 20%);
--surface2-dim: hsl(var(--brand-hue) 10% 25%);
--surface3-dim: hsl(var(--brand-hue) 5% 30%);
--surface4-dim: hsl(var(--brand-hue) 5% 35%);
}
Sombras
* {
--surface-shadow-dim: var(--brand-hue) 30% 13%;
--shadow-strength-dim: .2;
}
Escurecer todas as cores
* {
--brand-dim: hsl(var(--brand-hue) calc(var(--brand-saturation) / 1.25) calc(var(--brand-lightness) / 1.25));
--text1-dim: hsl(var(--brand-hue) 15% 75%);
--text2-dim: hsl(var(--brand-hue) 10% 61%);
--surface1-dim: hsl(var(--brand-hue) 10% 20%);
--surface2-dim: hsl(var(--brand-hue) 10% 25%);
--surface3-dim: hsl(var(--brand-hue) 5% 30%);
--surface4-dim: hsl(var(--brand-hue) 5% 35%);
--surface-shadow-dim: var(--brand-hue) 30% 13%;
--shadow-strength-dim: .2;
}
Cores acessíveis
Observe como a menor luminosidade no conjunto de cores de texto escuro é de 65% e a maior luminosidade nas superfícies escuras é de 25%. Isso é 40% de espaço entre elas. No tema claro, há 55% de espaço o tema claro. Manter as diferenças de luminosidade entre o texto e as cores da superfície em cerca de 40 a 50% pode ajudar a manter as taxas de contraste de cores altas, além de ser uma variável sutil para ajustar caso as pontuações sejam baixas.
Eu chamo isso de "bump bump til ya pass", que é a interação de bater no lightness até que uma ferramenta mostre que passei.
Cada um dos temas criados neste desafio passou nas pontuações de contraste. O esquema de cores escuras tem o menor contraste, mas ainda atende aos requisitos mínimos. Para ajudar os outros membros da equipe a usar cores contrastantes, é uma boa ideia criar um nome de classe que combine uma cor de superfície com uma cor de texto acessível.
.surface1 {
background-color: var(--surface1);
color: var(--text2);
}
.surface2 {
background-color: var(--surface2);
color: var(--text2);
}
.surface3 {
background-color: var(--surface3);
color: var(--text1);
}
.surface4 {
background-color: var(--surface4);
color: var(--text1);
}
Sombra radical
Os temas usam uma classe de utilitário chamada .rad-shadow
. Essa sombra foi gerada
na ferramenta Sombra suave, que eu adoro. Peguei o snippet gerado e o personalizei com minhas próprias cores e
cálculos de opacidade. O motivo disso foi criar uma sombra que pudesse ser ajustada
em cada esquema de cores.
Para isso, criei duas variáveis para cada esquema de cores, uma cor de sombra e uma intensidade de sombra. A cor é para ajustes de saturação e escuridão, enquanto a intensidade é uma maneira fácil de aumentar a intensidade da sombra quando se trata de um esquema de cores escuras. O resultado final ficou assim.
:root {
--surface-shadow-light: var(--brand-hue) 10% 20%;
--shadow-strength-light: .02;
}
.rad-shadow {
box-shadow:
0 2.8px 2.2px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
0 6.7px 5.3px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .01)),
0 12.5px 10px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
0 22.3px 17.9px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .02)),
0 41.8px 33.4px hsl(var(--surface-shadow) / calc(var(--shadow-strength) + .03)),
0 100px 80px hsl(var(--surface-shadow) / var(--shadow-strength))
;
}
Se eu fosse mais longe com as sombras no meu esquema de cores, também faria com que os ângulos de sombra fossem um token de design constante, já que a direção da luz precisa ser a mesma entre todas as sombras do design.
Uso dos esquemas de cores
Com a pré-definição de cores concluída, é hora de transformá-las em propriedades independentes do esquema. Quero dizer que, como autor de CSS dentro deste projeto de esquema de cores, raramente é necessário acessar o valor de um esquema de cores específico. Quero facilitar a criação de conteúdo relacionado ao tema.
Para isso, o esquema de cores precisa ser usado exclusivamente pelas
propriedades personalizadas genéricas, que vamos definir em breve. Dessa forma,
as pessoas que usam as variáveis de design nunca precisam se preocupar com qual esquema de cores está
definido no momento, elas só precisam usar as cores da superfície e do texto. Em vez de
color: var(--text1-light)
, use color: var(--text1)
. Todas as adaptações e mudanças
de cores são feitas em um nível muito mais alto no CSS.
Os estilos de conexão do tema claro no bloco de código a seguir
conectam uma propriedade personalizada genérica com a cor específica do tema claro. Agora, todos
os usos de var(--brand)
vão usar a cor clara da marca.
Tema claro (automático)
:root {
color-scheme: light;
--brand: var(--brand-light);
--text1: var(--text1-light);
--text2: var(--text2-light);
--surface1: var(--surface1-light);
--surface2: var(--surface2-light);
--surface3: var(--surface3-light);
--surface4: var(--surface4-light);
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
}
O site está usando o tema claro. Este é um momento muito divertido de sucesso! Vamos ter mais alguns desses momentos à medida que usamos nossas cores predefinidas em outros contextos de esquema de cores.
Tema escuro (automático)
@media (prefers-color-scheme: dark) {
:root {
color-scheme: dark;
--brand: var(--brand-dark);
--text1: var(--text1-dark);
--text2: var(--text2-dark);
--surface1: var(--surface1-dark);
--surface2: var(--surface2-dark);
--surface3: var(--surface3-dark);
--surface4: var(--surface4-dark);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
}
}
Tema claro
[color-scheme="light"] {
color-scheme: light;
--brand: var(--brand-light);
--text1: var(--text1-light);
--text2: var(--text2-light);
--surface1: var(--surface1-light);
--surface2: var(--surface2-light);
--surface3: var(--surface3-light);
--surface4: var(--surface4-light);
--surface-shadow: var(--surface-shadow-light);
--shadow-strength: var(--shadow-strength-light);
}
Tema escuro
[color-scheme="dark"] {
color-scheme: dark;
--brand: var(--brand-dark);
--text1: var(--text1-dark);
--text2: var(--text2-dark);
--surface1: var(--surface1-dark);
--surface2: var(--surface2-dark);
--surface3: var(--surface3-dark);
--surface4: var(--surface4-dark);
--surface-shadow: var(--surface-shadow-dark);
--shadow-strength: var(--shadow-strength-dark);
}
Escurecer tema
[color-scheme="dim"] {
color-scheme: dark;
--brand: var(--brand-dim);
--text1: var(--text1-dim);
--text2: var(--text2-dim);
--surface1: var(--surface1-dim);
--surface2: var(--surface2-dim);
--surface3: var(--surface3-dim);
--surface4: var(--surface4-dim);
--surface-shadow: var(--surface-shadow-dim);
--shadow-strength: var(--shadow-strength-dim);
}
Nesse ponto, os autores podem usar os genéricos de esquema de cores fornecidos conforme necessário e não precisam se preocupar com temas novamente.
Conclusão
Agora que você sabe como eu fiz, como você faria? 🙂
Vamos diversificar nossas abordagens e aprender todas as maneiras de criar na Web. Crie um Codepen ou hospede sua própria demonstração, envie um tweet para mim e eu a adicionarei ao seção "Remixes da comunidade" abaixo.
Origem
Remixes da comunidade
- @chris-kruining adicionou um controle deslizante de matiz
cores de status e modos de contraste para no-preference
, more
e less
:
demonstração.