【问题标题】:How do I create a teardrop in HTML?如何在 HTML 中创建泪珠?
【发布时间】:2015-08-23 00:59:03
【问题描述】:

如何创建这样的形状以显示在网页上?

我不想使用 图像,因为它们在缩放时会变得模糊

我用 CSS 试过了:

.tear {
  display: inline-block;
  transform: rotate(-30deg);
  border: 5px solid green;
  width: 50px;
  height: 100px;
  border-top-left-radius: 50%;
  border-bottom-left-radius: 50%;
  border-bottom-right-radius: 50%;
}
<div class="tear">
</div>

结果真的很糟糕。

然后我尝试使用 SVG:

<svg viewBox="0 100 100">
  <polygon points="50,0 100,70 50,100 0,70"/>
</svg>

它确实得到了形状,但底部没有弯曲。

有没有办法创建这个形状以便在 HTML 页面中使用它?

【问题讨论】:

  • “我不想使用图像,因为它们在缩放时会变得模糊”,你为什么要缩放图像?如果您使用[srcset]&lt;picture&gt; 元素,它们不会变得模糊。更好的是,只需链接到 svg 图片:&lt;img src="tear.svg" alt="Teardrop"/&gt;
  • @zzzzBov:你真的推荐picture 元素吗? 不支持 IE,不支持 Chrome 的早期版本,不支持 safari。我应该继续吗?
  • @zzzzBov。 why are you scaling the image? 好吧,如果没有开发人员缩放图像,图像可能会显得模糊。你只需要一个放大的浏览器。在我的例子中,我有一个高 DPI 屏幕和大量模糊的图像。所以,是的,如果你可以避免使用 SVG 的图像,那就去吧。
  • Unicode 解决了这一切... U+1F4A7 ????
  • @Thomas 我看到一个正方形:/ i.stack.imgur.com/8fXMf.png

标签: html css svg css-shapes


【解决方案1】:

基本边界半径

您可以在 CSS 中使用border-radius' 和变换相对轻松地做到这一点。你的 CSS 有点过时了。

.tear {
  width: 50px;
  height: 50px;
  border-radius: 0 50% 50% 50%;
  border: 3px solid black;
  transform: rotate(45deg);
  margin-top: 20px;
}
&lt;div class="tear"&gt;&lt;/div&gt;

高级边界半径

这将与上面非常相似,但赋予了它更多的形状。

.tear {
  width: 50px;
  height: 50px;
  border-radius: 80% 0 55% 50% / 55% 0 80% 50%;
  border: 3px solid black;
  transform: rotate(-45deg);
  margin-top: 20px;
}
&lt;div class="tear"&gt;&lt;/div&gt;

【讨论】:

  • @zzzzBov 我不完全理解它为什么是错误的工具,OP 要求提供 CSS 或 SVG 解决方案,我想出了一个尽可能符合描述的 CSS 解决方案。它轻巧且易于修改。
  • @zzzzBov 对图像和精灵使用 CSS 是常见的用法。生成通用“图像”是一段非常少的代码。我认为这是合适的,因为它可以在网页上可用的问题规范中使用。
  • @zzzzBov:CSS 非常适合用于形状。谁说这样的形状是干什么用的? 语义上的图像 - OP 已明确表示他们不希望使用图像,否则为什么会问这样的问题?
  • @jbutler483,“CSS 非常适合形状”不,这很糟糕。仅仅因为你可以并不意味着你应该。它在标记中引入了各种垃圾,并且维护起来很繁琐。图像更易于维护,因为它们很容易分离到自己独立的文件中。
  • “标记中的垃圾”发生在您使用引导程序或字体真棒图标时。说真的,当(很明显)这可以使用边界半径声明来实现时,我认为你对这种情况有点过头了。但是干草,谁告诉你不要使用图像?
【解决方案2】:

您的 CSS 代码的主要问题是:

  1. 您使用的高度与宽度不同
  2. 您没有旋转正确的角度大小

因此,通过“修复”这些问题,您将生成:

.tear {
  display: inline-block;
  transform: rotate(-45deg);
  border: 5px solid green;
  width: 100px;
  height: 100px;
  border-top-left-radius: 50%;
  border-bottom-left-radius: 50%;
  border-bottom-right-radius: 50%;
}
/***for demo only***/

.tear {
  margin: 50px;
}
<div class="tear">
</div>

还请注意节省 CSS 长度,您可以将您的边框半径属性重写为:

border-radius: 50% 0 50% 50%;

这可以通过伪元素as shown in this fiddle来增强

替代方案

我在 codepen 上找到了 Vinay Challuruthis

请注意,使用这里的逻辑,我能够创建 SVG 到几乎任何可能的构建形状/等。例如,一个快速输出是:

