How do I create a teardrop in HTML?

后端 未结 12 546
生来不讨喜
生来不讨喜 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:31

    Your main issue with your CSS code was:

    1. You used a different height than width
    2. You haven't rotated the correct angle size

    So, by 'fixing' these issues, you would generate:

    .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;
    }

    Please also note to save on CSS length, you could re-write your border-radius properties to:

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

    this could be enhanced with pseudo elements as shown in this fiddle

    Alternatives

    I found this by Vinay Challuru on codepen.

    Please note that with the logic here, I was able to create the SVG to nearly any possible build shape/etc. For example, a quick output was:

    
      
    

    It's using an SVG and allows you to alter the shape in multiple ways, having the ability to alter its shape to the desired result:

    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');
    }
    
    

    Disclaimer I did not write the above pen, only sourced it.


    CSS Version

    Although this is far from complete, you may also be able to generate this shape using 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%);
    }

    SVG Version

    I should know that SVG should be at the top of this answer, however, I like a challenge and so here is an attempt with SVG.

    svg {
      height: 300px;
    }
    svg path {
      fill: tomato;
    }
    
    
      
    
    
    

    Altering the path values, you would be able to alter the shape of your teardrop design.

提交回复
热议问题