
Sabe quando você vai ler uma revista, e no meio do texto há uma imagem irregular, mas o texto elegantemente a contorna, respeitando sua forma? Ou quando aparece por exemplo, um gráfico de pizza, e dentro de cada fatia tem um texto que se adequa a forma dela?
Pois é, eu não faço a mínima ideia de como eles fazem isso. Só sei que agora podemos fazer o mesmo com CSS!
Se você ainda não entendeu nada, dê uma boa olhada na imagem a seguir.
Não estou falando das colunas, isso é assunto para outro post ;) Perceba como o texto da coluna direita acompanha a forma do penhasco.
Antes de continuar
Para visualizar os exemplos deste post corretamente, você deve estar utilizando o navegador Google Chrome e é preciso habilitar uma flag dele primeiro. Na versão estável (atualmente 27) basta digitar chrome://flags na barra de endereços, e habilitar a opção Experimental WebKit features, como na imagem abaixo. Depois reinicie o navegador.
CSS shapes
Antes de falar das aplicações das CSS shapes, vamos primeiramente entender do que se tratam estas entidades.
Shapes são formas geométricas que definem contornos os quais conteúdos inline flutuam – ou seja, conteúdo textual e inicialmente imagens e elementos definidos com display: inline
ou display: inline-block
.
Shapes define arbitrary geometric contours around which inline content flows.
A Adobe e a Microsoft estão por trás desta especificação – CSS Shapes Module Level 1 – cujo trabalho ainda está em andamento, porém já podemos testar e brincar com várias coisas graças ao Google Chrome.
Formas básicas
Inicialmente, há 4 formas básicas definidas:
- Retângulo: através das funções
rectangle()
einset-rectangle()
; - Círculo: através da função
circle()
; - Elípse: através da função
ellipse()
; - Polígono: através da função
polygon()
.
Vale observar que todos os valores usados como parâmetros destas funções podem ser absolutos (px
, in
, pt
, cm
, etc.) ou relativos (%
, em
, rem
, ex
, etc.)
rectangle()
/* rectangle(x, y, width, height, rx, ry) */
rectangle(0, 0, 100px, 80px, 20%, 40%)
x
ey
: coordenadas do ponto inicial nos eixos X e Y (horizontal e vertical);width
eheight
: largura e altura;rx
ery
: raio dos cantos nas direções horizontal e vertical (para bordas arredondadas) (opcional).
inset-rectangle()
/* inset-rectangle(top, right, bottom, left, rx, ry) */
inset-rectangle(10%, 20%, 40px, 20%, 8px, 8px)
top
,right
,bottom
eleft
: Define o retângulo em relação ao seu elemento ancestral;rx
ery
: raio dos cantos nas direções horizontal e vertical (para bordas arredondadas) – opcionais.
circle()
/* circle(cx, cy, radius) */
circle(50%, 50%, 80px)
cx
ecy
: coordenadas do ponto central nos eixos X e Y (horizontal e vertical);radius
: raio do círculo;
ellipse()
/* ellipse(cx, cy, rx, ry) */
ellipse(50%, 50%, 80px, 200px)
cx
ecy
: coordenadas do ponto central nos eixos X e Y (horizontal e vertical);rx
ery
: raios nos eixos X e Y (horizontal e vertical).
polygon()
/* polygon(x1 y1, x2 y2, ..., xn yn) */
polygon(10px 10px, 20px 10px, 20px 20px) /* um triângulo */
xn
eyn
: tuplas com as coordenadas dos pontos do polígono no eixos X e Y (horizontal e vertical). O polígono será fechado automaticamente ligando-se o primeiro ao último ponto da lista.
Aplicando as shapes
Agora que conhecemos os 4 tipos de formas básicas, podemos começar a utilizá-las através das propriedades shape-outside
e shape-inside
. Há também outras propriedades relacionadas às shapes, como shape-margin
, shape-padding
e shape-image-threshold
. Vamos a elas.
shape-outside
Com shape-outside
é possível definir o contorno externo de um elemento. Atualmente apenas funciona em elementos flutuantes (com float: left
ou float: right
).
Por exemplo, podemos ter uma <div>
de tamanho 100x100px que flutua à esquerda de um texto, e ainda ter a forma de um círculo (com a propriedade border-radius
):
<article>
<div class="flutua"></div>
Vou mostrando como sou e vou sendo como posso (...)
</article>
E .flutua
definido no CSS abaixo, vamos ter algo parecido como isto:
.flutua
.flutua {
width: 100px;
height: 100px;
float: left;
border-radius: 50%;
}
Perceba que, apesar do elemento .flutua
ter sua aparência circular, o seu layout é retangular. Todos os elementos HTML são assim – no final das contas, tudo é um monte de quadrado pro navegador –, com exceção aos elementos gráficos SVG.
Como já foi dito, a propriedade shape-outside
permite definir um contorno externo de maneira um pouco diferente. Vamos definir um círculo do mesmo tamanho e localização que o ilustrado por .flutua
, e veremos o que acontece.
shape-outside: circle()
.flutua
.flutua {
/* ... */
shape-outside: circle(50px, 50px, 50px);
}
Voilà! Agora o texto acompanha a forma definida! Como o tamanho de .flutua
é 100x100px, seu ponto central é (50px
, 50px
), e seu raio também é 50px
, de modo a preencher toda a largura e altura do elemento. Hora de brincar com outras formas:
shape-outside: ellipse()
.flutua
.flutua {
width: 200px;
height: 60px;
/* ... */
shape-outside: ellipse(50%, 50%, 50%, 50%);
}
shape-outside: polygon()
.flutua {
width: 100px;
height: 88px;
/* um triângulo: */
shape-outside: polygon(0 0, 100% 100%, 0 100%);
}
shape-margin
Esta propriedade é bem simples, apenas define uma margem para a shape definida (o resultado é o mesmo da propriedade margin
em elementos comuns).
OBS.: Tentei testar esta propriedade no Chrome Stable 27 e no Chrome Canary 30, mas o resultado ainda não é o esperado nas implementações atuais. O exemplo abaixo é apenas uma representação do que deveria acontecer.
.flutua
.flutua {
/* ... */
shape-outside: circle(50%, 50%, 50%);
shape-margin: 15px;
}
Contornando imagens
Uma ótima aplicação das CSS Shapes é contornar imagens. Da mesma maneira que fizemos há pouco, a diferença é que o elemento em questão é uma imagem – e imagens são quadradas como qualquer outro elemento.

