Persijn Persijn - 1 month ago 22
CSS Question

Creating a Snowflake shape that contains text in shape

I'm trying to create a snowflake on my webpage for the winter season.

The first thing I tried was creating it with SVG:

enter image description here



<h3>Koch Snowflake Frac</h3>
<svg viewBox="-5 -5 110 110" xmlns="http://www.w3.org/2000/svg">
<polyline stroke="cornflowerblue" stroke-width="2" fill="rgba(255,255,255,0.5)" points="55 5,
60 10,
65 10,
65 15,
70 20,
75 20,
80 15,
85 20,
90 20,
85 25,
90 30,
80 30,
75 35,
80 40,
90 40,
85 45,
90 50,
85 50,
80 55,
75 50,
70 50,
65 55,
65 60,
60 60,
55 65,
50 60,
45 60,
45 55,
40 50,
35 50,
30 55,
25 50,
20 50,
25 45,
20 40,
30 40,
35 35,
30 30,
20 30,
25 25,
20 20,
25 20,
30 15,
35 20,
40 20,
45 15,
45 10,
50 10,
55 5" />
<foreignObject x="0" y="0" requiredExtensions="http://www.w3.org/1999/xhtml">

<body xmlns="http://www.w3.org/1999/xhtml">
<p>Here is a paragraph that requires word wrap</p>
</body>
</foreignObject>
</svg>





I could not get the <foreignObject> to work and even if I did it's not supported in IE browsers.

There is no need to support old IE browsers, but I would like support in at least one of them.

Also minor detail at the top, the shape is not closed.

Then I tried creating a snowflake in it with CSS:



.snowflake {
position: absolute;
width: 200px;
display: inline-block;
border-bottom: 10px solid cornflowerblue;
top: 200px;
left: 100px;
background-color: white;
}
.snowflake:before {
position: absolute;
content: "";
display: inline-block;
width: 50px;
border-bottom: 10px solid cornflowerblue;
transform: rotate(45deg);
top: -20px;
}
.snowflake:after {
position: absolute;
content: "";
display: inline-block;
width: 50px;
border-bottom: 10px solid cornflowerblue;
transform: rotate(-45deg);
top: 20px;
}
.smallbranch {
position: absolute;
right: 0px;
display: inline-block;
width: 50px;
border-bottom: 10px solid cornflowerblue;
transform: rotate(45deg);
top: 17px;
box-shadow: -130px -5px 0px 0px cornflowerblue;
}
.smallbranch:before {
position: absolute;
content: "";
display: inline-block;
width: 50px;
border-bottom: 10px solid cornflowerblue;
transform: rotate(90deg);
top: -22px;
left: -22px;
box-shadow: 130px -5px 0px 0px cornflowerblue;
}
.circle {
position: absolute;
left: 50%;
width: 50px;
height: 50px;
border-radius: 50%;
border: 5px solid cornflowerblue;
background-color: white;
transform: translate(-50%, -50%);
}
.circle:before {
position: absolute;
content: "";
display: inline-block;
width: 50px;
border-bottom: 10px solid cornflowerblue;
transform: rotate(90deg);
top: -52px;
left: 20px;
transform: rotate(-45deg);
}
.circle:after {
position: absolute;
content: "";
display: inline-block;
width: 50px;
border-bottom: 10px solid cornflowerblue;
transform: rotate(90deg);
top: 102px;
left: 20px;
transform: rotate(45deg);
}
.branch {
position: absolute;
display: inline-block;
height: 200px;
border-right: 10px solid cornflowerblue;
left: 50%;
top: -100px;
}

<div class="snowflake">
<div class="branch"></div>
<div class="smallbranch"></div>
<div class="circle">Text in here</div>
</div>





This was my best attempt with CSS.

Now here the text is displayed but its not on one line. My idea is to use this in a logo or for a button on the webpage. So I don't think I will need line wrap functionality on the shape, but it would be a plus if it had.

The shape I would like created:

enter image description here

TL;DR

What I would like is a snowflake with text in the middle of the shape.

I'm asking for a solution where the text could be any length and still be inside the shape.

You don't have to create a shape that's exactly the same as what I have tried as long as the shape is a snowflake with text in the center it's ok. I don't know how long the text will be so the shape has to contain the text.

Answer

Play with this demo

This is actually a quite interesting question, and coming up with an answer was not easy.

The question asks to make a shape(in this case a snowflake), that would scale to fit the text inside of it. My first advice is to use an image, not try and create the shape with CSS. Images are much easier to make scale, and can have more detail then a CSS shape.

So, lets show how we can accomplish this.

First of all, since you want the element to scale to fit the font, we need to make the element display:inline-block. This will make it only be as wide as it's content, unlike block which would make it as wide as it's parent, and still be able to set the height(which you cannot do with inline).

Next, we need to make the element with a height the same as the width. Luckily, there is a trick in CSS that allows you to do just that. The padding of an element is calculated based on it's width, so if you set the padding-bottom(or padding-top) to 100%, it will have the same width as height.(See this excellent SO answer for further info).

After this, it is just a matter of centering the text inside the snowflake, which may take a little playing with the values to fit your font-family.

If you want the jsfiddle with code: JSFiddle Demo

Full-Screen JSFiddle Demo

Tested in Chrome, FireFox, IE, and Safari. Minor adjustments may be needed for certain font-family's

.snowflake{
    display:inline-block;
      background:url("http://i.imgur.com/4M9MH1Q.png") scroll no-repeat center/contain;
    }
/*This is for setting the height the same as the width, a 1:1 ratio. more info http://www.mademyday.de/css-height-equals-width-with-pure-css.html#outer_wrap */
    .snowflake:after{
    	content: "";
    	display: block;
    	padding-top: 100%;
    }
    .snowflake span{
        display:inline-block;
        -webkit-transform: translateY(110%);
            -ms-transform: translateY(110%);
                transform: translateY(110%);
        width:100%;
        text-align:center;
       padding-top:20%;
      }
/*This part is ugly, but it is required to work in chrome or IE, you may have to change the char for different font types*/
 .snowflake span:before, .snowflake span:after{
     content:"aaa";
     visibility:hidden;
     opacity:0;
  }
        Font-size 12pt:
    <div class="snowflake" style="font-size:12pt;">
      <span>It's Snowing!</span>
    </div>
    Font-size 24pt:
    <div class="snowflake" style="font-size:24pt;">
      <span>It's Snowing!</span>
    </div>
    Font-size 48pt:
    <div class="snowflake" style="font-size:48pt;">
      <span>It's Snowing!</span>
    </div>

EDIT: This solution is prettier, but doesn't work in Chrome or IE

.snowflake{
display:inline-block;
  background:url("http://i.imgur.com/4M9MH1Q.png") scroll no-repeat center/contain;
}
/*This is for setting the height the same as the width, a 1:1 ratio. more info http://www.mademyday.de/css-height-equals-width-with-pure-css.html#outer_wrap */
.snowflake:after{
	content: "";
	display: block;
	padding-top: 100%;
}
.snowflake span{
  display:inline-block;
    transform: translateY(90%);
  padding:20%;
  }
Font-size 12pt:
<div class="snowflake" style="font-size:12pt;">
  <span>It's Snowing!</span>
</div>
Font-size 24pt:
<div class="snowflake" style="font-size:24pt;">
  <span>It's Snowing!</span>
</div>
Font-size 48pt:
<div class="snowflake" style="font-size:48pt;">
  <span>It's Snowing!</span>
</div>

The main condition for this to work is:

.snowflake must be display:inline-block;

Full-Screen JSFiddle Demo

Comments