Construindo Formas Geométricas com CSS e SVG

A criação de formas não retangulares na web tradicionalmente exigia imagens ou elementos complexos. No entanto, com o avanço das propriedades CSS3 e a integração do SVG, é possível construir uma vasta gama de formas geométricas diretamente no navegador, oferecendo maior flexibilidade e desempenho.

Elipses e Círculos com border-radius

A propriedade border-radius é fundamental para criar formas arredondadas, como círculos e elipses. Sua sintaxe permite controlar individualmente o arredondamento de cada canto, com a possibilidade de definir raios horizontais e verticais de forma independente (raio-horizontal / raio-vertical).

Círculo Perfeito

Um círculo é uma forma elíptica com raios horizontais e verticais iguais em todos os cantos. Aplica-se a um elemento quadrado.

.circulo-completo {
  border-radius: 50%; /* Define todos os cantos com 50% */
}

Meia Elipse

Para uma meia elipse, o arredondamento é aplicado apenas em lados específicos, formando uma curvatura em metade do elemento.

.meia-elipse {
  /* Canto superior esquerdo: 100% horizontal, 50% vertical */
  /* Canto superior direito: 0% */
  /* Canto inferior direito: 0% */
  /* Canto inferior esquerdo: 100% horizontal, 50% vertical */
  border-radius: 100% 0 0 100% / 50%;
}

Quarto de Elipse

Um quarto de elipse pode ser criado aplicando um arredondamento significativo a apenas um canto.

.quarto-elipse {
  border-radius: 100% 0 0 0; /* Apenas o canto superior esquerdo é arredondado */
}

Paralelogramos com transform: skew

Paralelogramos podem ser obtidos aplicando a transformação skewX() ou skewY() a um elemento retangular. No entanto, isso inclina não apenas a forma, mas também seu conteúdo, como o texto.

.elemento-inclinado {
  transform: skewX(-40deg); /* Inclina o elemento em 40 graus no eixo X */
}

Para evitar que o conteúdo interno (ex: texto) seja inclinado, uma solução robusta é usar pseudo-elementos (::before ou ::after). O pseudo-elemento recebe a inclinação e atua como o fundo da forma, enquanto o elemento principal mantém o texto sem inclinação.

.paralelogramo-container {
  width: 120px;
  height: 30px;
  position: relative;
  text-align: center;
  overflow: hidden; /* Garante que o pseudo-elemento não vaze */
}

.paralelogramo-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #6da584; /* Exemplo de cor de fundo */
  transform: skewX(-40deg); /* Aplica a inclinação ao fundo */
  transform-origin: bottom left; /* Ajusta o ponto de origem da transformação */
  z-index: -1; /* Envia o pseudo-elemento para trás do conteúdo */
}

Losangos com transform ou clip-path

A criação de losangos pode ser feita rotacionando um quadrado. Para que o losango preencha a área sem deixar lacunas nos cantos após a rotação de 45 graus, é necessário escalá-lo por aproximadamente sqrt(2) (cerca de 1.414). Contudo, assim como o paralelogramo, o conteúdo interno também seria rotacionado.

.losango-rotacionado {
  width: 100px;
  height: 100px;
  background-color: #a45;
  transform: rotate(45deg) scale(1.414); /* Rotaciona e escala */
}

Uma abordagem mais limpa e flexível para losangos e outras formas poligonais é usar a propriedade clip-path. Ela permite definir uma área de recorte de um elemento, tornando as partes fora do caminho invisíveis.

.losango-moderno {
  width: 100px;
  height: 100px;
  background-color: #c07a33; /* Cor de fundo */
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); /* Define os vértices do losango */
}

Efeitos de Cantos Decorativos

Cortes e chanfros em cantos podem adicionar um toque distintivo aos elementos. Diversas técnicas podem ser empregadas, incluindo múltiplos fundos e clip-path.

Cantos Chanfrados (Triangulares)

Usando múltiplos gradientes lineares, podemos simular cortes triangulares nos cantos de um elemento. Cada gradiente cobre um canto específico, com uma cor transparente e uma cor sólida.

