Có nhiều cách để tạo ra hình dạng với một cạnh xéo chỉ ở một bên.
Các phương pháp sau không thể hỗ trợ kích thước động như đã được đề cập trong câu hỏi:
- Phương pháp tam giác viền với các giá trị pixel cho
border-width
.
- Gradient tuyến tính với cú pháp góc (như 45deg, 30deg, v.v.).
Các phương pháp có thể hỗ trợ kích thước động được mô tả bên dưới.
Phương pháp 1 - SVG
( Khả năng tương thích của trình duyệt )
SVG có thể được sử dụng để tạo ra hình dạng bằng cách sử dụng polygon
s hoặc path
s. Đoạn mã dưới đây sử dụng polygon
. Bất kỳ nội dung văn bản nào được yêu cầu đều có thể được đặt trên đầu của hình dạng.
$(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>
Ưu điểm
- SVG được thiết kế để tạo ra đồ họa có thể mở rộng và có thể hoạt động tốt với mọi thay đổi về kích thước.
- Biên giới và hiệu ứng di chuột có thể đạt được với chi phí mã hóa tối thiểu.
- Hình ảnh hoặc nền gradient cũng có thể được cung cấp cho hình dạng.
Nhược điểm
- Hỗ trợ trình duyệt có lẽ là nhược điểm duy nhất vì IE8- không hỗ trợ SVG nhưng điều đó có thể được giảm thiểu bằng cách sử dụng các thư viện như Raphael và cả VML. Hơn nữa, hỗ trợ trình duyệt không có cách nào kém hơn các tùy chọn khác.
Phương pháp 2 - Nền Gradient
( Khả năng tương thích của trình duyệt )
Các gradient tuyến tính vẫn có thể được sử dụng để tạo ra hình dạng nhưng không phải với các góc như đã đề cập trong câu hỏi. Chúng ta phải sử dụng to [side] [side]
cú pháp (nhờ vals ) thay vì chỉ định góc. Khi các cạnh được chỉ định, các góc độ dốc được tự động điều chỉnh dựa trên kích thước của vùng chứa.
$(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>
Ưu điểm
- Hình dạng có thể đạt được và duy trì ngay cả khi kích thước của vật chứa là động.
- Có thể thêm hiệu ứng di chuột bằng cách thay đổi màu gradient.
Nhược điểm
- Hiệu ứng di chuột sẽ được kích hoạt ngay cả khi con trỏ ở bên ngoài hình dạng nhưng bên trong vùng chứa.
- Việc thêm đường viền sẽ yêu cầu các thao tác chuyển màu phức tạp.
- Gradients được biết đến với việc tạo ra các góc răng cưa khi chiều rộng (hoặc chiều cao) rất lớn.
- Không thể sử dụng nền hình ảnh trên hình dạng.
Phương pháp 3 - Biến đổi Skew
( Khả năng tương thích của trình duyệt )
Trong phương pháp này, một phần tử giả được thêm vào, làm lệch và định vị theo cách mà nó trông giống như một trong các cạnh bị nghiêng / góc. quay phải dọc theo trục X. Các transform-origin
nên có điều ngược lại bên này sang phía bên nghiêng.
$(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>
Ưu điểm
- Hình dạng có thể đạt được ngay cả với đường viền.
- Hiệu ứng di chuột sẽ bị hạn chế trong hình dạng.
Nhược điểm
- Kích thước cần phải tăng theo tỷ lệ để duy trì hình dạng bởi vì khi một phần tử bị lệch, độ lệch của nó trong trục Y sẽ tăng khi
width
tăng và ngược lại (hãy thử tăng width
lên 200px
trong đoạn mã). Bạn có thể tìm thêm thông tin về điều này tại đây .
Phương pháp 4 - Chuyển đổi phối cảnh
( Khả năng tương thích của trình duyệt )
Trong phương pháp này, vùng chứa chính được xoay dọc theo trục X hoặc Y với một chút phối cảnh. Đặt giá trị thích hợp transform-origin
sẽ chỉ tạo ra một cạnh nghiêng ở một bên.
Nếu mặt trên hoặc mặt dưới bị nghiêng, thì xoay phải dọc theo trục Y, ngược lại, xoay phải theo trục X. Các transform-origin
nên có điều ngược lại bên này sang phía bên nghiêng.
$(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>
Ưu điểm
- Hình dạng có thể đạt được với đường viền.
- Kích thước không cần phải tăng theo tỷ lệ để hình dạng được duy trì.
Nhược điểm
- Nội dung cũng sẽ được xoay và do đó chúng phải được xoay ngược để trông bình thường.
- Định vị văn bản sẽ tẻ nhạt nếu các kích thước không tĩnh.
Phương pháp 5 - Đường dẫn Clip CSS
( Khả năng tương thích của trình duyệt )
Trong phương pháp này, thùng chứa chính được cắt thành hình dạng yêu cầu bằng cách sử dụng một đa giác. Các điểm của đa giác phải được sửa đổi tùy thuộc vào phía mà cạnh nghiêng được yêu cầu.
$(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>
Ưu điểm
- Hình dạng có thể được duy trì ngay cả khi vùng chứa đang được thay đổi kích thước động.
- Hiệu ứng di chuột sẽ bị hạn chế hoàn toàn trong đường viền của hình dạng.
- Hình ảnh cũng có thể được sử dụng làm nền cho hình dạng.
Nhược điểm
- Hỗ trợ trình duyệt hiện tại rất kém.
- Các đường viền có thể được thêm vào bằng cách đặt một phần tử được định vị tuyệt đối trên đầu của hình dạng và tạo cho nó một đoạn clip cần thiết nhưng vượt quá một điểm, nó không vừa vặn khi định lại kích thước động.
Phương pháp 6 - Canvas
( Khả năng tương thích của trình duyệt )
Canvas cũng có thể được sử dụng để tạo ra hình dạng bằng cách vẽ các đường dẫn. Đoạn mã dưới đây có một bản demo. Bất kỳ nội dung văn bản nào được yêu cầu đều có thể được đặt trên đầu của hình dạng.
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>
Ưu điểm
- Hình dạng có thể đạt được và duy trì ngay cả khi kích thước của vật chứa là động. Các đường viền cũng có thể được thêm vào.
- Hiệu ứng di chuột có thể được giới hạn trong ranh giới của hình dạng bằng cách sử dụng
pointInpath
phương pháp.
- Hình ảnh hoặc nền gradient cũng có thể được cung cấp cho hình dạng.
- Lựa chọn tốt hơn nếu cần hiệu ứng hoạt ảnh thời gian thực vì nó không yêu cầu thao tác DOM.
Nhược điểm
- Canvas dựa trên raster và do đó các cạnh góc sẽ trở nên pixel hoặc mờ khi được chia tỷ lệ vượt quá một điểm * .
* - Tránh tạo pixel sẽ cần sửa lại hình dạng bất cứ khi nào khung nhìn được thay đổi kích thước. Có một ví dụ về nó ở đây nhưng đó là một chi phí.