Usar shape() para recorte responsivo

Publicado em 8 de abril de 2025

A propriedade clip-path permite mudar a forma de um elemento cortando-o em um círculo, polígono ou até mesmo um caminho SVG. No entanto, antes do Chrome 135 e do Safari 18.4, era necessário escolher entre polígonos responsivos e formas mais complexas que não são responsivas usando caminhos SVG. Com a nova função shape(), um clip-path pode recortar o elemento para uma forma não poligonal que também é responsiva.

Browser Support

  • Chrome: 135.
  • Edge: 135.
  • Firefox Technology Preview: supported.
  • Safari: 18.4.

Source

Criar uma forma de bandeira

Como exemplo, compare a criação de uma forma de bandeira com clip-path: path() e clip-path: shape().

Uma forma de bandeira verde com linhas curvas na parte de cima e de baixo.

Uma forma de bandeira não é exatamente um polígono, já que as bordas de cima e de baixo são curvas Bézier cúbicas, e não linhas retas ou cantos arredondados.

Crie a flag com clip-path: path()

Uma forma como esta bandeira pode ser representada usando um caminho SVG:

.flag {
  clip-path: path(
    "M 0 20 \
     C 25 0 75 40 100 20 \
     V 80 \
     C 75 100 25 60 0 80 \
     z");
}

Um caminho SVG é uma série de comandos de caminho:

  1. Mova para 0, 20.
  2. Curva para 100, 20, usando pontos de controle (25,0 e 75, 40).
  3. Linha vertical para 80.
  4. Curva para 0, 80, usando pontos de controle (75,100 e 25,50).
  5. Feche o caminho (linha para 0,20).

Isso desenha uma forma de bandeira, mas todas as unidades estão em pixels. O SVG pode dimensionar esses pixels para uma caixa de visualização, mas de uma maneira que sempre pareça uma escala geométrica de toda a forma.

Por exemplo, se você quiser que o retângulo inteiro seja dimensionado, mas mantenha a altura e a largura das curvas em 20 px, o SVG não vai conseguir fazer isso.

Crie a flag com shape()

Compare o mesmo resultado usando shape(). A função de forma aceita uma série de comandos, semelhante aos comandos de caminho SVG. No entanto, esses comandos aceitam comprimentos e porcentagens do CSS em qualquer unidade do CSS.

O CSS a seguir converte a flag shape() com unidades percentuais:

.flag {
  clip-path: shape(from 0% 20%,
     curve to 100% 20% with 25% 0% / 75% 40%,
     vline to 80%,
     curve to 0% 80% with 75% 100% / 25% 60%,
     close
  );
}

Crie uma versão responsiva

Com a gama completa de comprimentos CSS disponíveis, você pode escolher quais usar para cada coordenada.

Por exemplo, para fazer o tamanho inteiro da bandeira variar de acordo com o tamanho do elemento, mas manter a altura da curva constante, faça o seguinte:

.flag {
  clip-path: shape(from 0% 20px,
     curve to 100% 20px with 25% 0% / 75% 40px,
     vline to calc(100% - 20px),
     curve to 0% calc(100% - 20px) 
           with 75% 100% / 25% calc(100% - 40px),
     close
  );
}

Adicionar propriedades e animações personalizadas

Com a forma definida no CSS, você também pode usar propriedades personalizadas para facilitar a manipulação da altura:

.flag {
  --wave-height: 40px;
  clip-path: shape(
    from 0px var(--wave-height),
    curve to 100% var(--wave-height) 
          with 25% 0px / 75% calc(var(--wave-height) * 2),
    vline to calc(100% - var(--wave-height)),
    curve to 0 calc(100% - var(--wave-height))
          with 75% 100% / 25% calc(100% - var(--wave-height) * 2),
    close
  )
}

Você pode até animar a propriedade CSS usando o descritor @property e fixá-la para que ela não ultrapasse:

@property --animated-wave-height {
  syntax: "<length>";
  inherits: false;
  initial-value: 40px;
}

@keyframes curve {
  from { --animated-wave-height: 0px; }
  to { --animated-wave-height: 180px; }
}

.flag {
  width: 600px;
  height: 400px;
  background: green;
  animation: curve 1s infinite alternate;
  --wave-height: calc(min(var(--animated-wave-height, 40px), 40%));
  clip-path: shape(
    from 0px var(--wave-height),
    curve to 100% var(--wave-height)
          with 25% 0px / 75% calc(var(--wave-height) * 2),
    vline to calc(100% - var(--wave-height)),
    curve to 0 calc(100% - var(--wave-height)) 
          with 75% 100% / 25% calc(100% - var(--wave-height) * 2),
    close
  )
}

Teste a demonstração

No Chrome 135 ou no Safari 18.4, é possível ver a forma de bandeira animada criada usando clip-path: shape() nesta demonstração do CodePen.

Resumo

clip-path: shape() permite recortar o elemento usando formas arbitrárias e responsivas, o que antes só era possível usando técnicas como gradientes cônicos ou SVGs construídos em JavaScript.

Consulte a especificação para conferir a sintaxe completa.

No momento, isso só funciona para clip-path. No futuro, planejamos usar esse tipo de forma para definir a forma da borda do elemento, o que permitiria ainda mais formas de expressão não retangulares.