Artigo original: CSS Shapes Explained: How to Draw a Circle, Triangle, and More Using Pure CSS
Antes de começarmos, saiba que, se você quiser mais conteúdo gratuito, porém em vídeo, o autor tem um canal no YouTube onde ele publica vídeos semanais sobre código para o front-end.
https://www.youtube.com/user/Weibenfalk
----------
Você é um novato em desenvolvimento para a web e em CSS? Já se perguntou como são feitas aquelas formas legais que você vê por toda a internet? Chega de se perguntar. Você veio ao lugar certo.
Abaixo, explicarei o básico na criação de formas com CSS. Existe muita coisa para dizer sobre o assunto! Portanto, eu não vou tratar de todas (longe disso) as ferramentas e formas, mas este artigo deve dar a você uma ideia básica de como são criadas as formas com CSS.
Algumas formas exigem mais "ajustes e truques" do que outras. Criar formas com CSS geralmente se resume a uma combinação dos atributos width, height, top, right, left, border, bottom, transform e de pseudoelementos como :before e :after. Também temos propriedades do CSS mais modernas para criar formas, como shape-outside e clip-path. Também falarei sobre elas mais abaixo.
Formas em CSS - o modo básico
Usando alguns truques em CSS, sempre foi possível criar formas básicas, como quadrados, círculos e triângulos usando as propriedades mais comuns. Vamos examinar algumas delas agora.
Quadriláteros e triângulos
Quadrados e retângulos são, provavelmente, as formas mais fáceis de se fazer. Por padrão, uma div é sempre um quadrado ou um retângulo.
Você define width (largura) e height (altura) conforme mostramos no código abaixo. Depois, é só uma questão de dar ao elemento uma background color (cor de fundo). Você pode usar todas as outras propriedades que quiser no elemento.
#quadrado {
background: lightblue;
width: 100px;
height: 100px;
}

Círculos
O círculo também é fácil de criar. Para criar um círculo, definimos o border-radius (raio da borda) do elemento. Isso criará cantos curvados no elemento.
Se os definirmos como 50%, criaremos um círculo. Se você definir uma width e uma height diferentes, obteremos uma figura oval.
#circulo {
background: lightblue;
border-radius: 50%;
width: 100px;
height: 100px;
}

Triângulos
Triângulos são um pouco mais complicados. Temos de definir as bordas no elemento para que correspondam a um triângulo. Ao definir width e height como zero no elemento, a width real do elemento será a da borda.
Lembre-se de que os cantos das bordas em um elemento são diagonais a 45 graus uns dos outros. É por isso que esse método funciona para criar um triângulo. Ao definir uma das bordas com uma cor sólida e as outras bordas como transparentes, o elemento tomará a forma de um triângulo.

#triangulo {
width: 0;
height: 0;
border-left: 40px solid transparent;
border-right: 40px solid transparent;
border-bottom: 80px solid lightblue;
}

Se quiser que o triângulo/seta aponte em outra direção, você pode trocar os valores de borda correspondentes ao lado que você quer que seja visível. Você também pode rodar o elemento com a propriedade transform se quiser ser realmente elegante.
#triangulo {
width: 0;
height: 0;
border-top: 40px solid transparent;
border-right: 80px solid lightblue;
border-bottom: 40px solid transparent;
}

Certo – essa foi a introdução sobre as formas básicas com CSS. Existem, provavelmente, infinitas formas que você pode pensar em criar. Essas são apenas as fundamentais, mas, com um pouco de criatividade e determinação, você conseguirá muito apenas com as propriedades básicas do CSS.
Em alguns casos, com formas mais avançadas, também é uma boa ideia usar os pseudosseletores :after e :before (depois e antes, respectivamente). Isto está fora do escopo deste artigo, no entanto, já que minha intenção é tratar das questões mais básicas para deixá-lo pronto para seguir em frente.
Desvantagem
Existe uma grande desvantagem com a abordagem acima. Por exemplo, se você quiser que seu texto flua ao redor e envolva sua forma. Uma div de HTML regular, com segundo plano e bordas compondo a forma, não permitirá isso. O texto não se adaptará nem circundará sua forma. Em vez disso, ele ficará em volta da própria div (que é um quadrado ou um retângulo).
Abaixo vemos uma ilustração de um triângulo e de como ficaria o fluxo do texto.

