Assim como o JavaScript, o CSS não tem a melhor reputação entre os desenvolvedores (Rails). E assim como o JavaScript (pense em Turbo, mas também em CoffeeScript), o CSS tem uma longa história de pré-processadores, pós-processadores e abstrações (pense em Tailwind CSS).
E por muito tempo, muitos desses recursos em camadas foram muito necessários. É difícil imaginar CSS sem seletores aninhados, não é?
Mas é 2025 e o CSS está (e é!) melhorando em alta velocidade. Longe vão os dias de spacer.gif
ou de criar imagens para cada canto de um componente de cartão para imitar raios de borda.
Se você tem negligenciado o CSS por um tempo (porque você usou Tailwind CSS, por exemplo), abaixo quero destacar alguns dos recursos mais recentes do CSS que tenho usado felizmente em alguns projetos (que são construídos sob o guarda-chuva do Rails Designer ou outros). Embora eu ainda goste de usar o Tailwind CSS, entender e realmente usar o CSS real é essencial. A web é construída em padrões (abertos) que são importantes para mantê-la acessível, fácil de manter e à prova do futuro.
Consultas de Contêiner (Container Queries)
As media queries são ótimas para adaptar seu layout ao tamanho da viewport. Mas e se você quiser adaptar um componente ao tamanho de seu contêiner pai? É aí que entram as consultas de contêiner. Elas permitem que você escreva estilos que se aplicam com base no tamanho de um elemento pai, em vez da viewport.
@container (min-width: 400px) {
.card {
grid-template-columns: 1fr 1fr;
}
}
Isso é especialmente útil para componentes reutilizáveis que podem ser colocados em diferentes layouts. Por exemplo, um componente de cartão pode ter um layout diferente quando colocado em uma barra lateral estreita do que quando colocado em uma área de conteúdo principal ampla.
@container (min-width: 400px) {
.card {
grid-template-columns: 1fr 1fr;
}
}
@container (max-width: 768px) {
.card {
flex-direction: column;
}
}
@container (min-width: 768px) and (max-width: 1199px) {
.card {
width: 65ch;
}
}
/* New range syntax */
@media (768px <= width <= 1199px) {
.card { width: 65ch; }
}
/* Common breakpoint patterns */
.container {
/* Smaller than 768px */
@media (width < 768px) {
padding: 1rem;
}
/* Larger than 1200px */
@media (width >= 1200px) {
max-width: 1140px;
}
/* Between breakpoints */
@media (480px <= width < 768px) {
margin: 1.5rem;
}
}
light-dark
Abreviação para definir diferentes valores com base na preferência de esquema de cores do usuário, sem escrever media queries separadas.
.card {
/* Basic color values */
background: light-dark(#f1f5f9, #0f172a);
color: light-dark(#0f172a, #f1f5f9);
/* Works with any color format */
border: 1px solid light-dark(rgb(226, 232, 240), rgb(51, 65, 85));
}
color-scheme
Junto com light-dark
, color-scheme
informa ao navegador quais esquemas de cores um componente suporta, permitindo que elementos nativos (como barras de rolagem, campos de formulário) correspondam automaticamente à preferência do usuário.
/* Global level - typically in :root */
:root {
/* Support both schemes, dark listed first means dark is preferred */
color-scheme: dark light;
}
/* Component level - useful for cards or modals that differ from global scheme */
.themed-card {
/* This card only supports light mode */
color-scheme: light;
/* System UI elements inside will stay light */
input {
/* Inputs remain light-styled even in dark mode */
border: 1px solid #ddd;
}
}
/* Dark-only interface section */
.code-editor {
/* Force dark appearance for all system UI within */
color-scheme: dark;
}
Aninhamento (Nesting)
Direto dos pré-processadores (como Less e Sass). Agora você pode escrever CSS nativamente com seletores filhos aninhados dentro de seus pais. Ajuda a manter relacionamentos claros entre componentes e seus filhos. Anteriormente, esses relacionamentos eram feitos implicitamente usando metodologias como BEM, por exemplo, card__header
.
.card {
padding: .75 1.25rem;
background-color: #fff;
border-radius: 1rem;
/* Nest direct children with & */
& .header {
font-size: 1.7rem;
}
/* Nest state changes */
&:hover {
background: #f1f5f9;
}
/* Nest multiple selectors */
& .title,
& .subtitle {
font-weight: 600;
}
/* Nest media queries */
@media (width > 768px) {
padding: 1 1.375rem;
}
}
Unidades (Units)
Em CSS, existem dois tipos principais de unidades: absolutas e relativas. Unidades absolutas como cm
, mm
, in
(e outras) representam medidas físicas fixas e estão disponíveis desde os primórdios do CSS. Pixels (px
) são, na verdade, unidades relativas (elas escalam com base no dispositivo de visualização). A maioria das outras unidades também são relativas, escalando com base em fontes, viewports ou outros fatores. O CSS1 nos deu em
para dimensionamento baseado em fonte, o CSS3 adicionou unidades de viewport como vh
e vw
(introduzidas por volta de 2012), e recentemente (2022) obtivemos dvh
para lidar melhor com os navegadores móveis. Observe que várias unidades relativas (como em
, ex
, ch
) podem ser calculadas de forma diferente com base em onde são usadas. Seu comportamento pode mudar quando usadas com font-size
versus outras propriedades como width
ou margin
.
Baseadas em Fonte
em
– Relativo ao tamanho da fonte do elemento pai
rem
– Relativo ao tamanho da fonte do elemento raiz
ex
– Representa a altura-x da fonte atual (aproximadamente a altura do caractere minúsculo “x”) – esta unidade existe desde o CSS1, mas só recentemente aprendi sobre ela
ch
– Largura do caractere “0” (zero) na fonte atual – disponível desde o CSS3, mas muitas vezes esquecida
lh
– Igual à altura da linha do elemento
Baseadas em Viewport
vh
– 1% da altura da viewport
vw
– 1% da largura da viewport
vmin
– 1% da menor dimensão da viewport (altura ou largura) – também do CSS3, mas menos comumente usada
vmax
– 1% da maior dimensão da viewport (altura ou largura) – também do CSS3, mas menos comumente usada
Viewport Moderna
dvh
– Altura dinâmica da viewport, ajusta-se ao chrome/elementos da UI do navegador móvel
dvw
– Largura dinâmica da viewport
svh
– Altura pequena da viewport, menor altura possível ao considerar elementos dinâmicos da UI
svw
– Largura pequena da viewport
lvh
– Altura grande da viewport, maior altura possível ao considerar elementos dinâmicos da UI
lvw
– Largura grande da viewport
@layer
Se você usou Tailwind CSS, isso pode parecer familiar. @layer
gerencia conflitos de especificidade ordenando explicitamente grupos de estilo. Camadas posteriores sempre “vencem” independentemente da especificidade, resolvendo a cascata que confunde (e irrita!) tantos desenvolvedores.
/* Define layer order - order here determines priority */
@layer reset, components, utilities;
/* Reset layer: lowest priority */
@layer reset {
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
}
/* Components layer: middle priority */
@layer components {
.button {
/* Even if utilities have lower specificity,
they\'ll still override these styles */
padding: .5rem 1rem;
background: blue;
}
}
/* Utilities layer: highest priority */
@layer utilities {
.p-4 {
/* This wins over component padding */
padding: 1.25rem;
}
.bg-red {
/* This wins over component background */
background: red;
}
}
E isso é apenas uma pequena visão geral de algumas das novas propriedades que tenho usado em um dos meus produtos mais recentes. Você aprendeu algo novo? Me diga!