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
.The methods that can support dynamic sizes are described below.
(Browser Compatibility)
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>
Pros
Cons
(Browser Compatibility)
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>
Pros
Cons
(Browser Compatibility)
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>
Pros
Cons
width
increases and vice-versa (try increasing the width
to 200px
in the snippet). You can find more information about this here.(Browser Compatibility)
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.
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>
Pros
Cons
(Browser Compatibility)
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>
Pros
Cons
(Browser Compatibility)
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>
Pros
pointInpath
method. Cons
* - Avoiding pixelation would need repaints of the shape whenever viewport is resized. There is an example of it here but that is an overhead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With