How do I create a teardrop in HTML?

后端 未结 12 520
生来不讨喜
生来不讨喜 2020-12-02 03:59

How do I create a shape like this to display on a webpage?

I don\'t want to use images since they would get blurry on scaling

相关标签:
12条回答
  • 2020-12-02 04:21

    SVG approach:

    You can achieve the double curve easily with an inline SVG and the <path/> element instead of the <polygon/> element which doesn't allow curved shapes.

    The following example uses the <path/> element with:

    • 2 quadratic bezier curve commands for the 2 top curves (lines beginning with Q)
    • 1 arc command for the big bottom one (line beginning with A)

    <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 is a great tool to make this kind of shapes with double curves. You can check this post about double curves with an SVG/CSS comparison. Some of the advantages of using SVG in this case are:

    • Curve control
    • Fill control (opacity, color)
    • Stroke control (width, opacity, color)
    • Amount of code
    • Time to build and maintain the shape
    • Scalable
    • No HTTP request (if used inline like in the example)

    Browser support for inline SVG goes back to Internet Explorer 9. See canIuse for more information.

    0 讨论(0)
  • 2020-12-02 04:21

    Basic Border-Radius

    You can do this within CSS relatively easily using border-radius' and transforms. Your CSS was just a little bit out.

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

    Advanced Border-Radius

    This will be very similar to above but gives it a bit more shape.

    .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;
    }
    <div class="tear"></div>

    0 讨论(0)
  • 2020-12-02 04:21

    I'd personally use an SVG for this. You can create SVGs in most vector graphics software. I'd recommend:

    • Inkscape
    • Sketch
    • Adobe Illustrator

    I have made one below that is a tracing of your shape in 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>

    0 讨论(0)
  • 2020-12-02 04:21

    HTML Canvas

    This is an option uncovered in this thread so far. The commands used for Canvas drawings are very similar to SVG (and web-tiki deserves the credits for the base idea used in this answer).

    The shape in question can be created either using canvas' own curve commands (Quadratic or Bezier) or the Path API. The answer contains examples for all three methods.

    The browser support for Canvas is quite good.


    Using Quadratic Curves

    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%);
    }
    <canvas id='canvas'></canvas>

    Below is an advanced version with gradient fill and shadows. I have also included a hover effect on the shape to illustrate one drawback of Canvas when compared to SVG. Canvas is raster (pixel) based and hence would look blurred/pixelated when scaled beyond a certain point. The only solution to that would be to repaint the shape on every browser resize which is an overhead.

    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);
    }
    <canvas id='canvas'></canvas>


    Using Bezier Curves

    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%);
    }
    <canvas id='canvas' height='300' width='300'></canvas>

    Using Path 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%);
    }
    <canvas id='canvas'></canvas>

    Note: As mentioned in my answere here, the Path API is not yet supported by IE and Safari.


    Further reading:

    • 7 Reasons to Consider SVGs Instead of Canvas
    • HTML5 Canvas vs. SVG: Choose the Best Tool for the Job
    • What is the difference between SVG and HTML5 Canvas?
    0 讨论(0)
  • 2020-12-02 04:22

    If you do choose to use SVG you should read up on paths. I would also suggest an SVG editor.

    <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>

    0 讨论(0)
  • 2020-12-02 04:26

    IMO this shape requires smooth curve-to beziers to ensure continuity of the curve.

    The Drop in question :

    For the drop in question,

    • smooth curves can't be used, as control points wont be of same length. But we still need to make the control points lie exactly opposite (180 deg) to the previous control points, to ensure full continuity of curve The picture given below illustrates this point :

    enter image description here
    Note: Red and blue curves are two different quadratic curves.

    • stroke-linejoin="miter", for the pointed top part.

    • AS this shape only uses successive c commands, we can omit it.

    Here's the final snippet:

    <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 though, accepted answer's curves are not quite continuous.


    For IE 5-8 (VML)

    Only works in IE 5-8. VML uses different commands than SVG. Eg. it uses v for relative cubic beziers.

    Note: This snippet won't run in IE 5-8 too. You need to create an html file and run it directly in the browser.

    <!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>
    
    0 讨论(0)
提交回复
热议问题