使用 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>
我必须用 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>