css to achieve unilateral oblique cutting effect

demand

In the UI diagram, there is a need for oblique cutting patterns. A progress bar with variable progress items is a list type. The effect is as shown in the figure. The following is a progress bar generated by traversing an array of three elements:

First attempt

It's not difficult to write the progress bar first. You only need the following structure:

// html
<div class="progress-outer">
	<div v-for="(item,key) in items" :key="index"  class="progress-inner" :style={'width': item.percent + '%','left': getLeft(index)}></div>
</div>

// css
.progress-outer {
	position: relative;
	width: 100%;
	height: 30px;
}
.progress-inner {
	position: absolute;
	top: 0;
	bottom: 0;
}

The getLeft function here accumulates the percentages of the previous elements. The part of the progress bar is completed. Now it is mainly the difficulty of the oblique cutting style.
The first thought is to use the transform ed skew to tilt the intermediate module and cover the empty part.

The skew() function defines the skew transformation of an element on a two-dimensional plane

Attribute reference here.
Set the following styles for the middle element:

transform: skew(-20deg);
border-width: 0;
border-left-width: 5px;
border-right-width: 5px;
border-color: #e9e9e9;
border-style: solid;

After setting the tilt, the inclined gap will be exposed. My solution is to widen the width of the middle element and set the migration amount of left.
But I soon found that this method is not applicable because when my list array is two, there is no intermediate element to split, so the effect cannot be achieved.

Second attempt

skew cannot achieve the effect of unilateral oblique cutting. The idea is to add a 5px sub element span to each progress bar, absolutely locate the rightmost and rotate, as follows:

<div class="progress-outer">
	<div v-for="(item,key) in items" :key="index"  class="progress-inner" :style={'width': item.percent + '%','left': getLeft(index)}>
		<span v-if="index !== items.length - 1" class="progress-inner_hr"></span>
	</div>
</div>

// css
.progress-outer {
	position: relative;
	width: 100%;
	height: 30px;
}
.progress-inner {
	position: absolute;
	top: 0;
	bottom: 0;
}
.progress-inner_hr {
	display: block;
	width: 5px;
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	background: #e9e9e9;
	transform: rotate(-20deg);
}

But it was soon found that there was only a slash and formed a right triangle shape that was not covered.

Third attempt

On the basis of the second attempt, it is found that only a parallelogram composed of two right triangles can cover the redundant positions on the left and right sides.
We know that the triangle can be realized by using border, so it is better to solve this oblique cutting problem.
The code is as follows:

<div class="progress-outer">
	<div v-for="(item,key) in items" :key="index"  class="progress-inner" :style={'width': item.percent + '%','left': getLeft(index)}>
		<span v-if="items.length > 1 && index !== 0" class="progress-inner_hr progress-inner_hr_left"></span>
		<span v-if="items.length > 1 && index !== items.length - 1" class="progress-inner_hr progress-inner_hr_right"></span>
	</div>
</div>

// css
.progress-outer {
	position: relative;
	width: 100%;
	height: 30px;
}
.progress-inner {
	position: absolute;
	top: 0;
	bottom: 0;
}
.progress-inner_hr {
	position: absolute;
	top: 0;
	display: block;
	width: 0;
	height: 0;
	// The border implements a right triangle
	border-style: solid;
}
.progress-inner_hr_left {
	left: 0;
    border-width: 0 0 30px 10px;
    border-color: transparent transparent transparent #e9e9e9;
}
.progress-inner_hr_right {
	right: 0;
    border-width: 30px 10px 0 0;
    border-color: transparent #e9e9e9 transparent transparent;
}

In this way, the oblique cutting composed of two right triangles solves the oblique cutting I want, and has high compatibility.

in addition

In the process of making this style, I learned that there is a new attribute that can set the coordinate value like svg to achieve the oblique cutting effect: clip-path , polygon is used to define coordinates to achieve unilateral oblique cutting effect, but its compatibility is poor, so it is selected carefully.
In addition, you can also use the gradient value of background to simulate the effect of oblique cutting.
I won't say much about the implementation code of these two attributes, which I haven't used here.

summary

There are thousands of methods to realize the oblique cutting effect, which is only realized after taking a detour. Write it down here to reduce the time cost for the later people.

Tags: Javascript Vue html css

Posted on Wed, 29 Sep 2021 17:29:12 -0400 by pankirk