正方形隐藏呈三角形html,CSS 搞事技巧:border+transparent

介绍

出门忘带电源线,快递到了终于可以继续水文章了。好不容易获得一个面试机会,面试官很 Nice,可惜的是当时处于懵逼状态,错过了大好的机会:

面试官:巴拉巴拉吧……

我:嗯,啊,这个,那(吱吱呜呜)……

面试官:你知道怎么绘制三角形嘛?

我:主要是利用了 border 和 transparent 这两个属性。其余边设置为 transparent,然后将对应的方向设置为需要的颜色即可,一般常用等边,等腰啊来装饰一下。

面试官:那你知道不等边三角形怎么写吗?

我:不就是那么写么(陷入懵逼状态),然后又迅速说用伪元素来模拟一下?

面试官:你分别设置下高度不就好了。

我:……

效果展示:

1460000018869758

三角形原理

通过图形展示能够更明显显示出区别:

1. 简单的正方形

代码:

$square-size = 100px

.square

width $square-size

height $square-size

border 5px solid

border-color #893615 #E76B56 #A72310 #0C1F22

效果图:

1460000018869759

加强一下效果:

$square-size = 100px

$border-size = 60px

.square

width $square-size

height $square-size

border $border-size solid

border-color #893615 #E76B56 #A72310 #0C1F22

1460000018869760

可以清晰的看到每个边都是一个梯形。

2. 检查正方形

打开控制台即可:

1460000018869761

可以看到中间的空白即为我们设置的 100 * 100 ,这是由于我们的盒模型(box-sizing)为 content-box 导致的结果。

那我们将其设置为 border-box ,查看其结果:

1460000018869762

由 border-box 可知,由于两边 border 大小为 60,所以 60*2=120 > 100,内部的 width 即为 0。

3. 默认盒模型的正方形

在上方已经说明了,正方形的 size 被挤压为 0 时就会得到三角形的效果。

那么此处就在默认盒模型的情况下创建一个三角形:

$square-size = 0

$border-size = 60px

.square

width $square-size

height $square-size

border $border-size solid

border-color #893615 #E76B56 #A72310 #0C1F22

1460000018869763

4. 隐藏不必的边

最后,生成三角形就水到渠成了(保留目标相反方向的颜色),举几个例子。

三角形开角向上:

$square-size = 0

$border-size = 60px

.triangle

width $square-size

height $square-size

border $border-size solid transparent

border-bottom-color #A72310

1460000018869764

三角形开角向右:

$square-size = 0

$border-size = 60px

.triangle

width $square-size

height $square-size

border $border-size solid transparent

border-left-color #0C1F22

1460000018869765

三角形开角向左上:

$square-size = 0

$border-size = 60px

.triangle

width $square-size

height $square-size

border $border-size solid transparent

border-left-color #0C1F22

border-top-color #893615

1460000018869766

三角形生成器

每次还要想一想怎么写三角形很麻烦,将其可视化,每次只需要点一点就创建一个三角形才是极好的。

友情提示:

以下涉及 Vue 相关概念

0. 基本结构

:background-color="bgColor"

class="generate-triangle"

>

三角形方向
三角形类型
三角形颜色
效果图
代码

.generate-triangle

display flex

.title

margin 0

padding 0

.settings

flex-basis 30%

.exhibition

flex auto

background-color #cdd1d3 // 银鱼白

.settings

display flex

flex-direction column

padding-top 12px

.settings_direction,

.settings_type,

.settings_color

display flex

justify-content center

.settings_type,

.settings_color

flex-basis 20%

.settings_direction

flex auto

.exhibition

display flex

flex-direction column

padding-top 12px

.rendering,

.code

display flex

justify-content center

.code

flex-basis 35%

.rendering

flex auto

效果图:

1460000018869767

1. 方向选择

在开始写一个三角形时,需要确定这个三角的朝向,如向上、向下、或向左上。这时候我们就需要一个点击的子组件来触发效果了:

:class="direction.name === 'oblique' ? 'square-t45' : 'square'"

v-for="(direction, index) in directions"

:key="index"

>

class="single"

v-for="(item, index) in direction.single"

:key="index"

:class="{active: direction.name + index === active}"

@click.stop="changeDirection(item, direction.name + index)"

>

export default {

name: "triangle-direction",

data: () => {

return {

active: "oblique0",

directions: [

{

name: "oblique",

single: ["top", "right", "bottom", "left"]

},

{

name: "positive",

single: ["top-left", "top-right", "bottom-right", "bottom-left"]

}

]

};

},

mounted() {

this.changeDirection("top", "oblique0");

},

methods: {

changeDirection(val, index) {

this.active = index;

this.$emit("getDirection", val);

}

}

};

效果图:

1460000018869768

2. 类型选择

此处将三角形分为三种:等边三角形、等腰三角形、不等边三角形。

类型选择组件依赖于方向组件,需要验证传入的值,并且在不同的值会有不同的输出结果。在上文解释过,斜方向的三角形是由两个 border 组成,所以这种类型的将不提供等边的形式:

class="type-button"

v-for="(type, index) in triangleTypes"

v-show="type.en !== 'equilateral' || equilateral"

:key="index"

:class="{active: index === active}"

