Como criar um tema sombrio e não prejudicar. Experiência em equipe do Yandex.Mail


Meu nome é Vladimir, estou envolvido em uma interface móvel no Yandex.Mail. Em nossa aplicação, já havia um tópico obscuro, mas não o suficiente: pudemos repintar a interface e letras simples. Mas as letras formatadas permaneciam claras e contrastavam com uma interface escura, o que podia cansar meus olhos à noite.


Hoje vou contar aos leitores da Habr como resolvemos esse problema. Você aprenderá sobre dois métodos simples que não nos convieram, então - sobre a nossa principal maneira de repintar adaptativamente as páginas e, finalmente, sobre a direção para a próxima iteração: repintar imagens. Embora a tarefa em si - repintar páginas com formatação arbitrária - seja específica, acho que nossa experiência será útil para você também.


Maneiras simples


Antes de chegarmos ao nosso mágico "repainter", testamos duas opções simples, como uma rolha: adicione um estilo escuro adicional ou filtro CSS ao elemento. Eles não nos agradaram, mas talvez, em alguns casos, sejam ainda melhores (porque é simplesmente = legal).


Substituir estilos


A maneira mais simples, expandindo logicamente o tema sombrio do aplicativo em CSS: penduraremos estilos escuros em um contêiner para cartas (no caso geral, para o conteúdo de outra pessoa que precise ser redesenhado):


.message--dark { background-color: black; color: white; } 