<svg viewBox='0 0 400 400'>
  <path fill="none" stroke="#333" stroke-width="5" d="M200,40 C200,115 280,180 280,240 A80,80,0 0,1,120,240 C120,180 200,115 200,40" stroke-linejoin='miter'></path>
</svg>

它使用 SVG 并允许您以多种方式更改形状,并能够将其形状更改为所需的结果:

var SVG = function() {
  this.element = document.getElementsByTagName("svg")[0];
  this.namespace = "http://www.w3.org/2000/svg";
  this.width = 400;
  this.height = 400;
}

/****Let's initialise our SVG ready to draw our shape****/
var svg = new SVG();

/****This sets up the user interface - we've included the script for this as an external library for the codepen****/
var gui = new dat.GUI();

/****Here's where the code to create the shape begins!****/
var Teardrop = function() {
  this.x = svg.width * 0.5;
  this.y = svg.height * 0.1;
  this.width = svg.width * 0.4;
  this.triangleHeight = svg.height * 0.5;
  this.yCP1 = svg.height * 0.2;
  this.yCP2 = svg.height * 0.45;
  this.element = null;
  this.ctrlPoints = [];
  this.anchors = [];
  this.fill = "none";
  this.stroke = "#333";
  this.strokeWidth = 2;
  this.showCtrlPoints = true;
  this.init();
}

Teardrop.prototype.init = function() {
  this.element = document.createElementNS(svg.namespace, "path");
  svg.element.appendChild(this.element);
  this.element.setAttribute("fill", this.fill);
  this.element.setAttribute("stroke", this.stroke);
  this.element.setAttribute("stroke-width", this.strokeWidth);

  for (var i = 0; i < 3; i++) {
    this.ctrlPoints.push(document.createElementNS(svg.namespace, "circle"));
    svg.element.appendChild(this.ctrlPoints[i]);

    this.ctrlPoints[i].setAttribute("fill", this.fill);
    this.ctrlPoints[i].setAttribute("stroke", 'red');
    this.ctrlPoints[i].setAttribute("stroke-width", 1);


    this.anchors.push(document.createElementNS(svg.namespace, "line"));
    svg.element.appendChild(this.anchors[i]);

    this.anchors[i].setAttribute("stroke-width", 1);
    this.anchors[i].setAttribute("stroke", this.stroke);
    this.anchors[i].setAttribute("stroke-dasharray", "3,2");
  }

  this.draw();
}

Teardrop.prototype.draw = function() {
  this.radius = this.width / 2;
  path = [
    "M", this.x, ",", this.y,
    "C", this.x, ",", this.yCP1, " ", this.x + this.width / 2, ",", this.yCP2, " ", this.x + this.width / 2, ",", this.y + this.triangleHeight,
    "A", this.radius, ",", this.radius, ",", "0 0,1,", this.x - this.width / 2, ",", this.y + this.triangleHeight,
    "C", this.x - this.width / 2, ",", this.yCP2, " ", this.x, ",", this.yCP1, " ", this.x, ",", this.y
  ];
  this.element.setAttribute("d", path.join(""));

  cpCoords = [];
  cpCoords[0] = [this.x, this.yCP1];
  cpCoords[1] = [this.x - this.width / 2, this.yCP2];
  cpCoords[2] = [this.x + this.width / 2, this.yCP2];

  anchorCoords = [];
  anchorCoords[0] = [this.x, this.y];
  anchorCoords[1] = [this.x - this.width / 2, this.y + this.triangleHeight];
  anchorCoords[2] = [this.x + this.width / 2, this.y + this.triangleHeight];

  for (var i = 0; i < 3; i++) {
    this.ctrlPoints[i].setAttribute("cx", cpCoords[i][0]);
    this.ctrlPoints[i].setAttribute("cy", cpCoords[i][1]);

    this.anchors[i].setAttribute("x1", cpCoords[i][0]);
    this.anchors[i].setAttribute("x2", anchorCoords[i][0]);
    this.anchors[i].setAttribute("y1", cpCoords[i][1]);
    this.anchors[i].setAttribute("y2", anchorCoords[i][1]);

    if (this.showCtrlPoints) {
      this.ctrlPoints[i].setAttribute("r", 2);
      this.anchors[i].setAttribute("stroke-width", 1);
    } else {
      this.ctrlPoints[i].setAttribute("r", 0);
      this.anchors[i].setAttribute("stroke-width", 0);
    }
  }
}

var teardrop = new Teardrop();

gui.add(teardrop, 'triangleHeight', 0, svg.height * 0.75);
gui.add(teardrop, 'width', 0, 200);
gui.add(teardrop, 'yCP1', 0, svg.height);
gui.add(teardrop, 'yCP2', 0, svg.height);
gui.add(teardrop, 'showCtrlPoints', 0, svg.height);

