Jonathan Siqueira

← Voltar ao blog

O que Design Engineer precisa saber sobre CSS moderno

2026-05-17 / CSS, Design Engineering, Front-End, Design System

CSS moderno deixou de ser só acabamento visual. Para quem trabalha entre design e código, ele virou uma camada de sistema, experiência e engenharia.

Tem uma diferença grande entre saber CSS e entender o que o CSS virou.

Durante muito tempo, CSS foi tratado quase como acabamento visual. A parte “menos importante” do front-end. Algo mais perto de decoração do que de engenharia.

Hoje não consigo mais separar assim.

Principalmente para quem trabalha entre design e código.

O próprio MDN mostra bem essa mudança. CSS não é mais uma especificação única, fechada, com uma versão definitiva. É um conjunto de módulos evoluindo ao mesmo tempo: layout, cascade, scoping, color, transitions, animations, anchor positioning, container queries, values, functions.

Isso muda a forma de estudar.

Não basta decorar display, position, margin e padding.

Tudo isso ainda importa, claro. Mas CSS moderno ficou muito mais sobre sistema do que sobre propriedade isolada.

Você não está só pintando interface. Você está definindo comportamento visual.

Quando comecei, muito layout ainda era feito no improviso.

Vários position: absolute. Muito margin-top: -12px. Muito ajuste manual tentando convencer a tela a ficar no lugar.

Hoje a lógica mudou bastante.

Flexbox ajudou a resolver distribuição. Grid mudou a forma de pensar composição. Subgrid levou isso um pouco mais longe, porque permite alinhar partes internas de um componente ao grid do contexto onde ele vive.

Essa é uma virada importante.

Não é só sobre alinhar elementos. É sobre estruturar relações.

Antes, era comum resolver layout assim:

.card {
  float: left;
  width: 33.333%;
  padding: 16px;
}

.card:nth-child(3n + 1) {
  clear: left;
}

Funcionava. Mas era um layout montado na força.

Hoje, a intenção fica mais clara:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
}

O CSS passa a descrever o sistema, não só o ajuste.

Depois que isso entra na cabeça, você para de montar blocos soltos de tela e começa a montar sistemas de layout.

Outra coisa que mudou muito foi variável CSS.

Antes, Design System no front-end quase sempre parecia depender de gambiarra, preprocessador ou alguma camada extra para ficar minimamente organizado.

Hoje o próprio CSS já resolve boa parte dessa ponte. E não só com --custom-properties.

:root {
  --color-primary: #2563eb;
  --spacing-md: 16px;
  --radius-lg: 24px;
}

Parece simples. Mas muda bastante a conversa.

O token deixa de existir só no Figma. Ele passa a viver na interface real. E quando isso acontece, design e engenharia começam a discutir a mesma linguagem, não duas versões desconectadas da mesma decisão.

Com @property, essa conversa fica ainda mais interessante. A variável pode ter tipo, valor inicial e regra de herança.

Antes, muita animação com variável customizada era meio “solta”:

.progress {
  --progress: 40%;
  background: linear-gradient(
    to right,
    #2563eb var(--progress),
    #e5e7eb 0
  );
}

Hoje, quando faz sentido, dá para registrar melhor essa intenção:

@property --progress {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}

Isso parece pequeno, mas aproxima token de contrato.

Não é só “uma string solta no CSS”. É uma decisão visual com intenção mais explícita.

Container Queries também entram nessa mudança.

Responsividade deixou de ser apenas uma resposta ao tamanho da tela. Agora o componente consegue reagir ao espaço em que está inserido.

Isso parece detalhe até você trabalhar em um Design System maior.

Porque o mesmo componente pode aparecer em contextos diferentes, com densidades diferentes, em layouts diferentes. E talvez a pergunta mais importante não seja mais “qual é o breakpoint da página?”, mas “qual é o espaço real desse componente aqui?”.

Antes, a adaptação quase sempre olhava para a viewport:

@media (min-width: 768px) {
  .product-card {
    display: grid;
    grid-template-columns: 12rem 1fr;
  }
}

Hoje, o componente pode responder ao próprio container:

.product-card-wrapper {
  container-type: inline-size;
}

@container (min-width: 36rem) {
  .product-card {
    display: grid;
    grid-template-columns: 12rem 1fr;
  }
}

Isso parece uma diferença pequena. Mas muda a responsabilidade do componente.

Em 2025, @scope também ficou mais importante nessa conversa.

A ideia é simples: limitar onde uma regra vale sem depender de seletor gigante, nome de classe defensivo ou acoplamento demais com a árvore do HTML.

Antes, a gente tentava se proteger com seletor comprido:

.checkout-page .summary-card .button.primary {
  background: #171717;
}

Hoje, @scope aponta melhor a área de atuação da regra:

@scope (.summary-card) {
  .button.primary {
    background: #171717;
  }
}

