创建一个包含形状文本的雪花形状
Creating a Snowflake shape that contains text in shape
我正在尝试在我的网页上为冬季制作雪花。
我尝试的第一件事是用 SVG 创建它:
<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>
我无法让 工作,即使我这样做了,IE 浏览器也不支持它。
不需要支持旧的 IE 浏览器,但我希望至少支持其中一种浏览器。
还有顶部的小细节,形状没有闭合。
然后我尝试用 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>
这是我对 CSS 的最佳尝试。
现在这里显示了文本,但它不在一行中。我的想法是在徽标或网页上的按钮中使用它。所以我认为我不需要在形状上使用换行功能,但如果有的话那就更好了。
我想要创建的形状:
TL;DR
我想要的是中间有文字的雪花。
我正在寻求一种解决方案,其中文本可以是任意长度并且仍然在形状内。
您不必创建与我尝试过的形状完全相同的形状,只要形状是中心有文字的雪花就可以了。我不知道文本有多长,所以形状必须包含文本。
Play with this demo
这其实是个很有意思的问题,想出答案也不容易。
该问题要求制作一个形状(在本例中为雪花),该形状将缩放以适合其中的文本。我的第一个建议是使用图像,而不是尝试使用 CSS 创建形状。图像更容易制作比例,并且可以比 CSS 形状具有更多细节。
那么,让我们展示一下如何实现这一目标。
首先,由于您希望元素缩放以适应字体,我们需要制作元素display:inline-block
。这将使它只和它的内容一样宽,不像 block
那样会使它和它的父级一样宽,并且仍然能够设置高度(你不能用 inline
做)。
接下来,我们需要让元素的高度和宽度一致。幸运的是,CSS 中有一个技巧可以让您做到这一点。元素的填充是根据它的宽度计算的,所以如果你将 padding-bottom(或 padding-top)设置为 100%,它将具有与高度相同的宽度。(See this excellent SO answer for further info)。
在此之后,只需将雪花内的文本居中即可,这可能需要稍微调整一下值以适合您的字体系列。
如果你想要带有代码的jsfiddle:
JSFiddle Demo
Full-Screen JSFiddle Demo
已在 Chrome、FireFox、IE 和 Safari 中测试。某些字体系列可能需要进行细微调整
.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>
编辑:这个解决方案更漂亮,但在 Chrome 或 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>
这个工作的主要条件是:
.snowflake
必须是 display:inline-block;
Full-Screen JSFiddle Demo
我的解决方案使用部分 SVG,部分 HTML/CSS 来创建所需的效果。
我使用了 calc()
CSS3 函数以及基于视口的 width/height 单元,然后赋予它所需的响应能力。
当元素宽度超过 200px 时看起来会更好。
代码
.container {
position: relative;
overflow: auto;
display: block;
width: 50vw;
height: 50vw;
}
.container svg {
width: 100%;
height: 100%;
position: absolute;
}
p {
position: absolute;
z-index: 100;
background: white;
left: 17.5vw;
top: 17.5vw;
margin: 0;
padding: 10px 0;
width: 10vw;
text-align: center;
font-size: 2vw;
border: 20px solid black;
}
@media screen and (min-width: 920px) {
p {
font-size: 3vw;
width: 12.5vw;
}
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve" width="50%">
<polygon id="christmas-snowflake-icon" points="441.535,346.644 373.955,307.624 438.697,290.354 431.342,262.782 338.967,287.424
284.535,255.999 339.49,224.271 431.299,249.242 438.787,221.705 374.311,204.168 441.535,165.356 427.266,140.644 359.686,179.66
377.1,114.956 349.545,107.541 324.697,199.861 270.27,231.285 270.27,167.831 337.797,100.809 317.695,80.554 270.27,127.624
270.27,50 241.732,50 241.732,128.036 194.404,80.604 174.203,100.76 241.732,168.438 241.732,231.286 186.779,199.558
162.498,107.565 134.906,114.847 151.957,179.455 84.732,140.644 70.465,165.356 138.045,204.373 73.303,221.645 80.66,249.218
173.035,224.574 227.465,255.999 172.51,287.727 80.701,262.758 73.211,290.293 137.688,307.832 70.465,346.644 84.732,371.356
152.312,332.337 134.898,397.042 162.457,404.459 187.303,312.137 241.732,280.711 241.732,344.169 174.203,411.191
194.307,431.446 241.732,384.376 241.732,462 270.27,462 270.27,383.964 317.598,431.396 337.797,411.24 270.27,343.562
270.27,280.712 325.223,312.439 349.502,404.435 377.094,397.15 360.043,332.545 427.268,371.356 "></polygon>
</svg>
<p>This is some text Now</p>
</div>
CodePen
使用 svg
我已经设法做出了一个几乎响应迅速的解决方案
.box{
display:inline-block;
position:relative;
width:300px;
height:300px;
}
.box:after{
position:absolute;
content:"Some text";
width:20%;
height:20%;
padding:5%;
font-size:100%;
left:calc(50% - 15%);
top:calc(50% - 19%);
}
<div class="box">
<svg viewBox="0 0 99.999997 100" height="100%" width="100%">
<g transform="translate(0,-952.36216)" id="layer1">
<path id="path4701" d="m 23,959 5,-3 6,11 6,-11 6,0 -9,17 4,7 8,-14 7,13 4,-7 -7,-13 3,-5 7,13 6,-11 4,2 -6,11 12,0 3,5 -18,0 -4,8 16,0 -7,13 8,0.12 7,-13 6,0 -7,13 12,0 -0.12,6 -12,-0 5,11 -3,5 -9,-17 -8,0.12 8,14 -16,0 4,8 18,0 -3,5 -12,-0.06 6,11 -4,3 -6,-11 -7,13 -3,-5 7,-13 -4,-7 -7,14 -8,-14 -4,7 9,17 -6,0.12 -6,-11 -6,11 -4,-3 6,-11 -14,-0.12 3,-6 15,0.12 4,-8 -15,-0.063 7,-14 -8,0 -9,17 -3,-5 6,-11 -12,0 0,-6 12,-0.06 -7,-13 6,-0.12 7,13 8,0.06 -7,-13 15,0.06 -4,-8 -15,-0.06 -3,-5 14,-0.06 z" style="fill:#2ad4ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
</g>
</svg>
</div>
尝试在以下代码段中调整大小,如果宽度和高度均等增加,它几乎保持响应
.box{
display:inline-block;
position:relative;
width:300px;
height:300px;
resize:both;
border:2px solid;
overflow:auto;
}
.box:after{
position:absolute;
content:"Some text";
width:20%;
height:20%;
padding:5%;
font-size:100%;
left:calc(50% - 15%);
top:calc(50% - 19%);
}
<div class="box">
<svg viewBox="0 0 99.999997 100" height="100%" width="100%">
<g transform="translate(0,-952.36216)" id="layer1">
<path id="path4701" d="m 23,959 5,-3 6,11 6,-11 6,0 -9,17 4,7 8,-14 7,13 4,-7 -7,-13 3,-5 7,13 6,-11 4,2 -6,11 12,0 3,5 -18,0 -4,8 16,0 -7,13 8,0.12 7,-13 6,0 -7,13 12,0 -0.12,6 -12,-0 5,11 -3,5 -9,-17 -8,0.12 8,14 -16,0 4,8 18,0 -3,5 -12,-0.06 6,11 -4,3 -6,-11 -7,13 -3,-5 7,-13 -4,-7 -7,14 -8,-14 -4,7 9,17 -6,0.12 -6,-11 -6,11 -4,-3 6,-11 -14,-0.12 3,-6 15,0.12 4,-8 -15,-0.063 7,-14 -8,0 -9,17 -3,-5 6,-11 -12,0 0,-6 12,-0.06 -7,-13 6,-0.12 7,13 8,0.06 -7,-13 15,0.06 -4,-8 -15,-0.06 -3,-5 14,-0.06 z" style="fill:#2ad4ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
</g>
</svg>
</div>
使用Canvas:
也可以使用 HTML5 Canvas 以编程方式创建雪花。以编程方式执行此操作可以更好地控制文本并将其始终保存在容器中。我确信此方法可以转换为等效的 SVG 版本,但我更喜欢 Canvas.
使用 Canvas 的一个缺点是输出没有响应。缩放时它变得模糊(像素化)。避免它的唯一方法是在文本(或)尺寸等发生变化时再次重新绘制形状。
施工
形状实际上由三部分组成,它们如下:
- 有 6 个尖刺的内星(绿色星)
- 线条(红色)
- 有 6 个尖刺的外星(蓝色星)
使用与 相同的方法绘制星星。基本上,我们为它们中的每一个分配一个内半径和一个外半径,在内圆和外圆上找到点,然后将它们交替连接以产生星星。
线也使用类似的方法绘制,只是它只有一个半径,并且线是从绿色星星的(假想)内圆上的点到圆上的指定点绘制的。
尺寸计算:由于文本必须适合形状并且形状必须扩展以适合文本,因此需要做的第一步是计算文本需要的 width
。这是使用 measureText().width
完成的。获得的值被设置为绿色星形内圆的半径(因为文本必须保留在其中)。
最后,由于外面的蓝色星星应该看起来像是被剪掉了(不是完整显示),因此设置小于蓝色星星外半径的 height
和 width
border-radius
分配给 canvas 元素。
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d"),
spikes = 6,
step = Math.PI / spikes,
rot; /* no. of spikes for the stars */
function drawSnowFlake(content, font) {
ctx.font = font; /* font of the text */
/* get width required to fit text and set radius of each star */
var text = ctx.measureText(content);
innerRadius = (text.width / 2) * 1.15; /* extra factor is to leave gap between text and shape */
outerRadius = text.width;
/* set center point for the individual parts of the shape */
x = leftOffset = outerRadius * 1.5;
y = topOffset = outerRadius * 1.5;
/* canvas height and width should be set same as the largest star for clip */
canvas.height = outerRadius * 3;
canvas.width = outerRadius * 3;
/* default settings */
rot = Math.PI / 2 * 3;
ctx.beginPath();
ctx.lineWidth = 15; /* thickness of the lines */
ctx.strokeStyle = 'blue'; /* color of the lines */
ctx.font = font; /* font of the text */
/* create the inner star */
ctx.moveTo(leftOffset, topOffset - outerRadius)
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * outerRadius;
y = topOffset + Math.sin(rot) * outerRadius;
ctx.lineTo(x, y);
rot += step;
x = leftOffset + Math.cos(rot) * innerRadius;
y = topOffset + Math.sin(rot) * innerRadius;
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(leftOffset, topOffset - outerRadius);
ctx.closePath();
ctx.stroke();
ctx.restore();
/* draws the outer star */
ctx.beginPath();
ctx.moveTo(leftOffset, topOffset - (outerRadius * 1.725));
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * (outerRadius * 1.725);
y = topOffset + Math.sin(rot) * (outerRadius * 1.725);
ctx.lineTo(x, y)
rot += step
x = leftOffset + Math.cos(rot) * (outerRadius * 1.15);
y = topOffset + Math.sin(rot) * (outerRadius * 1.15);
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(leftOffset, topOffset - (outerRadius * 1.725));
ctx.closePath();
ctx.stroke();
ctx.restore();
/* draws the lines from the stars */
rot = Math.PI / 3;
ctx.beginPath();
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * innerRadius;
y = topOffset + Math.sin(rot) * innerRadius;
x2 = leftOffset + Math.cos(rot) * (outerRadius * 1.5);
y2 = topOffset + Math.sin(rot) * (outerRadius * 1.5);
ctx.moveTo(x, y);
ctx.lineTo(x2, y2);
rot += 2 * Math.PI / spikes;
}
ctx.closePath();
ctx.stroke();
/* add text and position it */
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillText(content, leftOffset, topOffset);
}
document.getElementById('draw').addEventListener('click', function() {
var input = document.getElementById('content').value;
var fontsize = document.getElementById('fontsize').value;
var fontname = document.getElementById('fontname').value;
drawSnowFlake(input, fontsize + "px " + fontname);
});
drawSnowFlake("TEXT HERE", "16px Arial");
div {
margin-bottom: 10px;
}
canvas {
border-radius: 50%;
}
<div class='controls'>
<input id='content' type='textbox' value='TEXT HERE' />
<select id='fontsize'>
<option value='10'>10px</option>
<option value='12'>12px</option>
<option value='14'>14px</option>
<option value='16' selected>16px</option>
</select>
<select id='fontname'>
<option value='Arial' selected>Arial</option>
<option value='Verdana'>Verdana</option>
<option value='Courier'>Courier</option>
</select>
<button id='draw'>Draw</button>
</div>
<canvas id='canvas'></canvas>
使用文字环绕和斜边:
这是一个更复杂的演示,它还支持在内容超过一定宽度时将文本换行成多行。以下是此代码段将执行的操作:
- 如果文字要求的尺寸小于最大宽度,缩小形状
- 如果文本所需的大小(高度或宽度)大于最大宽度,将文本拆分为多行,扩展形状以适合居中的文本
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d"),
spikes = 6,
/* no. of spikes for the stars */
step = Math.PI / spikes,
rot, maxWidth = 100,
lineHeight = 20;
function drawSnowFlake(content, font) {
ctx.font = font; /* font of the text */
/* get width & height required to fit text and set radius of each star */
var text = ctx.measureText(content);
var width = text.width;
var height = splitText(ctx, content, maxWidth, lineHeight);
/* decide which among height & width should be used for radius */
if (width < maxWidth && height < maxWidth) {
innerRadius = (width / 2) * 1.15; /* extra factor is to leave gap between text and shape */
outerRadius = width;
} else if (width > maxWidth && height < maxWidth) {
innerRadius = (maxWidth / 2) * 1.15; /* extra factor is to leave gap between text and shape */
outerRadius = maxWidth;
} else {
innerRadius = (height / 2) * 1.15; /* extra factor is to leave gap between text and shape */
outerRadius = height;
}
/* set center point for the individual parts of the shape */
x = leftOffset = outerRadius * 1.5;
y = topOffset = outerRadius * 1.5;
/* canvas height and width should be set same as the largest star for clip */
canvas.height = outerRadius * 3;
canvas.width = outerRadius * 3;
/* default settings */
rot = Math.PI / 2 * 3;
ctx.beginPath();
ctx.lineWidth = 15; /* thickness of the lines */
ctx.lineJoin = 'bevel';
ctx.strokeStyle = 'blue'; /* color of the lines */
ctx.font = font; /* font of the text */
/* create the inner star */
ctx.moveTo(leftOffset, topOffset - outerRadius)
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * outerRadius;
y = topOffset + Math.sin(rot) * outerRadius;
ctx.lineTo(x, y);
rot += step;
x = leftOffset + Math.cos(rot) * innerRadius;
y = topOffset + Math.sin(rot) * innerRadius;
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(leftOffset, topOffset - outerRadius);
ctx.closePath();
ctx.stroke();
ctx.restore();
/* draws the outer star */
ctx.beginPath();
ctx.moveTo(leftOffset, topOffset - (outerRadius * 1.725));
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * (outerRadius * 1.725);
y = topOffset + Math.sin(rot) * (outerRadius * 1.725);
ctx.lineTo(x, y)
rot += step
x = leftOffset + Math.cos(rot) * (outerRadius * 1.15);
y = topOffset + Math.sin(rot) * (outerRadius * 1.15);
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(leftOffset, topOffset - (outerRadius * 1.725));
ctx.closePath();
ctx.stroke();
ctx.restore();
/* draws the lines from the stars */
rot = Math.PI / 3;
ctx.beginPath();
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * innerRadius;
y = topOffset + Math.sin(rot) * innerRadius;
x2 = leftOffset + Math.cos(rot) * (outerRadius * 1.5);
y2 = topOffset + Math.sin(rot) * (outerRadius * 1.5);
ctx.moveTo(x, y);
ctx.lineTo(x2, y2);
rot += 2 * Math.PI / spikes;
}
ctx.closePath();
ctx.stroke();
/* add text and position it */
wrapText(ctx, content, leftOffset, (topOffset - ((height - lineHeight) / 2)), maxWidth, lineHeight);
}
document.getElementById('draw').addEventListener('click', function() {
var input = document.getElementById('content').value;
var fontsize = document.getElementById('fontsize').value;
var fontname = document.getElementById('fontname').value;
drawSnowFlake(input, fontsize + "px " + fontname);
});
/* split text into lines based on width and calculate required height */
function splitText(context, text, maxWidth, lineHeight) {
var words = text.split(' ');
var line = '',
height = lineHeight;
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
line = words[n] + ' ';
height += lineHeight;
} else {
line = testLine;
}
}
return height;
}
/* source from http://www.html5canvastutorials.com/tutorials/html5-canvas-wrap-text-tutorial/ */
function wrapText(context, text, x, y, maxWidth, lineHeight) {
var words = text.split(' ');
var line = '';
context.textBaseline = "middle";
context.textAlign = "center";
var topOffset = x;
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
} else {
line = testLine;
}
}
context.fillText(line, x, y);
}
drawSnowFlake('CSS SHAPES, SVG, CANVAS DESIGNS ROCK', "16px Arial");
div {
margin-bottom: 10px;
}
canvas {
border-radius: 50%;
}
<div class='controls'>
<input id='content' type='textbox' value='CSS SHAPES, SVG, CANVAS DESIGNS ROCK' />
<select id='fontsize'>
<option value='10'>10px</option>
<option value='12'>12px</option>
<option value='14'>14px</option>
<option value='16' selected>16px</option>
</select>
<select id='fontname'>
<option value='Arial' selected>Arial</option>
<option value='Verdana'>Verdana</option>
<option value='Courier'>Courier</option>
</select>
<button id='draw'>Draw</button>
</div>
<canvas id='canvas'></canvas>
OP 希望雪花能够缩放以适应文本的大小。大多数其他答案都是相反的。
这是我能想到的最简单的解决方案。它主要只是 HTML 和带有一小段 JS 的 SVG。这是必需的,因为我认为不可能有一个 SVG 比例来适应没有明确尺寸的 parent。
将文本内容或内部 <div>
的 CSS 样式更改为您满意的内容,SVG 雪花将缩放以匹配。
如果您乐于使用位图背景图像而不是 SVG,您几乎可以肯定地取消 JS。
$().ready(function() {
divWidth = $(".snowflake div").outerWidth();
$(".snowflake svg").css("width", divWidth + "px");
});
.snowflake
{
display: inline-block;
position: relative;
}
.snowflake svg
{
position: absolute;
fill: #eef;
}
.snowflake DIV
{
position: absolute;
padding: 100px;
font: 30pt sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="snowflake">
<svg viewBox="2 0 32 36">
<path d="M33.212,26.16l-3.054-1.764l1.84-1.062c0.238-0.139,0.32-0.441,0.184-0.684c-0.14-0.238-0.445-0.322-0.684-0.183 L29.16,23.82l-2.32-1.34l4.729-2.73c0.239-0.139,0.321-0.441,0.184-0.684c-0.139-0.238-0.445-0.322-0.684-0.183l-5.23,3.019 l-3.619-2.09l4.352-1.918l-4.354-1.919l3.619-2.091l5.231,3.021c0.079,0.047,0.165,0.067,0.25,0.067 c0.174,0,0.342-0.091,0.435-0.25c0.139-0.239,0.057-0.546-0.184-0.683l-4.731-2.732l2.32-1.34L31.5,13.32 c0.079,0.046,0.165,0.066,0.25,0.066c0.173,0,0.341-0.09,0.435-0.25c0.138-0.238,0.056-0.545-0.184-0.682L30.16,11.39l3.052-1.762 c0.239-0.139,0.32-0.443,0.184-0.684c-0.14-0.238-0.446-0.322-0.684-0.184l-3.051,1.763L29.66,8.401c0-0.275-0.225-0.5-0.5-0.5 c-0.276,0-0.5,0.225-0.5,0.5l0.001,2.699l-2.32,1.34l0.001-5.46c0-0.276-0.224-0.5-0.5-0.5c-0.275,0-0.5,0.224-0.5,0.5 l-0.001,6.037l-3.619,2.09l0.515-4.728l-3.838,2.81V9.008l5.229-3.021c0.238-0.138,0.32-0.443,0.184-0.684 c-0.14-0.238-0.445-0.321-0.684-0.182l-4.729,2.73V5.173l2.339-1.352c0.239-0.138,0.321-0.443,0.184-0.684 c-0.14-0.238-0.445-0.322-0.684-0.182L18.399,4.02V0.5c0-0.276-0.224-0.5-0.5-0.5s-0.5,0.224-0.5,0.5v3.523L15.56,2.961 c-0.24-0.141-0.545-0.057-0.683,0.184c-0.138,0.239-0.056,0.545,0.183,0.684l2.339,1.352v2.678l-4.729-2.73 c-0.24-0.14-0.545-0.057-0.683,0.184c-0.138,0.239-0.056,0.545,0.183,0.684l5.229,3.02v4.184l-3.837-2.811l0.514,4.729 l-3.621-2.092V6.989c0-0.276-0.224-0.5-0.5-0.5c-0.276,0-0.5,0.224-0.5,0.5v5.462l-2.318-1.34L7.136,8.41 c0-0.277-0.224-0.5-0.5-0.5c-0.276,0-0.5,0.223-0.5,0.5l0.001,2.125L3.084,8.771C2.845,8.63,2.539,8.714,2.401,8.955 C2.263,9.194,2.345,9.5,2.584,9.638L5.636,11.4l-1.839,1.062c-0.239,0.139-0.321,0.443-0.183,0.684 c0.093,0.16,0.261,0.25,0.434,0.25c0.085,0,0.171-0.021,0.25-0.066l2.339-1.351l2.319,1.339l-4.729,2.73 c-0.239,0.139-0.321,0.443-0.183,0.684c0.093,0.16,0.261,0.25,0.434,0.25c0.085,0,0.171-0.021,0.25-0.066l5.23-3.021l3.622,2.091 l-4.352,1.919l4.351,1.919l-3.621,2.09l-5.231-3.018c-0.241-0.138-0.545-0.058-0.683,0.184c-0.138,0.24-0.056,0.545,0.183,0.686 l4.731,2.729l-2.321,1.34l-2.338-1.352c-0.239-0.142-0.545-0.058-0.683,0.184c-0.138,0.238-0.056,0.545,0.183,0.684l1.838,1.062 l-3.05,1.76c-0.239,0.139-0.321,0.443-0.183,0.684c0.093,0.16,0.261,0.25,0.434,0.25c0.085,0,0.171-0.021,0.25-0.065l3.051-1.763 L6.14,27.4c0,0.276,0.224,0.5,0.5,0.5l0,0c0.276,0,0.5-0.225,0.5-0.5l-0.001-2.701l2.322-1.34l-0.002,5.463 c0,0.277,0.224,0.5,0.5,0.5s0.5-0.223,0.5-0.5l0.002-6.041l3.619-2.09l-0.514,4.729l3.837-2.81v4.183l-5.228,3.021 c-0.239,0.139-0.321,0.442-0.183,0.684c0.138,0.236,0.444,0.318,0.683,0.184l4.728-2.73v2.679l-2.339,1.353 c-0.239,0.139-0.321,0.442-0.183,0.684c0.138,0.236,0.444,0.32,0.683,0.184l1.839-1.062V35.3c0,0.274,0.224,0.5,0.5,0.5 s0.5-0.226,0.5-0.5v-3.524l1.841,1.062c0.079,0.046,0.165,0.066,0.25,0.066c0.174,0,0.342-0.09,0.435-0.25 c0.139-0.239,0.057-0.545-0.184-0.684l-2.341-1.354v-2.678l4.729,2.73c0.079,0.046,0.165,0.066,0.25,0.066 c0.174,0,0.342-0.09,0.435-0.25c0.139-0.239,0.057-0.545-0.184-0.684l-5.229-3.021V22.6l3.838,2.811l-0.514-4.729l3.62,2.09v6.039 c0,0.276,0.224,0.5,0.5,0.5c0.275,0,0.5-0.224,0.5-0.5V23.35l2.318,1.34l0.001,2.699c0,0.275,0.225,0.5,0.5,0.5s0.5-0.225,0.5-0.5 l-0.001-2.123l3.053,1.764c0.079,0.045,0.165,0.066,0.25,0.066c0.174,0,0.342-0.09,0.435-0.25 C33.536,26.604,33.454,26.296,33.212,26.16z M20.997,23.259l-2.6-1.901l-0.499-0.363l-0.501,0.365l-2.598,1.9l0.348-3.201 l0.067-0.615l-0.567-0.25l-2.945-1.299l2.946-1.299l0.566-0.25l-0.067-0.616l-0.348-3.2l2.598,1.901l0.5,0.364l0.5-0.365l2.6-1.901 l-0.349,3.201l-0.066,0.616l0.564,0.249l2.946,1.3l-2.944,1.299l-0.566,0.25l0.066,0.615L20.997,23.259z"/>
</svg>
<div>Here is some text. It's even wrapped.</div>
</div>
我正在尝试在我的网页上为冬季制作雪花。
我尝试的第一件事是用 SVG 创建它:
<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>
我无法让
不需要支持旧的 IE 浏览器,但我希望至少支持其中一种浏览器。
还有顶部的小细节,形状没有闭合。
然后我尝试用 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>
这是我对 CSS 的最佳尝试。
现在这里显示了文本,但它不在一行中。我的想法是在徽标或网页上的按钮中使用它。所以我认为我不需要在形状上使用换行功能,但如果有的话那就更好了。
我想要创建的形状:
TL;DR
我想要的是中间有文字的雪花。
我正在寻求一种解决方案,其中文本可以是任意长度并且仍然在形状内。
您不必创建与我尝试过的形状完全相同的形状,只要形状是中心有文字的雪花就可以了。我不知道文本有多长,所以形状必须包含文本。
Play with this demo
这其实是个很有意思的问题,想出答案也不容易。
该问题要求制作一个形状(在本例中为雪花),该形状将缩放以适合其中的文本。我的第一个建议是使用图像,而不是尝试使用 CSS 创建形状。图像更容易制作比例,并且可以比 CSS 形状具有更多细节。
那么,让我们展示一下如何实现这一目标。
首先,由于您希望元素缩放以适应字体,我们需要制作元素display:inline-block
。这将使它只和它的内容一样宽,不像 block
那样会使它和它的父级一样宽,并且仍然能够设置高度(你不能用 inline
做)。
接下来,我们需要让元素的高度和宽度一致。幸运的是,CSS 中有一个技巧可以让您做到这一点。元素的填充是根据它的宽度计算的,所以如果你将 padding-bottom(或 padding-top)设置为 100%,它将具有与高度相同的宽度。(See this excellent SO answer for further info)。
在此之后,只需将雪花内的文本居中即可,这可能需要稍微调整一下值以适合您的字体系列。
如果你想要带有代码的jsfiddle: JSFiddle Demo
Full-Screen JSFiddle Demo
已在 Chrome、FireFox、IE 和 Safari 中测试。某些字体系列可能需要进行细微调整
.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>
编辑:这个解决方案更漂亮,但在 Chrome 或 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>
这个工作的主要条件是:
.snowflake
必须是 display:inline-block;
Full-Screen JSFiddle Demo
我的解决方案使用部分 SVG,部分 HTML/CSS 来创建所需的效果。
我使用了 calc()
CSS3 函数以及基于视口的 width/height 单元,然后赋予它所需的响应能力。
当元素宽度超过 200px 时看起来会更好。
代码
.container {
position: relative;
overflow: auto;
display: block;
width: 50vw;
height: 50vw;
}
.container svg {
width: 100%;
height: 100%;
position: absolute;
}
p {
position: absolute;
z-index: 100;
background: white;
left: 17.5vw;
top: 17.5vw;
margin: 0;
padding: 10px 0;
width: 10vw;
text-align: center;
font-size: 2vw;
border: 20px solid black;
}
@media screen and (min-width: 920px) {
p {
font-size: 3vw;
width: 12.5vw;
}
}
<div class="container">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve" width="50%">
<polygon id="christmas-snowflake-icon" points="441.535,346.644 373.955,307.624 438.697,290.354 431.342,262.782 338.967,287.424
284.535,255.999 339.49,224.271 431.299,249.242 438.787,221.705 374.311,204.168 441.535,165.356 427.266,140.644 359.686,179.66
377.1,114.956 349.545,107.541 324.697,199.861 270.27,231.285 270.27,167.831 337.797,100.809 317.695,80.554 270.27,127.624
270.27,50 241.732,50 241.732,128.036 194.404,80.604 174.203,100.76 241.732,168.438 241.732,231.286 186.779,199.558
162.498,107.565 134.906,114.847 151.957,179.455 84.732,140.644 70.465,165.356 138.045,204.373 73.303,221.645 80.66,249.218
173.035,224.574 227.465,255.999 172.51,287.727 80.701,262.758 73.211,290.293 137.688,307.832 70.465,346.644 84.732,371.356
152.312,332.337 134.898,397.042 162.457,404.459 187.303,312.137 241.732,280.711 241.732,344.169 174.203,411.191
194.307,431.446 241.732,384.376 241.732,462 270.27,462 270.27,383.964 317.598,431.396 337.797,411.24 270.27,343.562
270.27,280.712 325.223,312.439 349.502,404.435 377.094,397.15 360.043,332.545 427.268,371.356 "></polygon>
</svg>
<p>This is some text Now</p>
</div>
CodePen
使用 svg
我已经设法做出了一个几乎响应迅速的解决方案
.box{
display:inline-block;
position:relative;
width:300px;
height:300px;
}
.box:after{
position:absolute;
content:"Some text";
width:20%;
height:20%;
padding:5%;
font-size:100%;
left:calc(50% - 15%);
top:calc(50% - 19%);
}
<div class="box">
<svg viewBox="0 0 99.999997 100" height="100%" width="100%">
<g transform="translate(0,-952.36216)" id="layer1">
<path id="path4701" d="m 23,959 5,-3 6,11 6,-11 6,0 -9,17 4,7 8,-14 7,13 4,-7 -7,-13 3,-5 7,13 6,-11 4,2 -6,11 12,0 3,5 -18,0 -4,8 16,0 -7,13 8,0.12 7,-13 6,0 -7,13 12,0 -0.12,6 -12,-0 5,11 -3,5 -9,-17 -8,0.12 8,14 -16,0 4,8 18,0 -3,5 -12,-0.06 6,11 -4,3 -6,-11 -7,13 -3,-5 7,-13 -4,-7 -7,14 -8,-14 -4,7 9,17 -6,0.12 -6,-11 -6,11 -4,-3 6,-11 -14,-0.12 3,-6 15,0.12 4,-8 -15,-0.063 7,-14 -8,0 -9,17 -3,-5 6,-11 -12,0 0,-6 12,-0.06 -7,-13 6,-0.12 7,13 8,0.06 -7,-13 15,0.06 -4,-8 -15,-0.06 -3,-5 14,-0.06 z" style="fill:#2ad4ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
</g>
</svg>
</div>
尝试在以下代码段中调整大小,如果宽度和高度均等增加,它几乎保持响应
.box{
display:inline-block;
position:relative;
width:300px;
height:300px;
resize:both;
border:2px solid;
overflow:auto;
}
.box:after{
position:absolute;
content:"Some text";
width:20%;
height:20%;
padding:5%;
font-size:100%;
left:calc(50% - 15%);
top:calc(50% - 19%);
}
<div class="box">
<svg viewBox="0 0 99.999997 100" height="100%" width="100%">
<g transform="translate(0,-952.36216)" id="layer1">
<path id="path4701" d="m 23,959 5,-3 6,11 6,-11 6,0 -9,17 4,7 8,-14 7,13 4,-7 -7,-13 3,-5 7,13 6,-11 4,2 -6,11 12,0 3,5 -18,0 -4,8 16,0 -7,13 8,0.12 7,-13 6,0 -7,13 12,0 -0.12,6 -12,-0 5,11 -3,5 -9,-17 -8,0.12 8,14 -16,0 4,8 18,0 -3,5 -12,-0.06 6,11 -4,3 -6,-11 -7,13 -3,-5 7,-13 -4,-7 -7,14 -8,-14 -4,7 9,17 -6,0.12 -6,-11 -6,11 -4,-3 6,-11 -14,-0.12 3,-6 15,0.12 4,-8 -15,-0.063 7,-14 -8,0 -9,17 -3,-5 6,-11 -12,0 0,-6 12,-0.06 -7,-13 6,-0.12 7,13 8,0.06 -7,-13 15,0.06 -4,-8 -15,-0.06 -3,-5 14,-0.06 z" style="fill:#2ad4ff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"/>
</g>
</svg>
</div>
使用Canvas:
也可以使用 HTML5 Canvas 以编程方式创建雪花。以编程方式执行此操作可以更好地控制文本并将其始终保存在容器中。我确信此方法可以转换为等效的 SVG 版本,但我更喜欢 Canvas.
使用 Canvas 的一个缺点是输出没有响应。缩放时它变得模糊(像素化)。避免它的唯一方法是在文本(或)尺寸等发生变化时再次重新绘制形状。
施工
形状实际上由三部分组成,它们如下:
- 有 6 个尖刺的内星(绿色星)
- 线条(红色)
- 有 6 个尖刺的外星(蓝色星)
使用与
线也使用类似的方法绘制,只是它只有一个半径,并且线是从绿色星星的(假想)内圆上的点到圆上的指定点绘制的。
尺寸计算:由于文本必须适合形状并且形状必须扩展以适合文本,因此需要做的第一步是计算文本需要的 width
。这是使用 measureText().width
完成的。获得的值被设置为绿色星形内圆的半径(因为文本必须保留在其中)。
最后,由于外面的蓝色星星应该看起来像是被剪掉了(不是完整显示),因此设置小于蓝色星星外半径的 height
和 width
border-radius
分配给 canvas 元素。
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d"),
spikes = 6,
step = Math.PI / spikes,
rot; /* no. of spikes for the stars */
function drawSnowFlake(content, font) {
ctx.font = font; /* font of the text */
/* get width required to fit text and set radius of each star */
var text = ctx.measureText(content);
innerRadius = (text.width / 2) * 1.15; /* extra factor is to leave gap between text and shape */
outerRadius = text.width;
/* set center point for the individual parts of the shape */
x = leftOffset = outerRadius * 1.5;
y = topOffset = outerRadius * 1.5;
/* canvas height and width should be set same as the largest star for clip */
canvas.height = outerRadius * 3;
canvas.width = outerRadius * 3;
/* default settings */
rot = Math.PI / 2 * 3;
ctx.beginPath();
ctx.lineWidth = 15; /* thickness of the lines */
ctx.strokeStyle = 'blue'; /* color of the lines */
ctx.font = font; /* font of the text */
/* create the inner star */
ctx.moveTo(leftOffset, topOffset - outerRadius)
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * outerRadius;
y = topOffset + Math.sin(rot) * outerRadius;
ctx.lineTo(x, y);
rot += step;
x = leftOffset + Math.cos(rot) * innerRadius;
y = topOffset + Math.sin(rot) * innerRadius;
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(leftOffset, topOffset - outerRadius);
ctx.closePath();
ctx.stroke();
ctx.restore();
/* draws the outer star */
ctx.beginPath();
ctx.moveTo(leftOffset, topOffset - (outerRadius * 1.725));
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * (outerRadius * 1.725);
y = topOffset + Math.sin(rot) * (outerRadius * 1.725);
ctx.lineTo(x, y)
rot += step
x = leftOffset + Math.cos(rot) * (outerRadius * 1.15);
y = topOffset + Math.sin(rot) * (outerRadius * 1.15);
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(leftOffset, topOffset - (outerRadius * 1.725));
ctx.closePath();
ctx.stroke();
ctx.restore();
/* draws the lines from the stars */
rot = Math.PI / 3;
ctx.beginPath();
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * innerRadius;
y = topOffset + Math.sin(rot) * innerRadius;
x2 = leftOffset + Math.cos(rot) * (outerRadius * 1.5);
y2 = topOffset + Math.sin(rot) * (outerRadius * 1.5);
ctx.moveTo(x, y);
ctx.lineTo(x2, y2);
rot += 2 * Math.PI / spikes;
}
ctx.closePath();
ctx.stroke();
/* add text and position it */
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillText(content, leftOffset, topOffset);
}
document.getElementById('draw').addEventListener('click', function() {
var input = document.getElementById('content').value;
var fontsize = document.getElementById('fontsize').value;
var fontname = document.getElementById('fontname').value;
drawSnowFlake(input, fontsize + "px " + fontname);
});
drawSnowFlake("TEXT HERE", "16px Arial");
div {
margin-bottom: 10px;
}
canvas {
border-radius: 50%;
}
<div class='controls'>
<input id='content' type='textbox' value='TEXT HERE' />
<select id='fontsize'>
<option value='10'>10px</option>
<option value='12'>12px</option>
<option value='14'>14px</option>
<option value='16' selected>16px</option>
</select>
<select id='fontname'>
<option value='Arial' selected>Arial</option>
<option value='Verdana'>Verdana</option>
<option value='Courier'>Courier</option>
</select>
<button id='draw'>Draw</button>
</div>
<canvas id='canvas'></canvas>
使用文字环绕和斜边:
这是一个更复杂的演示,它还支持在内容超过一定宽度时将文本换行成多行。以下是此代码段将执行的操作:
- 如果文字要求的尺寸小于最大宽度,缩小形状
- 如果文本所需的大小(高度或宽度)大于最大宽度,将文本拆分为多行,扩展形状以适合居中的文本
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d"),
spikes = 6,
/* no. of spikes for the stars */
step = Math.PI / spikes,
rot, maxWidth = 100,
lineHeight = 20;
function drawSnowFlake(content, font) {
ctx.font = font; /* font of the text */
/* get width & height required to fit text and set radius of each star */
var text = ctx.measureText(content);
var width = text.width;
var height = splitText(ctx, content, maxWidth, lineHeight);
/* decide which among height & width should be used for radius */
if (width < maxWidth && height < maxWidth) {
innerRadius = (width / 2) * 1.15; /* extra factor is to leave gap between text and shape */
outerRadius = width;
} else if (width > maxWidth && height < maxWidth) {
innerRadius = (maxWidth / 2) * 1.15; /* extra factor is to leave gap between text and shape */
outerRadius = maxWidth;
} else {
innerRadius = (height / 2) * 1.15; /* extra factor is to leave gap between text and shape */
outerRadius = height;
}
/* set center point for the individual parts of the shape */
x = leftOffset = outerRadius * 1.5;
y = topOffset = outerRadius * 1.5;
/* canvas height and width should be set same as the largest star for clip */
canvas.height = outerRadius * 3;
canvas.width = outerRadius * 3;
/* default settings */
rot = Math.PI / 2 * 3;
ctx.beginPath();
ctx.lineWidth = 15; /* thickness of the lines */
ctx.lineJoin = 'bevel';
ctx.strokeStyle = 'blue'; /* color of the lines */
ctx.font = font; /* font of the text */
/* create the inner star */
ctx.moveTo(leftOffset, topOffset - outerRadius)
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * outerRadius;
y = topOffset + Math.sin(rot) * outerRadius;
ctx.lineTo(x, y);
rot += step;
x = leftOffset + Math.cos(rot) * innerRadius;
y = topOffset + Math.sin(rot) * innerRadius;
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(leftOffset, topOffset - outerRadius);
ctx.closePath();
ctx.stroke();
ctx.restore();
/* draws the outer star */
ctx.beginPath();
ctx.moveTo(leftOffset, topOffset - (outerRadius * 1.725));
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * (outerRadius * 1.725);
y = topOffset + Math.sin(rot) * (outerRadius * 1.725);
ctx.lineTo(x, y)
rot += step
x = leftOffset + Math.cos(rot) * (outerRadius * 1.15);
y = topOffset + Math.sin(rot) * (outerRadius * 1.15);
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(leftOffset, topOffset - (outerRadius * 1.725));
ctx.closePath();
ctx.stroke();
ctx.restore();
/* draws the lines from the stars */
rot = Math.PI / 3;
ctx.beginPath();
for (i = 0; i < spikes; i++) {
x = leftOffset + Math.cos(rot) * innerRadius;
y = topOffset + Math.sin(rot) * innerRadius;
x2 = leftOffset + Math.cos(rot) * (outerRadius * 1.5);
y2 = topOffset + Math.sin(rot) * (outerRadius * 1.5);
ctx.moveTo(x, y);
ctx.lineTo(x2, y2);
rot += 2 * Math.PI / spikes;
}
ctx.closePath();
ctx.stroke();
/* add text and position it */
wrapText(ctx, content, leftOffset, (topOffset - ((height - lineHeight) / 2)), maxWidth, lineHeight);
}
document.getElementById('draw').addEventListener('click', function() {
var input = document.getElementById('content').value;
var fontsize = document.getElementById('fontsize').value;
var fontname = document.getElementById('fontname').value;
drawSnowFlake(input, fontsize + "px " + fontname);
});
/* split text into lines based on width and calculate required height */
function splitText(context, text, maxWidth, lineHeight) {
var words = text.split(' ');
var line = '',
height = lineHeight;
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
line = words[n] + ' ';
height += lineHeight;
} else {
line = testLine;
}
}
return height;
}
/* source from http://www.html5canvastutorials.com/tutorials/html5-canvas-wrap-text-tutorial/ */
function wrapText(context, text, x, y, maxWidth, lineHeight) {
var words = text.split(' ');
var line = '';
context.textBaseline = "middle";
context.textAlign = "center";
var topOffset = x;
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n] + ' ';
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, y);
line = words[n] + ' ';
y += lineHeight;
} else {
line = testLine;
}
}
context.fillText(line, x, y);
}
drawSnowFlake('CSS SHAPES, SVG, CANVAS DESIGNS ROCK', "16px Arial");
div {
margin-bottom: 10px;
}
canvas {
border-radius: 50%;
}
<div class='controls'>
<input id='content' type='textbox' value='CSS SHAPES, SVG, CANVAS DESIGNS ROCK' />
<select id='fontsize'>
<option value='10'>10px</option>
<option value='12'>12px</option>
<option value='14'>14px</option>
<option value='16' selected>16px</option>
</select>
<select id='fontname'>
<option value='Arial' selected>Arial</option>
<option value='Verdana'>Verdana</option>
<option value='Courier'>Courier</option>
</select>
<button id='draw'>Draw</button>
</div>
<canvas id='canvas'></canvas>
OP 希望雪花能够缩放以适应文本的大小。大多数其他答案都是相反的。
这是我能想到的最简单的解决方案。它主要只是 HTML 和带有一小段 JS 的 SVG。这是必需的,因为我认为不可能有一个 SVG 比例来适应没有明确尺寸的 parent。
将文本内容或内部 <div>
的 CSS 样式更改为您满意的内容,SVG 雪花将缩放以匹配。
如果您乐于使用位图背景图像而不是 SVG,您几乎可以肯定地取消 JS。
$().ready(function() {
divWidth = $(".snowflake div").outerWidth();
$(".snowflake svg").css("width", divWidth + "px");
});
.snowflake
{
display: inline-block;
position: relative;
}
.snowflake svg
{
position: absolute;
fill: #eef;
}
.snowflake DIV
{
position: absolute;
padding: 100px;
font: 30pt sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="snowflake">
<svg viewBox="2 0 32 36">
<path d="M33.212,26.16l-3.054-1.764l1.84-1.062c0.238-0.139,0.32-0.441,0.184-0.684c-0.14-0.238-0.445-0.322-0.684-0.183 L29.16,23.82l-2.32-1.34l4.729-2.73c0.239-0.139,0.321-0.441,0.184-0.684c-0.139-0.238-0.445-0.322-0.684-0.183l-5.23,3.019 l-3.619-2.09l4.352-1.918l-4.354-1.919l3.619-2.091l5.231,3.021c0.079,0.047,0.165,0.067,0.25,0.067 c0.174,0,0.342-0.091,0.435-0.25c0.139-0.239,0.057-0.546-0.184-0.683l-4.731-2.732l2.32-1.34L31.5,13.32 c0.079,0.046,0.165,0.066,0.25,0.066c0.173,0,0.341-0.09,0.435-0.25c0.138-0.238,0.056-0.545-0.184-0.682L30.16,11.39l3.052-1.762 c0.239-0.139,0.32-0.443,0.184-0.684c-0.14-0.238-0.446-0.322-0.684-0.184l-3.051,1.763L29.66,8.401c0-0.275-0.225-0.5-0.5-0.5 c-0.276,0-0.5,0.225-0.5,0.5l0.001,2.699l-2.32,1.34l0.001-5.46c0-0.276-0.224-0.5-0.5-0.5c-0.275,0-0.5,0.224-0.5,0.5 l-0.001,6.037l-3.619,2.09l0.515-4.728l-3.838,2.81V9.008l5.229-3.021c0.238-0.138,0.32-0.443,0.184-0.684 c-0.14-0.238-0.445-0.321-0.684-0.182l-4.729,2.73V5.173l2.339-1.352c0.239-0.138,0.321-0.443,0.184-0.684 c-0.14-0.238-0.445-0.322-0.684-0.182L18.399,4.02V0.5c0-0.276-0.224-0.5-0.5-0.5s-0.5,0.224-0.5,0.5v3.523L15.56,2.961 c-0.24-0.141-0.545-0.057-0.683,0.184c-0.138,0.239-0.056,0.545,0.183,0.684l2.339,1.352v2.678l-4.729-2.73 c-0.24-0.14-0.545-0.057-0.683,0.184c-0.138,0.239-0.056,0.545,0.183,0.684l5.229,3.02v4.184l-3.837-2.811l0.514,4.729 l-3.621-2.092V6.989c0-0.276-0.224-0.5-0.5-0.5c-0.276,0-0.5,0.224-0.5,0.5v5.462l-2.318-1.34L7.136,8.41 c0-0.277-0.224-0.5-0.5-0.5c-0.276,0-0.5,0.223-0.5,0.5l0.001,2.125L3.084,8.771C2.845,8.63,2.539,8.714,2.401,8.955 C2.263,9.194,2.345,9.5,2.584,9.638L5.636,11.4l-1.839,1.062c-0.239,0.139-0.321,0.443-0.183,0.684 c0.093,0.16,0.261,0.25,0.434,0.25c0.085,0,0.171-0.021,0.25-0.066l2.339-1.351l2.319,1.339l-4.729,2.73 c-0.239,0.139-0.321,0.443-0.183,0.684c0.093,0.16,0.261,0.25,0.434,0.25c0.085,0,0.171-0.021,0.25-0.066l5.23-3.021l3.622,2.091 l-4.352,1.919l4.351,1.919l-3.621,2.09l-5.231-3.018c-0.241-0.138-0.545-0.058-0.683,0.184c-0.138,0.24-0.056,0.545,0.183,0.686 l4.731,2.729l-2.321,1.34l-2.338-1.352c-0.239-0.142-0.545-0.058-0.683,0.184c-0.138,0.238-0.056,0.545,0.183,0.684l1.838,1.062 l-3.05,1.76c-0.239,0.139-0.321,0.443-0.183,0.684c0.093,0.16,0.261,0.25,0.434,0.25c0.085,0,0.171-0.021,0.25-0.065l3.051-1.763 L6.14,27.4c0,0.276,0.224,0.5,0.5,0.5l0,0c0.276,0,0.5-0.225,0.5-0.5l-0.001-2.701l2.322-1.34l-0.002,5.463 c0,0.277,0.224,0.5,0.5,0.5s0.5-0.223,0.5-0.5l0.002-6.041l3.619-2.09l-0.514,4.729l3.837-2.81v4.183l-5.228,3.021 c-0.239,0.139-0.321,0.442-0.183,0.684c0.138,0.236,0.444,0.318,0.683,0.184l4.728-2.73v2.679l-2.339,1.353 c-0.239,0.139-0.321,0.442-0.183,0.684c0.138,0.236,0.444,0.32,0.683,0.184l1.839-1.062V35.3c0,0.274,0.224,0.5,0.5,0.5 s0.5-0.226,0.5-0.5v-3.524l1.841,1.062c0.079,0.046,0.165,0.066,0.25,0.066c0.174,0,0.342-0.09,0.435-0.25 c0.139-0.239,0.057-0.545-0.184-0.684l-2.341-1.354v-2.678l4.729,2.73c0.079,0.046,0.165,0.066,0.25,0.066 c0.174,0,0.342-0.09,0.435-0.25c0.139-0.239,0.057-0.545-0.184-0.684l-5.229-3.021V22.6l3.838,2.811l-0.514-4.729l3.62,2.09v6.039 c0,0.276,0.224,0.5,0.5,0.5c0.275,0,0.5-0.224,0.5-0.5V23.35l2.318,1.34l0.001,2.699c0,0.275,0.225,0.5,0.5,0.5s0.5-0.225,0.5-0.5 l-0.001-2.123l3.053,1.764c0.079,0.045,0.165,0.066,0.25,0.066c0.174,0,0.342-0.09,0.435-0.25 C33.536,26.604,33.454,26.296,33.212,26.16z M20.997,23.259l-2.6-1.901l-0.499-0.363l-0.501,0.365l-2.598,1.9l0.348-3.201 l0.067-0.615l-0.567-0.25l-2.945-1.299l2.946-1.299l0.566-0.25l-0.067-0.616l-0.348-3.2l2.598,1.901l0.5,0.364l0.5-0.365l2.6-1.901 l-0.349,3.201l-0.066,0.616l0.564,0.249l2.946,1.3l-2.944,1.299l-0.566,0.25l0.066,0.615L20.997,23.259z"/>
</svg>
<div>Here is some text. It's even wrapped.</div>
</div>