Estado do CSS 2022

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:

  1. Posicionamento de sticky
  2. Dimensionamento de aspect-ratio
  3. Layout do flex
  4. Layout do grid
  5. 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:

  1. @layer
  2. Espaços de cor e funções
  3. Contenção
  4. <dialog>
  5. Compatibilidade do formulário
  6. Rolagem
  7. Subgrade
  8. Tipografia
  9. Unidades de janela de visualização
  10. 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

Compatibilidade com navegadores

  • Chrome: 99.
  • Edge: 99.
  • Firefox: 97.
  • Safari: 15.4.

Origem

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:

Captura de tela da barra lateral &quot;Styles&quot; do Chrome DevTools, destacando como os estilos aparecem em novos grupos de camadas.

Recursos

Subgrade

Compatibilidade com navegadores

  • Chrome: 117.
  • Borda: 117.
  • Firefox: 71.
  • Safari: 16.

Origem

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.

Captura de tela de uma demonstração de subgrade, usando a ferramenta de sobreposição de grade do Chrome DevTools para mostrar as linhas definidas por CSS.

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.

Captura de tela do painel Elements do Chrome DevTools que identifica quais elementos têm layouts de grade ou subgrade.
Captura de tela do Firefox Devtools

Recursos

Consultas em contêiner

Compatibilidade com navegadores

  • Chrome: 105.
  • Edge: 105.
  • Firefox: 110.
  • Safari: 16.

Origem

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.

Demonstração por Una Kravets

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:

Demo por Max Böck

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

accent-color

Compatibilidade com navegadores

  • Chrome: 93.
  • Edge: 93.
  • Firefox: 92.
  • Safari: 15.4.

Origem

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;
}

Elementos HTML com detalhes claros e escuros lado a lado para comparação.

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

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()

Compatibilidade com navegadores

  • Introdução ao Chrome.
  • Edge: 101.
  • Firefox: 96.
  • Safari: 15.

Origem

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()

Compatibilidade com navegadores

  • Chrome: 111.
  • Edge: 111.
  • Firefox: 113.
  • Safari: 16.2.

Origem

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

color-contrast()

Compatibilidade com navegadores

  • Chrome: não é compatível.
  • Edge: não compatível.
  • Firefox: não é compatível.
  • Safari: atrás de uma flag.

Origem

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.

Captura de tela de três paletas do Material Design mostrando 14 cores e as cores de contraste brancas ou pretas adequadas para o texto.
Exemplo de paletas de cores do Material Design de 2014

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:

Captura de tela da demonstração de HWB em que cada paleta tem um par diferente de texto claro ou escuro, conforme determinado pelo navegador.
Confira a demonstração

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

Compatibilidade com navegadores

  • Chrome: 111.
  • Edge: 111.
  • Firefox: 113.
  • Safari: 15

Origem

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:

Captura de tela com três colunas, cada uma mais escura ou mais clara que a coluna central.
Confira a demonstração

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);
}
Captura de tela de 15 paletas geradas dinamicamente pelo CSS.
Confira a demonstração

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

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.

Quatro gradientes em uma grade, todos de ciano a rosa-escuro. O LCH e o LAB têm uma vibração mais consistente, enquanto o sRGB fica um pouco dessaturado no meio.

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.

11 espaços de cor comparando preto e branco.

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.

Onze espaços de cores mostrados comparando azul e preto.

Para mais informações detalhadas, exemplos e comentários, leia esta conversa do Twitter.

Recursos

inert

Compatibilidade com navegadores

  • Chrome: 102.
  • Edge: 102.
  • Firefox: 112.
  • Safari: 15.5.

Origem

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:

O site é mostrado como interativo, depois um alert() é chamado e a página não está mais ativa.

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

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.

Visualização de comparação e gráfico de barras, mostrando como as fontes COLRv1 são mais nítidas e menores.
Imagem extraída de https://developer.chrome.com/blog/colrv1-fonts/

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;
}
Captura de tela da fonte Bungee Spice com a palavra DUNE.
Fonte Bungee Spice mostrada com cores personalizadas, fonte de https://developer.chrome.com/blog/colrv1-fonts/

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

Unidades de janela de visualização

Gráfico mostrando como a tela do dispositivo, a janela do navegador e um iframe têm viewports diferentes.

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.

Um gráfico com três smartphones para ajudar a ilustrar DVH, LVH e SVH. O smartphone do exemplo de DVH tem duas linhas verticais, uma entre a parte de baixo da barra de pesquisa e a parte de baixo da janela de visualização e outra acima da barra de pesquisa (abaixo da barra de status do sistema) até a parte de baixo da janela de visualização. Isso mostra como o DVH pode ter qualquer um desses dois tamanhos. A LVH é mostrada no meio, com uma linha entre a
   parte de baixo da barra de status do dispositivo e o botão da janela de visualização do smartphone. O último é
   o exemplo de unidade de SVH, mostrando uma linha da parte inferior da barra de pesquisa do navegador
   até a parte inferior da viewport.

Confira uma lista completa de todas as novas opções de unidade de viewport disponibilizadas com as novas variantes de viewport:

Unidades de altura 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;
}
Unidades da janela de visualização para a largura
.new-width-viewport-units {
  width: 100vw;
  width: 100dvw;
  width: 100svw;
  width: 100lvw;
  inline-size: 100vi;
  inline-size: 100dvi;
  inline-size: 100svi;
  inline-size: 100lvi;
}
Menores blocos laterais da janela de visualização
.new-min-viewport-units {
  --size: 100vmin;
  --size: 100dvmin;
  --size: 100svmin;
  --size: 100lvmin;
}
Maiores blocos laterais da janela de visualização
.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

:has()

Compatibilidade com navegadores

  • Chrome: 105.
  • Borda: 105.
  • Firefox: 121.
  • Safari: 15.4.

Origem

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

Compatibilidade com navegadores

  • Chrome: 85.
  • Edge: 85.
  • Firefox: 128.
  • Safari: 16.4.

Origem

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:

Confira a demonstração
.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;
}
Confira a demonstração

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

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

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

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

Compatibilidade com navegadores

  • Chrome: 118.
  • Edge: 118.
  • Firefox: atrás de uma flag.
  • Safari: 17.4

Origem

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.

Captura de tela do layout de alvenaria que mostra números que percorrem a parte de cima e depois descem.
Imagem e demonstração da Smashing Magazine
https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/

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

O CSS não pode ajudar os usuários a reduzir dados

Compatibilidade com navegadores

  • Chrome: por trás de uma flag.
  • Edge: atrás de uma flag.
  • Firefox: não é compatível.
  • Safari: não é compatível.

Origem

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.

Captura de tela da interface de carrossel de um programa de TV com muitas miniaturas e títulos exibidos.

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.

Captura de tela da interface de um carrossel de programas de TV sem miniaturas e com muitos títulos mostrados.

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

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

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;
}

Um menu de seleção com cores de destaque vermelhas.

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