I have a slider, I want the edges of the content div to have a blur effect, blurring the background image behind it. The background image is from the parent div. As you can see the content inside it is not blurred and you can see through the background, but the edges are blurred. Any ideas on how to achieve this effect?
It doesn't matter if it's CSS only or mixed with JavaScript, I'm using React anyways.
Here's an approach using clip-path (documentation) and backdrop-filter (documentation) Both are relatively new rules, so check your browser compatibility.
We use the clip path to select a 10% "frame" around the inside of your box, and then apply a 10px blur with backdrop-filter
body {
min-height: 100%;
background-image: url('https://i.picsum.photos/id/502/1000/1000.jpg?hmac=L-KRcO3K2TOyaVRnDSO13QrAo73FnHrIBApbvfakTOw')
}
.box {
position: relative;
width: 300px;
height: 300px;
margin: 30px 100px;
}
.frame {
position: absolute;
width: 100%;
height: 100%;
clip-path: polygon(0% 0%, 0% 100%, 10% 100%, 10% 10%, 90% 10%, 90% 90%, 10% 90%, 10% 100%, 100% 100%, 100% 0%);
backdrop-filter: blur(10px);
}
.content {
position: absolute;
border: 1px #fff solid;
top: 10%;
left: 10%;
right: 10%;
bottom: 10%;
}
<div class="box">
<div class="frame"></div>
<div class="content"> Your text here</div>
</div>
Here's a version using CSS variables so you can quickly/easily adjust the blurred border thickness. Just change the --b CSS variable:
body {
min-height: 100%;
background-image: url('https://i.picsum.photos/id/502/1000/1000.jpg?hmac=L-KRcO3K2TOyaVRnDSO13QrAo73FnHrIBApbvfakTOw')
}
.box {
/* The border thickness (Can be a percentage or pixel value) */
--b: 6px;
/* Work out the inverse value for the right/bottom sides of the clip path */
--b2: calc(100% - var(--b));
position: relative;
width: 300px;
height: 300px;
margin: 30px 100px;
}
.frame {
position: absolute;
width: 100%;
height: 100%;
clip-path: polygon(0% 0%, 0% 100%, var(--b) 100%, var(--b) var(--b), var(--b2) var(--b), var(--b2) var(--b2), var(--b) var(--b2), var(--b) 100%, 100% 100%, 100% 0%);
backdrop-filter: blur(10px);
}
.content {
position: absolute;
border: 1px #fff solid;
top: var(--b);
left: var(--b);
right: var(--b);
bottom: var(--b);
}
<div class="box">
<div class="frame"></div>
<div class="content"> Your text here</div>
</div>
You don't need to use clip-path if you set the same background image on the content box. Caveat: background-attachment needs to be fixed. And if you use flex for all the boxes, just setting position: absolute on the content would be enough to center it on top.
html, body, .bg {
height: 100%;
width: 100%;
}
.bg, .blur-box, .content-box {
display: flex;
align-items: center;
justify-content: center;
}
.bg, .content-box {
background: url(https://picsum.photos/seed/1/1920/1080/) no-repeat fixed 0 0 / cover;
}
.blur-box {
position: relative;
width: 70vh;
height: 70vh;
backdrop-filter: blur(5px);
}
.content-box {
position: absolute;
width: 50vh;
height: 50vh;
color: white;
border: 1px solid white;
}
<div class="bg">
<div class="blur-box">
</div>
<div class="content-box">
TEXT
</div>
</div>
Ok, so I want to position on top of another div which has a background image. The image-div has the following properties:
position: absolute;
top:0;
left:0;
width:100%;
height:100%;
background-image: url('../img/1.jpg');
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
This looks like I want on all devices. But now I need to overlay the image-div with a clickable div that fits a certain part of the image. Getting the div to fit is easy, just set position to absolute and set top, left, width and height, but as soon as i display in another resolution/density the div is way off, no surprise there. So i tried with positioning by using % or vh and vw but nothing seems to work.
How would I go about positioning divs on top of the image regardless on what device, resolution and density I'm at?
It's a combination of background-position, background-size and an offset in percentages of the containing div.
Keep the background-position at a certain value so the spot on the image is always in screen.
Use background-size: cover; or background-size: contain; to keep the image (or it's container) responsive.
If you have two or more spots on the outer edges of the image I suggest using contain, but this will reduce the image size considerably on smaller screens while your inner div will stay reasonably large.
In other cases, use cover for resize purposes.
Here I created an example: (I used Jquery UI to make the image resizable)
$( function() {
$( "#resizable" ).resizable();
} );
.container {
background-image: url('https://images.unsplash.com/photo-1465218550585-6d069382d2a9?dpr=1&auto=format&fit=crop&w=1500&h=994&q=80&cs=tinysrgb&crop=');
background-size: cover;
background-position: 50% 50%;
height: 500px;
position: relative;
width: 800px;
}
.hit-me-container {
height: 16px;
left: 52%;
position: absolute;
top: 45%;
width: 16px;
}
.hit-me {
animation: pulse 1s ease infinite;
background-color: #fff;
border: 3px solid #777;
box-sizing: border-box;
border-radius: 50%;
cursor: pointer;
height: 100%;
width: 100%;
}
.hit-me-container:hover:after {
background-color: #333;
color: #fff;
content: 'Buy these glasses';
display: block;
font-family: sans-serif;
font-size: 12px;
left: 20px;
padding: 5px;
position: absolute;
width: 100px;
top: -4px;
}
#keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="container" id="resizable">
<div class="hit-me-container">
<div class="hit-me"></div>
</div>
</div>
Or check this fiddle
You can use a div inside of the div with the background-image, but then position it within the div wherever you want using %s, not px or absolute values.
#bg{
position: relative;
width:100vw;
height:100vh;
background-image: url('/favicon.ico');
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
z-index: 5
}
#overlay {
position: absolute;
height: 40%;
width: 30%;
z-index: 10;
top: 13%;
left: 34%
}
#overlay:hover {
background-color: rgba(50,50,200,0.5);
}
<div id="bg">
<div id="overlay"></div>
</div>
<style type="text/css">
#div_1
{
position:relative;
top:0;
left:0;
width:100%;
height:200px;
background-image: url('../img/1.jpg');
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
}
#div_2
{
position:absolute;
width:50%;
height:60%;
margin:0px auto;
}
</style>
<div id="div_1">
<div id="div_2">
testing...
</div>
</div>
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 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.
Method 1 - SVG
(Browser Compatibility)
SVG can be used to produce the shape either by using polygons or paths. 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
SVG is designed to produce scalable graphics and can work well with all dimension changes.
Borders and hover effect can be achieved with minimal coding overhead.
Image or gradient background can also be provided to the shape.
Cons
Browser support is probably the only downside because IE8- doesn't support SVG but that can be mitigated by using libraries like Raphael and also VML. Moreover, the browser support is in no way worse than the other options.
Method 2 - Gradient Background
(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
Shape can be achieved and maintained even if the dimensions of the container are dynamic.
Hover effect can be added by changing the gradient color.
Cons
Hover effect will be triggered even when cursor is outside the shape but within the container.
Adding borders would require tricky gradient manipulations.
Gradients are known for producing jagged corners when the width (or height) is very big.
Image backgrounds cannot be used on the shape.
Method 3 - Skew Transforms
(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
Shape can be achieved even with borders.
Hover effect will be restricted to within the shape.
Cons
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 the width to 200px in the snippet). You can find more information about this here.
Method 4 - Perspective Transforms
(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
Shape can be achieved with borders.
Dimensions need not increase proportionally for the shape to be maintained.
Cons
Content will also be rotated and hence they have to be counter rotated to look normal.
Positioning text will be tedious if the dimensions are not static.
Method 5 - CSS Clip Path
(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
Shape can be maintained even when the container is being resized dynamically.
Hover effect will be perfectly restricted within the borders of the shape.
Image can also be used as background for the shape.
Cons
Browser support is very poor at present.
Borders can be added by placing an absolutely positioned element on top of the shape and giving it the necessary clip but beyond a point it doesn't fit well when re-sizing dynamically.
Method 6 - Canvas
(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
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.
Cons
Canvas is raster based and hence the angled edges will become pixelated or blurred when scaled beyond a point *.
* - Avoiding pixelation would need repaints of the shape whenever viewport is resized. There is an example of it here but that is an overhead.
I tried using the border method but the dimensions of my shape are dynamic and hence I cannot use this method.
Method 7 - Viewport Units (Border Redux)
(Browser Compatibility)
Viewport Units are a great innovation in CSS3. While you can usually use percentage values to dynamize your properties, you can't do it for border-widths (nor for font-sizes).
With Viewport Units instead you can dynamically set your border widths, along with the sizes of your objects, compared to the viewport dimension.
Note: percentage values are referred to the parent object, not to the viewport (visible area of the window).
To test the method, launch the following snippet Full Page and resize it both horizontally and vertically.
.shape {
position: relative;
height: 20vh;
width: 40vw;
background: tomato;
}
.shape:after {
position: absolute;
content: '';
left: 0px;
right: 0px;
top: 20vh;
border-width: 10vh 20vw;
border-style: solid;
border-color: tomato tomato rgba(0,0,0,0) rgba(0,0,0,0);
}
<div class="shape">Some content</div>
Pros - (1) Everything is dynamic, browser coverage is wide.
Cons - (1) You should pay attention at how your OS handles the scrollbar with overflow: auto;.
My solution is inspired by the one called Method 7 - Viewport Units by Andrea Ligios, above in this page.
I used the "horizontal" unit for the height too (height:10vw) to keep the given proportions in the trapezoid when resizing the width of the navigation window. We could call this Method 7b - Viewport Width.
Further, using two nested divs, instead of one and the :after selector, allows a better tuning of the text content styles, in my opinion (e.g. text-align, etc.).
.dtrapz {
position: relative;
margin: 10px 40vw;
width: 0;
height: 10vw;
border: none;
border-right: 20vw solid #f22;
border-bottom: 5vw solid transparent;
}
.dtcont {
position: absolute;
width: 20vw;
height: 10vw;
text-align: center;
color: #fff;/* just aesthetic */
}
<div class="dtrapz">
<div class="dtcont">Some content</div>
</div>
http://jsfiddle.net/sXLg7/1/
I am trying to place the background image such that there is 50px space left at the top and bottom of the div.
I can position background image easily 50px below top by this property
background-position: 0 50px;
But, how do i also position this background image so that there is 50px space lefft at the bottom
I tried this
background-position: 0 50px 0 50px;
but this doesn't seem to work. I assumed it would accept 4 parameters for positioning it from 4 directions.
Any ideas?
Try the background-clip property instead :
padding-top:50px;
padding-bottom:50px;
background-clip: content-box;
See this Fiddle : http://jsfiddle.net/A5u8j/
Unfortunately, I do not believe this is possible. Depending on what it's being used for, you might be able to use two divs, with the inner div having the background image and a top & bottom margin of 50px;
try adding this two properties
background-size: 500px 400px;
background-position: 0 50px;
You can't do this with background position; however, you could hack something together using a pseudo-element.
http://jsfiddle.net/sXLg7/3/
Here is the updated CSS:
.test {
border: 2px solid red;
height: 500px;
width: 500px;
position: relative;
}
.test:before {
content: '';
z-index: -1;
background-image: url("http://www.reallyslick.com/pictures/helios.jpg");
background-repeat: no-repeat;
position: absolute;
top: 50px; left: 0; right: 0; bottom: 50px;
}
You can use CSS background-size, although browser support is somewhat limited.
.test {
border: 2px solid red;
background-image: url("http://www.reallyslick.com/pictures/helios.jpg");
background-position: 0 50px;
background-size:100% 400px;
height: 500px;
width: 500px;
background-repeat: no-repeat;
}
Working Example
Alternate Method
Alternately, you can use two nested elements. The outer has padding set on the top and bottom to so that the inner won't reach the top/bottom.
I've used CSS box-sizing so that the padding is accounted for in the height. Note that support for this is also somewhat limited.
Working Example
Alternatively, you can subtract the padding from the height of the outer element.
Working Example
Heres one way todo it. Place an image with absolute positioning, and a negative z-index. Places it behind any content in your test div.
http://jsfiddle.net/sXLg7/8/
html
<div class="test">
Text on top of background.
<img src="http://www.reallyslick.com/pictures/helios.jpg" class="background"/>
</div>
and the css
.test {
border: 2px solid red;
height: 500px;
width: 500px;
overflow: hidden;
position: relative;
color: #fff;
}
.test .background {
position: absolute;
bottom: 50px;
left: 0;
z-index: -1;
}
You could put a 50px border on the element.
http://jsfiddle.net/sXLg7/10/
html
<div class="test"></div>
css
.test {
outline: 2px solid red;
border: 50px solid transparent;
background-image: url("http://www.reallyslick.com/pictures/helios.jpg");
background-position: center;
background-size: auto 100%;
height: 500px;
width: 500px;
background-repeat: no-repeat;
box-sizing: border-box;
}
why not just add a 50px margin? like this:
.test {
border: 2px solid red;
background-image: url("http://www.reallyslick.com/pictures/helios.jpg");
height: 500px;
width: 500px;
background-repeat: no-repeat;
margin:50px;
}
http://jsfiddle.net/4Dmkv/