@click.stop="changeType(type.en, index)"

>{{type.zh}}

export default {

name: "triangle-type",

data: () => {

return {

active: 0,

equilateral: false,

triangleTypes: [

{

en: "equilateral",

zh: "等边"

},

{

en: "isosceles",

zh: "等腰"

},

{

en: "scalene",

zh: "不等边"

}

]

};

},

props: {

type: {

type: String,

validator: function(val) {

return [

"top",

"right",

"left",

"bottom",

"top-left",

"top-right",

"bottom-left",

"bottom-right"

].includes(val);

}

}

},

watch: {

type: {

handler: function(val) {

const isPositive = ["top", "right", "left", "bottom"].includes(val);

this.equilateral = isPositive;

if (isPositive) {

this.changeType('equilateral', 0);

} else {

this.changeType('isosceles', 1);

}

},

immediate: true

}

},

methods: {

changeType(item, index) {

this.active = index;

this.$emit("getType", item);

}

}

};

效果图:

1460000018869769

3. 颜色选取

现在 input 提供了 type="color" 这一选项,制作一个颜色选择器还是很简单的,对于 input 可以使用之前提及的 CSS 搞事技巧:checkbox+label+selector 来隐藏它:

{{color}}

export default {

name: 'color-picker',

data: () => {

return {

color: '#000000'

}

},

mounted() {

this.changeColor();

},

methods: {

changeColor() {

this.$emit('getColor', this.color);

}

}

}

效果图:

1460000018869770

4. 初步效果

效果图来依赖于三个数据:方向、类型及颜色。依次适配这三个即可。

首先完成,方向及颜色问题,先初步看一下效果图:

1460000018869771

5. 宽高选取

在原理中说明了,三角形实际上是一个矩形隐藏了其余 border 形成的。以方向等边三角形为例子:若需要边长度为 50px 的的三角形,则根据勾股定理可得出:border-width: 0 28.87px 50px;

v-model="bottom"

class="width-input"

type="number"

min="0"

max="180"

placeholder="底"

:disabled="!isPositive"

@change="getBorder"

>

v-model="sideOne"

class="width-input"

type="number"

min="0"

max="180"

placeholder="边"

:disabled="type !== 'isosceles' && type !== 'scalene'"

@change="getBorder"

>

v-model="sideTwo"

class="width-input"

type="number"

min="0"

max="180"

placeholder="侧边"

:disabled="type !== 'scalene'"

@change="getBorder"

>

export default {

name: "triangle-width",

props: {

type: {

type: String,

validator: function(val) {

return ["equilateral", "isosceles", "scalene"].includes(val);

}

},

direction: {

type: String,

validator: function(val) {

return [

"top",

"right",

"left",

"bottom",

"top-left",

"top-right",

"bottom-left",

"bottom-right"

].includes(val);

}

}

},

data: () => {

return {

bottom: 50,

sideOne: 50,

sideTwo: 50,

borderWidth: '',

isPositive: false

};

},

watch: {

direction: {

handler: function(val) {

this.isPositive = ["top", "right", "left", "bottom"].includes(val)

this.getBorder();

},

immediate: true

},

type: {

handler: function() {

this.getBorder();

}

}

},

methods: {

getBorder() {

let direction = this.direction;

let type = this.type;

switch(type) {

case 'equilateral':

this.calcEquBorder(direction);

break;

case 'isosceles':

this.calcIsoBorder(direction);

break;

case 'scalene':

this.calcScaBorder(direction);

break;

default:

break;

}

this.$emit('getBorderWidth', this.borderWidth);

},

calcEquBorder(direction) {

let bottom = this.bottom;

let height = (bottom / Math.sqrt(3)).toFixed(2);

switch(direction) {

case 'top':

this.borderWidth = `0 ${height}px ${bottom}px`;

break;

case 'right':

this.borderWidth = `${height}px 0 ${height}px ${bottom}px`;

break;

case 'bottom':

this.borderWidth = `${bottom}px ${height}px 0`;

break;

case 'left':

this.borderWidth = `${height}px ${bottom}px ${height}px 0`;

break;

default:

break;

}

},

}

};

效果图:

1460000018869772

6. 生成代码

终于到了最后一步了,生成代码有很多方式,可以将之前从子组件传递出来的数据处理下输出。这里选择一种较为取巧的形式,因为这边使用的是行内 style 样式,所以可以直接在它的 DOM 上获取。

export default {

methods: {

postCode() {

this.$nextTick(() => {

let dom = this.$refs.triangleRendering;

let code = dom.attributes.style.textContent;

this.$emit('getCode', code);

})

}

}

}

export default {

name: 'triangle-code',

props: {

code: {

type: String,

required: true

}

},

watch: {

code: {

handler: function(code) {

this.handleCode(code);

},

immediate: true

}

},

data: () => {

return {

copyCode: ''

}

},

methods: {

handleCode(code) {

code = code.replace(/\;/g,";\n");

this.copyCode = `width: 0;\n height: 0;\n border: solid transparent;\n ${code}`;

}

}

}

效果图:

1460000018869758

最后

期间步骤只是思路过程,详情请查看项目源码,调试过程中不可避免会进行一些修改。

面试前还是要为面试刷下题目的,不然真的容易懵……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值