The things you wanted I bought them for you
Graceless lady, you know who I am
You know I can't let you slide through my hands
Wild horses couldn't drag me away
Wild, wild horses couldn't drag me away
I watched you suffer a dull aching pain
Now you decided to show me the same
No sweeping exits or offstage lines
.rolling-stones {
float: left;
shape-outside: polygon(0 0, 123px 0, 134px 36px, 155px 56px, 134px 78px, 109px 129px, 62px 164px, 0 164px);
}
Contornando imagens automaticamente
A especificação define também que deve ser possível realizar o contorno de uma imagem de maneira automática apenas passando a URL da imagem como valor da propriedade shape-outside
.
O problema disso é que o navegador vai usar heurísticas e algoritmos para processamento de imagens que não são perfeitos. Os resultados podem ser bastante divergentes dependendo da imagem e da sua qualidade gráfica. Por isso, foi preciso deixar isso um pouco no controle do desenvolvedor, que pode utilizar-se da propriedade shape-image-threshold
para controlar a aplicação da shape.
OBS.: Esta funcionalidade ainda não foi implementada em nenhum navegador até o momento.
.rolling-stones {
float: left;
shape-outside: url('rolling_stones.png');
shape-image-threshold: 0.3;
}
shape-inside
Com shape-inside
é possível realizar o oposto de shape-outside
, ou seja, é possível definir limites internos ao elemento. Podemos dizer que uma shape definida em shape-inside
vai “empacotar” o conteúdo do elemento em si. Dois exemplos:
.inside-circle {
shape-inside: circle(50%, 50%, 50%);
}
.inside-hexagon {
shape-inside: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}
shape-padding
Simplesmente aplica um padding interior à shape. Funcionando no Chrome.
Lindo, né? Mas…
Apesar de já estar implementada com prefixo no Google Chrome (-webkit-shape-inside
), esta propriedade foi removida da Especificação Level 1, pois optou-se por apenas incluí-la em especificações futuras. O mesmo se aplica à propriedade shape-padding
.
A future level of CSS Shapes will define a shape-inside property, which will define a shape to wrap content within the element.
Suporte | |||||
---|---|---|---|---|---|
shape-outside | 25 *1 -webkit- | -- | -- | -- | -- |
shape-margin | -- | -- | -- | -- | -- |
shape-image-threshold | -- | -- | -- | -- | -- |
shape-inside | 25 *1 *2 -webkit- | -- | -- | -- | -- |
shape-padding | 25 *1 *2 -webkit- | -- | -- | -- | -- |
*1 – Features habilitadas através de uma flag *2 – Propriedades removidas da spec por hora |