4

I know how to create a notch on the outside like:

div:after {
    content: '';
    display: block;
    width: 20px;
    height: 20px;
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
}

But I can't figure out how to solve this thingy using CSS only:

enter image description here

The notch has to be inside of the container and it has to be transparent. So the above solution or an image won't solve it.

Maybe this can be created using SVG?

Edit

What I tried is this:

body {
    background: #eee;
}

div {
    position: relative;
    height: 100px;
    width: 200px;
    background: #ccc;
}

div:after {
    content: '';
    position: absolute;
    display: block;
    top: 40px;
    right: -10px;
    width: 20px;
    height: 20px;
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
    background: #eee;
}

But this is clearly no soultion, because the pseudo element is not tranparent.

lampshade
  • 2,470
  • 3
  • 36
  • 74

4 Answers4

4

You cannot do this with pure CSS as clipping is not fully supported yet in all browsers (if cross-compatibility is important).

You would need to combine SVG clipping paths with CSS clipping and would end up with a not so elegant solution.

What you can do however is to create a background image using canvas. Canvas is supported in all the major HTML5 capable browsers. The backdraw with canvas is that you need to do a little more coding to create the shape. Optional an image could have been used instead but using canvas allow you to keep everything sharp (and not blurry as with an image when it is stretched).

The following solution will produce this result (I added red border to show the transparent region). You can tweak the parameters to get it look exactly as you need it to look and extend it with arguments to define size of the notch, width of transparent area etc. The code automatically adopts to the size of the element given as argument.

demo preview

To add a notch simply call:

addNotch(element);

ONLINE DEMO HERE

The code is straight-forward and performs fast:

function addNotch(element) {

    /// some setup
    var canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d'),

        /// get size of element in pixels
        cs = window.getComputedStyle(element),
        w = parseInt(cs.getPropertyValue('width') || '0', 10),
        h = parseInt(cs.getPropertyValue('height') || '0', 10),

        /// pre-calculate some values
        hh = h * 0.5,
        nw = 20,  /// notch size
        nh = nw * 0.5;

    canvas.width = w;
    canvas.height = h;

    /// draw the main shape        
    ctx.moveTo(0, 0);
    ctx.lineTo(w - nw, 0);
    ctx.lineTo(w - nw, hh - nh);
    ctx.lineTo(w - nw - nh, hh);
    ctx.lineTo(w - nw, hh + nh);
    ctx.lineTo(w - nw, h);
    ctx.lineTo(0, h);
    ctx.closePath();

    ctx.fillStyle = '#7c7058';
    ctx.fill();

    /// draw the white arrow
    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = '#eee';
    ctx.moveTo(w - nw - nw * 0.33, hh - nw * 0.75);
    ctx.lineTo(w - nw - nw * 1.1, hh);
    ctx.lineTo(w - nw - nw * 0.33, hh + nw * 0.75);
    ctx.stroke();

    /// convert canvas to image and set background of element
    /// with this image    
    element.style.background = 'url(' + canvas.toDataURL() +
                               ') no-repeat left top';

}
  • 1
    +10 (I actually can only upvote once - I don't have super powers). This one is pretty straight forward. It's way cooler then what I posted in my answer. And its generic. Awesome. – lampshade Sep 06 '13 at 18:38
2

Here's an example using SVG clipping.

jsFiddle Demo

<div></div>
<svg>
  <defs>
    <clipPath id="clipping">
        <polygon points="
             0 0, 202 0,
             202 36, 185 50, 202 64,
             202 102, 0 102" />
    </clipPath>
  </defs>
</svg>
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
Itay
  • 16,601
  • 2
  • 51
  • 72
  • +1 Thanks for your effort. I played around a little with this soluton and it looks like it works fine in Firefox. It behaved differently in Chrome and it doesn't work in Safari. Still a good idea though. – lampshade Sep 06 '13 at 17:43
  • It can be made cross-browser. Post a fiddle if you need help with it. – Itay Sep 06 '13 at 17:45
  • Here's an [updated fiddle](http://jsfiddle.net/Xqyaf/) based on yours. Actually it has only to run in Chrome. There can be multiple of those elements and they are positioned absolutely within their parent containers. If this is too much work, I stick to my canvas solution. I don't want to bother you with this problem to much. – lampshade Sep 06 '13 at 17:56
  • @lampshade Check [this fiddle](http://jsfiddle.net/itay1989/Xqyaf/2/) out. It works in both FF and Chrome. Safari and Opera still has some problems rendering it. Using an SVG image will be more compatible. – Itay Sep 06 '13 at 18:10
1

Try this fiddle out, it should set you on your way for what you're looking for.

#notched {
     width: 0px;
     height: 0px;
     border-right: 60px solid transparent;
     border-top: 60px solid #d35400;
     border-left: 60px solid #d35400;
     border-bottom: 60px solid #d35400;
}

Updated fiddle

lampshade
  • 2,470
  • 3
  • 36
  • 74
  • Unfortunately the border-trick doesn't work here, as the triangle doesn't start and end at the top and bottom edges. But thanks for your effort. – lampshade Sep 06 '13 at 16:50
  • I hadn't intended that to be the end-all fix (that's why I said it should set you on your way to find the solution), though I have coded a proof of concept using the original fiddle. I wouldn't particularly use it because of the somewhat "unfriendly" nature of the code, but [here it is](http://jsfiddle.net/CopperCreekMedia/5z2SA/5/) if you wish to take a look. – CopperCreekMedia Sep 06 '13 at 17:30
  • 1
    +1 Thanks. Now I see where this is going. Although it's a bit hacky, it can get you there. – lampshade Sep 06 '13 at 17:42
0

You can use the :before for mask and after selector for the border, just set border-lef and border-bottom property.

div:before {
    content: '';
    position: absolute;
    display: block;
    top: 40px;
    right: -10px;
    width: 20px;
    height: 20px;
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
    background: #eee;
}
div:after {
    content: '';
    position: absolute;
    display: block;
    top: 38px;
    right: -5px;
    width: 20px;
    height: 21px;
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
    background: transparent;
    border-left: 2px solid #eee;
    border-bottom: 2px solid #eee;
}



the result:

enter image description here
jsFiddle

Mustapha Aoussar
  • 5,833
  • 15
  • 62
  • 107