Recursos de estilo da Web atuais e futuros, como vimos no Google IO 2022, além de alguns extras.
O ano de 2022 será um dos melhores para o CSS, tanto em recursos quanto em lançamentos de recursos de navegador cooperativo, com uma meta colaborativa de implementar 14 recursos.
Visão geral
Esta postagem é o artigo da palestra apresentada no Google IO 2022. O objetivo não é ser um guia aprofundado sobre cada recurso, mas uma introdução e uma breve visão geral para despertar seu interesse, fornecendo amplitude em vez de profundidade. Se você tiver interesse, confira no final de uma seção os links de recursos para mais informações.
Índice
Use a lista abaixo para acessar os tópicos de interesse:
Compatibilidade com navegadores
Um dos principais motivos para tantos recursos do CSS serem definidos para lançamento cooperativo é devido aos esforços da Interop 2022. Antes de estudar os esforços de interoperabilidade, é importante analisar os esforços da Compat 2021.
Compatibilidade 2021
As metas para 2021, impulsionadas pelo feedback dos desenvolvedores via pesquisas, eram estabilizar os recursos atuais, melhorar o pacote de testes e aumentar a pontuação de aprovação dos navegadores em cinco recursos:
- Posicionamento de
sticky
- Dimensionamento de
aspect-ratio
- Layout do
flex
- Layout do
grid
- Posicionamento e animação
transform
As pontuações dos testes foram aumentadas em todos os aspectos, demonstrando maior estabilidade e confiabilidade. Parabéns às equipes!
Interop 2022
Este ano, os navegadores se reuniram para discutir os recursos e as prioridades em que pretendiam trabalhar, unindo os esforços. Eles planejavam oferecer os seguintes recursos da Web para desenvolvedores:
@layer
- Espaços de cor e funções
- Contenção
<dialog>
- Compatibilidade do formulário
- Rolagem
- Subgrade
- Tipografia
- Unidades de janela de visualização
- Compatibilidade com a Web
Esta é uma lista empolgante e ambiciosa que mal posso esperar para ver se desenrolar.
Novidades para 2022
Não é surpresa que o estado do CSS 2022 seja drasticamente afetado pelo trabalho de interoperabilidade 2022.
Camadas em cascata
Antes da @layer
, a ordem descoberta das folhas de estilo carregadas era muito importante,
porque os estilos carregados por último podiam substituir os estilos carregados anteriormente. Isso levou a
folhas de estilo de entrada gerenciadas meticulosamente, em que os desenvolvedores precisavam carregar os estilos menos
importantes primeiro e os mais importantes depois. Existem metodologias
inteiras para ajudar os desenvolvedores a gerenciar essa importância, como o
ITCSS.
Com @layer
, o arquivo de entrada pode pré-definir camadas e a ordem delas com
antecedência. Em seguida, à medida que os estilos são carregados ou definidos, eles podem ser colocados dentro de uma
camada, permitindo a preservação da importância da substituição de estilo, mas sem a
orquestração de carregamento meticulosamente gerenciada.
O vídeo mostra como as camadas de cascata definidas permitem um processo de criação e carregamento mais livre e livre, mantendo a cascata conforme necessário.
O Chrome DevTools é útil para visualizar quais estilos vêm de quais camadas:
Recursos
- Especificação do CSS Cascade 5
- Explicação das camadas em cascata
- Camadas em cascata no MDN
- Una Kravets: camadas em cascata
- Ahmad Shadeed: Olá, camadas em cascata do CSS
Subgrade
Antes da subgrid
, uma grade dentro de outra não podia se alinhar às
células ou linhas de grade principais. Cada layout de grade era único. Muitos designers colocam uma
grade única sobre todo o design e alinham constantemente os itens nela, o que
não pode ser feito no CSS.
Depois de subgrid
, uma filha de uma grade pode adotar as colunas ou linhas das mães como
próprias e se alinhar a elas ou às filhas.
Na demonstração a seguir, o elemento "body" cria uma grade clássica de três colunas:
a coluna do meio é chamada de main
e as colunas esquerda e direita nomeam suas
linhas
fullbleed
. Em seguida, cada elemento no corpo, <nav>
e <main>
, adota as
linhas nomeadas do corpo definindo grid-template-columns: subgrid
.
body {
display: grid;
grid-template-columns:
[fullbleed-start]
auto [main-start] min(90%, 60ch) [main-end] auto
[fullbleed-end]
;
}
body > * {
display: grid;
grid-template-columns: subgrid;
}
Por fim, os filhos de <nav>
ou <main>
podem se alinhar ou dimensionar usando as
colunas e linhas fullbleed
e main
.
.main-content {
grid-column: main;
}
.fullbleed {
grid-column: fullbleed;
}
O Devtools pode ajudar você a ver as linhas e subgrades (apenas Firefox no momento). Na imagem a seguir, a grade principal e as subgrades foram sobrepostas. Agora, lembra como os designers estavam pensando sobre o layout.
No painel de elementos do DevTools, é possível ver quais elementos são grades e subgrades, o que é muito útil para depurar ou validar o layout.
Recursos
Consultas em contêiner
Antes de @container
, os elementos de uma página da Web só podiam responder ao tamanho de
toda a viewport. Isso é ótimo para layouts macro, mas para micro layouts, em que
o contêiner externo não é a janela de visualização inteira, é impossível que o layout
se ajuste adequadamente.
Depois de @container
, os elementos podem responder a um tamanho ou estilo de contêiner pai.
A única ressalva é que os contêineres precisam se declarar como possíveis destinos de consulta, o que é um pequeno requisito para um grande benefício.
/* establish a container */
.day {
container-type: inline-size;
container-name: calendar-day;
}
Esses estilos fazem com que as colunas Seg, Ter, Qua, Qui e Sex no vídeo abaixo possam ser consultadas pelos elementos do evento.
Este é o CSS para consultar o tamanho do contêiner calendar-day
e ajustar os tamanhos de uma fonte e de um layout:
@container calendar-day (max-width: 200px) {
.date {
display: block;
}
.date-num {
font-size: 2.5rem;
display: block;
}
}
Confira outro exemplo: um componente de livro se adapta ao espaço disponível na coluna para onde é arrastado:
Una está correta ao avaliar a situação como o novo
responsivo. Há
muitas decisões de design interessantes e significativas a serem tomadas ao usar
@container
.
Recursos
- Especificação das consultas de contêiner
- Explicação sobre as consultas de contêiner
- Consultas de contêiner no MDN
- O novo responsivo no web.dev
- Demonstração do Google Agenda por Una
- Coleção de consultas de contêineres do Awesome
- Como criamos o Designcember no web.dev
- Ahmad Shadeed: Conheça as consultas de contêineres do CSS
accent-color
Antes do accent-color
, quando você queria um formulário com cores correspondentes à marca,
você podia acabar com bibliotecas complexas ou soluções CSS que se tornaram difíceis de gerenciar
com o tempo. Embora eles tenham oferecido todas as opções e, esperançosamente, incluído
acessibilidade, a escolha de usar os componentes integrados ou adotar os próprios
se torna tediosa.
Depois de accent-color
, uma linha de CSS traz uma cor de marca para os componentes
integrados. Além de uma tonalidade, o navegador escolhe de forma inteligente as cores
contrastantes adequadas para partes secundárias do componente e se adapta aos esquemas
de cores do sistema (claro ou escuro).
/* tint everything */
:root {
accent-color: hotpink;
}
/* tint one element */
progress {
accent-color: indigo;
}
Para saber mais sobre accent-color
, confira minha postagem no
web.dev, em que falo sobre muitos outros aspectos
dessa propriedade útil do CSS.
Recursos
- especificação acent-color (link em inglês)
- accent-color no MDN
- accent-color no web.dev
- Bramus: Tint User-Interface Controls with CSS accent-color
Nível de cor 4 e 5
A Web foi dominada pelo sRGB nas últimas décadas, mas, em um mundo digital em expansão de telas de alta definição e dispositivos móveis pré-equipados com telas OLED ou QLED, o sRGB não é suficiente. Além disso, páginas dinâmicas que se adaptam às preferências do usuário são esperadas, e o gerenciamento de cores tem sido uma preocupação cada vez maior para designers, sistemas de design e mantenedores de código.
Mas não em 2022. O CSS tem várias novas funções e espaços de cores: - Cores que alcançam os recursos de cores HD das telas. - Espaços de cores que correspondem a uma intent, como uniformidade perceptiva. - Espaços de cor para gradientes que alteram drasticamente os resultados da interpolação. - Funções de cor para ajudar a misturar e contrastar e escolher em qual espaço você vai trabalhar.
Antes de todos esses recursos de cores, os sistemas de design precisavam pré-calcular as cores de contraste adequadas e garantir paletas vibrantes adequadamente, enquanto os pré-processadores ou o JavaScript faziam o trabalho pesado.
Depois de todos esses recursos de cor, o navegador e o CSS podem fazer todo o trabalho, de forma dinâmica e no momento certo. Em vez de enviar muitos KBs de CSS e JavaScript para os usuários ativar a aplicação de temas e as cores de visualização de dados, o CSS pode fazer a orquestração e os cálculos. O CSS também está mais bem equipado para verificar o suporte antes do uso ou lidar com substitutos de maneira adequada.
@media (dynamic-range: high) {
.neon-pink {
--neon-glow: color(display-p3 1 0 1);
}
}
@supports (color: lab(0% 0 0)) {
.neon-pink {
--neon-glow: lab(150% 160 0);
}
}
hwb()
HWB significa matiz, brancura e escuridão. Ele se apresenta como uma maneira amigável de articular cores, já que é apenas uma tonalidade e uma quantidade de branco ou preto para clarear ou escurecer. Artistas que misturam cores com branco ou preto podem gostar dessa adição de sintaxe de cores.
O uso dessa função de cor resulta em cores do espaço de cor sRGB, o mesmo que HSL e RGB. Em termos de novidades para 2022, isso não oferece novas cores, mas pode facilitar algumas tarefas para os fãs da sintaxe e do modelo mental.
Recursos
Espaços de cor
A forma como as cores são representadas é feita com um espaço de cores. Cada espaço de cor oferece vários recursos e compensações para trabalhar com cores. Alguns podem agrupar todas as cores brilhantes. Outros podem alinhá-las primeiro com base na luminosidade.
O CSS 2022 está configurado para oferecer 10 novos espaços de cores, cada um com recursos exclusivos para ajudar designers e desenvolvedores a exibir, escolher e misturar cores. Anteriormente, sRGB era a única opção para trabalhar com cores, mas agora o CSS proporciona um novo potencial e um novo espaço de cores padrão, o LCH.
color-mix()
Antes do color-mix()
, os desenvolvedores e designers precisavam de pré-processadores como o
Sass (link em inglês) para misturar as cores antes que o navegador as detectasse.
A maioria das funções de mistura de cores também não oferecia a opção de especificar em qual
espaço de cores fazer a mistura, o que às vezes gerava resultados confusos.
Após color-mix()
, os desenvolvedores e designers podem misturar cores no navegador,
além de todos os outros estilos, sem executar processos de build ou incluir
JavaScript. Além disso, eles podem especificar em qual espaço de cores fazer a mistura
ou usar o espaço de cores de mistura padrão do LCH.
Muitas vezes, uma cor de marca é usada como base e variantes são criadas a partir dela, como cores mais claras ou mais escuras para estilos de passar o cursor. Confira como isso fica com
color-mix()
:
.color-mix-example {
--brand: #0af;
--darker: color-mix(var(--brand) 25%, black);
--lighter: color-mix(var(--brand) 25%, white);
}
E, se você quiser misturar essas cores em um espaço de cores diferente, como s rgb, mude-o:
.color-mix-example {
--brand: #0af;
--darker: color-mix(in srgb, var(--brand) 25%, black);
--lighter: color-mix(in srgb, var(--brand) 25%, white);
}
Confira a seguir uma demonstração de aplicação de temas usando color-mix()
. Tente mudar a cor da marca
e observe a atualização do tema:
Aproveite a mistura de cores em vários espaços de cores nas suas folhas de estilo em 2022!
Recursos
- Especificação da função color-mix()
- color-mix() no MDN
- Demonstração de temas
- Outra demonstração de temas
- Fabio Giolito: Criar um tema de cores com estes próximos recursos de CSS
color-contrast()
Antes de color-contrast()
, os autores da folha de estilo precisavam saber as cores acessíveis
com antecedência. Muitas vezes, uma paleta mostra texto preto ou branco em uma amostra de cor
para indicar ao usuário do sistema de cores qual cor de texto seria necessária para
contrastar adequadamente com essa amostra.
Depois de color-contrast()
, os autores de folhas de estilo podem transferir a tarefa totalmente para
o navegador. Além de usar o navegador para escolher automaticamente uma cor preta
ou branca, você pode fornecer uma lista de cores adequadas ao sistema de design e
escolher a primeira que atenda à proporção de contraste desejada.
Esta é uma captura de tela de uma demonstração do conjunto de paletas de cores do HWB (link em inglês) em que as cores do texto são escolhidas automaticamente pelo navegador com base na cor da amostra:
O básico da sintaxe é parecido com este, em que o cinza é transmitido para a função e o navegador determina se o preto ou o branco tem o maior contraste:
color: color-contrast(gray);
A função também pode ser personalizada com uma lista de cores, da qual será escolhida a cor de maior contraste na seleção:
color: color-contrast(gray vs indigo, rebeccapurple, hotpink);
Por fim, caso seja preferível não escolher a cor de contraste mais alta da lista, uma proporção de contraste de destino pode ser fornecida, e a primeira cor que passar por ela será escolhida:
color: color-contrast(
var(--bg-blue-1)
vs
var(--text-lightest), var(--text-light), var(--text-subdued)
to AA /* 4.5 could also be passed */
);
Essa função pode ser usada para mais do que apenas a cor do texto, embora eu estime que esse será o caso de uso principal. Pense em como será mais fácil fornecer interfaces acessíveis e legíveis depois que a escolha de cores contrastantes adequadas for integrada à própria linguagem CSS.
Recursos
Sintaxe de cor relativa
Antes da sintaxe de cores relativa, para calcular a cor e fazer ajustes, os
canais de cor precisavam ser colocados individualmente em propriedades personalizadas. Essa
limitação também fez com que o HSL fosse a função de cor principal para manipular cores
porque a matiz, a saturação ou a luminosidade podiam ser ajustadas de maneira
simples com calc()
.
Após a sintaxe de cor relativa, qualquer cor em qualquer espaço pode ser desconstruída, modificada e retornada como uma cor, tudo em uma linha de CSS. Não há mais limitações para HSL. As manipulações podem ser feitas em qualquer espaço de cores desejado, e é necessário criar muito menos propriedades personalizadas para facilitar isso.
No exemplo de sintaxe abaixo, um valor hexadecimal básico é fornecido e duas novas cores são
criadas em relação a ele. A primeira cor --absolute-change
cria uma nova cor no LCH da cor base e, em seguida, substitui o brilho da cor base por 75%
, mantendo o chroma (c
) e o matiz (h
). A segunda cor --relative-change
cria uma nova cor no LCH a partir da cor base, mas desta vez reduz o chroma (c
) em 20%.
.relative-color-syntax {
--color: #0af;
--absolute-change: lch(from var(--color) 75% c h);
--relative-change: lch(from var(--color) l calc(c-20%) h);
}
É semelhante a misturar cores, mas é mais semelhante a alterações do que mistura. Você pode transmitir uma cor de outra cor, tendo acesso aos três valores de canal conforme nomeado pela função de cor usada, com a oportunidade de ajustar esses canais. No geral, essa é uma sintaxe muito legal e poderosa para cores.
Na demonstração a seguir, usei a sintaxe de cor relativa para criar variantes mais claras e
mais escuras de uma cor base e usei color-contrast()
para garantir que os
rótulos tivessem o contraste adequado:
Essa função também pode ser usada para gerar paletas de cores. Esta é uma demonstração em que paletas inteiras são geradas a partir de uma cor de base fornecida. Esse conjunto de CSS é usado em todas as paletas, e cada uma delas fornece uma base diferente. Como bônus, já que usei LCH, observe como até mesmo as paletas são perceptivamente: não há pontos quentes ou mortos a serem vistos, graças a esse espaço de cores.
:root {
--_color-base: #339af0;
--color-0: lch(from var(--_color-base) 98% 10 h);
--color-1: lch(from var(--_color-base) 93% 20 h);
--color-2: lch(from var(--_color-base) 85% 40 h);
--color-3: lch(from var(--_color-base) 75% 46 h);
--color-4: lch(from var(--_color-base) 66% 51 h);
--color-5: lch(from var(--_color-base) 61% 52 h);
--color-6: lch(from var(--_color-base) 55% 57 h);
--color-7: lch(from var(--_color-base) 49% 58 h);
--color-8: lch(from var(--_color-base) 43% 55 h);
--color-9: lch(from var(--_color-base) 39% 52 h);
--color-10: lch(from var(--_color-base) 32% 48 h);
--color-11: lch(from var(--_color-base) 25% 45 h);
--color-12: lch(from var(--_color-base) 17% 40 h);
--color-13: lch(from var(--_color-base) 10% 30 h);
--color-14: lch(from var(--_color-base) 5% 20 h);
--color-15: lch(from var(--_color-base) 1% 5 h);
}
Esperamos que você já tenha percebido como os espaços de cor e as diferentes funções de cor podem ser usados para diferentes finalidades, com base nos pontos fortes e fracos deles.
Recursos
- Especificação de sintaxe de cor relativa
- Como criar paletas de cores com a sintaxe de cores relativas
- Como criar variantes de cor com a sintaxe de cor relativa
Espaços de cores em gradiente
Antes dos espaços de cores do gradiente, o sRGB era o espaço de cores padrão usado. Geralmente, o sRGB é confiável, mas tem alguns pontos fracos, como a zona morta cinzenta.
Depois dos espaços de cores de gradiente, informe ao navegador qual espaço de cores usar para a interpolação de cores. Isso permite que desenvolvedores e designers escolham o gradiente de preferência. O espaço de cores padrão também muda para LCH em vez de sRGB.
A adição de sintaxe segue a direção do gradiente, usa a nova sintaxe in
e é opcional:
background-image: linear-gradient(
to right in hsl,
black, white
);
background-image: linear-gradient(
to right in lch,
black, white
);
Aqui está um gradiente básico e essencial de preto para branco. Observe o intervalo de resultados em cada espaço de cores. Alguns atingem o preto escuro mais cedo que outros, alguns esmaecem muito tarde.
Neste próximo exemplo, o preto é transferido para o azul porque é um espaço de problema conhecido para gradientes. A maioria dos espaços de cor se infiltra para o roxo durante a interpolação de cor ou, como gosto de pensar, à medida que as cores viajam dentro do espaço de cores do ponto A ao ponto B. Como o gradiente vai seguir uma linha reta do ponto A ao ponto B, a forma do espaço de cores muda drasticamente as paradas que o caminho faz ao longo do caminho.
Para mais informações detalhadas, exemplos e comentários, leia esta conversa do Twitter.
Recursos
- Especificação de interpolação de gradiente
- Demonstração de comparação de gradientes em espaços
- Notebook observável comparando gradientes
inert
Antes do inert
, era uma boa prática direcionar o foco do usuário para áreas da
página ou do app que precisavam de atenção imediata. Essa estratégia de foco guiado ficou
conhecida como retenção de foco, porque os desenvolvedores o colocavam em um espaço
interativo, ouvissem eventos de mudança de foco e, se o foco deixasse o espaço
interativo, ele seria forçado a entrar novamente. Os usuários de teclados ou leitores de tela são
direcionados de volta ao espaço interativo para garantir que a tarefa seja concluída antes
de prosseguir.
Após inert
, nenhuma captura é necessária, porque é possível congelar ou proteger seções inteiras
da página ou do app. Os cliques e as tentativas de mudança de foco simplesmente
não estarão disponíveis enquanto essas partes de um documento estiverem inertes. Também é possível pensar
nisso como guardas, e não como armadilhas, em que inert
não tem interesse em fazer
você ficar em algum lugar, mas sim em deixar outros lugares indisponíveis.
Um bom exemplo disso é a função alert()
JavaScript:
Observe no vídeo anterior como a página era acessível por mouse e teclado
até que uma alert()
fosse chamada. Quando a caixa de diálogo de alerta foi mostrada, o restante
da página foi congelado ou inert
. O foco dos usuários é colocado dentro da caixa de diálogo
de alerta e não tem para onde ir. Quando o usuário interage e conclui a
solicitação da função de alerta, a página volta a ser interativa. O inert
permite
que os desenvolvedores alcancem essa mesma experiência de foco guiada com facilidade.
Confira um exemplo de código para mostrar como isso funciona:
<body>
<div class="modal">
<h2>Modal Title</h2>
<p>...<p>
<button>Save</button>
<button>Discard</button>
</div>
<main inert>
<!-- cannot be keyboard focused or clicked -->
</main>
</body>
Uma caixa de diálogo é um ótimo exemplo, mas inert
também é útil para coisas como a
experiência do usuário no menu lateral deslizante. Quando um usuário desliza o menu lateral, não é
permitido que o mouse ou o teclado interaja com a página por trás dele. Isso é
um pouco complicado para os usuários. Em vez disso, quando o menu lateral estiver sendo mostrado, torne a página
inativa. Agora, os usuários precisam fechar ou navegar nesse menu lateral e não
se perderão em outro lugar da página com um menu aberto.
Recursos
- Especificação de inert
- Inert no MDN
- Desenvolvedores do Chrome: Apresentação do inert (link em inglês)
Fontes COLRv1
Antes das fontes COLRv1, a Web tinha fontes OT-SVG, também um formato aberto para fontes com gradientes e cores e efeitos integrados. No entanto, eles poderiam ficar muito grandes e, embora permitissem a edição do texto, não havia muito escopo para personalização.
Depois das fontes COLRv1, a Web tem uma pegada menor, fontes vetoriais escalonáveis, reposicionáveis, com gradiente e modo de mesclagem que aceitam parâmetros para personalizar a fonte por caso de uso ou para combinar com uma marca.
Confira um exemplo da postagem do blog do Chrome para desenvolvedores sobre emojis. Talvez você tenha notado que, se você aumentar o tamanho da fonte em um emoji, ele não fica nítido. É uma imagem, não uma arte vetorial. Muitas vezes, em aplicativos, quando um emoji é usado, ele é substituído por um recurso de maior qualidade. Com fontes COLRv1, os emojis são vetoriais e bonitos:
As fontes de ícones podem fazer coisas incríveis com esse formato, oferecendo paletas de cores de tons duplos personalizadas e muito mais. O carregamento de uma fonte COLRv1 é igual a qualquer outro arquivo de fonte:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
A personalização da fonte COLRv1 é feita com @font-palette-values
, um CSS especial em regra para agrupar e nomear um conjunto de opções de personalização em um pacote para referência futura. Confira como especificar um nome personalizado, assim como uma propriedade
personalizada, começando com --
:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
Com --colorized
como um alias para as personalizações, a última etapa é aplicar
a paleta a um elemento que está usando a família de fontes de cores:
@import url(https://fonts.googleapis.com/css2?family=Bungee+Spice);
@font-palette-values --colorized {
font-family: "Bungee Spice";
base-palette: 0;
override-colors: 0 hotpink, 1 cyan, 2 white;
}
.spicy {
font-family: "Bungee Spice";
font-palette: --colorized;
}
Com o aumento da disponibilidade de fontes variáveis e coloridas, a tipografia da Web está em um caminho magnífico em direção à personalização rica e à expressão criativa.
Recursos
- Especificação do Colrv1 no Github (link em inglês)
- Desenvolvedores do Chrome: fontes Colrv1
- Vídeo explicativo para desenvolvedores do BlinkOn
Unidades de janela de visualização
Antes das novas variantes de janela de visualização, a Web oferecia unidades físicas para ajudar a ajustar janelas de visualização. Havia um para altura, largura, tamanho menor (vmin) e lado maior (vmax). Isso funcionou bem para muitas coisas, mas os navegadores para dispositivos móveis introduziram uma complexidade.
Em dispositivos móveis, ao carregar uma página, a barra de status com o URL é mostrada, e essa
barra consome parte do espaço da viewport. Depois de alguns segundos e alguma
interatividade, a barra de status pode deslizar para permitir uma experiência de visualização
maior para o usuário. No entanto, quando essa barra desliza, a altura da janela de visualização muda, e todas as unidades vh
são deslocadas e redimensionadas à medida que o tamanho de destino muda.
Nos anos seguintes, a unidade vh
precisava decidir qual dos dois
tamanhos de viewport ela usaria, porque estava causando problemas de layout visual
em dispositivos móveis. Foi determinado que vh
sempre representaria
a maior janela de visualização.
.original-viewport-units {
height: 100vh;
width: 100vw;
--size: 100vmin;
--size: 100vmax;
}
Depois das novas variantes de janela de visualização, as unidades de janela de visualização pequenas, grandes e dinâmicas são
disponibilizadas, com a adição de equivalentes
lógicos aos físicos. A ideia é
dar aos desenvolvedores e designers a capacidade de escolher qual unidade eles querem
usar para o cenário em questão. Talvez não haja problema em ter uma pequena mudança de layout desagradável
quando a barra de status desaparecer. Assim, dvh
(altura dinâmica da janela de visualização) pode ser
usado sem se preocupar.
Confira uma lista completa de todas as novas opções de unidade de viewport disponibilizadas com as novas variantes de viewport:
.new-height-viewport-units { height: 100vh; height: 100dvh; height: 100svh; height: 100lvh; block-size: 100vb; block-size: 100dvb; block-size: 100svb; block-size: 100lvb; }
.new-width-viewport-units { width: 100vw; width: 100dvw; width: 100svw; width: 100lvw; inline-size: 100vi; inline-size: 100dvi; inline-size: 100svi; inline-size: 100lvi; }
.new-min-viewport-units { --size: 100vmin; --size: 100dvmin; --size: 100svmin; --size: 100lvmin; }
.new-max-viewport-units { --size: 100vmax; --size: 100dvmax; --size: 100svmax; --size: 100lvmax; }
Esperamos que isso dê a desenvolvedores e designers a flexibilidade necessária para alcançar designs responsivos para a janela de visualização.
Recursos
- Especificação de unidades relativas da janela de visualização
- Bramus: viewports grandes, pequenos e dinâmicos
:has()
Antes de :has()
, o
assunto
de um selector estava sempre no final. Por exemplo, o
assunto desse seletor é um item de lista: ul > li
. Os pseudoseletores podem alterar
o seletor, mas não mudam o assunto: ul > li:hover
ou ul >
li:not(.selected)
.
Depois de :has()
, um assunto mais alto na árvore de elementos pode permanecer como o assunto
enquanto fornece uma consulta sobre filhos: ul:has(> li)
. É fácil entender
como :has()
recebeu um nome comum de "seletor pai", já que o assunto do
seletor agora é o pai nesse caso.
Confira um exemplo de sintaxe básico em que a classe .parent
permanece como o assunto, mas
é selecionada apenas se um elemento filho tiver a classe .child
:
.parent:has(.child) {...}
Confira um exemplo em que um elemento <section>
é o assunto, mas o seletor
só corresponde se uma das crianças tiver :focus-visible
:
section:has(*:focus-visible) {...}
O seletor :has()
começa a se tornar um utilitário fantástico quando mais casos de uso
práticos se tornam aparentes. Por exemplo, no momento, não é possível selecionar
tags <a>
quando elas envolvem imagens, o que dificulta ensinar à tag âncora
como mudar os estilos nesse caso de uso. No entanto, é possível usar :has()
para:
a:has(> img) {...}
Esses são exemplos em que :has()
parece apenas um seletor pai.
Considere o caso de uso de imagens dentro de elementos <figure>
e ajuste
os estilos nas imagens se a figura tiver um <figcaption>
. No exemplo
abaixo, as figuras com figcaptions são selecionadas e, em seguida, as imagens dentro desse
contexto. O :has()
é usado e não muda o assunto, porque o assunto que
estamos segmentando é imagens, não figuras:
figure:has(figcaption) img {...}
As combinações parecem infinitas. Combine :has()
com consultas
de quantidade e ajuste
os layouts de grade CSS com base no número de filhos. Combine :has()
com
estados de pseudoclasse
interativos e crie
apps que respondam de novas maneiras criativas.
A verificação de suporte é simplificada com
@supports
e
a função
selector()
,
que testa se o navegador entende a sintaxe antes de usá-la:
@supports (selector(:has(works))) {
/* safe to use :has() */
}
Recursos
2022 e além
Ainda há várias coisas que serão difíceis de fazer depois que todos esses recursos incríveis forem lançados em 2022. A próxima seção aborda alguns dos problemas restantes e as soluções que estão sendo ativamente desenvolvidas para resolvê-los. Essas soluções são experimentais, mesmo que possam ser especificadas ou disponíveis com flags nos navegadores.
O resultado das próximas seções deve mostrar que os problemas listados têm muitas pessoas de muitas empresas buscando uma resolução, não que essas soluções serão lançadas em 2023.
Propriedades personalizadas com tipo indefinido
As propriedades personalizadas do CSS são incríveis. Eles permitem que vários tipos de coisas sejam armazenados em uma variável nomeada, que pode ser estendida, calculada, compartilhada e muito mais. Na verdade, eles são tão flexíveis que seria bom ter alguns menos flexíveis.
Considere um cenário em que uma box-shadow
usa propriedades personalizadas para os valores:
box-shadow: var(--x) var(--y) var(--blur) var(--spread) var(--color);
Tudo isso funciona bem até que qualquer uma das propriedades seja alterada para um valor que o CSS não aceite, como --x: red
. A sombra inteira é interrompida se alguma
das variáveis aninhadas estiver ausente ou for definida como um tipo de valor inválido.
É aqui que entra o @property
: o --x
pode
se tornar uma propriedade personalizada digitada, não mais flexível e solta, mas segura com alguns
limites definidos:
@property --x {
syntax: '<length>';
initial-value: 0px;
inherits: false;
}
Agora, quando a box-shadow
usar var(--x)
e depois uma tentativa de --x: red
for feita,
red
será ignorado, já que não é um <length>
. Isso significa que a sombra continua
funcionando, mesmo que um valor inválido tenha sido fornecido a uma das propriedades personalizadas.
Em vez de falhar, ele reverte para o initial-value
de 0px
.
Animação
Além da segurança de tipo, ela também abre muitas portas para a animação. A
flexibilidade da sintaxe do CSS torna impossível animar algumas coisas, como
gradientes. @property
é útil nesse caso, porque a propriedade CSS tipada pode informar o navegador sobre a intenção do desenvolvedor dentro de uma interpolação excessivamente complexa. Ele limita essencialmente o escopo de possibilidades, de modo que um
navegador pode animar aspectos de um estilo que não podia antes.
Considere este exemplo de demonstração, em que um gradiente radial é usado para criar uma parte de uma sobreposição, criando um efeito de foco de holofote. O JavaScript define o x e y do mouse quando a tecla alt/opt é pressionada e muda o tamanho focal para um valor menor como 25%, criando o círculo de foco de destaque na posição do mouse:
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
}
No entanto, os gradientes não podem ser animados. Eles são muito flexíveis e complexos
para o navegador "simplesmente derivar" como você quer que eles sejam animados. No entanto, com @property
,
uma propriedade pode ser digitada e animada de forma isolada, para que o
navegador possa entender facilmente a intenção.
Os videogames que usam esse efeito de foco sempre animam o círculo, de um círculo grande
para um círculo de alfinete. Veja como usar @property
com nossa demonstração para que o
navegador anime a máscara de gradiente:
@property --focal-size {
syntax: '<length-percentage>';
initial-value: 100%;
inherits: false;
}
.focus-effect {
--focal-size: 100%;
--mouse-x: center;
--mouse-y: center;
mask-image: radial-gradient(
circle at var(--mouse-x) var(--mouse-y),
transparent 0%,
transparent var(--focal-size),
black 0%
);
transition: --focal-size .3s ease;
}
O navegador agora pode animar o tamanho do gradiente porque reduzimos a área da superfície da modificação para apenas uma propriedade e digitamos o valor para que o navegador possa interpolar os comprimentos de maneira inteligente.
O @property
pode fazer muito mais, mas essas pequenas ativações podem ajudar muito.
Recursos
- @property specification
- @propriedade no MDN
- @property no web.dev
- Demonstração do foco do Zoom
- Truques de CSS: como usar @property e seus poderes de animação
Estava em min-width
ou max-width
Antes dos intervalos de consulta de mídia, uma consulta de mídia CSS usa min-width
e max-width
para
articular condições acima e abaixo. Ela pode ter esta aparência:
@media (min-width: 320px) {
…
}
Depois dos intervalos de consulta de mídia, a mesma consulta de mídia pode ficar assim:
@media (width >= 320px) {
…
}
Uma consulta de mídia CSS que usa min-width
e max-width
pode ter esta aparência:
@media (min-width: 320px) and (max-width: 1280px) {
…
}
Depois dos intervalos de consulta de mídia, a mesma consulta de mídia pode ficar assim:
@media (320px <= width <= 1280px) {
…
}
Dependendo do seu conhecimento em programação, uma delas vai parecer muito mais legível do que a outra. Graças às adições de especificações, os desenvolvedores poderão escolher a que preferirem ou até mesmo usá-las de forma intercambiável.
Recursos
- Especificação da sintaxe do intervalo de consulta de mídia
- Sintaxe do intervalo de consulta de mídia no MDN
- Sintaxe de intervalo de consulta de mídia do plug-in PostCSS
Nenhuma variável de consulta de mídia
Antes do @custom-media
, as consultas de mídia precisavam se repetir várias vezes ou
depender de pré-processadores para gerar a saída adequada com base em variáveis estáticas
durante o build.
Após @custom-media
, o CSS permite o uso de alias de consultas de mídia e a referência a
elas, assim como uma propriedade personalizada.
Nomear coisas é muito importante: isso pode alinhar o propósito com a sintaxe, facilitando o compartilhamento e o uso em equipes. Confira algumas consultas de mídia personalizadas que me acompanham entre projetos:
@custom-media --OSdark (prefers-color-scheme: dark);
@custom-media --OSlight (prefers-color-scheme: light);
@custom-media --pointer (hover) and (pointer: coarse);
@custom-media --mouse (hover) and (pointer: fine);
@custom-media --xxs-and-above (width >= 240px);
@custom-media --xxs-and-below (width <= 240px);
Agora que eles estão definidos, posso usar um deles assim:
@media (--OSdark) {
:root {
…
}
}
Encontre uma lista completa de consultas de mídia personalizadas que uso na minha biblioteca de propriedades personalizadas do CSS Open Props.
Recursos
- Especificação de consultas de mídia personalizadas
- Plugin PostCSS para consultas de mídia personalizadas
Aninhar seletores é muito bom
Antes da @nest
, havia muita repetição nas folhas de estilo. Isso se tornou
especialmente difícil de usar quando os seletores eram longos e cada um deles tinha como alvo pequenas
diferenças. A conveniência do aninhamento é um dos motivos mais comuns para
adotar um pré-processador.
Após @nest
, a repetição é removida. Quase todos os recursos de aninhamento ativado para pré-processador serão disponibilizados integrado ao CSS.
article {
color: darkgray;
}
article > a {
color: var(--link-color);
}
/* with @nest becomes */
article {
color: darkgray;
& > a {
color: var(--link-color);
}
}
O mais importante no aninhamento para mim, além de não repetir article
no seletor aninhado, é que o contexto de estilo permanece dentro de um bloco de estilo.
Em vez de pular de um seletor e seus estilos para outro seletor com
estilos (exemplo 1), o leitor pode permanecer no contexto de um artigo e
acessar os links dele. A relação e a intent de estilo são
agrupadas, de modo que article
pode parecer ter os próprios estilos.
A propriedade também pode ser considerada como centralização. Em vez de procurar estilos relevantes em uma folha de estilo, todos eles podem ser encontrados aninhados em um contexto. Isso funciona com relações pai-filho, mas também com relações filho-pai.
Considere um componente filho que quer se ajustar quando estiver em um contexto pai diferente, em vez de o pai ter o estilo e mudar um filho:
/* parent owns this, adjusting children */
section:focus-within > article {
border: 1px solid hotpink;
}
/* with @nest becomes */
/* article owns this, adjusting itself when inside a section:focus-within */
article {
@nest section:focus-within > & {
border: 1px solid hotpink;
}
}
O @nest
ajuda na organização, centralização e
propriedade de estilos mais saudáveis. Os componentes podem agrupar e ter os próprios estilos, em vez de espalhá-los
entre outros blocos de estilo. Pode parecer pequeno nesses exemplos, mas pode ter impactos muito grandes, por conveniência e de legibilidade.
Recursos
É muito difícil definir estilos
Antes do @scope
, muitas estratégias existiam porque os estilos no CSS cascateiam, herdam
e têm escopo global por padrão. Esses recursos do CSS são muito convenientes
para muitas coisas, mas para sites e aplicativos complexos, com potencialmente muitos
estilos diferentes de componentes, o espaço global e a natureza da cascata podem
fazer com que os estilos pareçam estar vazando.
Depois de @scope
, os estilos não só podem ser aplicados apenas em um contexto, como uma
classe, como também podem articular onde os estilos terminam e não continuam
em cascata ou herdados.
No exemplo a seguir, o escopo da convenção de nomenclatura do BEM
pode ser revertido para a intent real. O seletor BEM está tentando
especificar a cor de um elemento header
para um contêiner .card
com convenções
de nomenclatura. Isso exige que o cabeçalho tenha essa classe, concluindo
a meta. Com @scope
, nenhuma convenção de nomenclatura é necessária para concluir
a mesma meta sem marcar o elemento de cabeçalho:
.card__header {
color: var(--text);
}
/* with @scope becomes */
@scope (.card) {
header {
color: var(--text);
}
}
Veja outro exemplo, menos específico de um componente e mais sobre a natureza do escopo global do CSS. Os temas escuro e claro precisam coexistir em uma folha de estilo, em que
a ordem é importante para determinar um estilo vencedor. Isso geralmente significa que os estilos do tema escuro
vêm depois do tema claro. Isso estabelece o claro como padrão e
o escuro como o estilo opcional. Evite a ordem e o escopo de batalha com @scope
:
@scope (.light-theme) {
a { color: purple; }
}
@scope (.dark-theme) {
a { color: plum; }
}
Para concluir a história, @scope
também permite estabelecer onde o
escopo do estilo termina. Isso não pode ser feito com nenhuma convenção de nomenclatura ou pré-processador.
É especial e só pode ser feito por um CSS integrado ao navegador. No
exemplo abaixo, os estilos img
e .content
são aplicados exclusivamente quando um
filho de um .media-block
é um irmão ou pai de .content
:
@scope (.media-block) to (.content) {
img {
border-radius: 50%;
}
.content {
padding: 1em;
}
}
Recursos
Não há maneira de usar CSS para um layout de alvenaria
Antes da alvenaria CSS com grade, o JavaScript era a melhor maneira de conseguir um layout de alvenaria, já que qualquer um dos métodos CSS com colunas ou flexbox representaria imprecisamente a ordem do conteúdo.
Depois de trabalhar com alvenaria CSS com grade, nenhuma biblioteca JavaScript será necessária e a ordem do conteúdo será correta.
A demonstração anterior é alcançada com o seguinte CSS:
.container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: masonry;
}
É reconfortante saber que isso está no radar como uma estratégia de layout ausente. Além disso, você pode testar hoje mesmo no Firefox.
Recursos
- Especificação de layout de alvenaria
- Layout de alvenaria no MDN
- Smashing Magazine: layout de alvenaria CSS nativo com CSS Grid
O CSS não pode ajudar os usuários a reduzir dados
Antes da consulta de mídia prefers-reduced-data
, o JavaScript e um servidor podiam
mudar o comportamento com base na opção "data saver" do sistema operacional ou do navegador de um usuário,
mas o CSS não podia.
Depois da consulta de mídia prefers-reduced-data
, o CSS pode participar da melhoria da experiência
do usuário e desempenhar seu papel no salvamento de dados.
@media (prefers-reduced-data: reduce) {
picture, video {
display: none;
}
}
O CSS anterior é usado em este componente de rolagem de
mídia, e a economia
pode ser enorme. Quanto maior a janela de visualização, maior a economia
no carregamento da página. A gravação continua enquanto os usuários interagem com os controles
de mídia. Todas as imagens têm atributos loading="lazy"
e,
combinadas com o CSS que oculta o elemento por completo, significa que uma solicitação de rede para a
imagem nunca é feita.
Para meus testes, em uma janela de visualização de tamanho médio, 40 solicitações e 700 KB de recursos foram carregados inicialmente. À medida que um usuário rola a seleção de mídia, mais solicitações e recursos são carregados. Com o CSS e a consulta de mídia de dados reduzida, 10 solicitações e 172 KB de recursos são carregados. Isso representa metade de um megabyte de economia e o usuário nem mesmo rolou nenhuma das mídias, momento em que não há mais solicitações feitas.
Essa experiência de dados reduzidos tem mais vantagens do que apenas a economia de dados. Mais títulos podem ser vistos e não há imagens de capa que distraem para roubar a atenção. Muitos usuários navegam em um modo de economia de dados porque pagam por megabyte de dados. É muito bom ver o CSS ajudando aqui.
Recursos
- prefers-reduced-data specification
- prefers-reduced-data na MDN
- prefers-reduced-data em um desafio de GUI
- Smashing Magazine: Improving Core Web Vitals, A Smashing Magazine Case Study
Os recursos de ajuste de rolagem são muito limitados
Antes dessas propostas de ajuste de rolagem, escrever seu próprio JavaScript para gerenciar um carrinho, um controle deslizante ou uma galeria podia se tornar rapidamente complexo, com todos os observadores e gerenciamento de estado. Além disso, se não forem cuidadosos, as velocidades de rolagem naturais poderão ser normalizadas pelo script, fazendo com que a interação do usuário pareça um pouco não natural e potencialmente desajeitada.
Novas APIs
snapChanging()
Assim que o navegador libera um filho de encaixe, esse evento é acionado. Isso permite que a interface reflita a falta de uma criança de ajuste e o estado de ajuste indeterminado do rolagem, já que ele está sendo usado e será direcionado a um novo local.
document.querySelector('.snap-carousel').addEventListener('snapchanging', event => {
console.log('Snap is changing', event.snappedTargetsList);
});
snapChanged()
Assim que o navegador se encaixar em um novo filho e o controle deslizante for parado, esse evento será acionado. Isso permite que qualquer interface que dependa da filha encaixada seja atualizada e reflita a conexão.
document.querySelector('.snap-carousel').addEventListener('snapchanged', event => {
console.log('Snap changed', event.snappedTargetsList);
});
scroll-start
A rolagem nem sempre começa no início. Considere componentes deslizáveis em que deslizar para a esquerda ou direita aciona eventos diferentes ou uma barra de pesquisa que, no carregamento da página, fica inicialmente oculta até você rolar até a parte de cima. Essa propriedade CSS permite que os desenvolvedores especifiquem que um botão de rolagem precisa começar em um ponto específico.
:root { --nav-height: 100px }
.snap-scroll-y {
scroll-start-y: var(--nav-height);
}
:snap-target
Esse seletor de CSS vai corresponder a elementos em um contêiner de ajuste de rolagem que estão atualmente ajustados pelo navegador.
.card {
--shadow-distance: 5px;
box-shadow: 0 var(--shadow-distance) 5px hsl(0 0% 0% / 25%);
transition: box-shadow 350ms ease;
}
.card:snapped {
--shadow-distance: 30px;
}
Depois dessas propostas de ajuste de rolagem, criar um controle deslizante, carrossel ou galeria fica muito mais fácil, já que o navegador agora oferece conveniências para a tarefa, eliminando observadores e código de orquestração de rolagem em favor do uso de APIs integradas.
Ainda é muito cedo para esses recursos de CSS e JS, mas fique de olho em polyfills que podem ajudar na adoção e nos testes deles em breve.
Recursos
- Rascunho de especificação do Role Snap 2 (link em inglês)
- Explicações de rolagem do Snap 2
- Demonstrações instantâneas (link em inglês)
Ciclo entre estados conhecidos
Antes da toggle()
, apenas os estados integrados ao navegador podiam ser usados
para estilização e interação. A entrada de caixa de seleção, por exemplo, tem :checked
, um
estado do navegador gerenciado internamente para a entrada que o CSS pode usar para
mudar o elemento visualmente.
Depois de toggle()
, estados personalizados podem ser criados em qualquer elemento para que o CSS mude
e use o estilo. Ela permite usar grupos, ciclismo, alternância direcionada e muito mais.
No exemplo abaixo, o mesmo efeito de um item de lista riscado na conclusão é alcançado, mas sem elementos de caixa de seleção:
<ul class='ingredients'>
<li>1 banana
<li>1 cup blueberries
...
</ul>
E os estilos CSS toggle()
relevantes:
li {
toggle-root: check self;
}
li:toggle(check) {
text-decoration: line-through;
}
Se você conhece bem as máquinas de estado, pode notar o quanto de crossover
há com toggle()
. Esse recurso permite que os desenvolvedores criem mais estados
no CSS, o que pode resultar em maneiras mais claras e semânticas de orquestrar
a interação e o estado.
Recursos
Como personalizar elementos SELECT
Antes do <selectmenu>
, o CSS não tinha a capacidade de personalizar elementos <option>
com HTML rico ou mudar muito a exibição de uma lista de opções.
Isso levou os desenvolvedores a carregar bibliotecas externas que recriavam grande parte da
funcionalidade de um <select>
, o que acabou sendo muito trabalho.
Após <selectmenu>
, os desenvolvedores podem fornecer HTML avançado para elementos de opções e
estimar o quanto necessário, atendendo aos requisitos de acessibilidade
e fornecendo HTML semântico.
No exemplo a seguir, retirado da página explicativa
de <selectmenu>
, um novo menu de seleção é criado
com algumas opções básicas:
<selectmenu>
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</selectmenu>
O CSS pode segmentar e estilizar as partes do elemento:
.my-select-menu::part(button) {
color: white;
background-color: red;
padding: 5px;
border-radius: 5px;
}
.my-select-menu::part(listbox) {
padding: 10px;
margin-top: 5px;
border: 1px solid red;
border-radius: 5px;
}
Você pode testar o elemento <selectmenu>
no Chromium no Canary com a flag de experimentos
da Web ativada. Em 2023 e nos próximos anos, não perca os elementos personalizáveis
de menu selecionados.
Recursos
Ancorar um elemento a outro
Antes de anchor()
, a posição absoluta e relativa eram estratégias de posição
fornecidas para que os desenvolvedores pudessem mover elementos filhos dentro de um elemento
pai.
Depois de anchor()
, os desenvolvedores podem posicionar elementos em outros elementos, sejam filhos ou não. Ele também permite que os desenvolvedores especifiquem em qual borda
se posicionar e outras funcionalidades para criar relações de posição entre
elementos.
Caso você tenha interesse em saber mais, a explicação traz alguns ótimos exemplos e exemplos de código.
Recursos
- explicação de anchor() (link em inglês).