163

I need round corners on a parent div to mask content from its childen. overflow: hidden works in simple situations, but breaks in webkit based browsers and Opera when the parent is positioned relatively or absolutely.

This works in Firefox and IE9:

CSS

#wrapper {
  width: 300px;
  height: 300px;
  border-radius: 100px;
  overflow: hidden;
  position: absolute;
}

#box {
  width: 300px;
  height: 300px;
  background-color: #cde;
}

HTML

<div id="wrapper">
  <div id="box"></div>
</div>

Example on JSFiddle

Thanks for the help!

UPDATE: The bug causing this issue has been since fixed in Chrome. I have not re-tested Opera or Safari however.

Igor Ivancha
  • 3,413
  • 4
  • 30
  • 39
jmotes
  • 2,669
  • 2
  • 22
  • 19

12 Answers12

192

I found another solution for this problem. This looks like another bug in WebKit (or probably Chrome), but it works. All you need to do - is to add a WebKit CSS Mask to the #wrapper element. You can use a single pixel png image and even include it to the CSS to save a HTTP request.

#wrapper {
    width: 300px; height: 300px;
    border-radius: 100px;
    overflow: hidden;
    position: absolute; /* this breaks the overflow:hidden in Chrome/Opera */
    -webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC); /* this fixes the overflow:hidden in Chrome/Opera */
}

#box {
    width: 300px; height: 300px;
    background-color: #cde;
}
<div id="wrapper">
    <div id="box"></div>
</div>
jameshfisher
  • 34,029
  • 31
  • 121
  • 167
graycrow
  • 3,675
  • 6
  • 26
  • 28
  • 3
    thank you for this fix. tried it out in safari today (v6.0.2) and worked for me there! – billythetalented Nov 22 '12 at 13:29
  • 10
    this will break any shadows on the element however. – Jack James Jan 25 '13 at 17:34
  • 1
    This works on wrappers with absolutely positioned children as well, where the other solution here doesn't. Nice! – Dan Tello Mar 08 '13 at 20:11
  • This solution works in chrome Version 27.0.1453.93, the other answer above doesn't seem to work. – jozecuervo Jun 05 '13 at 00:34
  • This solution worked for me for Chrome 27, Safari 6.0.5, and Safari on iOS 6.1. Note: Recent builds of Chrome 27 fixed this issue. I noticed that with the fix, a text selection that includes such a box (e.g. a div with border-radius and overflow:hidden) will show the rounded corners. Whereas before the text selection would show square corners (even though things were sometimes being clipped correctly). – Josh Jun 25 '13 at 17:22
  • @TomElmore E: you're quite right. the shadow must be put on the masking element – Jack James Aug 01 '13 at 16:20
  • 2
    using Chrome 42.0.2311.90 (64-bit), and this fix is *still* required... thanks! – simon Apr 19 '15 at 04:41
  • 1
    You can use a slightly smaller data uri: `-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==);` – Erwin Wessels Oct 20 '15 at 08:08
  • 2
    your solutions removes shadows of parent element. – Ahmad Badpey May 09 '16 at 11:20
  • This fix does remove box-shadow. Z-index works for me. – Rafael Staib Aug 27 '21 at 09:27
123

Add a z-index to your border-radius'd item, and it will mask the things inside of it.

