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 */
}