6

This is basically what i want to achieve --> https://jsfiddle.net/tak1pyt7/1/

.clip {
  width: 500px;
  height: 500px;
  -webkit-clip-path: polygon(100% 0, 100% 81%, 82% 100%, 0 100%, 0 0);
  clip-path: polygon(100% 0, 100% 81%, 82% 100%, 0 100%, 0 0);
}
body {
  background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
  height: 100%;
  width: 100%;
}
<body>
  <div class="clip">
    <img src="http://lorempixel.com/600/600/" width="100%" height="100%" />
  </div>
</body>

Although i have a solution but there are various issues with the code in the fiddle as follows :

  • It doesn't work in IE or Edge as clip path isn't supported
  • Clip path doesn't support css shapes in firefox and if you need to make it work in firefox then you need to supply inline svg
  • Tried supplying inline svg as well but it has it's own set of issues that doesn't solve my requirement. I need the cut dimensions to remain the same irrespective of the height and width of the container. With inline svg that cuts the image right now, it's dimension changes with change in height and width i.e. the cut is responsive. I need static dimensions of the cut.

Other than above solution i searched a whole lot of solutions that might help me create div's with corners cut and the cut is transparent itself because i don't have a solid background at the back.

Other solutions explored

Using CSS3 Gradients sample

Using CSS Borders

Using jQuery plugin (http://jquery.malsup.com/corner/)

A Solution that WORKS but is very HACKY

  • Sample --> http://jsfiddle.net/26v7pfLb/

  • I am using this solution right now for containers that have fixed height and width but i have a page in my app where the containers have a static width but dynamic height. In that case the hack would be pretty difficult to implement and it seems very weird to use this solution personally.

  • I am trying to find something more elegant and clean to implement such a kind of solution in CSS

Any pointers would be helpful.

web-tiki
  • 99,765
  • 32
  • 217
  • 249
Vinay
  • 723
  • 9
  • 32
  • The solution provided by @web-tiki is a very nice one. You can also try something like the one provided in my answere here - http://stackoverflow.com/questions/19248443/is-it-possible-to-create-an-angled-corner-in-css/30729446#30729446. The CSS version can support non-solid backgrounds and is also responsive. – Harry Sep 03 '15 at 11:35
  • @Harry your solution is valid in cases where i have a solid background known to me. Here i have an image in background and hence this solution does not work. – Vinay Sep 07 '15 at 12:13
  • In both the snippets, you would notice that the `body` element has a radial gradient image as background. They are not solid backgrounds :) Even the content of the shape is not a solid color in both the SVG snippet and the 3rd sample within the CSS version. – Harry Sep 07 '15 at 12:16
  • sorry that was my bad. I checked it once again. Still the solution remains not effective for me as my container may contain any combination of text+image+video content. I see that you have used two images to produce the cut effect. I cannot guarantee that my content will just be plain images. Any help on how to counter this issue ? – Vinay Sep 07 '15 at 12:33
  • In that case, I think you are out of luck because the best I can think of is SVG clip-path and IE support is always a drawback. – Harry Sep 07 '15 at 12:46
  • Yes i too think clip path is the viable option but in that too i have an issue regarding the inline SVG shape i use for clipping. I need a square shape with a beveled right corner and the dimensions of the cut should remain the same irrespective of how the height and width change. I cannot figure out how to supply points to SVG so that it generates a shape with the required sized cut on bottom right corner. – Vinay Sep 07 '15 at 13:25

2 Answers2

4

You can use the approach I described in this question : Cut Corners using CSS using a rotate container with overflow:hidden;

For your example (as you want to display an image inside the element) you need to "unrotate" the content like this :

.clip {
  margin: -150px 0 0 -150px;
  display: inline-block;
  transform: rotate(-45deg);
  overflow: hidden;
}
img {
  margin: 150px 150px 0 150px;
  display: block;
  transform: rotate(45deg);
}
body{background:url(http://lorempixel.com/output/nature-q-g-640-480-7.jpg);background-size:cover;}
<div class="clip">
    <img src="http://lorempixel.com/600/600/" />
</div>

This solution also requires positioning either with margins or with absolute positioning.

Community
  • 1
  • 1
web-tiki
  • 99,765
  • 32
  • 217
  • 249
  • That is the solution OP already uses, check [his Fiddle](http://jsfiddle.net/26v7pfLb/). – skobaljic Sep 03 '15 at 12:51
  • I already use this solution. The reason why i don't prefer using this is that the actual screen that i am working on is for user comments. The comment block can contain text/video/image or any combination of the 3 things. Also the height of the comment block and number of overall comments can be varying so in that case how much optimal will this solution be ? – Vinay Sep 07 '15 at 10:35
  • Also as the dimensions of my container dynamic it becomes very difficult to calculate the positioning of the the clipping div dynamically when the html is being created in the dom. – Vinay Sep 07 '15 at 12:13
2

CSS Solution:

A Solution that WORKS but is very HACKY

The solution you use is best at this time (September 2015). It is not a hack, but just a simple 2D rotations and it will work in IE also.

Best article for CSS masking in browsers other than IE you can find on this page. It uses SVG with html foreignObject element, which is not fully supported.

I am trying to find something more elegant and clean to implement such a kind of solution in CSS

An elegant and clean CSS solution will be available in years to come, when css-mask and clip-path come alive.


Javascript Solution:

We can use HTML Canvas element to store the image data, than using Javascript to make part of the image transparent.

In following example we shall make bottom-right triangle transparent. There is a catch: the image must be on same domain, which is not case here on StackOverflow (it also cannot be base64 encoded).

I made it work on Liveweave playground, just open and wait for image to load and script to execute (the image is huge).

The source code is also below.

// get the image, the image MUST BE LOCAL
var img = document.getElementById("your-image");
var height = img.offsetHeight;
var width = img.offsetWidth;
// create and customize the canvas
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;

// get the context
var ctx = canvas.getContext("2d");
// draw the image into the canvas
ctx.drawImage(img, 0, 0);

// get the image data object
var image = ctx.getImageData(0, 0, width, height);

// get the image data values 
var imageData = image.data,
 length = imageData.length;

// every fourth value is Alpha channel
// lets make bottom right triangle transparent
for(var i=3; i<length; i+=4){  
 // for calculations we need to know current pixel position on image
 // we define pixel left, top, right and bottom relative to the image rectangle
 // first index is 1, first pixel for width=4: left=1, right=4
 var pixel = (i+1)/4;
 var left = (pixel-1)%width+1;
 var top = Math.floor(pixel/width);
 var right = width-left+1;
 var bottom = height-top+1;
 // it is easy now to find pixel in bottom right rectangle:
 if( (right+bottom)<=30 ) {
  // make this pixel transparent
  imageData[i] = 0;
 };
}

// after the manipulation, reset the data
image.data = imageData;

// and put the imagedata back to the canvas
ctx.putImageData(image, 0, 0);

img.src = canvas.toDataURL();
<p>The image must be on same domain :(</p>    
<img id="your-image" src="https://i.stack.imgur.com/PKxQk.png"/>

The image we (cannot) use:

enter image description here


PHP Solution:

Similar to above, you could use iMagick library to make part of the images transparent. You could use iMagick mask, or directly change pixels' alpha - you can find an example in this answer.

Community
  • 1
  • 1
skobaljic
  • 9,379
  • 1
  • 25
  • 51