Jackolai
  • 1,357
  • 1
  • 8
  • 11
  • @Sifu: you're simply wrong. For whatever reason, adding a z-index as suggested solved this exact problem for me (in the current version of Chrome), and this is a simpler, more general solution than the top answer. – Nick F Nov 19 '14 at 09:38
  • 7
    @simon: remember that for z-index to have an effect, certain conditions need to be met (eg. position needs to be set). See [here](https://css-tricks.com/almanac/properties/z/z-index/) for the details. – Nick F May 14 '15 at 11:31
  • @NickF -- it was a bug in Chrome(-ium); `-webkit-mask-image: -webkit-radial-gradient(circle, white, black);` was an effective workaround, but, thankfully, the bug is fixed in the most recent update I received to Chrome. – simon May 16 '15 at 01:39
  • z-index 1 to container. z-index -1 to absolute element solved it for me. – aZtraL-EnForceR Jul 08 '15 at 13:48
  • This one worked for me. The above wrapper solution doesn't. – Ruwen Jul 17 '15 at 06:42
  • Yes!! This worked for me. There seems to be different circumstances in which this issue is encountered, and only some appear fixed. In my case, I'm animating a child into position, and the border-radius only masked the child once the animation was completed. During the animation, the border-radius had no effect. Adding the z-index fixed the issue. – Chase Nov 10 '15 at 06:36
  • after trying a lot of *sensible* things and failing, this apparent hack works like a charm. This bug has been in Webkit for ages, and they haven't fixed it still. – kumarharsh Jul 09 '16 at 21:02
  • Wow this worked. I had issue only on Chrome, as on FireFox it was working just fine. – Muhammad Asadullah Oct 25 '16 at 15:05
  • z-index fix works! But... How... Why... WTF Chrome :| – Kees van Lierop Jan 19 '17 at 15:52
  • Worked for me as well. I actually had this issue on Chrome, but only when implementing my plugin into a specific site. It most likely is effected by the site's global styles, as well as other elements that are z-indexed differently. – Eckstein Feb 07 '17 at 17:08
  • Can verify that this proposition fixed it and it still doesn't work on current Chrome (in my case on changing the render mode after animating an element) – Paracetamol Jun 29 '17 at 11:39
  • 5
    2021, and this bug still exists (Safari version 14.0.3 (16610.4.3.1.4) Desktop) – Matt Mar 28 '21 at 14:58
60

Nevermind everyone, I managed to solve the problem by adding an additional div between the wrapper and box.

CSS

#wrapper {
    position: absolute;
}

#middle {
    border-radius: 100px;
    overflow: hidden; 
}

#box {
    width: 300px; height: 300px;
    background-color: #cde;
}

HTML

<div id="wrapper">
    <div id="middle">
        <div id="box"></div>
    </div>
</div>

Thanks everyone who helped!

http://jsfiddle.net/5fwjp/

Joan
  • 659
  • 2
  • 7
  • 20
jmotes
  • 2,669
  • 2
  • 22
  • 19
  • 12
    This works because positioned elements don't clip their contents to their border-radius in Webkit. This extra layer simply makes it so the div with border-radius is NOT positioned, and simply sits inside a positioned element. – Daniel Beardsley Jun 21 '11 at 00:28
  • 9
    Would you by chance know if this is a bug/intended behavior? – jmotes Jun 21 '11 at 19:01
  • 4
    +1 vote to bug... When you have an image gallery which automatically generates the divs and sets the position to absolute, then this "feature" really sux... – inf3rno Aug 31 '12 at 14:19
  • @RunLoop I just tested the jsfiddle in Safari 7.1 and works fine. Can you be more specific about what's not working? – jmotes Oct 16 '14 at 15:23
  • 1
    Our colleague the graphic designer actually "discovered" this 20 seconds prior to finding this answer :D – Pere May 04 '16 at 09:19
22

opacity: 0.99; on wrapper solve webkit bug

flavi1
  • 229
  • 2
  • 5
  • 4
    `transform: translateY(0);` is an alternative that achieves the same result without interfering with the visual representation of the object (unless you are using perspective). – kontur Jul 05 '17 at 12:09
16

Seems this one works:

.wrap {
    -webkit-transform: translateZ(0);
    -webkit-mask-image: -webkit-radial-gradient(circle, white 100%, black 100%);
}

http://jsfiddle.net/qWdf6/82/

nakrill
  • 720
  • 6
  • 7
  • 4
    `transform: translateZ(0)` is enough for me. – kalvn Dec 13 '15 at 10:47
  • Note that this (in particular, `translateZ`) will implicitly enable hardware acceleration for your elements, which opens a brand new can of worms in some cases, sadly. – doldt Jul 12 '16 at 12:21
  • `transform: translateZ(0)` also worked for me. In my case it's not a bad idea that this item is hardware accelerated. – Sebastien Lorber Aug 23 '16 at 15:45
15