Mas se os elementos dentro da letra tiverem seus próprios estilos, eles redefinirão nosso estilo raiz. Não !important não vai ajudar. Você pode espremer uma idéia cortando a herança:


 .message--dark * { background-color: black !important; color: white !important; border-color: #333 !important; } 

Nesse caso, você não pode prescindir !important , porque o seletor em si não é muito específico. Além disso, será necessário redefinir os estilos inline (e os estilos inline com !important serão rastreados de qualquer maneira, não há nada a ser feito).


Nosso estilo é bastante desajeitado e as cores são iguais, então surge outro problema: provavelmente o designer quis dizer alguma coisa organizando as cores (prioridades dos elementos e outras coisas do designer), mas adotamos e descartamos toda essa ideia.



Se você respeita menos os designers do que eu, e ainda decide usar esse método, não se esqueça de terminar ninharias não óbvias:


  • box-shadow - apenas a cor não pode ser redefinida; você precisa remover todas as sombras ou conviver com as claras.
  • Cores dos elementos semânticos - links, elementos de entrada.
  • SVG embutido - em vez de background eles precisam definir fill e, em vez de color - stroke , mas isso não é preciso, dependendo de qual SVG - pode ser e vice-versa.

Tecnicamente, o método não é ruim: são três linhas de código (ok, trinta para a versão redi de produção com caixas de canto), compatibilidade com todos os navegadores do mundo, processamento de páginas dinâmicas prontas para uso e sem vinculação à maneira de conectar estilos no documento original. Um bônus especial é que você pode ajustar facilmente as cores no estilo para que elas se ajustem ao aplicativo principal (por exemplo, faça o plano de fundo #bbbbb8 vez de preto).


A propósito, costumávamos repintar as letras dessa maneira, mas se encontrássemos algum estilo na carta, ficávamos assustados e deixávamos a letra leve.


Filtro CSS


Opção muito espirituosa e elegante. Você pode redesenhar a página com um filtro CSS:


 .message--dark { filter: invert(100) hue-rotate(180deg); /* hue-rotate    */ } 

Depois disso, as fotos ficarão assustadoras, mas isso não importa - nós as pintaremos de volta:


 .message-dark img { filter: invert(100) hue-rotate(180deg); } 


Ainda há problemas com imagens de conteúdo vinculadas por background (sabemos que é mais conveniente ajustar a proporção, mas e a semântica?). Suponha que possamos encontrar todos esses elementos, marcá-los explicitamente e repintá-los de volta.


O método é bom, pois mantém a proporção original de brilho e contraste. Por outro lado, existem muitos problemas e eles superam as vantagens:



  1. Páginas escuras clareiam.
  2. As cores resultantes não podem ser controladas - qual filtro aplicar para ajustar o plano de fundo ao seu #bbbbb8 corporativo? O enigma.
  3. Após duas repinturas, as imagens desaparecem.
  4. Tudo fica mais lento (especialmente em telefones) - é lógico, agora, em vez de uma renderização simples, o navegador precisa direcionar o processamento de imagens em cada tela.

Esse método seria adequado para letras compostas de texto em tons neutros, mas quem são os estetas que obtêm uma caixa de entrada completa de conteúdo tão peculiar? Mas os filtros podem redesenhar elementos cujo conteúdo não é acessível - quadros, componentes da web, fotos.


Tema responsivo


Está na hora da mágica! A partir das deficiências das duas primeiras abordagens, coletamos uma lista de verificação:


  1. Faça o fundo escuro, o texto claro, as bordas médias.
  2. Identifique as páginas já escuras e não as repinte.
  3. Mantenha a proporção original de brilho e contraste.
  4. Dê a capacidade de personalizar cores.
  5. Deixe os tons como estavam no começo.

Precisamos mudar as cores dos estilos para que o fundo fique escuro. E por que não fazer isso literalmente? Nós apenas pegamos todos os estilos, procuramos as regras associadas às cores ( color , background , border , box-shadow suas subpropriedades) e substituímos por “escurecido” - escurece o fundo, clareia o texto, escurece as bordas menos que o fundo, etc.


Este método tem uma vantagem incrível que aquecerá a alma de qualquer desenvolvedor. Cada propriedade pode ser configurada (sim, descreva diretamente com um código!) Suas próprias regras para conversão de cores. Com imaginação suficiente, você pode integrar-se a qualquer tema externo, fazer qualquer correção de cor (por exemplo, criar framboesa clara ou cinza-marrom-marrom em vez de um tema escuro) e até adicionar um pouco de contexto - por exemplo, lidar com bordas amplas e estreitas de maneira diferente.


As desvantagens são padrão para tudo em js. Sim, executamos scripts, quebramos o encapsulamento de estilos e analisamos CSS regexp. Bem, diferentemente do HTML, o último não é tão vergonhoso porque a gramática CSS (do nível que precisamos) ainda é regular.


O plano de repintura é o seguinte:


  1. Normalizamos as propriedades herdadas do estilo ( bgcolor e amigos), mudamos para style="..." .
  2. Encontre todos os estilos em linha.
  3. Em cada estilo, encontramos todas as regras de cores ( background-color , color , box-shadow etc.).
  4. De todas as regras de cores, obtemos as cores, encontramos o conversor desejado (escurecedor para o fundo, clarificador para o texto).
  5. Nós chamamos o conversor.
  6. Colocando as regras convertidas novamente em CSS.

A ligação (normalização, pesquisa de estilo, análise) é bastante simples. Vamos descobrir como exatamente nosso conversor mágico funciona.


Conversões HSL


"Escurecer a cor" não é uma ação tão simples quanto pode parecer, especialmente se queremos manter o tom (o ciano fica azul escuro, não laranja). Isso pode ser feito em RGB normal, mas problemático. Os fãs de design algorítmico sabem que mesmo os gradientes são tortos. Mas trabalhar com cores no HSL é um prazer: em vez de vermelho, verde e azul, com os quais não está claro o que fazer, temos três outros canais:


  • Matiz é apenas o tom que queremos manter.
  • Saturaion - saturação, que não é muito importante para nós agora.
  • Luminosidade - o brilho que vamos mudar.

É conveniente imaginar esse espaço na forma de um cilindro. E nossa tarefa é virar esse cilindro de cabeça para baixo. As funções de classificação de cores fazem algo como (h, s, l) => [h, s, 1 - l] .


As cores com as quais tudo é bom


Às vezes a situação é bem-sucedida: o design exclusivo da carta (ou parte dela) já está escuro. Nesse caso, você não precisa alterar nada, é melhor ficar quieto - provavelmente o designer escolheu as cores não piores que o nosso algoritmo. No HSL, basta olhar para o brilho L. Se for maior (para texto) ou menor (para segundo plano) o limite (que, é claro, é personalizável), não fazemos nada.


Circo dinâmico


Embora não precisássemos disso (obrigado novamente, desinfetante, você me salvou da loucura!), Ainda vou lhe dizer que tipo de complementos um tema adaptativo precisa para escurecer as páginas inteiras, e não apenas as letras estáticas estúpidas dos anos 90. Mais precisamente, essa é uma tarefa para quem gosta do cheiro dos seletores pela manhã.


Estilos inline dinâmicos


O caso mais simples que quebra nossa página escura é a mudança de estilos embutidos. A operação é frequente, mas a correção é simples: adicione MutationObserver e repare rapidamente os estilos embutidos ao alterar.


Estilos externos


Trabalhar com estilos do <link> do lado de dentro da página é bastante doloroso devido à assincronia e ao @import , e o CORS não é mais divertido. Parece que esse problema pode ser resolvido com bastante elegância por meio de um trabalhador da Web (proxy para *.css ).


Estilos dinâmicos


Finalmente, reunindo todos os nossos problemas, lembramos que o script geralmente pode adicionar, excluir e reorganizar (especificidade! Cascade!) <style> e <link> , e até alterar as regras em <style> . Tudo é resolvido pelo mesmo MutationObserver para elementos de estilo, mas para cada alteração há mais processamento.


Variáveis ​​CSS


Uma nova rodada de loucura acontece quando variáveis ​​CSS entram no jogo. Não podemos obscurecer as próprias variáveis: mesmo se assumirmos que adivinharemos pelo formato que a variável contém cor (embora eu não o aconselho a fazer isso), não se sabe em que função ela nos encontrará - fundo, texto, borda, tudo de uma vez? Além disso, os valores das variáveis ​​são herdados, portanto, precisamos considerar não apenas os estilos, mas também os elementos aos quais elas são aplicadas, e tudo isso rapidamente aumenta e explode.


Se as variáveis ​​CSS chegarem ao mainstream, temos um problema. Por outro lado, a essa altura, color() já será iniciado, com o qual será possível não alterar as cores em JS, mas simplesmente substituí-las por color(var(--bg) lightness(-50%)) .


Sumário



No nosso caso, quando o desinfetante deixa apenas estilos embutidos, o escurecimento adaptável no nível CSS funciona bem: oferece a melhor qualidade de escurecimento, não quebra letras e funciona de forma relativamente rápida e fácil. Não tenho certeza se vale a pena a opção com todo o material para a dinâmica. Felizmente, se você trabalha com conteúdo gerado pelo usuário e não escreve um navegador, o seu desinfetante deve fazer o mesmo.


Na prática, o modo adaptativo deve ser usado junto com a redefinição de estilos: os estilos geralmente não são explicitamente aplicados a elementos padrão como <input> ou <a> , mas, por padrão, são leves.


Como escurecer imagens


Repintar fotos é uma questão separada que me incomoda pessoalmente. Isso é interessante e finalmente tenho a chance de usar a frase "análise espectral". Existem vários problemas comuns com fotos em objetos escuros.


Em primeiro lugar, as imagens são muito claras. Funciona da mesma maneira que as letras não pintadas com as quais tudo começou. Frequentemente (mas não necessariamente), essas são fotografias comuns. Como o layout dos boletins não é muito divertido, muitos caras simplesmente exportam a parte difícil da carta como uma imagem, ela não é redesenhada e à noite ilumina meu perfeccionismo. Tais imagens precisam ser escurecidas, mas não invertidas - caso contrário, um negativo terrível será revelado.



Em segundo lugar, imagens escuras com transparência real. Esse problema geralmente é encontrado nos logotipos - eles são projetados para um fundo claro e, quando o substituímos por um escuro, mesclamos com ele. Tais imagens precisam ser invertidas.



Em algum lugar no meio, há fotos nas quais o branco representava um "fundo transparente", mas agora elas ficam em algum estranho retângulo branco. Em um mundo ideal, substituiríamos um fundo branco por um transparente, mas se você já trabalhou com uma varinha mágica em um editor de fotos, sabe que fazer isso automaticamente não é tão fácil.



É interessante que, às vezes, as imagens não tenham nenhum significado - são pixels de rastreamento e "suportes de formato" em um layout particularmente perverso. Eles podem ser invisíveis com segurança (digamos, opacity: 0 ).



Heurísticas de introspecção


Para decidir o que fazer com a imagem, precisamos entrar e analisar seu conteúdo - e de maneira simples e rápida. De acordo com nosso conjunto de problemas, a primeira versão do algoritmo aparece. Lá está ela.


Consideramos pixels escuros, claros e transparentes na imagem, e não todos, mas seletivamente - otimização óbvia. Determinamos o brilho geral da imagem (claro, escuro, médio) e a presença de transparência. Inverta imagens escuras com transparência, luz sem transparência - mudo, não toque no resto.


A alegria dessa maravilhosa heurística terminou quando me deparei com um boletim de caridade com uma foto de uma lição em uma escola africana. Tudo ficaria bem, mas o designer a centralizou, adicionando pixels transparentes nas bordas. Não queríamos nos encontrar no centro de uma nova história sobre o reconhecimento ofensivo de fotos, e decidimos não fazer nenhum processamento de imagem na primeira versão.


No futuro, uma heurística adicional que eu chamo de “análise espectral” deve proteger contra esses problemas - contamos o número de cores diferentes na imagem e a invertemos apenas se houver poucas. O mesmo critério pode ser usado para procurar imagens com luz gráfica e repintá-las também - parece tentador.



Sumário


Para um tópico obscuro completo no correio, não tínhamos repintado as letras com estilos e descobrimos como organizá-lo. Duas opções simples em CSS puro - redefinir estilos e um filtro CSS - não funcionaram: a primeira é muito rígida no design original, a segunda simplesmente não funciona bem. Como resultado, usamos o escurecimento adaptável - analisamos estilos, substituímos cores por outras mais adequadas e as recuperamos. Agora, estamos trabalhando para expandir o tema em imagens - para isso, precisamos analisar o conteúdo e repintar apenas alguns.


Se você precisar repintar HTML personalizado para um tema sombrio, lembre-se de três métodos:


  • Substituindo estilos - você precisa, de qualquer maneira, para a sua aplicação principal, de forma barata e com raiva, mas mata todas as cores originais.
  • O filtro CSS é legal, mas funciona mais ou menos. Use apenas para elementos opacos (em termos de acesso), como quadros ou componentes da web.
  • Convertendo estilos - escurece uma qualidade muito alta, mas mais complicada do que outros métodos.

Mesmo que você nunca faça isso, espero que você tenha se divertido!


Links úteis :


  1. Se você estiver interessado em discutir esse tópico de maneira dinâmica e no contexto de desenvolvimento para Android, convidamos você a visitar o escritório da Yandex em Petersburgo em 18 de abril.


  2. Recentemente, conversamos sobre a solução de outro problema de usuários de email - problemas de email.


Source: https://habr.com/ru/post/pt446780/


All Articles