for (var i in gui.__controllers) {
  gui.__controllers[i].onChange(function() {
    teardrop.draw();
  });
}
html,
body {
  height: 100%;
}
svg {
  display: block;
  margin: 0 auto;
  background: url('http://unitedshapes.com/images/graph-paper/graph-paper.png');
}
<script src="//cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
<svg width='400px' height='400px'></svg>

免责声明上面的笔不是我写的,只是来源。


CSS 版本

虽然这还远未完成,但您也可以使用 CSS 生成此形状。

.tear{
    height:200px;
    width:200px;
    background: linear-gradient(to bottom, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 29%,rgba(0,0,0,1) 30%,rgba(0,0,0,1) 100%);
    border-radius:50%;
    margin:120px;
    position:relative;
}
.tear:before{
    content:"";
    position:absolute;
    top:-70%;left:0%;
    height:100%;width:50%;
    background: radial-gradient(ellipse at -50% -50%, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 75%,rgba(0,0,0,1) 76%,rgba(0,0,0,1) 100%);
}
.tear:after{
    content:"";
    position:absolute;
    top:-70%;left:50%;
    height:100%;width:50%;
    background: radial-gradient(ellipse at 150% -50%, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 75%,rgba(0,0,0,1) 76%,rgba(0,0,0,1) 100%);
}
&lt;div class="tear"&gt;&lt;/div&gt;

SVG 版本

我应该知道 SVG 应该在这个答案的顶部,但是,我喜欢挑战,所以这里是 SVG 的尝试。