Supported in latest chrome, opera and safari, you can do this:

-webkit-clip-path: inset(0 0 0 0 round 100px);
clip-path: inset(0 0 0 0 round 100px);

You should definitely check out the tool http://bennettfeely.com/clippy/!

antoni
  • 5,001
  • 1
  • 35
  • 44
6

Not an answer, but this is a filed bug under the Chromium source: http://code.google.com/p/chromium/issues/detail?id=62363

Unfortunately, doesn't look like there's anyone working on it. :(

ryan
  • 61
  • 1
  • 1
4

change the opacity of the parent element with the border and this will re organize the stacked elements. This worked miraculously for me after hours of research and failed attempts. It was as simple as adding an opacity of 0.99 to re organize this paint process of browsers. Check out http://philipwalton.com/articles/what-no-one-told-you-about-z-index/

Rami Awar
  • 663
  • 7
  • 28
3

As for me none of the solutions worked well, only using:

-webkit-mask-image: -webkit-radial-gradient(circle, white, black);

on the wrapper element did the job.

Here the example: http://jsfiddle.net/gpawlik/qWdf6/74/

Grzegorz Pawlik
  • 2,198
  • 1
  • 18
  • 18
2

based on graycrow's excellent answer...

Here's a more real world example that has two cicular divs with some filler content. I replaced the hard-coded png background with just a hex value, i.e.

-=-webkit-mask-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC);

is replaced with

-webkit-mask-image:#fff;

See this JSFiddle... http://jsfiddle.net/hqLkA/

gts101
  • 719
  • 7
  • 13
1

Here look at how I done it; Jsfiddle

With the Code I put in, I managed to get it working on Webkit (Chrome/Safari) and Firefox. I don't know if it works with the latest version of Opera. Yes it does work under the latest version of Opera.

#wrapper {
  width: 300px; height: 300px;
  border-radius: 100px;
  overflow: hidden;
  position: absolute; /* this breaks the overflow:hidden in Chrome/Opera */
}

#box {
  width: 300px; height: 300px;
  background-color: #cde;
  border-radius: 100px;
  -webkit-border-radius: 100px;
  -moz-border-radius: 100px;
  -o-border-radius: 100px;
}
Maze
  • 453
  • 2
  • 5
  • 9
  • Why bother putting the `border-radius` on wrapper at all in that situation, you get the same result with just setting it on `#box`. Also, if the `#box` border radius is only to fix WebKit you could just include the `-webkit-` property there. – robertc Apr 21 '11 at 12:25
  • Maze, this might work in some situations, but in my case I'm looking for a solution that doesn't transform the shape of the box (and the wrapper still works as a mask). My example was very simplified but I'm trying to use the wrapper to hide dropshadow from the box (using padding on the wrapper to make only the shadow edges I want visible). – jmotes Apr 21 '11 at 14:42
  • 1
    Thanks for the help though Maze! Your solution helped me think about the problem more critically. Btw, you can ignore the edit I made to your post. I meant to make it to my own. Sorry :) – jmotes Apr 21 '11 at 15:09
  • @user480837 No Problem mate, glad that I have been of help. :) – Maze Apr 21 '11 at 16:19
  • 1
    @Maze That won't work if a border of any sort is applied: http://jsfiddle.net/ptW85/228/ – antitoxic Apr 12 '12 at 10:57
  • In addition to last antitoxic comment, just try to also set #box width at 100px to see the actual problem in all its gloriousness ... grrr – superjos Aug 13 '13 at 16:18
0

If you are looking to create a mask for an image and position the image inside the container don't set the 'position: absolute' attribute. All you have to do is change the margin-left and margin-right. Chrome/Opera will adhere to the overflow: hidden and border-radius rules.

// Breaks in Chrome/Opera.
    .container {
        overflow: hidden;
        border-radius: 50%;
        img {
            position: absolute;
            left: 20px;
            right: 20px;
        }
    }

// Works in Chrome/Opera.
    .container {
        overflow: hidden;
        border-radius: 50%;
        img {
            margin-left: 20px;
            margin-right: 20px;
        }
    }