侧面倾斜的形状(响应式)
我正在尝试创建一个如下图所示的形状,仅在一侧具有倾斜边缘(例如,底侧),而其他边缘保持笔直.
I am trying to create a shape like in the image below with a slanted edge on only one side (for example, the bottom side) while the other edges remain straight.
我尝试使用边框方法(代码如下),但我的形状尺寸是动态的,因此我无法使用此方法.
I tried using the border method (code is given below) but the dimensions of my shape are dynamic and hence I cannot use this method.
.shape {
position: relative;
height: 100px;
width: 200px;
background: tomato;
}
.shape:after {
position: absolute;
content: '';
height: 0px;
width: 0px;
left: 0px;
bottom: -100px;
border-width: 50px 100px;
border-style: solid;
border-color: tomato tomato transparent transparent;
}
<div class="shape">
Some content
</div>
我也尝试过使用渐变作为背景(如下面的代码),但随着尺寸的变化,它会变得混乱.您可以通过将鼠标悬停在以下代码段中的形状上来了解我的意思.
I have also tried using gradients for background (like in the below code) but it gets messed up as the dimensions change. You can see what I mean by hovering on the shape in the below snippet.
.gradient {
display: inline-block;
vertical-align: top;
height: 200px;
width: 100px;
margin: 10px;
color: beige;
transition: all 1s;
padding: 10px;
background: linear-gradient(45deg, transparent 45%, tomato 45%) no-repeat;
}
.gradient:hover {
width: 200px;
}
<div class="gradient"></div>
如何创建这种带有斜边的形状,并且还能够支持动态尺寸?
How can I create this shape with a slanted side and also be able to support dynamic sizes?
推荐答案
有很多方法可以创建仅在一侧具有倾斜边缘的形状.
There are many ways to create the shape with a slanted edge only on one side.
以下方法不支持问题中已经提到的动态尺寸:
The following methods cannot support dynamic sizes as already mentioned in the question:
border-width
的像素值的边界三角形方法.- 使用角度语法的线性渐变(如 45 度、30 度等).
- Border triangle method with pixel values for
border-width
. - Linear gradients with the angle syntax (like 45deg, 30deg etc).
下面介绍了可以支持动态尺寸的方法.
The methods that can support dynamic sizes are described below.
(浏览器兼容性)
SVG 可用于通过使用 polygon
s 或 path
s 来生成形状.下面的代码片段使用了 polygon
.所需的任何文本内容都可以放置在形状的顶部.
SVG can be used to produce the shape either by using polygon
s or path
s. The below snippet makes use of polygon
. Any text content required can be positioned on top of the shape.
$(document).ready(function() {
$('#increasew-vector').on('click', function() {
$('.vector').css({
'width': '150px',
'height': '100px'
});
});
$('#increaseh-vector').on('click', function() {
$('.vector').css({
'width': '100px',
'height': '150px'
});
});
$('#increaseb-vector').on('click', function() {
$('.vector').css({
'width': '150px',
'height': '150px'
});
});
})
div {
float: left;
height: 100px;
width: 100px;
margin: 20px;
color: beige;
transition: all 1s;
}
.vector {
position: relative;
}
svg {
position: absolute;
margin: 10px;
top: 0px;
left: 0px;
height: 100%;
width: 100%;
z-index: 0;
}
polygon {
fill: tomato;
}
.vector > span {
position: absolute;
display: block;
padding: 10px;
z-index: 1;
}
.vector.top > span{
height: 50%;
width: 100%;
top: calc(40% + 5px); /* size of the angled area + buffer */
left: 5px;
}
.vector.bottom > span{
height: 50%;
width: 100%;
top: 5px;
left: 5px;
}
.vector.left > span{
width: 50%;
height: 100%;
left: 50%; /* size of the angled area */
top: 5px;
}
.vector.right > span{
width: 50%;
height: 100%;
left: 5px;
top: 5px;
}
/* Just for demo */
body {
background: radial-gradient(circle at 50% 50%, aliceblue, steelblue);
}
polygon:hover, span:hover + svg > polygon{
fill: steelblue;
}
.btn-container {
position: absolute;
top: 0px;
right: 0px;
width: 150px;
}
button {
width: 150px;
margin-bottom: 10px;
}
.vector.left{
clear: both;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="vector bottom">
<span>Some content</span>
<svg viewBox="0 0 40 100" preserveAspectRatio="none">
<polygon points="0,0 40,0 40,100 0,60" />
</svg>
</div>
<div class="vector top">
<span>Some content</span>
<svg viewBox="0 0 40 100" preserveAspectRatio="none">
<polygon points="0,40 40,0 40,100 0,100" />
</svg>
</div>
<div class="vector left">
<span>Some content</span>
<svg viewBox="0 0 40 100" preserveAspectRatio="none">
<polygon points="0,0 40,0 40,100 20,100" />
</svg>
</div>
<div class="vector right">
<span>Some content</span>
<svg viewBox="0 0 40 100" preserveAspectRatio="none">
<polygon points="0,0 20,0 40,100 0,100" />
</svg>
</div>
<div class='btn-container'>
<button id="increasew-vector">Increase Width</button>
<button id="increaseh-vector">Increase Height</button>
<button id="increaseb-vector">Increase Both</button>
</div>
优点
- SVG 旨在生成可缩放的图形,并且可以很好地适应所有尺寸变化.
- 可以以最少的编码开销实现边框和悬停效果.
- 还可以为形状提供图像或渐变背景.
缺点
- 浏览器支持可能是唯一的缺点,因为 IE8- 不支持 SVG,但可以通过使用 Raphael 和 VML 等库来缓解这种情况.此外,浏览器支持绝不比其他选项差.
(浏览器兼容性)
仍然可以使用线性渐变来生成形状,但不能使用问题中提到的角度.我们必须使用 to [side] [side]
语法(感谢 vals) 而不是指定角度.当指定边时,渐变角度会根据容器的尺寸自动调整.
Linear gradients can still be used to produce the shape but not with angles as mentioned in the question. We have to use the to [side] [side]
syntax (thanks to vals) instead of specifying angles. When sides are specified, the gradient angles are automatically adjusted based on the container's dimensions.
$(document).ready(function() {
$('#increasew-gradient').on('click', function() {
$('.gradient').css({
'height': '100px',
'width': '150px'
});
});
$('#increaseh-gradient').on('click', function() {
$('.gradient').css({
'height': '150px',
'width': '100px'
});
});
$('#increaseb-gradient').on('click', function() {
$('.gradient').css({
'height': '150px',
'width': '150px'
});
});
})
div {
float: left;
height: 100px;
width: 100px;
margin: 10px 20px;
color: beige;
transition: all 1s;
}
.gradient{
position: relative;
}
.gradient.bottom {
background: linear-gradient(to top right, transparent 50%, tomato 50%) no-repeat, linear-gradient(to top right, transparent 0.1%, tomato 0.1%) no-repeat;
background-size: 100% 40%, 100% 60%;
background-position: 0% 100%, 0% 0%;
}
.gradient.top {
background: linear-gradient(to bottom right, transparent 50%, tomato 50%) no-repeat, linear-gradient(to bottom right, transparent 0.1%, tomato 0.1%) no-repeat;
background-size: 100% 40%, 100% 60%;
background-position: 0% 0%, 0% 100%;
}
.gradient.left {
background: linear-gradient(to top right, transparent 50%, tomato 50%) no-repeat, linear-gradient(to top right, transparent 0.1%, tomato 0.1%) no-repeat;
background-size: 40% 100%, 60% 100%;
background-position: 0% 0%, 100% 0%;
}
.gradient.right {
background: linear-gradient(to top left, transparent 50%, tomato 50%) no-repeat, linear-gradient(to top left, transparent 0.1%, tomato 0.1%) no-repeat;
background-size: 40% 100%, 60% 100%;
background-position: 100% 0%, 0% 0%;
}
.gradient span{
position: absolute;
}
.gradient.top span{
top: calc(40% + 5px); /* background size + buffer */
left: 5px;
height: 50%;
}
.gradient.bottom span{
top: 5px;
left: 5px;
height: 50%;
}
.gradient.left span{
left: 40%; /* background size */
top: 5px;
width: 50%;
}
.gradient.right span{
left: 5px;
top: 5px;
width: 50%;
}
/* Just for demo */
body {
background: radial-gradient(circle at 50% 50%, aliceblue, steelblue);
}
.btn-container {
position: absolute;
top: 0px;
right: 0px;
width: 150px;
}
button {
width: 150px;
margin-bottom: 10px;
}
.gradient.left{
clear:both;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="gradient bottom"><span>Some content</span>
</div>
<div class="gradient top"><span>Some content</span>
</div>
<div class="gradient left"><span>Some content</span>
</div>
<div class="gradient right"><span>Some content</span>
</div>
<div class='btn-container'>
<button id="increasew-gradient">Increase Width</button>
<button id="increaseh-gradient">Increase Height</button>
<button id="increaseb-gradient">Increase Both</button>
</div>
优点
- 即使容器的尺寸是动态的,也可以实现和保持形状.
- 可以通过改变渐变颜色来添加悬停效果.
缺点
- 即使光标在形状之外但在容器内,也会触发悬停效果.
- 添加边框需要复杂的渐变操作.
- 众所周知,当宽度(或高度)很大时,渐变会产生锯齿状的角.
- 不能在形状上使用图像背景.
(浏览器兼容性)
在此方法中,添加、倾斜和定位伪元素,使其看起来像其中一个边缘倾斜/倾斜.如果顶部或底部边缘倾斜,则倾斜应沿 Y 轴,否则旋转应沿 X 轴.transform-origin
的一侧应与倾斜的一侧相反.
In this method, a pseudo-element is added, skewed and positioned in such a way that it looks like one of the edges is slanted/angled.If the top or bottom edge is slanted, the skew should be along Y axis, else the rotation should be along X axis. The transform-origin
should have the side opposite to the slanted side.
$(document).ready(function() {
$('#increasew-skew').on('click', function() {
$('.skew').css({
'height': '100px',
'width': '150px'
});
});
$('#increaseh-skew').on('click', function() {
$('.skew').css({
'height': '150px',
'width': '100px'
});
});
$('#increaseb-skew').on('click', function() {
$('.skew').css({
'height': '150px',
'width': '150px'
});
});
})
div {
float: left;
height: 100px;
width: 100px;
margin: 50px;
color: beige;
transition: all 1s;
}
.skew {
padding: 10px;
position: relative;
background: tomato;
}
.skew:after {
position: absolute;
content: '';
background: inherit;
z-index: -1;
}
.skew.bottom:after,
.skew.top:after {
width: 100%;
height: 60%;
}
.skew.left:after,
.skew.right:after {
height: 100%;
width: 60%;
}
.skew.bottom:after {
bottom: 0px;
left: 0px;
transform-origin: top left;
transform: skewY(22deg);
}
.skew.top:after {
top: 0px;
left: 0px;
transform-origin: top left;
transform: skewY(-22deg);
}
.skew.left:after {
top: 0px;
left: 0px;
transform-origin: bottom left;
transform: skewX(22deg);
}
.skew.right:after {
top: 0px;
right: 0px;
transform-origin: bottom right;
transform: skewX(-22deg);
}
.skew:hover {
background: steelblue;
}
/* Just for demo */
body {
background: radial-gradient(circle at 50% 50%, aliceblue, steelblue);
}
.skew.bottom {
margin-top: 10px;
}
.skew.left {
clear: both;
}
.btn-container {
position: absolute;
top: 0px;
right: 0px;
width: 150px;
}
button {
width: 150px;
margin-bottom: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="skew bottom">Some content</div>
<div class="skew top">Some content</div>
<div class="skew left">Some content</div>
<div class="skew right">Some content</div>
<div class='btn-container'>
<button id="increasew-skew">Increase Width</button>
<button id="increaseh-skew">Increase Height</button>
<button id="increaseb-skew">Increase Both</button>
</div>
优点
- 即使有边框也可以实现形状.
- 悬停效果将限制在形状内.
缺点
- 尺寸需要按比例增加以保持形状,因为当元素倾斜时,它在 Y 轴上的偏移量会随着
width
的增加而增加,反之亦然(尝试增加width
到200px
片段).您可以在此处找到更多信息.
- Dimensions need to increase proportionally for the shape to be maintained because when an element is skewed, its offset in Y-axis increases as
width
increases and vice-versa (try increasing thewidth
to200px
in the snippet). You can find more information about this here.
(浏览器兼容性)
在这种方法中,主容器沿 X 或 Y 轴旋转,带有一点透视.将适当的值设置为 transform-origin
只会在一侧产生倾斜的边缘.
In this method, the main container is rotated along the X or Y axis with a bit of perspective. Setting the appropriate value to transform-origin
would produce a slanted edge on only one side.
如果顶边或底边倾斜,则应沿 Y 轴旋转,否则应沿 X 轴旋转.transform-origin
的一侧应与倾斜的一侧相反.
If the top or bottom side is slanted, the rotation should be along Y axis, else the rotation should be along X axis. The transform-origin
should have the side opposite to the slanted side.
$(document).ready(function() {
$('#increasew-rotate').on('click', function() {
$('.rotate').css({
'height': '100px',
'width': '150px'
});
});
$('#increaseh-rotate').on('click', function() {
$('.rotate').css({
'height': '150px',
'width': '100px'
});
});
$('#increaseb-rotate').on('click', function() {
$('.rotate').css({
'height': '150px',
'width': '150px'
});
});
})
div {
float: left;
height: 100px;
width: 100px;
margin: 50px;
color: beige;
transition: all 1s;
}
.rotate {
position: relative;
width: 100px;
background: tomato;
}
.rotate.bottom {
transform-origin: top;
transform: perspective(10px) rotateY(-2deg);
}
.rotate.top {
transform-origin: bottom;
transform: perspective(10px) rotateY(-2deg);
}
.rotate.left {
transform-origin: right;
transform: perspective(10px) rotateX(-2deg);
}
.rotate.right {
transform-origin: left;
transform: perspective(10px) rotateX(-2deg);
}
.rotate span {
position: absolute;
display: block;
top: 0px;
right: 0px;
width: 50%;
height: 100%;
}
.rotate.bottom span {
padding: 10px;
transform-origin: top;
transform: perspective(10px) rotateY(2deg);
}
.rotate.top span {
padding: 20px;
transform-origin: bottom;
transform: perspective(20px) rotateY(2deg);
}
.rotate.left span {
padding: 10px;
transform-origin: right;
transform: perspective(10px) rotateX(2deg);
}
.rotate.right span {
padding: 0px 30px;
transform-origin: left;
transform: perspective(10px) rotateX(2deg);
}
.rotate:hover {
background: steelblue;
}
/* Just for demo */
body {
background: radial-gradient(circle at 50% 50%, aliceblue, steelblue);
}
.rotate.left{
clear:both;
}
.btn-container {
position: absolute;
top: 0px;
right: 0px;
width: 150px;
}
button {
width: 150px;
margin-bottom: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="rotate bottom"><span>Some content</span>
</div>
<div class="rotate top"><span>Some content</span>
</div>
<div class="rotate left"><span>Some content</span>
</div>
<div class="rotate right"><span>Some content</span>
</div>
<div class='btn-container'>
<button id="increasew-rotate">Increase Width</button>
<button id="increaseh-rotate">Increase Height</button>
<button id="increaseb-rotate">Increase Both</button>
</div>
优点
- 形状可以通过边框来实现.
- 尺寸无需按比例增加即可保持形状.
缺点
- 内容也会被旋转,因此它们必须反向旋转才能看起来正常.
- 如果尺寸不是静态的,定位文本会很繁琐.
(浏览器兼容性)
在此方法中,使用多边形将主容器裁剪为所需的形状.多边形的点应根据需要倾斜边缘的一侧进行修改.
In this method, the main container is clipped into the required shape using a polygon. The polygon's points should be modified depending on the side where the slanted edge is required.
$(document).ready(function() {
$('#increasew-clip').on('click', function() {
$('.clip-path').css({
'height': '100px',
'width': '150px'
});
});
$('#increaseh-clip').on('click', function() {
$('.clip-path').css({
'height': '150px',
'width': '100px'
});
});
$('#increaseb-clip').on('click', function() {
$('.clip-path').css({
'height': '150px',
'width': '150px'
});
});
})
.clip-path {
position: relative;
float: left;
margin: 20px;
height: 100px;
width: 100px;
background: tomato;
padding: 4px;
transition: all 1s;
}
.clip-path.bottom {
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 60%);
}
.clip-path.top {
-webkit-clip-path: polygon(0% 40%, 100% 0%, 100% 100%, 0% 100%);
}
.clip-path.left {
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 40% 100%);
}
.clip-path.right {
-webkit-clip-path: polygon(0% 0%, 60% 0%, 100% 100%, 0% 100%);
}
.clip-path .content {
position: absolute;
content: '';
height: calc(100% - 10px);
width: calc(100% - 8px);
background: bisque;
}
.clip-path.bottom .content {
-webkit-clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 60%);
}
.clip-path.top .content {
-webkit-clip-path: polygon(0% 40%, 100% 0%, 100% 100%, 0% 100%);
}
.clip-path .content.img {
top: 6px;
background: url(http://lorempixel.com/250/250);
background-size: 100% 100%;
}
/* Just for demo */
body {
background: radial-gradient(circle at 50% 50%, aliceblue, steelblue);
}
.clip-path.left {
clear: both;
}
.clip-path:hover {
background: gold;
}
.btn-container {
position: absolute;
top: 0px;
right: 0px;
margin: 20px;
width: 150px;
}
button {
width: 150px;
margin-bottom: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="clip-path bottom">
<div class="content">abcd</div>
</div>
<div class="clip-path top">
<div class="content img"></div>
</div>
<div class="clip-path left"></div>
<div class="clip-path right"></div>
<div class='btn-container'>
<button id="increasew-clip">Increase Width</button>
<button id="increaseh-clip">Increase Height</button>
<button id="increaseb-clip">Increase Both</button>
</div>
优点
- 即使在动态调整容器大小时也可以保持形状.
- 悬停效果将完全限制在形状的边界内.
- 图片也可以用作形状的背景.
缺点
- 目前浏览器支持很差.
- 可以通过在形状顶部放置一个绝对定位的元素并为其提供必要的剪辑来添加边框,但超出了一个点,当动态调整大小时它就不能很好地适应了.
(浏览器兼容性)
Canvas 也可用于通过绘制路径来生成形状.下面的代码片段有一个演示.所需的任何文本内容都可以放置在形状的顶部.
Canvas can also be used to produce the shape by drawing paths. The below snippet has a demo. Any text content required can be positioned on top of the shape.
window.onload = function() {
var canvasEls = document.getElementsByTagName('canvas');
for (var i = 0; i < canvasEls.length; i++) {
paint(canvasEls[i]);
}
function paint(canvas) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
if (canvas.className == 'bottom') {
ctx.moveTo(0, 0);
ctx.lineTo(250, 0);
ctx.lineTo(250, 100);
ctx.lineTo(0, 60);
} else if (canvas.className == 'top') {
ctx.moveTo(0, 40);
ctx.lineTo(250, 0);
ctx.lineTo(250, 100);
ctx.lineTo(0, 100);
} else if (canvas.className == 'left') {
ctx.moveTo(0, 0);
ctx.lineTo(250, 0);
ctx.lineTo(250, 100);
ctx.lineTo(60, 100);
} else if (canvas.className == 'right') {
ctx.moveTo(0, 0);
ctx.lineTo(190, 0);
ctx.lineTo(250, 100);
ctx.lineTo(0, 100);
}
ctx.closePath();
ctx.lineCap = 'round';
ctx.fillStyle = 'tomato';
ctx.fill();
}
$('#increasew-canvas').on('click', function() {
$('.container').css({
'width': '150px',
'height': '100px'
});
});
$('#increaseh-canvas').on('click', function() {
$('.container').css({
'width': '100px',
'height': '150px'
});
});
$('#increaseb-canvas').on('click', function() {
$('.container').css({
'width': '150px',
'height': '150px'
});
});
};
.container {
float: left;
position: relative;
height: 100px;
width: 100px;
margin: 20px;
color: beige;
transition: all 1s;
}
canvas {
height: 100%;
width: 100%;
}
.container > span {
position: absolute;
top: 5px;
left: 5px;
padding: 5px;
}
.top + span {
top: 40%; /* size of the angled area */
}
.left + span {
left: 40%; /* size of the angled area */
}
/* Just for demo */
body {
background: radial-gradient(circle at 50% 50%, aliceblue, steelblue);
}
.btn-container {
position: absolute;
top: 0px;
right: 0px;
width: 150px;
}
button {
width: 150px;
margin-bottom: 10px;
}
div:nth-of-type(3) {
clear: both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<div class="container">
<canvas height="100px" width="250px" class="bottom"></canvas> <span>Some content</span>
</div>
<div class="container">
<canvas height="100px" width="250px" class="top"></canvas> <span>Some content</span>
</div>
<div class="container">
<canvas height="100px" width="250px" class="left"></canvas> <span>Some content</span>
</div>
<div class="container">
<canvas height="100px" width="250px" class="right"></canvas> <span>Some content</span>
</div>
<div class='btn-container'>
<button id="increasew-canvas">Increase Width</button>
<button id="increaseh-canvas">Increase Height</button>
<button id="increaseb-canvas">Increase Both</button>
</div>
优点
- 即使容器的尺寸是动态的,也可以实现和保持形状.也可以添加边框.
- 可以使用
pointInpath
方法将悬停效果限制在形状的边界内. - 还可以为形状提供图像或渐变背景.
- 如果需要实时动画效果是更好的选择,因为它不需要 DOM 操作.
- Shape can be achieved and maintained even if the dimensions of the container are dynamic. Borders can also be added.
- Hover effect can be restricted to within the shape's boundaries by using
pointInpath
method. - Image or gradient background can also be provided to the shape.
- Better choice if real-time animation effects are needed as it doesn't require DOM manipulation.
缺点
- 画布是基于光栅的,因此当缩放超出点 * 时,倾斜的边缘会变得像素化或模糊.
- Canvas is raster based and hence the angled edges will become pixelated or blurred when scaled beyond a point *.
* - 每当调整视口大小时,避免像素化需要重新绘制形状.here 有一个例子,但这是一个开销.
* - Avoiding pixelation would need repaints of the shape whenever viewport is resized. There is an example of it here but that is an overhead.
相关文章