svg {
  height: 300px;
}
svg path {
  fill: tomato;
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 100 100">

  <path d="M49.015,0.803
    c-0.133-1.071-1.896-1.071-2.029,0
    C42.57,36.344,20,43.666,20,68.367   
    C20,83.627,32.816,96,48,96
    s28-12.373,28-27.633
    C76,43.666,53.43,36.344,49.015,0.803z 
    M44.751,40.09   
    c-0.297,1.095-0.615,2.223-0.942,3.386
    c-2.007,7.123-4.281,15.195-4.281,24.537
    c0,5.055-2.988,6.854-5.784,6.854   
    c-3.189,0-5.782-2.616-5.782-5.831
    c0-11.034,5.315-18.243,10.005-24.604
    c1.469-1.991,2.855-3.873,3.983-5.749   
    c0.516-0.856,1.903-0.82,2.533,0.029
    C44.781,39.116,44.879,39.619,44.751,40.09z"/>


</svg>

更改path 值,您将能够更改泪珠设计的形状。

【讨论】:

  • 这些看起来都非常……冗长。 js方案特别荒唐。
  • @egid:我在回答中确实声明我没有创建 js 版本。另请注意,js 版本允许您在运行时更改形状
【解决方案3】:

我个人会为此使用 SVG。您可以在大多数矢量图形软件中创建 SVG。我建议:

我在下面做了一个,是你在 Illustrator 中的形状描摹。

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="223.14px" height="319.008px" viewBox="0 0 223.14 319.008" enable-background="new 0 0 223.14 319.008" xml:space="preserve">
  <path fill="none" stroke="#000000" stroke-width="12" stroke-miterlimit="10" d="M111.57,13.291c0,0,57.179,86.984,72.719,108.819
    	c30.359,42.66,41.005,114.694,1.626,154.074c-20.464,20.463-47.533,30.293-74.344,29.488h-0.002
    	c-26.811,0.805-53.88-9.025-74.344-29.488C-2.154,236.804,8.492,164.77,38.851,122.11C54.391,100.275,111.57,13.291,111.57,13.291z" />
</svg>

【讨论】:

    【解决方案4】:

    使用 SVG 很容易做到这一点,只需使用图像转换资源,例如 http://image.online-convert.com/convert-to-svg,它用于创建以下内容:

    <?xml version="1.0" standalone="no"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
     "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
    <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
     width="213.000000pt" height="300.000000pt" viewBox="0 0 213.000000 300.000000"
     preserveAspectRatio="xMidYMid meet">
    <metadata>
    Created by potrace 1.12, written by Peter Selinger 2001-2015
    </metadata>
    <g transform="translate(0.000000,300.000000) scale(0.100000,-0.100000)"
    fill="#000000" stroke="none">
    <path d="M1035 2944 c-143 -250 -231 -380 -508 -752 -347 -465 -432 -616 -493
    -882 -91 -394 10 -753 285 -1013 508 -479 1334 -361 1677 240 126 221 165 494
    105 726 -66 254 -178 452 -609 1076 -96 140 -226 335 -288 435 -155 249 -135
    229 -169 170z m85 -212 c40 -69 192 -298 543 -818 268 -396 354 -593 364 -835
    12 -281 -82 -509 -296 -714 -103 -99 -236 -173 -396 -221 -82 -25 -105 -27
    -260 -28 -148 -1 -181 2 -255 22 -348 96 -611 357 -691 689 -41 167 -25 392
    41 587 62 185 154 334 444 716 177 235 320 444 402 592 27 49 51 88 54 88 3 0
    25 -35 50 -78z"/>
    </g>
    </svg>

    【讨论】:

    • @Persijn 你为什么一直问从某个编辑那里复制? svg 是 svg ,你可以使用任何你想创建的工具。
    • @AbhinavGauniyal: 'editors' 你喜欢称呼他们,在声明中添加额外的'fluff'。例如,300.000000pt 和不是真正需要的元数据
    • @Persijn 你所说的手工/编码是什么意思。有人刚刚制作/手工/编码的插画家只是为了简化他们的编码任务,它仍然会产生同样的东西。再说一次,当您在浏览器中使用 svg 时,您为什么不自己使用汇编语言对其进行手动/编码呢?以及为什么要在组装时停下来,用电线手工/编码,或者自己画。这不是我所期待的原因。
    • @jbutler483 是的,它们可以被修剪掉。有很多工具可以为您做到这一点,这里有一个适合您github.com/svg/svgo
    • @persijn 这个答案提供了所需的 svg 路径。我真的不知道你的反对意见是什么。
    【解决方案5】:

    我还在Codepen 上发现this 由用户Ana Tudor 使用CSS 和box-shadow 样式和参数方程制作。非常简单,代码很少。还有很多browsers 支持CSS3 Box-shadow 样式:

    body {
      background-color: black;
    }
    .tear {
      position: absolute;
      top: 50%;
      left: 50%;
      margin: -0.125em;
      width: 0.25em;
      height: 0.25em;
      border-radius: 50%;
      box-shadow: 0em -5em red, 0.00118em -4.97592em #ff1800, 0.00937em -4.90393em #ff3000, 0.03125em -4.7847em #ff4800, 0.07283em -4.6194em #ff6000, 0.13915em -4.40961em #ff7800, 0.23408em -4.15735em #ff8f00, 0.36em -3.86505em #ffa700, 0.51777em -3.53553em #ffbf00, 0.70654em -3.17197em gold, 0.92382em -2.77785em #ffef00, 1.16547em -2.35698em #f7ff00, 1.42582em -1.91342em #dfff00, 1.69789em -1.45142em #c7ff00, 1.97361em -0.97545em #afff00, 2.2441em -0.49009em #97ff00, 2.5em 0.0em #80ff00, 2.73182em 0.49009em #68ff00, 2.93032em 0.97545em #50ff00, 3.08681em 1.45142em #38ff00, 3.19358em 1.91342em #20ff00, 3.24414em 2.35698em #08ff00, 3.23352em 2.77785em #00ff10, 3.15851em 3.17197em #00ff28, 3.01777em 3.53553em #00ff40, 2.81196em 3.86505em #00ff58, 2.54377em 4.15735em #00ff70, 2.21783em 4.40961em #00ff87, 1.84059em 4.6194em #00ff9f, 1.42017em 4.7847em #00ffb7, 0.96608em 4.90393em #00ffcf, 0.48891em 4.97592em #00ffe7, 0.0em 5em cyan, -0.48891em 4.97592em #00e7ff, -0.96608em 4.90393em #00cfff, -1.42017em 4.7847em #00b7ff, -1.84059em 4.6194em #009fff, -2.21783em 4.40961em #0087ff, -2.54377em 4.15735em #0070ff, -2.81196em 3.86505em #0058ff, -3.01777em 3.53553em #0040ff, -3.15851em 3.17197em #0028ff, -3.23352em 2.77785em #0010ff, -3.24414em 2.35698em #0800ff, -3.19358em 1.91342em #2000ff, -3.08681em 1.45142em #3800ff, -2.93032em 0.97545em #5000ff, -2.73182em 0.49009em #6800ff, -2.5em 0.0em #7f00ff, -2.2441em -0.49009em #9700ff, -1.97361em -0.97545em #af00ff, -1.69789em -1.45142em #c700ff, -1.42582em -1.91342em #df00ff, -1.16547em -2.35698em #f700ff, -0.92382em -2.77785em #ff00ef, -0.70654em -3.17197em #ff00d7, -0.51777em -3.53553em #ff00bf, -0.36em -3.86505em #ff00a7, -0.23408em -4.15735em #ff008f, -0.13915em -4.40961em #ff0078, -0.07283em -4.6194em #ff0060, -0.03125em -4.7847em #ff0048, -0.00937em -4.90393em #ff0030, -0.00118em -4.97592em #ff0018;
    }
    &lt;div class="tear"&gt;&lt;/div&gt;

    【讨论】:

    • 不过,这不像要求的那种泪珠。
    【解决方案6】:

    如果您确实选择使用 SVG,您应该阅读路径。我还建议使用 SVG 编辑器。

    <svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="-0.05 0 1195.1 703" preserveAspectRatio="xMidYMid meet" zoomAndPan="disable" transform="">
        <defs id="svgEditorDefs">
            <line id="svgEditorLineDefs" stroke="black" style="fill: none; vector-effect: non-scaling-stroke; stroke-width: 1px;"/>
        </defs>
        <rect id="svgEditorBackground" x="0" y="0" width="1195" height="703" style="fill: none; stroke: none;"/>
        <path stroke="black" id="e1_circleArc" style="fill: none; stroke-width: 1px; vector-effect: non-scaling-stroke;" d="M 198 207 a 117.969 117.969 0 1 0 213 8" transform=""/>
        <path stroke="black" id="e4_circleArc" style="fill: none; stroke-width: 1px; vector-effect: non-scaling-stroke;" transform="" d="M 411.348 215.696 a 349.677 349.677 0 0 0 -110.37 -131.718"/>
        <path stroke="black" style="fill: none; stroke-width: 1px; vector-effect: non-scaling-stroke;" transform="matrix(-0.182706 -0.983168 0.983168 -0.182706 157.664 417.408)" id="e6_circleArc" d="M 301.799 202.299 a 329.763 329.763 0 0 0 -102.951 -124.781"/>
    </svg>

    【讨论】:

    • 为什么要在 defs 标签内使用一行?你不能在一条路径上做这个形状而不是 3 + 一个矩形吗?
    【解决方案7】:

    SVG 方法:

    您可以使用 内联 SVG&lt;path/&gt; 元素而不是不允许弯曲形状的 &lt;polygon/&gt; 元素轻松实现双曲线。

    以下示例使用&lt;path/&gt; 元素:

    <svg width="30%" viewbox="0 0 30 42">
      <path fill="transparent" stroke="#000" stroke-width="1.5"
            d="M15 3
               Q16.5 6.8 25 18
               A12.8 12.8 0 1 1 5 18
               Q13.5 6.8 15 3z" />
    </svg>

    SVG 是制作这种双曲线形状的好工具。您可以通过 SVG/CSS 比较检查此 post about double curves。在这种情况下使用 SVG 的一些优点是:

    • 曲线控制
    • 填充控制(不透明度、颜色)
    • 描边控制(宽度、不透明度、颜色)
    • 代码量
    • 是时候建立和保持形状了
    • 可扩展
    • 没有 HTTP 请求(如果像示例中那样内联使用)

    浏览器支持可追溯到 Internet Explorer 9。有关详细信息,请参阅 canIuse

    【讨论】:

    • 它可以减少到:&lt;svg width="100%" height="100%" viewBox="0 0 8 8" /&gt; &lt;path d="M4 1L3 4A1.2 2 0 1 0 5 4"/&gt; &lt;/svg&gt; ...这会填满你给它的区域,所以它可能会产生“胖”或“瘦”的雨滴......如果发生变化,则更改为固定的高度/宽度必要的
    • @technosaurus 减少d="..." 属性中的命令数量的问题是,您不再有下降顶部的双曲线。
    • +1 因为您应该为此使用 SVG,而不是 CSS。实现它所需的 CSS 功能具有与 SVG 大致相同的浏览器支持,因此 CSS 在这方面没有优势。 CSS 可以做形状,但这不是它的设计目的;不要为了聪明而试图用螺丝刀敲钉子,因为你可以使用专为这项工作设计的工具来完成它。
    • 更好:创建一个 SVG 文件并在超文本文档中使用 &lt;img /&gt;
    • @AndreasRejbrand 这可能是一个好主意,具体取决于项目,但它添加了一个 OP 似乎想要避免的 HTTP 请求。
    【解决方案8】:

    或者,如果您的观众的字体支持,请使用 Unicode 字符

    水滴:? (&amp;#128167;)

    黑色水滴:? (&amp;#127778;)

    相应地缩放!

    【讨论】:

    • 你可以将它与@font-face 一起使用,但是你有一个字体文件可以保存在正确的位置等等。
    • SVG 和这样的专用 Unicode 符号很好。这方面的 CSS 很糟糕。 PNG 还可以,但并不完美,因为它是光栅图形。 JPG非常糟糕,糟糕到我看到它会做噩梦。
    • @AndreasRejbrand 20x20 PNG 的缩放比 200x200 JPG 最差。而且,在相同大小的情况下,未压缩的 JPG 相当于 PNG。它们都是光栅,并且遇到相同的问题。
    • @nico:理论上,是的,您可以使用零压缩的 JPG。但是网上到处都是这样的灾难:en.wikipedia.org/wiki/Atomic_number#/media/…
    【解决方案9】:

    IMO 这种形状需要平滑的曲线到贝塞尔曲线,以确保曲线的连续性。

    有问题的掉落:

    对于有问题的丢弃,

    • 不能使用平滑曲线,因为控制点的长度不同。但是我们仍然需要使控制点与之前的控制点完全相反(180 度),以确保曲线的完全连续性下图说明了这一点:


    注意:红色和蓝色曲线是两条不同的二次曲线。

    • stroke-linejoin="miter",用于尖顶部分。

    • 由于这个形状只使用连续的c命令,我们可以省略它。

    这是最终的 sn-p:

    <svg height="300px" width="300px" viewBox="0 0 12 16">
      <path fill="#FFF" stroke="black" stroke-width="0.5" stroke-linejoin="miter" 
            d="M 6 1 c -2 3 -5 5 -5 9
               0 7 10 7 10 0 
               0 -4 -3 -6 -5 -9z" />
    </svg>

    TBH 虽然,接受答案的曲线不是很连续。


    对于 IE 5-8 (VML)

    仅适用于 IE 5-8。 VML 使用与 SVG 不同的命令。例如。它使用 v 表示相对三次贝塞尔曲线

    注意:这个 sn-p 也不会在 IE 5-8 中运行。您需要创建一个html文件并直接在浏览器中运行。

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html xmlns:v="urn:schemas-microsoft-com:vml">
    <head>
        <style> v\:* { behavior: url(#default#VML); }
    
        </style >
    </head>
    <body>
        <div style="width:240; height:320;">
            <v:shape coordorigin="0 0" coordsize="12 16" fillcolor="white" strokecolor="black" strokewidth="1"
                strokeweight="5" style="width:240; height:320" 
                path="M 6 1 v -2 3 -5 5 -5 9
               0 7 10 7 10 0 
               0 -4 -3 -6 -5 -9 x e">
            </v:shape>
        </div>
    </body>
    </html>
    

    【讨论】:

    • "不能使用平滑曲线,因为控制点的长度不同。" “平滑”不只是意味着切线手柄(控制点)位于一条直线上吗?为什么它们的长度必须相同?
    • @NiccoloM。在 svg 中,平滑曲线(T 和 S 命令)意味着手柄对称地相对,并且等于前一个手柄的长度。在正常语言中,平滑曲线可能意味着不同的句柄长度,但在 svg 中,长度也等于先前的曲线句柄:)
    【解决方案10】:

    HTML 画布

    到目前为止,这是该线程中未发现的一个选项。用于 Canvas 绘图的命令与 SVG 非常相似(并且 web-tiki 应该归功于此答案中使用的基本思想)。

    可以使用画布自己的曲线命令(二次曲线或贝塞尔曲线)或路径 API 创建相关形状。答案包含所有三种方法的示例。

    Canvas 的浏览器支持是quite good


    使用二次曲线

    window.onload = function() {
      var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
    
        ctx.beginPath();
        ctx.lineJoin = 'miter';
        ctx.moveTo(120, 20);
        ctx.quadraticCurveTo(117.5, 30, 148, 68);
        ctx.arc(120, 88, 34.5, 5.75, 3.66, false);
        ctx.quadraticCurveTo(117.5, 35, 120, 20);
        ctx.closePath();
        ctx.strokeStyle = '#000';
        ctx.lineWidth = 2;
        ctx.fillStyle = '#77CCEE'
        ctx.stroke();
        ctx.fill();
      }
    }
    canvas {
      margin: 50px;
      height: 100px;
      width: 200px;
      transform: scale(1.5);
    }
    
    body{
      background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
    }
    &lt;canvas id='canvas'&gt;&lt;/canvas&gt;

    下面是带有渐变填充和阴影的高级版本。我还在形状上添加了hover 效果,以说明 Canvas 与 SVG 相比的一个缺点。画布是基于光栅(像素)的,因此当缩放超过某个点时会看起来模糊/像素化。唯一的解决方案是在每次浏览器调整大小时重新绘制形状,这是一种开销。

    window.onload = function() {
      var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
        var lineargradient = ctx.createRadialGradient(135, 95, 1, 135, 95, 10);
        lineargradient.addColorStop(0, 'white');
        lineargradient.addColorStop(1, '#77CCEE');      
        ctx.beginPath();
        ctx.lineJoin = 'miter';
        ctx.moveTo(120, 20);
        ctx.quadraticCurveTo(117.5, 30, 148, 68);
        ctx.arc(120, 88, 34.5, 5.75, 3.66, false);
        ctx.quadraticCurveTo(117.5, 35, 120, 20);
        ctx.closePath();
        ctx.strokeStyle = '#333';
        ctx.lineWidth = 3;
        ctx.fillStyle = lineargradient;
        ctx.shadowOffsetX = 2;
        ctx.shadowOffsetY = 2;
        ctx.shadowBlur = 2;
        ctx.shadowColor = "rgba(50, 50, 50, 0.5)";      
        ctx.stroke();
        ctx.fill();
      }
    }
    canvas {
      margin: 50px;
      height: 100px;
      width: 200px;
      transform: scale(1.5);
    }
    
    
    /* Just for demo */
    
    body{
      background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
    }
    
    canvas{
      transition: all 1s;
    }
    
    canvas:hover{
      transform: scale(2);
    }
    &lt;canvas id='canvas'&gt;&lt;/canvas&gt;

    使用贝塞尔曲线

    window.onload = function() {
      var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
        var lineargradient = ctx.createRadialGradient(135, 95, 1, 135, 95, 10);
        lineargradient.addColorStop(0, 'white');
        lineargradient.addColorStop(1, '#77CCEE');
        ctx.beginPath();
        ctx.lineJoin = 'miter';
        ctx.arc(120, 88, 35, 5.74, 3.66, false);
        ctx.bezierCurveTo(100, 55, 122, 27.5, 120, 20);
        ctx.bezierCurveTo(122, 27.5, 121, 31.5, 150, 70);
        ctx.closePath();
        ctx.strokeStyle = 'rgba(109,195,250,0.2)';
        ctx.lineWidth = 1;
        ctx.fillStyle = lineargradient;
        ctx.shadowOffsetX = 2;
        ctx.shadowOffsetY = 2;
        ctx.shadowBlur = 2;
        ctx.shadowColor = "rgba(50, 50, 50, 0.5)";
        ctx.stroke();
        ctx.fill();
      }
    }
    canvas {
      margin: 75px;
      height: 300px;
      width: 300px;
      transform: scale(1.5);
    }
    body {
      background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
    }
    &lt;canvas id='canvas' height='300' width='300'&gt;&lt;/canvas&gt;

    使用路径 API

    window.onload = function() {
      var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
    
        ctx.lineJoin = 'miter';
        var p = new Path2D("M120 20 Q117.5 30 146 68 A34 34 0 1 1 92 68 Q117.5 35 120 20z");
        ctx.strokeStyle = '#000';
        ctx.lineWidth = 2;
        ctx.fillStyle = '#77CCEE'
        ctx.stroke(p);
        ctx.fill(p);
      }
    }
    canvas {
      margin: 50px;
      height: 100px;
      width: 200px;
      transform: scale(1.5);
    }
    
    body {
      background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
    }
    &lt;canvas id='canvas'&gt;&lt;/canvas&gt;

    注意:正如我在回答 here 中提到的,IE 和 Safari 尚不支持 Path API。


    进一步阅读:

    【讨论】:

    • 我看不出 svg 总是更好的选择。在很多情况下,这肯定是更好的选择。但是画布有它自己的优点。不错的答案。从您的回答中我可以看出,使用 SVG 肯定要容易得多!
    • 是的@TimKrul,它更容易编写/使用 SVG。 Canvas 有其自身的优点,但从我读到的任何内容来看,它在用于简单的标志之类的形状时并没有太大优势,主要是因为它与 SVG 不同,它是基于光栅的。
    【解决方案11】:

    CSS 版本

    由于这里有很多答案,我想为什么不用另一种方法添加它。这是同时使用 HTMLCSS 来创建泪珠。

    这将允许您更改泪滴的边框和背景的颜色,并重新调整其顶部的大小。

    使用单个div,我们可以用borderborder-radius 创建一个圆圈。然后使用伪元素(:before & :after)我们创建一个CSS triangle more here,这将充当泪珠的尖端。使用:before 作为边框,我们将:after 放在顶部,尺寸更小,背景颜色更小。

    div {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      border: 4px solid;
      margin: 80px auto;
      position: relative;
    }
    div:before,
    div:after {
      content: "";
      display: block;
      position: absolute;
      width: 0;
      height: 0;
    }
    div:before {
      border-left: 50px solid transparent;
      border-right: 50px solid transparent;
      border-bottom: 104px solid black;
      top: -75px;
    }
    div:after {
      border-left: 46px solid transparent;
      border-right: 46px solid transparent;
      border-bottom: 96px solid #fff;
      top: -66px;
      left: 0;
      right: 0;
      margin: auto;
      z-index: 1;
    }
    &lt;div&gt;&lt;/div&gt;

    这是一个带背景色的泪珠演示

    div {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      border: 4px solid;
      background: red;
      margin: 80px;
      position: relative;
    }
    div:before,
    div:after {
      content: "";
      display: block;
      position: absolute;
      width: 0;
      height: 0;
    }
    div:before {
      border-left: 50px solid transparent;
      border-right: 50px solid transparent;
      border-bottom: 100px solid black;
      top: -70px;
    }
    div:after {
      border-left: 46px solid transparent;
      border-right: 46px solid transparent;
      border-bottom: 96px solid red;
      top: -66px;
      left: 0;
      right: 0;
      margin: auto;
      z-index: 1;
    }
    &lt;div&gt;&lt;/div&gt;

    就像在div 上添加背景颜色并将:after bottom-border 颜色更改为相同颜色一样简单。要更改边框,您还需要更改div 边框颜色和:before 背景颜色。

    【讨论】:

    • Ruddy 笔缺少背景颜色值。
    • @Persijn Harry 在聊天中说了些什么,我在那支笔上看着它,忘记了它时不时地自动保存。哈哈,我会恢复原来的样子。完成。
    【解决方案12】:

    这里有四种逐渐简单的 SVG 泪滴形状:

    <svg viewbox="-20 -20 180 180">
      <g stroke="black" fill="none">
        
        <path transform="translate(0)"
         d="M   0  0
            C   0 10  10 17  10 27
            C  10 40 -10 40 -10 27
            C -10 17   0 10   0  0
            Z"/>
    
        <path transform="translate(40)"
         d="M   0  0
            C   0 16  15 25   5 34
            Q   0 38         -5 34
            C -15 25   0 16   0  0
            Z"/>
        
        <path transform="translate(80)"
         d="M   0  0
            C   0 10  18 36   0 36
            S          0 10   0  0
            Z"/>
    
        <path transform="translate(120)"
         d="M   0  0
            Q  18 36   0 36
            T          0  0
            Z"/>
        
        
        
        
        <g stroke-width="0.25" stroke="red">
          <g transform="translate(0)">
            <ellipse rx="1" ry="1" cx="0"   cy="0" />
            <ellipse rx="1" ry="1" cx="0"   cy="10"/>
            <ellipse rx="1" ry="1" cx="10"  cy="17"/>
            <ellipse rx="1" ry="1" cx="10"  cy="27"/>
            <ellipse rx="1" ry="1" cx="10"  cy="40"/>
            <ellipse rx="1" ry="1" cx="-10" cy="40"/>
            <ellipse rx="1" ry="1" cx="-10" cy="27"/>
            <ellipse rx="1" ry="1" cx="-10" cy="17"/>
            <line x1="0"   y1="0"  x2="0"   y2="10"/>
            <line x1="10"  y1="17" x2="10"  y2="40"/>
            <line x1="-10" y1="40" x2="-10" y2="17"/>
          </g>
          <g transform="translate(40)">
            <ellipse rx="1" ry="1" cx="0"   cy="0" />
            <ellipse rx="1" ry="1" cx="0"   cy="16"/>
            <ellipse rx="1" ry="1" cx="15"  cy="25"/>
            <ellipse rx="1" ry="1" cx="5"   cy="34"/>
            <ellipse rx="1" ry="1" cx="0"   cy="38"/>
            <ellipse rx="1" ry="1" cx="-5"  cy="34"/>
            <ellipse rx="1" ry="1" cx="-15" cy="25"/>
            <line x1="0"  y1="0"  x2="0"   y2="16"/>
            <line x1="15" y1="25" x2="0"   y2="38"/>
            <line x1="0"  y1="38" x2="-15" y2="25"/>
          </g>
          <g transform="translate(80)">
            <ellipse rx="1" ry="1" cx="0"   cy="0" />
            <ellipse rx="1" ry="1" cx="0"   cy="10"/>
            <ellipse rx="1" ry="1" cx="18"  cy="36"/>
            <ellipse rx="1" ry="1" cx="0"   cy="36"/>
            <ellipse rx="1" ry="1" cx="-18" cy="36" stroke="gray"/>
            <line x1="0"  y1="0"  x2="0"   y2="10"/>
            <line x1="18" y1="36" x2="0"   y2="36"/>
            <line x1="0"  y1="36" x2="-18" y2="36" stroke="gray" stroke-dasharray="0.5"/>
          </g>
          <g transform="translate(120)">
            <ellipse rx="1" ry="1" cx="0"   cy="0" />
            <ellipse rx="1" ry="1" cx="18"  cy="36"/>
            <ellipse rx="1" ry="1" cx="0"   cy="36"/>
            <ellipse rx="1" ry="1" cx="-18" cy="36" stroke="gray"/>
            <line x1="18" y1="36" x2="0"   y2="36"/>
            <line x1="0"  y1="36" x2="-18" y2="36" stroke="gray" stroke-dasharray="0.5"/>
          </g>
        </g>    
      </g>
      <g font-size="6" transform="translate(-1.5,-4)">
        <text x="-10" y="-8"># of unique points:</text>
        <text transform="translate(  0)">8</text>
        <text transform="translate( 40)">7</text>
        <text transform="translate( 80)">4</text>
        <text transform="translate(120)">3</text>
      </g>
    </svg>

    【讨论】:

      猜你喜欢
      • 2023-03-27
      • 2018-10-14
      • 1970-01-01
      • 2021-02-08
      • 2020-06-01
      • 2014-04-27
      • 1970-01-01
      • 2013-04-14
      • 1970-01-01
      相关资源
      最近更新 更多