.cantos-chanfrados {
  background-color: #2b7a7c;
  background-image:
    /* Canto superior esquerdo */
    linear-gradient(45deg, transparent 15px, #2b7a7c 0),
    /* Canto superior direito */
    linear-gradient(-45deg, transparent 15px, #2b7a7c 0),
    /* Canto inferior esquerdo */
    linear-gradient(135deg, transparent 15px, #2b7a7c 0),
    /* Canto inferior direito */
    linear-gradient(-135deg, transparent 15px, #2b7a7c 0);
  background-size: 50% 50%; /* Cada gradiente ocupa um quarto do elemento */
  background-repeat: no-repeat;
  background-position: top left, top right, bottom left, bottom right;
}

Cantos Arredondados (Côncavos)

Para criar cortes côncavos, podemos utilizar gradientes radiais. Cada gradiente é posicionado em um canto e se expande a partir de um ponto transparente.

.cantos-arredondados {
  background-color: #0d7377;
  background-image:
    /* Canto superior esquerdo */
    radial-gradient(circle at top left, transparent 20px, #0d7377 0),
    /* Canto superior direito */
    radial-gradient(circle at top right, transparent 20px, #0d7377 0),
    /* Canto inferior esquerdo */
    radial-gradient(circle at bottom left, transparent 20px, #0d7377 0),
    /* Canto inferior direito */
    radial-gradient(circle at bottom right, transparent 20px, #0d7377 0);
  background-size: 50% 50%;
  background-repeat: no-repeat;
  background-position: top left, top right, bottom left, bottom right;
}

Cortes com border-image e SVG

A propriedade border-image permite usar uma imagem (incluindo SVGs embutidos como Data URIs) para criar bordas complexas. Isso é útil para padrões repetitivos ou formas geométricas específicas nos cantos ou ao longo da borda.

.borda-svg-customizada {
  background-color: #555c68;
  background-clip: padding-box; /* O fundo não se estende para a área da borda */
  border: 10px solid #555c68; /* Uma borda sólida base */
  border-image: 1 url('data:image/svg+xml,<svg fill="%23555c68" height="3" width="3" xmlns="http://www.w3.org/2000/svg"><polygon points="0,1 1,0 2,0 3,1 3,2 2,3 1,3 0,2"></polygon></svg>');
}

Recortes Complexos via clip-path

Para formas com múltiplos vértices, clip-path oferece a maior flexibilidade, permitindo definir polígonos arbitrários para o recorte.

.recorte-multipolar {
  background-color: #4b6a7a;
  width: 150px;
  height: 80px;
  clip-path:
    polygon(
      15px 0, calc(100% - 15px) 0, 100% 15px,
      100% calc(100% - 15px), calc(100% - 15px) 100%,
      15px 100%, 0 calc(100% - 15px), 0 15px
    );
}

Trapezoides e Efeitos de Perspectiva

Trapezoides podem ser criados usando transformações 3D como perspective e rotateX.

Trapezoide Básico

Aplicando uma pequena rotação no eixo X com perspectiva, um retângulo pode ser visualmente transformado em um trapezoide.

.trapezoide-simples {
  width: 100px;
  height: 60px;
  background-color: #721817;
  transform: perspective(0.7em) rotateX(8deg); /* Perspectiva e rotação leve */
}

Efeito de Aba/Marcador

Ajustando a origem da transformação (transform-origin), é possível criar efeitos como abas ou marcadores de página, onde a transformação parece pivotar de um ponto específico.

.aba-marcador {
  width: 80px;
  height: 120px;
  background-color: #fa9f42;
  transform: perspective(0.8em) rotateX(10deg);
  transform-origin: bottom right; /* Ponto de pivô para a rotação */
}

Gráficos de Pizza (Setores Circulares)

Gráficos de pizza, ou setoriais, são formas circulares divididas em proporções. Podem ser construídos com CSS ou SVG.

Método CSS com Pseudo-elementos

Para gráficos até 50%, uma combinação de background-image com linear-gradient e um pseudo-elemento rotacionado funciona bem. O gradietne cria a metade base, e o pseudo-elemento cobre parte dela, criando o setor.

.grafico-pizza-css {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background-color: #555c68; /* Cor para a parte maior (>50%) */
  position: relative;
  /* Cria uma linha divisória para 50% */
  background-image: linear-gradient(90deg, transparent 50%, #29303d 0);
  overflow: hidden; /* Importante para esconder partes excedentes */
}

/* Pseudo-elemento para o setor do gráfico */
.grafico-pizza-css::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%; /* Posiciona no centro da borda direita */
  width: 50%;
  height: 100%;
  background-color: #555c68; /* Cor para a parte menor (até 50%) */
  transform-origin: left center; /* Gira a partir do centro */
  border-radius: 0 100% 100% 0 / 50%; /* Arredonda para formar a curva */
  transform: rotate(0.15turn); /* Exemplo: 15% de 360deg = 0.15 turn */
}

Para valores acima de 50%, a abordagem com gradiente e pseudo-elemento requer uma técnica diferente, pois o pseudo-elemento não consegue cobrir mais da metade do círculo corretamente. Uma solução avançada envolve o uso de animações CSS pausadas.

@keyframes rotacaoSetor {
  to { transform: rotate(0.5turn); } /* Gira 180 graus */
}

@keyframes trocaFundo {
  50% { background-color: #29303d; } /* Troca de cor no meio da animação */
}

.grafico-pizza-css.setor-60::before {
  /* Estilos básicos como acima, mas com animação */
  animation: rotacaoSetor 5s linear infinite, trocaFundo 10s step-end infinite;
  animation-delay: calc(-60 * 0.05s); /* -60% do tempo total de rotacaoSetor (5s * 0.6) */
  animation-play-state: paused; /* Congela na posição definida pelo delay negativo */
}

/* O tempo da animação e o delay negativo precisam ser calibrados:
   - `rotacaoSetor`: dura `X` segundos para 0.5turn (180deg).
   - `animation-delay`: `- (porcentagem / 100) * (tempo de rotacaoSetor * 2)`
     Exemplo para 60%: `-(0.6 * 5s * 2) = -6s`.
     O `trocaFundo` também precisa de ajuste para garantir a cor correta na seção maior.
     Isso é um truque para posicionar o "fim" da animação em um ponto específico.
*/

Método SVG

O SVG oferece uma maneira robusta e mais controlável de criar gráficos de pizza, usando elementos <circle> e as prporiedades stroke-width e stroke-dasharray.

  • stroke-width: Define a espessura do traço do caminho.
  • stroke-dasharray: Controla o padrão de traços e espaços ao longo do caminho. Aceita uma lista de números; o primeiro define o comprimento do traço, o segundo o comprimento do espaço, e assim por diante.

Ao definir um círculo e seu traço, podemos usar stroke-dasharray para "desenhar" apenas uma parte do círculo, formando um setor.

<div class="grafico-svg">
  <svg width="100" height="100" viewBox="0 0 100 100">
    <circle class="fundo-pizza" r="45" cx="50" cy="50"/>
    <circle class="setor-pizza" r="45" cx="50" cy="50"/>
  </svg>
</div>

.grafico-svg svg {
  transform: rotate(-90deg); /* Inicia o círculo de cima */
}

.grafico-svg .fundo-pizza {
  fill: none;
  stroke: #e0e0e0; /* Cor de fundo da pizza */
  stroke-width: 10;
}

.grafico-svg .setor-pizza {
  fill: none;
  stroke: #66b3cc; /* Cor do setor principal */
  stroke-width: 10;
  stroke-dasharray: 0 282.7; /* Inicializa com nenhum traço e um grande espaço */
  /* O perímetro de um círculo com r=45 é 2 * pi * 45 = ~282.7 */
  transition: stroke-dasharray 0.5s ease-out; /* Transição suave */
}

/* Exemplo de preenchimento de 60% */
.grafico-svg.preenchido-60 .setor-pizza {
  stroke-dasharray: calc(0.60 * 282.7) 282.7; /* 60% do perímetro, seguido do restante */
}

Para gráficos de pizza multicoloridos, empilhamos múltiplos círculos SVG, cada um representando um setor. A propriedade stroke-dashoffset é crucial aqui, pois ela desloca o ponto de partida do padrão de traços.

<div class="grafico-multi-setor">
  <svg width="100" height="100" viewBox="0 0 100 100">
    <circle class="fundo-total" r="45" cx="50" cy="50"/>
    <circle class="setor-um" r="45" cx="50" cy="50"/>
    <circle class="setor-dois" r="45" cx="50" cy="50"/>
    <circle class="setor-tres" r="45" cx="50" cy="50"/>
  </svg>
</div>

.grafico-multi-setor svg {
  transform: rotate(-90deg);
}

.grafico-multi-setor .fundo-total {
  fill: none;
  stroke: #eee;
  stroke-width: 10;
}

.grafico-multi-setor .setor-um,
.grafico-multi-setor .setor-dois,
.grafico-multi-setor .setor-tres {
  fill: none;
  stroke-width: 10;
  stroke-dasharray: 0 282.7; /* Perímetro total para cálculo */
  transition: all 0.3s ease-in-out;
}

/* Setor 1: 30% - Azul */
.grafico-multi-setor .setor-um {
  stroke: #428bca;
  stroke-dasharray: calc(0.30 * 282.7) 282.7;
  stroke-dashoffset: 0; /* Começa do topo */
}

/* Setor 2: 40% - Verde. Inicia após o Setor 1 */
.grafico-multi-setor .setor-dois {
  stroke: #5cb85c;
  stroke-dasharray: calc(0.40 * 282.7) 282.7;
  stroke-dashoffset: calc(-0.30 * 282.7); /* Desloca pelo comprimento do Setor 1 */
}

/* Setor 3: 30% - Vermelho. Inicia após o Setor 2 */
.grafico-multi-setor .setor-tres {
  stroke: #d9534f;
  stroke-dasharray: calc(0.30 * 282.7) 282.7;
  stroke-dashoffset: calc(-0.70 * 282.7); /* Desloca pelo comprimento do Setor 1 + Setor 2 */
}

Tags: CSS SVG border-radius clip-path transform

Publicado em 6-3 19:33 por Thomas