Para Design System, isso toca em um ponto sensível.

CSS moderno não está só ficando mais poderoso. Ele está ficando mais consciente de contexto.

E contexto é exatamente onde muita interface quebra.

Outra novidade que entrou no meu radar é CSS Anchor Positioning.

Por muito tempo, tooltip, popover, menu flutuante e dropdown foram quase sinônimo de JavaScript medindo posição na tela.

Anchor positioning muda essa relação. Ele permite amarrar um elemento a outro e deixar o CSS participar mais diretamente desse posicionamento.

Antes, muita gente acabava indo para cálculo manual:

const rect = button.getBoundingClientRect();

popover.style.top = `${rect.bottom + 8}px`;
popover.style.left = `${rect.left}px`;

Hoje, a direção do CSS é deixar esse vínculo mais declarativo:

.button {
  anchor-name: --menu-button;
}

.popover {
  position: absolute;
  position-anchor: --menu-button;
  top: anchor(bottom);
  left: anchor(left);
}

Ainda é uma área para olhar com atenção, suporte e fallback. Mas a direção é clara: muito comportamento visual que antes parecia inevitavelmente “scriptado” está voltando para a camada de estilo.

Outra coisa que fui percebendo com o tempo: motion virou parte da arquitetura da experiência.

Não como efeito bonito.

Como comunicação.

Um hover comunica intenção. Uma transição comunica continuidade. Uma animação comunica estado.

Com @starting-style, transition-behavior e animações guiadas por scroll, CSS começou a descrever melhor momentos que antes eram tratados como exceção: entrada de elemento, mudança de estado, continuidade entre uma posição e outra.

Antes, era comum criar uma classe só para forçar o primeiro estado:

.toast {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 200ms, transform 200ms;
}

.toast.is-entering {
  opacity: 0;
  transform: translateY(8px);
}

Hoje, o CSS consegue declarar esse começo:

.toast {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 200ms, transform 200ms;

  @starting-style {
    opacity: 0;
    transform: translateY(8px);
  }
}

Isso não significa animar tudo.

Significa entender que movimento também é interface.

CSS moderno participa mais da experiência do produto do que muita gente admite. Ele não está só no visual final. Ele está na forma como a interface responde, orienta e dá feedback.

Cor também mudou.

Hoje faz pouco sentido pensar só em hex estático. Temos color-mix(), cores relativas, oklch(), light-dark() e uma conversa muito mais próxima de sistema, contraste, tema e acessibilidade.

Antes, tema costumava virar duplicação:

:root {
  --bg: #ffffff;
  --fg: #171717;
}

[data-theme="dark"] {
  --bg: #171717;
  --fg: #ffffff;
}

Hoje, dependendo do caso, a intenção pode ficar mais direta:

:root {
  color-scheme: light dark;
  --bg: light-dark(#ffffff, #171717);
  --fg: light-dark(#171717, #ffffff);
  --border: color-mix(in oklch, var(--fg) 16%, transparent);
}

Para quem desenha e implementa, isso é enorme.

Porque um tema não precisa ser uma pilha infinita de exceções. Pode ser uma lógica.

E o CSS está ficando melhor em expressar lógica.

Ao mesmo tempo, nem tudo que aparece no MDN deve virar produção no dia seguinte.

if(), por exemplo, é uma função muito interessante porque leva condições para valores CSS. Mas o próprio MDN marca como experimental e fora de Baseline no momento.

Para mim, essa talvez seja uma das habilidades mais importantes hoje: saber diferenciar o que já dá para usar, o que dá para testar e o que ainda precisa ficar no laboratório.

E tem uma parte menos falada que, para mim, ficou cada vez mais importante: performance visual.

Tem muita interface bonita que performa mal.

Blur pesado. Sombra exagerada. Animação em tudo. Camada demais.

Em algum momento, Design Engineer começa a perceber que estética também custa renderização. E isso muda a forma de desenhar interface.

Não é sobre deixar tudo simples demais. É sobre entender o custo das decisões visuais.

A IA também acelerou uma coisa interessante: a aproximação entre design e front-end.

Hoje já virou comum ver designer mexendo em código, dev discutindo tipografia, token conectando design e implementação, protótipo ficando mais perto de produção.

A fronteira ficou mais borrada.

E sinceramente, acho difícil trabalhar nessa interseção sem entender CSS moderno de verdade.

Mesmo usando framework. Mesmo usando IA. Mesmo usando abstração.

Talvez até principalmente por isso.

Porque IA costuma gerar alguma coisa que parece interface. Mas quem entende CSS consegue perceber se aquilo escala, se performa, se respeita contexto, se vira componente, se dá manutenção.

No fim, CSS continua sendo a camada que transforma intenção visual em produto real.

Talvez seja justamente isso que mais me interessa hoje nessa área: essa mistura de sistema, visual, experiência e engenharia vivendo no mesmo lugar.