使用 div 创建的按钮的形状边框

Shape borders of button created with divs

我必须用 the shape of a triangle in each side 创建一个按钮。

我的方法是创建一个 div,其中包含另外 4 个 div(每个角一个),因此我可以使用线性渐变通过重叠 div 来塑造三角形背景为白色。

问题是我还需要为创建的形状编辑边框,这是不可能的,因为每个 div 都有自己的边框。

有没有办法只为最终按钮的形状获取边框?

.button {
  height: 50px;
  width: 140px;
  position: relative;
  background: darkred;
}

.button:hover {
  background: black;
}

.text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  color: white;
  font-size: 15px;
  font-family: Tahoma;
}

.text:hover {
  color: red;
}

.left,
.right {
  width: 8%;
  height: 50%;
  position: absolute;
}

.left {
  right: 0;
}

.right {
  left: 0;
}

.down {
  bottom: 0;
}

.up {
  top: 0;
}

.left.up {
  background: linear-gradient(225deg, white 87%, white 87%, transparent 0%);
}

.left.down {
  background: linear-gradient(-45deg, white 87%, white 87%, transparent 0%);
}

.right.down {
  background: linear-gradient(45deg, white 87%, white 87%, transparent 0%);
}

.right.up {
  background: linear-gradient(135deg, white 87%, white 87%, transparent 0%);
}
<div class="button text">
  <span>Discover More</span>
  <div class="left up"></div>
  <div class="left down"></div>
  <div class="right up"></div>
  <div class="right down"></div>
</div>

这是一个用很少的代码和 CSS 个变量来轻松调整形状的想法:

.box {
  --c:green; /* color */
  --a:30deg; /* angle */
  --b:3px;   /* border thickness */
  --w:20px;  /* width of of arrow */

  padding:30px calc(var(--w) + 20px);
  text-align:center;
  margin:10px;
  background:
    linear-gradient(var(--c) 0 0) top,
    linear-gradient(var(--c) 0 0) bottom;
  background-size:calc(100% - 2*var(--w)) var(--b);
  background-repeat:no-repeat;
  overflow:hidden;
  display:inline-block;
  position:relative;
}
.box::before,
.box::after,
.box span::before,
.box span::after{
  content:"";
  position:absolute;
  box-sizing:border-box;
  left:0;
  top:0;
  height:50%;
  width:var(--w);
  border-right:var(--b) solid var(--c);
  border-bottom:var(--b) solid var(--c);
  transform-origin:0 calc(100% - var(--b)/2);
  transform:scaleY(var(--s,1)) skewY(calc(-1*var(--a)));
}
.box::after,
.box span::after{
  --s:-1;
}

.box span::before,
.box span::after {
  left:auto;
  right:0;
  border-right:0;
  border-left:var(--b) solid var(--c);
  transform-origin:100% calc(100% - var(--b)/2);
  transform:scaleY(var(--s,1)) skewY(var(--a));
}
<div class="box"><span></span> some text here </div>
<div class="box" style="--c:red;--b:5px;--a:45deg"><span></span> some text here </div>
<div class="box" style="--c:blue;--b:2px;--a:25deg"><span></span> some text<br> here </div>

获得完全响应的最终解决方案是将 SVG 图像创建为 Vue.js 组件,其中大小和形状(在 SVG 中称为“路径”)取决于插入的文本。

<script>
export default {
  data() {
    return {
      width: 150,
      height: 8,
      triangle: 12
    };
  },
  props: {
    text: {
      type: String,
      required: true
    },
    left: {
      type: Boolean,
      default: false
    },
    right: {
      type: Boolean,
      default: false
    },
    icon: {
      type: String,
      default: null
    }
  },
  computed: {
    rightTriangle() {
      const t = this.triangle;
      const h = this.height;

      return this.right
        ? `l 0 ${h} l ${t} ${t} l -${t} ${t} l 0 ${h}`
        : `l 0 ${h} l 0 ${t} l 0 ${t} l 0 ${h}`;
    },
    leftTriangle() {
      const t = this.triangle;
      const h = this.height;

      return this.left
        ? `l 0 -${h} l -${t} -${t} l ${t} -${t} l 0 -${h}`
        : `l 0 -${h} l 0 -${t} l 0 -${t} l 0 -${h}`;
    },
    svgPath() {
      return `m ${this.svgMargin.x} ${this.svgMargin.y} l ${this.width} 0 ${
        this.rightTriangle
      } l -${this.width} 0 ${this.leftTriangle}`;
    },
    svgHeight() {
      return this.height * 2 + this.triangle * 2 + 4;
    },
    svgWidth() {
      //
      //distance between [0,0] to [x, y]
      var triangleWidth = Math.sqrt(this.triangle * this.triangle);
      var numTriangles = 2;

      return this.width + triangleWidth * numTriangles + 2;
    },
    svgMargin() {
      return {
        x: this.triangle + 1,
        y: 2
      };
    }
  },
  watch: {
    text: {
      handler() {
        this.$nextTick(() => {
          this.updateButtonWidth();
        });
      },
      immediate: true
    }
  },
  methods: {
    updateButtonWidth() {
      const iconSize = this.icon ? 40 : 0;

      this.width =
        document.querySelector(".atc-button-text").getBBox().width +
        40 +
        iconSize;
    },
    handleClickEvent() {
      this.$emit("click-event");
    }
  }
};
</script>
<style scoped>
.atc-button-wrapper {
  display: flex;
  justify-content: center;
  position: relative;
}
.atc-button-wrapper.push-left {
  justify-content: flex-start;
}
.atc-button-wrapper.push-right {
  justify-content: flex-end;
}
.svg-content {
  position: relative;
}
.atc-button-content:hover {
  cursor: pointer;
}
.atc-button-content path {
  fill: transparent;
  stroke: #ccba83;
}
.atc-button-content:hover path {
  fill: #ccba83;
  stroke: #ccba83;
}
.atc-button-content text {
  fill: #ccba83;
  font-family: cursive;
  font-weight: bold;
}
.atc-button-content:hover text {
  fill: white;
}

.atc-button-icon-wrapper {
  position: absolute;
  display: flex;
  align-items: center;
  margin: auto;
  top: -4px;
  left: 30px;
  bottom: 0;
}
.atc-button-icon {
  font-size: 20pt;
  color: #ccba83;
}
.atc-button-icon:hover {
  cursor: pointer;
  color: white;
}

.atc-button-content:hover ~ .atc-button-icon-wrapper .atc-button-icon {
  color: white;
}

.atc-button-icon-wrapper:hover ~ .atc-button .atc-button-content path {
  fill: #ccba83 !important;
  stroke: #ccba83 !important;
}
</style>
<template>
  <div class="atc-button-wrapper">
    <div class="svg-content">
      <svg class="atc-button" :height="svgHeight" :width="svgWidth">
        <g @click="handleClickEvent()" class="atc-button-content">
          <path stroke="red" :d="svgPath"></path>
          <text
            class="atc-button-text"
            :x="icon ? '56%' : '50%'"
            y="52%"
            dominant-baseline="middle"
            text-anchor="middle"
          >{{text}}</text>
        </g>
      </svg>

      <div class="atc-button-icon-wrapper">
        <fa-icon :icon="icon" class="atc-button-icon"></fa-icon>
      </div>
    </div>
  </div>
</template>