Por sorte, temos propriedades modernas de CSS para usar.
Formas em CSS - A outra maneira
Hoje em dia, temos uma propriedade chamada shape-outside para usar no CSS. Essa propriedade permite que você defina uma forma para que o texto a envolva e flua ao seu redor.
Junto dessa propriedade, temos algumas formas básicas:
inset()
circle()
ellipse()
polygon()
Aqui vai uma dica: Você também pode usar a propriedade clip-path. Você pode criar sua forma com ela da mesma maneira, mas ela não deixará o texto envolver sua forma do jeito que shape-outside permite.
O elemento em que vamos aplicar a forma com a propriedade shape-outside precisa ter a propriedade float. Ele também precisa ter width e height definidos. É realmente importante que você saiba disso!
Você pode ler mais a respeito do motivo aqui (texto em inglês). Abaixo, vemos um texto que extraí do link fornecido para o developer.mozilla.org.
A propriedade shape-outside
é especificada usando os valores da lista abaixo, que define a área de flutuação dos elementos com float. A área de flutuação determina a forma ao redor da qual o conteúdo em linha (os elementos com float) ficará envolvido.
inset()
O tipo inset() pode ser usado para criar um retângulo/quadrado com um deslocamento opcional para o texto que o envolve. Ele permite fornecer valores para quanto você quer que o texto ao redor da forma entrecruze a forma.
Você pode especificar o deslocamento para que ele seja igual para todas as quatro direções assim: inset(20px). Também é possível fazer isso individualmente para cada direção: inset(20px 5px 30px 10px).
Você pode usar outras unidades para definir o deslocamentos, como, por exemplo, porcentagem. Os valores têm essa sequência: inset(acima direita abaixo esquerda).
Confira o exemplo do código abaixo. Especifiquei os valores de inset como 20px na parte superior, 5px à direita, 30px na parte inferior e 10px à esquerda. Se quiser que seu texto cerque seu quadrado ao invés disso, nem precisa usar inset(). Apenas defina o segundo plano (background) de sua div e o tamanho como sempre.
#quadrado {
float: left;
width: 100px;
height: 100px;
shape-outside: inset(20px 5px 30px 10px);
background: lightblue;
}

Também é possível dar a inset() um segundo valor que especifica o border-radius do inset. Veja o exemplo abaixo:
#quadrado {
float: left;
width: 100px;
height: 100px;
shape-outside: inset(20px 5px 30px 10px round 50px);
background: lightblue;
}

circle()
Aqui, um círculo é criado usando a propriedade shape-outside. Você também precisa aplicar um clip-path com a propriedade correspondente para que o círculo apareça.
A propriedade clip-path pode receber o mesmo valor que a propriedade shape-outside para darmos a ela a forma padrão de circle(), que usamos para shape-outside. Além disso, observe que apliquei uma margem de 20px no elemento aqui para dar ao texto algum espaço.
#circulo {
float: left;
width: 300px;
height: 300px;
margin: 20px;
shape-outside: circle();
clip-path: circle();
background: lightblue;
}

No exemplo acima, eu não especifico o raio do círculo. Isso ocorre porque eu quis que ele fosse do tamanho da div (300px). Se quiser especificar um tamanho diferente para o círculo, é possível fazer isso.
A propriedade circle() recebe dois valores. O primeiro é o raio e o segundo é a posição. Esses valores especificarão o centro do círculo.
No exemplo abaixo, defini radius (raio) como 50%. Em seguida, mudei o centro do círculo para 30%. Observe que a palavra "at" tem de ser usada entre os valores de radius e de position (posição).
Eu também especifiquei outro valor de position em clip-path. Isso cortará o círculo pela metade já que o movi para a posição zero.
#circulo {
float: left;
width: 150px;
height: 150px;
margin: 20px;
shape-outside: circle(50% at 30%);
clip-path: circle(50% at 0%);
background: lightblue;
}

ellipse()
As elipses funcionam da mesma forma que os círculos, exceto pelo fato de criarem uma figura oval. Você pode definir os valores de X e de Y, assim: ellipse(25px 50px).
Da mesma forma que no círculo, ela também recebe um valor de position como o último valor.
#elipse {
float: left;
width: 150px;
height: 150px;
margin: 20px;
shape-outside: ellipse(20% 50%);
clip-path: ellipse(20% 50%);
background: lightblue;
}

polygon()
Um polígono é uma forma com vértices/coordenadas definidas. Abaixo, eu crio uma forma de "T", que é a primeira letra do meu nome. Eu começo nas coordenadas 0,0 e vou me movendo da esquerda para a direita para criar a forma de "T".
#poligono {
float: left;
width: 150px;
height: 150px;
margin: 0 20px;
shape-outside: polygon(
0 0,
100% 0,
100% 20%,
60% 20%,
60% 100%,
40% 100%,
40% 20%,
0 20%
);
clip-path: polygon(
0 0,
100% 0,
100% 20%,
60% 20%,
60% 100%,
40% 100%,
40% 20%,
0 20%
);
background: lightblue;
}

Imagens
Você também pode usar as imagens com segundo plano transparente para criar sua forma, como esta linda lua redonda abaixo.
Essa é uma imagem .png com um segundo plano transparente.
<img src="src/moon.png" id="moon" />

#lua {
float: left;
width: 150px;
height: 150px;
shape-outside: url("./src/moon.png");
}

É isso! Obrigado pela leitura.
Sobre o autor desse artigo
O nome do autor é Thomas Weibenfalk, um desenvolvedor da Suécia. Ele cria regularmente tutoriais gratuitos no canal dele no YouTube. Ele também tem alguns cursos premium sobre React e Gatsby. Visite-o em um desses links:
Twitter — @weibenfalk,
Weibenfalk no YouTube,
Site de cursos de Thomas Weibenfalk.