Como configurar esquemas de cores de aplicativos com propriedades personalizadas de CSS
Publicados: 2022-03-10As variáveis são uma ferramenta básica que ajuda a organizar as cores em um projeto. Por muito tempo, os engenheiros de front-end usaram variáveis de pré-processador para configurar cores em um projeto. Mas agora, muitos desenvolvedores preferem o mecanismo nativo moderno para organizar as variáveis de cor: CSS Custom Properties. Sua vantagem mais importante sobre as variáveis do pré-processador é que elas funcionam em tempo real, não na fase de compilação do projeto, e têm suporte para o modelo em cascata que permite usar herança e redefinição de valores em tempo real.
Ao tentar organizar um esquema de cores de aplicativo, você sempre pode colocar todas as propriedades personalizadas relacionadas à cor na seção raiz, nomeá-las e usá-las em todos os locais necessários.
Essa é uma opção, mas isso ajuda você a resolver problemas de temas de aplicativos, rótulos brancos, atualização de marca ou organização de um modo claro ou escuro? E se você precisar ajustar o esquema de cores para aumentar o contraste? Com a abordagem atual, você terá que atualizar cada valor em suas variáveis.
Neste artigo, quero sugerir uma abordagem mais flexível e resistente sobre como dividir variáveis de cores usando propriedades personalizadas, o que pode resolver muitos desses problemas.
Configurar paleta de cores
A coloração de qualquer site começa com a configuração de um esquema de cores. Tal esquema é baseado na roda de cores. Normalmente, apenas algumas cores primárias formam a base de uma paleta, o restante são cores derivadas – tons e tons médios. Na maioria das vezes, a paleta é estática e não muda enquanto o aplicativo da Web está em execução.
De acordo com a teoria das cores, existem apenas algumas opções para esquemas de cores:
- Esquema monocromático (uma cor primária)
- Esquema complementar (duas cores primárias)
- Esquema de tríade (três cores primárias)
- Esquema tetrádico (quatro cores primárias)
- Padrão adjacente (duas ou três cores primárias)
Para o meu exemplo, vou gerar um esquema de cores triad usando o serviço Paletton:
Agora tenho três cores principais. Com base nisso, vou calcular os tons e tons médios (o formato HSL em combinação com a função calc
é uma ferramenta muito útil para isso). Ao alterar o valor da luminosidade, posso gerar várias cores adicionais para a paleta.
Agora, se a paleta for modificada, será necessário alterar apenas o valor das cores primárias. O restante será recalculado automaticamente.
Se você preferir os formatos HEX ou RGB, não importa; uma paleta pode ser formada na fase de compilação do projeto com as funções correspondentes do pré-processador (por exemplo, com SCSS e a função color-adjust
). Como mencionei antes, essa camada é principalmente estática; é extremamente raro que a paleta possa ser alterada em um aplicativo em execução. É por isso que podemos calculá-lo com pré-processadores.
Nota : Eu recomendo também gerar literal HEX e RGB para cada cor. Isso permitirá jogar com o canal alfa no futuro.
O nível da paleta é o único nível onde a cor é codificada diretamente nos nomes das variáveis, ou seja, podemos identificar de forma única a cor lendo o nome.
Definir Tema ou Cores Funcionais
Feita a paleta, o próximo passo é o nível de cores funcionais . Nesse nível, o valor da cor não é tão importante quanto sua finalidade, a função que desempenha e o que exatamente colore. Por exemplo, a cor principal ou da marca do aplicativo, a cor da borda, a cor do texto em um plano de fundo escuro, a cor do texto em um plano de fundo claro, a cor do plano de fundo do botão, a cor do link, a cor do link ao passar o mouse, a cor do texto de dica e assim por diante .
Essas são coisas extremamente comuns para quase qualquer site ou aplicativo. Podemos dizer que tais cores são responsáveis por um determinado tema de cores do aplicativo. Além disso, os valores de tais variáveis são retirados estritamente da paleta. Assim, podemos alterar facilmente os temas do aplicativo simplesmente operando com diferentes paletas de cores.
Abaixo, criei três controles de interface do usuário típicos: um botão, um link e um campo de entrada. Eles são coloridos usando variáveis funcionais que contêm valores da paleta que gerei anteriormente. A principal variável funcional responsável pelo tema do aplicativo (marca condicional) é a variável de cor primária.
Usando os três botões na parte superior, você pode alternar os temas (alterar a cor da marca para os controles). A alteração ocorre usando a API CSSOM apropriada (setProperty).
Essa abordagem é conveniente não apenas para temas, mas também para configurar páginas da Web individuais. Por exemplo, no site zubry.by, usei uma folha de estilo comum e uma variável funcional --page-color
para colorir o logotipo, títulos, controles e seleção de texto para todas as páginas. E nos estilos próprios de cada página, apenas redefini essa variável para definir a página com sua cor primária individual.
Usar cores de componentes
Grandes projetos da web sempre contêm decomposição; dividimos tudo em pequenos componentes e os reutilizamos em muitos lugares. Cada componente geralmente tem seu próprio estilo, o que significa que não importa o que usamos para decompor os módulos BEM ou CSS, ou outra abordagem; é importante que cada pedaço de código possa ser chamado de escopo local e reutilizado.
Em geral, vejo sentido em usar variáveis de cor no nível do componente em dois casos.
A primeira é quando componentes que de acordo com o guia de estilo de aplicação são repetidos com configurações diferentes, por exemplo, botões para diferentes necessidades como botão primário (marca), botão secundário, terciário e assim por diante.
A segunda é quando componentes que possuem vários estados com cores diferentes, por exemplo, botão hover, estado ativo e estado de foco; estados normais e inválidos para campo de entrada ou seleção, e assim por diante.
Um caso mais raro em que variáveis de componentes podem ser úteis é a funcionalidade de um “white label”. O “white label” é um recurso de serviço que permite ao usuário personalizar ou marcar alguma parte da interface do usuário para melhorar a experiência de interação com seus clientes. Por exemplo, documentos eletrônicos que um usuário compartilha com seus clientes por meio de um serviço ou modelos de e-mail. Nesse caso, as variáveis no nível do componente ajudarão a configurar determinados componentes separadamente do restante do tema de cores do aplicativo.
No exemplo abaixo, agora adicionei controles para personalizar as cores do botão primário (marca). Usando variáveis de cor do nível do componente, podemos configurar os controles da interface do usuário separadamente uns dos outros.
Como determinar o nível de uma variável?
Me deparei com a questão de como entender o que pode ser colocado na raiz (tema ou nível funcional), e o que deixar no nível de um componente. Esta é uma excelente pergunta que é difícil de responder sem ver a situação com a qual você está trabalhando.
Infelizmente, a mesma abordagem da programação não funciona com cores e estilos, se vemos três partes idênticas de código, precisamos refatorá-lo.
A cor pode ser repetida de componente para componente, mas isso não significa que seja uma regra. Não pode haver relação entre tais componentes. Por exemplo, a borda do campo de entrada e o plano de fundo do botão principal. Sim, no meu exemplo acima esse é o caso, mas vamos verificar o seguinte exemplo:
A cor cinza escuro é repetida — essa é a borda do campo de entrada, a cor de preenchimento do ícone de fechamento e o plano de fundo do botão secundário. Mas esses componentes não estão de forma alguma conectados uns com os outros. Se a cor da borda do campo de entrada for alterada, não alteraremos o plano de fundo do botão secundário. Para tal caso devemos manter aqui apenas a variável da paleta.
E o verde? Podemos defini-lo claramente como a cor primária ou da marca, provavelmente, se a cor do botão principal mudar, a cor do link e do cabeçalho do primeiro nível também mudará.
E o vermelho? O estado inválido dos campos de entrada, mensagens de erro e os botões destrutivos terão a mesma cor em todo o nível do aplicativo. Este é um padrão. Agora posso definir várias variáveis funcionais comuns na seção raiz:
Em relação ao nível de cores dos componentes, podemos identificar facilmente os componentes que podem ser personalizados usando propriedades personalizadas.
O botão é repetido com configurações diferentes, a cor de fundo e o texto para diferentes casos de uso mudam - caso primário, secundário, terciário, destrutivo ou negativo.
O campo de entrada tem dois estados — incorreto e normal, onde as cores de fundo e de borda diferem. E assim, vamos colocar essas configurações em variáveis de cor no nível dos componentes correspondentes.
Para os demais componentes, não é necessário definir variáveis de cores locais, isso será redundante.
Você precisa mergulhar na linguagem de padrões do seu projeto, que provavelmente está sendo desenvolvido pela equipe de design e UX. Os engenheiros devem entender completamente todo o conceito de uma linguagem visual, só assim podemos determinar o que é comum e deve viver em um nível funcional, e o que deve permanecer no escopo local de visibilidade.
Mas nem tudo é tão complicado, há coisas óbvias. O plano de fundo geral da página, o plano de fundo e a cor do texto principal, na maioria dos casos, é isso que define o tema do seu aplicativo. É extremamente conveniente coletar essas coisas que são responsáveis pela configuração de um modo específico (como o modo escuro ou claro).
Por que não colocar tudo na seção raiz?
Eu tive uma experiência assim. No projeto Lition, a equipe e eu nos deparamos com o fato de que precisávamos oferecer suporte ao IE11 para o aplicativo da Web, mas não para o site e os desembarques. Um UI Kit comum foi usado entre os projetos, e decidimos colocar todas as variáveis na raiz, isso nos permitirá redefini-las em qualquer nível.
E também com essa abordagem para o aplicativo da Web e o caso do IE11, simplesmente passamos o código pelo plug-in de pós-processador a seguir e transformamos essas variáveis em literais para todos os componentes de interface do usuário no projeto. Este truque só é possível se todas as variáveis forem definidas na seção raiz porque o pós-processador não consegue entender as especificidades do modelo em cascata.
Agora eu entendo que este não era o caminho certo. Em primeiro lugar, se você colocar cores de componentes na seção raiz, quebrará o princípio da separação de interesses. Como resultado, você pode acabar com CSS redundante na folha de estilo. Por exemplo, você tem a pasta de componentes onde cada componente tem seus próprios estilos. Você também tem uma folha de estilo comum onde descreve as variáveis de cor na seção raiz. Você decide remover o componente de botão; neste caso, lembre-se de remover também as variáveis associadas ao botão do arquivo de estilos comuns.
Em segundo lugar, esta não é a melhor solução em termos de desempenho. Sim, uma mudança de cor causa apenas o processo de repintura, não de reflow/layout, isso por si só não é muito caro, mas quando você faz algumas alterações no nível mais alto, você usará mais recursos para verificar a árvore inteira do que quando estas as mudanças estão em uma pequena área local. Eu recomendo ler o benchmark de desempenho de variáveis CSS de Lisi Linhart para mais detalhes.
No meu projeto atual Tispr, a equipe e eu usamos split e não despejo tudo na raiz, no alto nível apenas uma paleta e cores funcionais. Além disso, não temos medo do IE11, porque esse problema é resolvido pelo polyfill correspondente. Basta instalar o módulo npm ie11-custom-properties e importar a biblioteca para o pacote JS do seu aplicativo:
// Use ES6 syntax import "ie11-custom-properties"; // or CommonJS require('ie11-custom-properties');
Ou adicione módulo por tag de script:
<script async src="./node_modules/ie11-custom-properties/ie11CustomProperties.js">
Além disso, você pode adicionar a biblioteca sem npm via CDN. O trabalho deste polyfill é baseado no fato de que o IE11 tem suporte mínimo para propriedades customizadas, onde as propriedades podem ser definidas e lidas com base na cascata. Isso não é possível com propriedades que começam com traços duplos, mas possivelmente com um único traço (o mecanismo semelhante aos prefixos do fornecedor). Você pode ler mais sobre isso na documentação do repositório, bem como se familiarizar com alguns limites. Outros navegadores irão ignorar este polyfill.
Abaixo está uma paleta do aplicativo da web Tispr, bem como os controles da funcionalidade “white label” para os documentos eletrônicos (como contratos de usuário, faturas ou propostas).
Por que não armazenar variáveis de cor no lado do JavaScript?
Outra pergunta razoável: por que não armazenar as variáveis de paleta e função no código JavaScript? Isso também pode ser alterado dinamicamente e as cores redefinidas posteriormente por meio de estilos embutidos. Isso pode ser uma opção, mas provavelmente essa abordagem seria menos ideal, pois você precisa ter acesso a determinados elementos e alterar suas propriedades de cor. Com variáveis CSS, você mudará apenas uma única propriedade, ou seja, o valor da variável.
Em JavaScript, não há funções nativas ou API para trabalhar com cores. No CSS Color Module 5, haverá muitas oportunidades para criar cores derivadas ou de alguma forma calculá-las. Da perspectiva do futuro, as propriedades personalizadas do CSS são mais ricas e flexíveis do que as variáveis do JS. Além disso, com variáveis JS, não haverá possibilidade de usar herança em cascata e essa é a principal desvantagem.
Conclusão
A divisão de cores em três níveis (paleta, funcional e componente) pode ajudá-lo a se adaptar melhor a mudanças e novos requisitos enquanto trabalha em um projeto. Acredito que CSS Custom Properties é a ferramenta certa para organizar a divisão de cores — não importa o que você usa para estilizar: CSS puro, pré-processadores ou abordagem CSS-in-JS.
Cheguei a essa abordagem por experiência própria, mas não estou sozinho. Sara Soueidan descreveu em seu artigo uma abordagem semelhante na qual ela dividia variáveis em níveis globais e de componentes.
Também gostaria de sugerir a leitura do artigo da Lea Verou onde ela descreve possíveis casos de aplicação de variáveis CSS (não apenas em termos de cor).