Recursos de estilização na Web atuais e futuros, como foram apresentados no Google I/O 2022, além de alguns extras.
O ano de 2022 está configurado para ser um dos melhores anos para o CSS, tanto em recursos quanto no lançamento cooperativo de recursos de navegador, com o objetivo colaborativo de implementar 14 recursos.
Visão geral
Esta postagem é o formato de artigo da palestra apresentada no Google I/O 2022. A ideia não é ser um guia aprofundado sobre cada recurso, mas uma introdução e uma breve visão geral para despertar seu interesse, oferecendo amplitude em vez de profundidade. Caso você tenha interesse, confira o final de uma seção para encontrar links de recursos com mais informações.
Índice
Use a lista abaixo para acessar os tópicos de interesse:
Compatibilidade com navegadores
Um dos principais motivos para que muitos recursos CSS sejam definidos para lançamento cooperativo é devido aos esforços da Interoperabilidade de 2022 (link em inglês). Antes de analisar os esforços do Interop, é 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 as pontuações de aprovação dos navegadores para cinco recursos:
- Posicionamento de
sticky
- Tamanho:
aspect-ratio
- Layout do
flex
- Layout do
grid
- Posicionamento e animação de
transform
As pontuações dos testes foram aumentadas em geral, demonstrando estabilidade e confiabilidade atualizadas. Parabéns às equipes!
Interoperabilidade de 2022
Este ano, os navegadores se reuniram para discutir os recursos e prioridades em que pretendiam trabalhar, unindo esforços. A empresa planejava oferecer os seguintes recursos da Web para desenvolvedores:
@layer
- Espaços e funções de cor
- Contenção
<dialog>
- Compatibilidade do formulário
- Rolagem
- Subgrade
- Tipografia
- Unidades da janela de visualização
- Compatibilidade com a Web
Mal posso esperar para ver esta lista emocionante e ambiciosa.
Novidades para 2022
Não surpreende que o estado do CSS 2022 seja drasticamente afetado pelo trabalho de Interoperabilidade de 2022.
Propagar camadas
Antes de @layer
, a ordem descoberta das folhas de estilo carregadas era muito importante, já que os estilos carregados por último podem substituir os estilos carregados anteriormente. Isso levou a
folhas de estilo de entrada meticulosamente gerenciadas, em que os desenvolvedores precisavam carregar estilos menos
importantes primeiro e estilos mais importantes depois. Há metodologias inteiras
para ajudar os desenvolvedores a gerenciar essa importância, como o
ITCSS.
Com @layer
, o arquivo de entrada pode predefinir camadas e a ordem delas com antecedência. Em seguida, à medida que os estilos são carregados ou definidos, eles podem ser colocados em 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 em cascata definidas permitem um processo de criação e carregamento mais liberado e de estilo livre, mantendo a cascata conforme necessário.
O Chrome DevTools é útil para visualizar quais estilos estão vindo de quais camadas:
Recursos
- Especificação CSS Cascade 5
- Explicação sobre camadas em cascata
- Camadas em cascata no MDN
- Una Kravets: Camadas da cascata
- Ahmad Shadeed: Hello, CSS Cascade Layers
Subgrade
Antes de subgrid
, uma grade dentro de outra grade não podia se alinhar às
células mãe ou às linhas de grade. Cada layout de grade era único. Muitos designers colocam uma
única grade em todo o design e alinham constantemente itens nela, o que
não pode ser feito em CSS.
Depois de subgrid
, um filho de uma grade pode adotar as colunas ou linhas dos pais como
próprias e alinhar a si mesmo ou aos filhos a elas.
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 da esquerda e da direita nomeam as
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 a si mesmos 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 as subgrades (apenas no Firefox no momento). Na imagem a seguir, a grade e as subgrades mãe foram sobrepostas. Agora, ele lembra como os designers estavam pensando sobre o layout.
No painel de elementos do DevTools, você pode 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 da janela de visualização inteira. Isso é ótimo para layouts macro. No entanto, para microlayouts, em que
o contêiner externo não é a janela de visualização inteira, é impossível que o layout
se ajuste corretamente.
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 são o que faz com que as colunas Seg, Ter, Qua, Qui e Sex do vídeo a seguir possam ser consultadas pelos elementos de evento.
Este é o CSS para consultar o tamanho do contêiner calendar-day
e ajustar um layout e tamanhos de fonte:
@container calendar-day (max-width: 200px) {
.date {
display: block;
}
.date-num {
font-size: 2.5rem;
display: block;
}
}
Veja outro exemplo: um componente de livro se adapta ao espaço disponível na coluna para a qual ele é arrastado:
Una está correto 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 de consultas de contêiner
- Explicação sobre consultas de contêiner
- Consultas de contêiner no MDN
- O novo recurso responsivo em web.dev
- Demonstração do Google Agenda por Una
- Coleção incrível de consultas de contêiner
- Como criamos a Designcember no web.dev
- Ahmad Shadeed: Olá às consultas de contêiner CSS
accent-color
Antes de accent-color
, quando você queria um formulário com cores correspondentes à marca, podia acabar com bibliotecas complexas ou soluções CSS que se tornavam difíceis de gerenciar ao longo do tempo. Embora eles ofereçam todas as opções e, esperamos, incluem
a acessibilidade, a escolha de usar os componentes integrados ou adotar os seus
se torna tedioso continuar escolhendo.
Depois de accent-color
, uma linha de CSS traz uma cor da marca para os componentes
integrados. Além de uma tonalidade, o navegador escolhe de maneira inteligente as cores
de contraste adequadas para as partes complementares 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
, consulte minha postagem no web.dev (link em inglês), em que explico muitos outros aspectos dessa propriedade CSS útil.
Recursos
- especificação accent-color
- acent-color no MDN
- accent-color no web.dev
- Bramus: matize os controles da interface do usuário com CSS de cor de destaque.
Nível de cores 4 e 5
A Web é dominada por 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, 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 crescente para designers, sistemas de design e mantenedores de código.
No entanto, não em 2022. O CSS tem várias novas funções de cor e espaços: - Cores que alcançam os recursos de cor de alta definição das telas. - Espaços de cor que correspondem a uma intent, como uniformidade perceptível. - Espaços de cores para gradientes que alteram drasticamente os resultados de interpolação. - funções de cor para ajudar você a misturar e contrastar e escolher em qual espaço você fará o trabalho.
Antes de todas essas características de cores, os sistemas de design precisavam pré-calcular as cores de contraste adequadas e garantir paletas vibrantes, tudo isso enquanto os pré-processadores ou o JavaScript faziam o trabalho pesado.
Depois de todos esses recursos de cores, o navegador e o CSS podem fazer todo o trabalho dinamicamente e no momento certo. Em vez de enviar muitos KBs de CSS e JavaScript aos usuários para ativar temas e cores de visualização de dados, o CSS pode fazer a orquestração e os cálculos. O CSS também é mais bem equipado para verificar o suporte antes do uso ou lidar com os substitutos sem problemas.
@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, branco e escuridão. Ela se apresenta como uma maneira correta 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 cor.
O uso dessa função de cor resulta em cores do espaço de cores sRGB, da mesma forma 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 de sintaxe e modelo mental.
Recursos
Espaços de cor
A forma como as cores são representadas é feita com um espaço de cor. Cada espaço de cores 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.
Em 2022, o CSS vai 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 libera um novo potencial e um novo espaço de cores padrão, o LCH.
color-mix()
Antes de color-mix()
, desenvolvedores e designers precisavam de pré-processadores como o
Sass (link em inglês) para misturar as cores antes que o navegador as visse.
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, às vezes, resultando em resultados confusos.
Depois de color-mix()
, os desenvolvedores e designers podem misturar cores no navegador,
junto com todos os outros estilos, sem executar processos de build ou incluir
JavaScript. Além disso, eles podem especificar em qual espaço de cor fazer a mistura
ou usar o espaço de cores de mistura padrão de LCH.
Muitas vezes, uma cor da marca é usada como base, e variantes são criadas com ela, como
cores mais claras ou mais escuras para estilos de passar cursor. Veja 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);
}
Se você quiser misturar essas cores em um espaço de cores diferente, como srgb, 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);
}
Veja a seguir uma demonstraçã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 de color-mix()
- color-mix() no MDN
- Demonstração de temas
- Outra demonstração de aplicação de temas
- Fabio Giolito: crie 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 com antecedência as cores acessíveis. Muitas vezes, uma paleta mostra texto em preto ou branco em uma amostra de cor
para indicar ao usuário do sistema de cores qual cor do texto seria necessária para
contrastar adequadamente essa amostra.
Após color-contrast()
, os autores da folha de estilo podem descarregar a tarefa inteiramente no navegador. É possível usar o navegador para selecionar automaticamente uma cor
preta ou branca, além de fornecer uma lista de cores adequadas ao sistema de design e
fazer com que ele escolha a primeira para transmitir a taxa de contraste desejada.
Esta é uma captura de tela de uma demonstração do conjunto da paleta de cores HWB em que as cores do texto são escolhidas automaticamente pelo navegador com base na cor da amostra:
Os princípios básicos da sintaxe têm esta aparência, em que cinza é transmitido para a função e o navegador determina se preto ou branco têm mais contraste:
color: color-contrast(gray);
A função também pode ser personalizada com uma lista de cores, na qual ela vai escolher 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 maior contraste da lista, é possível fornecer uma taxa de contraste desejada e escolher a primeira cor a ser transmitida:
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 outras situações além da cor do texto, mas estimamos que esse será o caso de uso principal. Pense em como será mais fácil oferecer interfaces acessíveis e legíveis quando a escolha das cores contrastantes adequadas é integrada à própria linguagem CSS.
Recursos
Sintaxe de cor relativa
Antes da sintaxe de cor relativa, para calcular a cor e fazer ajustes, os
canais de cores precisavam ser colocados individualmente nas propriedades personalizadas. Essa
limitação também tornou a HSL a função de cor principal para manipular cores, já que a matiz, a saturação ou o brilho podiam ser ajustados
de maneira direta com calc()
.
Depois da sintaxe de cor relativa, qualquer cor em qualquer espaço pode ser desconstruída, modificada e retornada como uma cor, tudo em uma linha do CSS. Não há mais limitações ao HSL. As manipulações podem ser feitas em qualquer espaço de cor desejado, e muito menos propriedades personalizadas precisam ser criadas para facilitar isso.
No exemplo de sintaxe a seguir, um hexadecimal base é fornecido e duas novas cores são criadas em relação a ele. A primeira cor --absolute-change
cria uma nova cor
em LCH a partir da cor de base e, em seguida, substitui o brilho da cor de base
por 75%
, mantendo o chroma (c
) e a matiz (h
). A segunda cor
--relative-change
cria uma nova cor em LCH a partir da cor de 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);
}
Isso é parecido com misturar cores, mas é mais semelhante a alterações do que mistura. Você pode transmitir uma cor de outra cor e ter acesso aos três valores de canal, nomeados pela função de cor usada, com a oportunidade de ajustar esses canais. Resumindo, essa é uma sintaxe muito legal e poderosa para cor.
Na demonstração a seguir, usei a sintaxe de cor relativa para criar variantes mais claras e
escuras de uma cor base e usei color-contrast()
para garantir que os
rótulos tenham o contraste adequado:
Essa função também pode ser usada para gerar a paleta de cores. Confira uma demonstração em que paletas inteiras são geradas com base em uma cor de base. Esse conjunto de CSS alimenta todas as várias paletas. Cada paleta fornece uma base diferente. Como bônus, já usei o LCH, e veja como as paletas são perceptíveis. Não há pontos quentes ou mortos para 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 agora você já possa ver como os espaços de cor e as diferentes funções de cor podem ser usados para diferentes propósitos, com base nos pontos fortes e fracos deles.
Recursos
- Especificação de sintaxe de cor relativa
- Como criar paletas de cores com sintaxe de cores relativa
- Como criar variantes de cor com sintaxe de cor relativa
Espaços de cor gradiente
Antes dos espaços de cores gradientes, sRGB era o espaço de cores padrão usado. sRGB geralmente é confiável, mas tem alguns pontos fracos, como a zona sem saída cinza (link em inglês).
Após os espaços de cor gradiente, informe ao navegador qual espaço de cores usar para a interpolação de cores. Isso dá aos desenvolvedores e designers a capacidade de escolher o gradiente que preferem. O espaço de cores padrão também muda para LCH em vez de sRGB.
A adição de sintaxe vem após 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
);
Veja aqui um gradiente básico e essencial de preto para branco. Veja a faixa de resultados em cada espaço de cor. Alguns alcançam o preto escuro mais cedo do que outros, alguns se tornam brancos tarde demais.
No próximo exemplo, o preto é transferido para o azul porque é um espaço problemático conhecido para gradientes. A maioria dos espaços de cor se transforma em roxo durante a interpolação de cores ou, como gosto de pensar nisso, à medida que as cores transitam dentro do espaço de cores do ponto A ao ponto B. Como o gradiente pega uma linha reta do ponto A ao ponto B, a forma do espaço de cores muda drasticamente as paradas que o caminho percorre ao longo do caminho.
Para acessar mais análises detalhadas, exemplos e comentários, leia esta conversa no Twitter (em inglês).
Recursos
- Especificação de interpolação do gradiente (link em inglês)
- Demonstração comparando gradientes em espaços
- Notebook observável comparando gradientes
inert
Antes de inert
, era uma prática recomendada orientar 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 captura de foco porque os desenvolvedores colocavam o foco em um espaço
interativo, detectavam eventos de mudança de foco e, quando o foco deixava o espaço
interativo, era 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 avançar.
Depois de inert
, nenhuma armadilha é necessária, porque você pode congelar ou proteger seções inteiras da página ou do app. Cliques e tentativas de mudança de foco simplesmente não estão disponíveis enquanto essas partes de um documento estão inertes. Também é possível pensar nisso
como guardas em vez de uma armadilha, em que inert
não tem interesse em fazer você ficar em algum lugar, mas deixar outros locais indisponíveis.
Um bom exemplo é a função JavaScript alert()
:
Observe no vídeo anterior como a página ficou acessível por mouse e teclado
até que um alert()
fosse chamado. Depois que a caixa de diálogo de alerta pop-up foi mostrada, o restante
da página foi congelado, ou inert
. O foco do usuário é colocado na caixa de diálogo de alerta e não tem outro lugar para ir. Depois que o usuário interage e conclui a solicitação da função de alerta, a página fica interativa novamente. O inert
capacita
os desenvolvedores a ter essa mesma experiência de foco guiado com facilidade.
Este é um pequeno exemplo de código que mostra como 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 aspectos como a
experiência do usuário do menu lateral deslizante. Quando um usuário desliza para fora do menu lateral, não
é permitido que o mouse ou o teclado interajam com a página por trás dele, porque isso
é um pouco complicado para os usuários. Em vez disso, quando o menu lateral estiver aparecendo, torne a página
inerte. Agora os usuários precisam fechar ou navegar nesse menu, sem
se perder em outro lugar da página com um menu aberto.
Recursos
Fontes COLRv1
Antes das fontes COLRv1, a Web tinha fontes OT-SVG, também um formato aberto para fontes com gradientes, cores e efeitos integrados. No entanto, elas podiam crescer muito e, embora permitissem a edição do texto, não havia muito escopo para personalização.
Depois das fontes COLRv1, a Web tem menor consumo, escalonável em vetores, reposicional, com gradiente e recursos de modo de combinação, que aceitam parâmetros para personalizar a fonte por caso de uso ou de acordo com uma marca.
Confira um exemplo de uma postagem do Blog de desenvolvedores Chrome sobre emojis. Talvez você tenha notado que, se você aumentar o tamanho da fonte em um emoji, ele não ficará nítido. É uma imagem, e não uma arte vetorial. Muitas vezes, quando um emoji é usado, ele é trocado por um recurso de maior qualidade. Com as fontes COLRv1, os emojis são vetores e bonitos:
As fontes de ícones podem fazer coisas incríveis com esse formato, oferecendo paletas de cores duplas personalizadas e muito mais. Carregar uma fonte COLRv1 é como 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
para agrupar e nomear um conjunto de opções de personalização em um pacote para
referência futura. Observe como um nome personalizado é especificado, 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 esteja 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 cada vez mais fontes variáveis e de cores sendo disponibilizadas, a tipografia da Web está em um caminho magnífico em direção à personalização avançada e à expressão criativa.
Recursos
- Especificação Colrv1 no GitHub (link em inglês)
- Desenvolvedores do Chrome: Fontes Colrv1
- Vídeo de explicação para desenvolvedores do BlinkOn (link em inglês)
Unidades da janela de visualização
Antes das novas variantes da janela de visualização, a Web oferecia unidades físicas para ajudar no ajuste delas. Havia um para altura, largura, menor tamanho (vmin) e maior lado (vmax). Isso funcionou bem para muitas coisas, mas os navegadores para dispositivos móveis apresentavam uma complexidade.
Em dispositivos móveis, ao carregar uma página, a barra de status com o URL é exibida, e ela
ocupa parte do espaço da janela de visualização. Depois de alguns segundos e um pouco
de interatividade, a barra de status pode desaparecer para permitir uma experiência melhor
da janela de visualização. No entanto, quando essa barra desliza para fora, a altura da janela de visualização muda, e todas as unidades de vh
são deslocadas e redimensionadas conforme o tamanho de destino muda.
Nos últimos anos, a unidade vh
precisava decidir especificamente qual dos dois
tamanhos da janela de visualização seria usado, porque isso estava causando problemas de layout visual
desagradáveis 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 que as novas variantes da janela de visualização, as unidades pequenas, grandes e dinâmicas da janela de visualização serão
disponibilizadas, com a adição de equivalentes
lógicos aos físicos. A ideia é
oferecer aos desenvolvedores e designers a capacidade de escolher qual unidade querem
usar no cenário em questão. Talvez não haja problema em fazer uma pequena mudança de layout
desagradável quando a barra de status desaparece. Então, a dvh
(altura dinâmica da janela de visualização) pode ser
usada sem problemas.
Confira uma lista completa com todas as novas opções de unidade da janela de visualização disponibilizadas com as novas variantes da janela de visualização:
.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ê aos desenvolvedores e designers a flexibilidade necessária para criar designs responsivos na janela de visualização.
Recursos
- Especificação de unidades relativas da janela de visualização
- Bramus: as janelas de visualização grandes, pequenas e dinâmicas
:has()
Antes de :has()
, o
assunto
de um seletor estava sempre no final. Por exemplo, o
assunto desse seletor é um item da lista: ul > li
. Os pseudosseletores podem alterá-lo, mas não alteram o assunto: ul > li:hover
ou ul >
li:not(.selected)
.
Depois de :has()
, um assunto mais alto na árvore de elementos pode permanecer como assunto
ao fornecer uma consulta sobre filhos: ul:has(> li)
. É fácil entender
como :has()
recebeu o nome comum de "seletor pai", já que o assunto do
seletor agora é o pai nesse caso.
Este é um exemplo de sintaxe básica em que a classe .parent
permanece como assunto, mas
só é selecionada 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ó faz a correspondência se um dos filhos tiver :focus-visible
:
section:has(*:focus-visible) {...}
O seletor :has()
começa a se tornar um utilitário fantástico quando casos de uso
mais práticos se tornam aparentes. Por exemplo, no momento, não é possível selecionar tags
<a>
ao unir imagens. Isso dificulta ensinar à tag âncora
como mudar os estilos nesse caso de uso. Isso é possível com :has()
:
a:has(> img) {...}
Esses foram exemplos em que :has()
se parece apenas com um seletor pai.
Considere o caso de uso de imagens dentro de elementos <figure>
e ajuste
de estilos nas imagens se a figura tiver um <figcaption>
. No exemplo
a seguir, as figuras com CMEKs são selecionadas e, em seguida, as imagens dentro desse
contexto. O :has()
é usado sem mudar o assunto, já que o assunto
são imagens, não figuras:
figure:has(figcaption) img {...}
As combinações são aparentemente 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
aplicativos 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á-lo:
@supports (selector(:has(works))) {
/* safe to use :has() */
}
Recursos
2022 em diante
Ainda haverá várias coisas difíceis de realizar depois que todos esses recursos incríveis forem lançados, em 2022. Na próxima seção, você verá alguns dos problemas restantes e as soluções que estão sendo desenvolvidas ativamente para resolvê-los. Essas soluções são experimentais, mesmo que possam estar especificadas ou disponíveis atrás de sinalizações nos navegadores.
O resultado das próximas seções deve ser confiante de que os problemas listados têm muitas pessoas de muitas empresas em busca de resolução, e não que essas soluções serão lançadas em 2023.
Propriedades personalizadas com baixa digitação
As propriedades personalizadas do CSS são incríveis. Eles permitem que todos os tipos de coisas sejam armazenados dentro de 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
. Toda a sombra quebra se alguma
das variáveis aninhadas estiver ausente ou estiver definida como um tipo de valor inválido.
É aí que entra a @property
: --x
pode se tornar uma propriedade personalizada tipada, que não é mais flexível e flexível, mas segura com alguns limites definidos:
@property --x {
syntax: '<length>';
initial-value: 0px;
inherits: false;
}
Agora, quando o box-shadow
usar var(--x)
e depois uma tentativa de --x: red
for feita,
o red
vai ser ignorado, já que não é um <length>
. Isso significa que a sombra continua
funcionando, mesmo que um valor inválido tenha sido atribuído 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 tipos, ela também abre muitas portas para animação. A
flexibilidade da sintaxe CSS impossibilita a animação de algumas coisas, como
gradientes. O @property
é útil aqui, porque a propriedade de CSS digitada pode informar o
navegador sobre a intenção do desenvolvedor dentro de uma interpolação
excessivamente complexa. Essencialmente, ela limita o escopo de possibilidade, de modo que um
navegador possa animar aspectos de um estilo que antes não conseguia.
Considere este exemplo de demonstração, em que um gradiente radial é usado para fazer uma parte de uma sobreposição, criando um efeito de foco de destaque. O JavaScript define o "x" e o "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ê deseja que eles sejam animados. No entanto, com @property
, uma propriedade pode ser digitada e animada de forma isolada, permitindo que o
navegador entenda facilmente a intent.
Videogames que usam esse efeito de foco sempre animam o círculo, de um círculo grande
para um círculo. Confira como usar @property
na 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 de superfície da modificação a 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
- @especificação da propriedade
- @property no MDN
- @property no web.dev
- Demonstração do foco do zoom
- Truques do CSS: como explorar o @property e os poderes de animação
Esteve 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 as condições. Ela pode ter esta aparência:
@media (min-width: 320px) {
…
}
Após os intervalos das consultas de mídia, a mesma consulta de mídia teria esta aparência:
@media (width >= 320px) {
…
}
Uma consulta de mídia CSS usando min-width
e max-width
pode ter esta aparência:
@media (min-width: 320px) and (max-width: 1280px) {
…
}
Após os intervalos das consultas de mídia, a mesma consulta de mídia teria esta aparência:
@media (320px <= width <= 1280px) {
…
}
Dependendo do seu conhecimento em programação, um desses métodos parecerá muito mais legível que o outro. Graças às especificações adicionadas, os desenvolvedores poderão escolher qual a melhor opção 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
- Plug-in PostCSS da sintaxe de intervalo de consulta de mídia
Nenhuma variável de consulta de mídia
Antes de @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 tempo de build.
Depois de @custom-media
, o CSS permite a atribuição de alias a consultas de mídia e a referência delas, assim como em uma propriedade personalizada.
Nomear itens é muito importante: ele pode alinhar o propósito com a sintaxe, facilitando o compartilhamento e o uso em equipes. Aqui estão algumas consultas de mídia personalizadas que me seguem 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 estão definidos, posso usar um deles assim:
@media (--OSdark) {
:root {
…
}
}
Encontre uma lista completa de consultas de mídia personalizadas que eu uso na minha biblioteca de propriedades personalizadas do CSS Open Props.
Recursos
- Especificação de consultas de mídia personalizadas
- Plug-in PostCSS de consultas de mídia personalizada
É muito bom aninhar seletores
Antes de @nest
, havia muita repetição nas folhas de estilo. Ele se tornou
especialmente difícil de administrar quando os seletores eram longos e cada um visava pequenas
diferenças. A conveniência do aninhamento é um dos motivos mais comuns para
adotar um pré-processador.
Depois de @nest
, a repetição desaparece. Quase todos os recursos de aninhamento ativado para pré-processador serão disponibilizados integrados ao CSS.
article {
color: darkgray;
}
article > a {
color: var(--link-color);
}
/* with @nest becomes */
article {
color: darkgray;
& > a {
color: var(--link-color);
}
}
Para mim, o que é mais importante sobre o aninhamento, além de não repetir article
no seletor aninhado, é que o contexto de estilo permanece em um bloco de estilo.
Em vez de pular de um seletor e seus estilos para outro com estilos (exemplo 1), o leitor pode permanecer no contexto de um artigo e conferir que o artigo tem links dentro dele. A relação e a intent de estilo são
agrupadas, para que article
pareça ser proprietário dos 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 para filho, mas também com relações pai para pai.
Considere um componente filho que quer se ajustar quando em um contexto pai diferente, em vez de o pai ser proprietário do 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;
}
}
De modo geral, o @nest
ajuda na organização, centralização e propriedade de estilo mais
saudáveis. Os componentes podem agrupar e ter os próprios estilos, em vez de distribuí-los entre outros blocos de estilo. Pode parecer pequeno nesses exemplos, mas pode ter impactos muito grandes por conveniência e legibilidade.
Recursos
- Especificação@nest
- Plug-in@nest PostCSS
- Bramus: O futuro do CSS: seletores de aninhamento (em inglês)
Definir o escopo dos estilos é muito difícil
Compatibilidade com navegadores
- 118
- 118
- x
- 17,4
Antes de @scope
, muitas estratégias existiam porque os estilos em CSS são propagados, 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 possivelmente muitos estilos diferentes de componentes, o espaço global e a natureza da cascata podem fazer com que os estilos pareçam estar vazando.
Após @scope
, não é possível definir o escopo dos estilos apenas em um contexto, como uma
classe, mas também articular onde os estilos terminam e não continuar
em cascata ou herdar.
No exemplo a seguir, o escopo da convenção de nomenclatura
BEM pode ser revertido para a intent real. O seletor de BEM está tentando definir o escopo da cor de um elemento header
para um contêiner .card
com convenções de nomenclatura. Isso exige que o cabeçalho tenha esse nome de 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);
}
}
Confira outro exemplo, menos específico de componente e mais sobre a natureza de escopo
global do CSS. Temas escuros e claros precisam coexistir em uma folha de estilo, em que a ordem é importante para determinar um estilo vencedor. Normalmente, isso significa que os estilos de tema
escuro vêm depois do tema claro, estabelecendo claro como padrão e
escuro como opcional. Evite a ordenação e a disputa de escopo com @scope
:
@scope (.light-theme) {
a { color: purple; }
}
@scope (.dark-theme) {
a { color: plum; }
}
Para completar a história aqui, o @scope
também permite estabelecer onde termina o escopo do estilo. Isso não pode ser feito com nenhuma convenção de nomenclatura ou pré-processador.
Isso é especial e somente algo que o CSS integrado ao navegador pode fazer. No
exemplo a seguir, os estilos img
e .content
são aplicados exclusivamente quando um
filho de uma .media-block
é irmão ou pai de .content
:
@scope (.media-block) to (.content) {
img {
border-radius: 50%;
}
.content {
padding: 1em;
}
}
Recursos
Não há maneira CSS para um layout de alvenaria
Antes da alvenaria CSS com grade, o JavaScript era a melhor maneira de criar um layout de alvenaria, já que qualquer um dos métodos CSS com colunas ou flexbox representava de maneira imprecisa a ordem do conteúdo.
Após a alvenaria CSS com grade, nenhuma biblioteca JavaScript será necessária, e a ordem do conteúdo será correta.
A demonstração anterior é realizada com o seguinte CSS:
.container {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: masonry;
}
É bom saber que essa estratégia está faltando, e você pode fazer um teste hoje mesmo no Firefox.
Recursos
- Especificação de layout de alvenaria
- Layout de alvenaria no MDN
- Smashing Magazine: Layout nativo de alvenaria CSS com grade CSS
O CSS não pode ajudar os usuários a reduzir os dados
Antes da consulta de mídia prefers-reduced-data
, o JavaScript e um servidor podiam
mudar o comportamento deles com base na opção de "economia de dados" do navegador ou do sistema operacional de um usuário, mas o CSS não.
Após a consulta de mídia prefers-reduced-data
, o CSS pode participar da melhoria da experiência
do usuário e salvar dados.
@media (prefers-reduced-data: reduce) {
picture, video {
display: none;
}
}
O CSS anterior é usado neste componente de rolagem
de mídia, e a economia
pode ser enorme. Dependendo do tamanho da janela de visualização de visitas, maior será a economia de carregamento da página. O salvamento continua à medida que os usuários interagem com os
controles de mídia. Todas as imagens têm atributos loading="lazy"
e isso,
combinado com o CSS que oculta totalmente o elemento, significa que uma solicitação de rede para a
imagem nunca é feita.
Para meu teste, 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 meio megabyte de economia e o usuário ainda não rolou nenhuma mídia e, nesse momento, não há outras solicitações feitas.
Essa experiência de dados reduzida traz mais vantagens do que apenas a economia de dados. Mais títulos podem ser vistos e não há imagens de capa que chamem a atenção. Muitos usuários navegam no modo de economia de dados porque pagam por megabyte de dados. É muito bom ver o CSS capaz de ajudar aqui.
Recursos
- especificação deprefers-reduced-data.
- prefers-reduced-data no MDN
- prefers-reduced-data in a GUI Challenge
- Smashing Magazine: melhorias nas Core Web Vitals, um estudo de caso da Smashing Magazine
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 carrossel, controle deslizante ou galeria poderia ficar complexo rapidamente, com todos os observadores e gerenciamento de estado. Além disso, se não tomar cuidado, as velocidades de rolagem naturais poderão ser normalizadas pelo script, fazendo com que a interação do usuário pareça um pouco natural e possivelmente desajeitada.
Novas APIs
snapChanging()
Assim que o navegador liberar um filho de ajuste, esse evento será disparado. Isso permite que a interface reflita a falta de um filho de ajuste e o estado de ajuste indeterminado do rolador, já que ele está sendo usado e vai ser direcionado a um novo recurso.
document.querySelector('.snap-carousel').addEventListener('snapchanging', event => {
console.log('Snap is changing', event.snappedTargetsList);
});
snapChanged()
Assim que o navegador é direcionado a um novo filho e o botão de rolagem é pausado, esse evento é disparado. Isso permite que qualquer interface que dependa do filho selecionado atualize 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 o gesto de deslizar para a esquerda ou direita aciona eventos diferentes, ou uma barra de pesquisa que, no carregamento da página, fica oculta até você rolar para 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 fará a correspondência de elementos em um contêiner de ajuste de rolagem que está sendo ajustado 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, um carrossel ou uma galeria é 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.
Esses recursos de CSS e JS ainda estão em desenvolvimento, mas é importante ficar atento aos polyfills que poderão ajudar na adoção e teste deles em breve.
Recursos
Como alternar entre estados conhecidos
Antes de toggle()
, apenas os estados integrados ao navegador já podiam ser usados
para estilo e interação. A entrada da 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()
, os estados personalizados podem ser criados em qualquer elemento para que o CSS mude
e use para estilização. Ela permite a alternância em grupos, de bicicleta, em rotas e muito mais.
No exemplo abaixo, o mesmo efeito de um item de lista tachado na conclusão é alcançado, mas sem elementos da 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 a quantidade de crossovers
com toggle()
. Esse recurso permite que os desenvolvedores criem mais do estado
em CSS, resultando em maneiras mais claras e semânticas de orquestrar
interação e estado.
Recursos
- especificação de rascunho do toggle() (em inglês)
- Bramus: The Future of CSS: CSS Toggles (em inglês)
Como personalizar elementos de seleção
Antes de <selectmenu>
, o CSS não conseguia personalizar elementos <option>
com HTML avançado nem mudar muito a exibição de uma lista de opções.
Isso levou os desenvolvedores a carregar bibliotecas externas que recriaram grande parte da
funcionalidade de uma <select>
, o que acabou sendo muito trabalho.
Depois de <selectmenu>
, os desenvolvedores podem fornecer HTML avançado para elementos de opções e
estilizá-los o quanto precisarem, além de atender aos requisitos de acessibilidade
e fornecer HTML semântico.
No exemplo a seguir, retirado da página de explicação 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 sinalização de experimentos
da Web ativada. Confira os elementos personalizáveis do menu selecionado
em 2023 e além.
Recursos
Ancorar um elemento em outro
Antes de anchor()
, a posição absoluta e relativa eram estratégias de posição
fornecidas aos desenvolvedores para que os elementos filhos se movessem dentro de um elemento
pai.
Depois de anchor()
, os desenvolvedores podem posicionar elementos em outros elementos, independentemente
de serem filhos ou não. Ele também permite que os desenvolvedores especifiquem em qual borda
se posicionar e outras comodidades para criar relações de posição entre
elementos.
Caso você queira saber mais, há alguns ótimos exemplos e amostras de código na explicação.