36

I have two divs, both with 0.6 opacity. I need them to overlap but retain their opacity and not create a new combined opacity level. I can't use an image.

EDIT -- The little circle is supposed to have a canvas element in it. Not sure if pseudo-elements would be the best solution.

Is there anyway to do this with CSS, or should I just use canvas?

example -

http://dabblet.com/gist/1566209

HTML:

<div id="foo">
    <div id="bar">
    </div>
</div>

CSS:

/**
 * Double Opacity
 */
body{background:green;}

#foo{
height:150px;
width:250px;
background:rgba(0, 0, 0, 0.6);
position:absolute;
left:40%;
top:20%;
}

#bar{
height:40px;
width:40px;
background:rgba(0, 0, 0, 0.6);
border-radius:40px;
position:absolute;
top:-15px;
left:-15px;
}
web-tiki
  • 99,765
  • 32
  • 217
  • 249
tripleZee
  • 458
  • 2
  • 5
  • 11
  • 1
    Do you mean that you want the opacity in the overlapped area to also have an apparent value of 0.6? – dgvid Jan 05 '12 at 17:30
  • 2
    i'm not sure that's possible. that is the natural function of opacity. - at least not with CSS anyway... – Dan Jan 05 '12 at 17:31
  • That is an awesome problem! Very much looking forward to the solution (=hack) (if any). – Rudie Jan 05 '12 at 18:02
  • Side-note: Dabblet _looks_ pretty cool as a jsFiddle alternative. Too bad it does not work at all in Safari... infinitely loading and syntax errors in the console. – Sparky Jan 05 '12 at 18:54
  • 2
    The editor in Dabbblet is horrible. jsFiddle's editor is almost perfect. – Rudie Jan 06 '12 at 20:48

5 Answers5

49

SUMMARY:


Depending on what is needed it can be tricky but the basic approach is pretty straight forward.


This approach is a little different from my first thought... but this has the same result.

  1. I made a black/transparent pattern for the circle and set it to :before.
  2. The circle is then transformed rotate(180deg) and moved to fit on the corner of the <div>.
  3. Then I set the opacity of that circle to 0.6.
  4. The <div> itself is not affected by the opacity.
  5. Next I added the :after element and put an image as background (you can control this via js if needed)
  6. I added some effects to the image (border-radius, box-shadow, border) to show how easily and independent this element can be controlled.
  7. I used a lighter background and set the opacity to 0.3 to show the result

HERE'S THE FIDDLE: http://jsfiddle.net/pixelass/nPjQh/4/

Look at this version for some crazy results: http://jsfiddle.net/pixelass/nPjQh/5/

each of these examples only use a single div element

Basic rules. (these rules "could" be used to create a dynamic behavior with js)

position = absolute;

top = circleHeight / -2;

left = circleHeight / -2; //(left = top)

rotation = 180deg;

opacity = valueAofBackground;

bgColor = valueRGBofBackground;

#inner {
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0;
    top: 0;
    z-index: -1;
    background-color: rgba(0, 0, 0, 0.3);
    padding:20px;
    border-radius: 20px;
    border-top-left-radius: 0;
}
#inner:before {
    content: "";
    background-image: -webkit-linear-gradient(transparent 50%, rgb(0, 0, 0) 50%, rgb(0, 0, 0)),
        -webkit-linear-gradient(0deg, transparent 50%, rgb(0, 0, 0) 50%, rgb(0, 0, 0));
    height: 40px;
    width: 40px;
    border-radius: 40px;
    position: absolute;
    top: -20px;
    left: -20px;
    -webkit-transform: rotateZ(180deg);
    opacity:0.3;
}
#inner:after {
    content: "";
    background: url('http://lorempixel.com/10/10/sports/1/') no-repeat;
    background-position:0;
    height: 10px;
    width: 10px;
    border-radius: 10px;
    position: absolute;
    top: -6px;
    left: -6px;
    -webkit-box-shadow: 0 0 10px rgb(255,255,255);
    border: 1px rgb(255,255,255) solid;

}

Better explanaition


Original commented version http://jsfiddle.net/pixelass/nPjQh/10/

see the comments in the code below

#inner {
background: rgba(0,0,0,0.5) /*this is the full color-code of the div (with alpha)*/
}
#inner:before {
    /*the solid color of the circle = rgbValue of the div*/
    background-image: -webkit-linear-gradient(transparent 50%, rgb(0, 0, 0) 50%, rgb(0, 0, 0)),
        -webkit-linear-gradient(0deg, transparent 50%, rgb(0, 0, 0) 50%, rgb(0, 0, 0));
    /*opacity of the circle = alpha of the div*/
    opacity: 0.5;
}

This example has a full transparent div ...the circle is a "pacman"- shape: http://jsfiddle.net/pixelass/nPjQh/14/

pacman shaped circle


Managing the offset of the circle


Look at these examples that handle the offset of the circle (NOT USING PSEUDEO-ELEMENTS)

1:1 copy of the OP's code (15px offset): http://jsfiddle.net/pixelass/nPjQh/12/

With a lot smaller offset (5px): http://jsfiddle.net/pixelass/nPjQh/13/

(the content has the same opacity as the circle)

How does the offset work?

Control the background-size vs. the top and left

Rules:

top = left;

background-size = elementHeight * 2 + top * 2;

Look at the flower (it is also only one <div> with pseudo-elements) the background-size is bigger than the circle. which creates the green leaves on the bottom

http://jsfiddle.net/pixelass/nPjQh/15/

one div makes a flower


CURRENT PROBLEM


See this fiddle: http://jsfiddle.net/pixelass/nPjQh/16/

If not using another layer as seen in the examples at the top of the post the content will be transparent. So if you only need an image inside the circle the above examples will work fine.

conent is transparent

HOW TO SOLVE THIS ISSUE

If you need a canvas or another div inside the circle you would have to put the circle on the div and layer the needed div over the circle

See this fiddle: http://jsfiddle.net/pixelass/nPjQh/17/

change around a little and it will work fine. GET THE CODE FROM THE FIDDLE

correcting the opacity issue


Different shape /advanced Styling


If you use a different shape with flat sides, you could even put a border around the sum of the two divs.. or even add a box shadow

still using the simple markup of....

<div id="foo">
    <div id="bar">
    </div>
</div>

See the fiddle for the box-shadow: http://jsfiddle.net/pixelass/nPjQh/21/

adding a box-shadow


Apply a border to the circle


Using -webkit-mask-image we could add a border to the circle. http://jsfiddle.net/pixelass/nPjQh/24/

border on round element


More examples:


Four circles around the div

http://jsfiddle.net/pixelass/nPjQh/25/

Markup:

<div id="foo">
    <div id="bar1"></div>
    <div id="bar2"></div>
    <div id="bar3"></div>
    <div id="bar4"></div>
</div>

4 circles

Using this technique to make a tooltip

http://jsfiddle.net/pixelass/nPjQh/31/

Markup:

<div id="foo">
    <div id="bar"></div>
    I am a pure css tooltip with a semi-transparent background and a black border. <br/>
    My width is static an my height is dynamic...
</div>

css tooltip

Community
  • 1
  • 1
  • The overlapping area never changes. I don't understand how the background gradient would work. Please post an example if you can. – tripleZee Jan 05 '12 at 18:12
  • I am at home in about 2 hours. if the position is static it's a really simple hack.. –  Jan 05 '12 at 18:18
  • I may be a bit dense, but in all your fiddle examples currently posted (4, 5, 6), I don't see one that actually recreates and addresses the OP's issue of overlapping opacity of a color that is creating the darker region he is trying to avoid. – ScottS Jan 06 '12 at 02:53
  • the goal is to make a semi- transparent box with an extended round corner on the top left... right? well that's exactly what these examples show. –  Jan 06 '12 at 05:17
  • Awesome =) But why doesn't this one work? http://jsfiddle.net/rudiedirkx/nPjQh/9/ I don't get these gradients... I want the circle bg to be `rgba(0, 0, 0, 0.5)`, but now it's not 'solid' black. – Rudie Jan 06 '12 at 13:30
  • the circle has to be solid (rgb) or hex. then use opacity: 0.5.... the circle is a "pacman" shape –  Jan 06 '12 at 13:34
  • look at the answer-part.. (BETTER EXPLANATION).. I just added an example where the div itself is transparent so you can see the shape of the circle. –  Jan 06 '12 at 13:52
  • 2
    @pixelass Ah yes, the `opacity`! Missed that one =) I dare say it's brilliant. How does this answer have only 2 upvotes?? Your crazy examples are awesome! I'm totally using that somewhere. – Rudie Jan 06 '12 at 20:44
  • @Rudie Who cares about the votes. THis should be checked as ANSWERED. I added a circle with border example too –  Jan 06 '12 at 21:18
  • Awesome answer and you rule in general pixelass, but I found some problems with your method -- 1) The new webkit gradient syntax isn't supported by iOS < 5. 2) The original overlayed area was not exactly 3/4 of a circle and the gradient is straight only in your specific example - once you start playing with the degrees you lose the right angle and straight edges... Rebuttal? =P – tripleZee Jan 08 '12 at 01:50
  • Nearly all your fiddle examples are not working in my Firefox 8 (I would assume IE as well, though I have not checked it). Undoubtedly this is because you are using `webkit` functions to achieve the effects. While I do admire the work you have done in that regard, I'm not sure your lobbying for this as "the answer" is quite valid. – ScottS Jan 08 '12 at 02:38
  • @ScottS for anybody familiar with CSS it should be very easy to add the -moz- or -o- styles. I am using -webkit- because most developers use Chrome to develop. I am also not including it, so the code is shorter. THis is generally not IE compatible.. everybody should know that. –  Jan 08 '12 at 02:57
  • @trippleZee what do you mean by "the overlapped area was not exactly 3/4 of a circle? The gradient can be modified to fit on almost any shape (even round corners if we would use a radial box-shadow instead of the background-gradient or smaller angles if we change the gradient angle). I will update this answer if needed. But I already wrote you an e-mail. This will not work on an iPhone due to a small gaap that cannot be worked around –  Jan 08 '12 at 03:06
  • @pixelass--by your response I felt as though you missed my point. I think the work you have done and shown here is quite well done. However, as a full answer it lacked in 1) being "complete" (there are many on stack overflow who seek answers who are not necessarily familiar with css, so adding full working fiddles/code for cross browser is not unreasonable), and 2) the solution not being compatible with IE is, to me, not a full enough answer (and again, not something "everybody should know" if someone were new to css). Just my opinion. Peace. – ScottS Jan 09 '12 at 11:27
  • it's a community wiki, so feel free ta add the missing stuff. i talked to the OP in private and he was looking for webkit olny. things like this can't be made compatible to IE and I do not support IE at all for stuff like this. i support IE on basic webdesign. anyways if it makes you feel better you can downvote my answer , add the missing stuff yourself or ask me nicely if I can update the answer with at least the -moz- and -o- prefixes. –  Jan 09 '12 at 14:57
  • I'm certainly not going to down vote your answer, because the work you have done is excellent. Further, had the OP mentioned he was only interested in `webkit` compatibility, then I would have kept my mouth shut about that aspect (I assumed this was for "basic webdesign"). You may update if you wish for `-moz-` and `-o-`, I'll let you make the call as it is your answer. – ScottS Jan 09 '12 at 15:29
  • The linked explanation isn't currently working. The server is giving: PHP version not supported. – Drigan Jan 08 '18 at 16:52
  • @Drigan yes, sorry, I don't use the blog anymore but this answer pretty much describes the same thing. I hope it helps. –  Jan 17 '18 at 15:25
13

I think the only way would be to do the opacity separately,

e.g. http://dabblet.com/gist/1566278

Andrew
  • 13,757
  • 13
  • 66
  • 84
2

How about this: http://jsfiddle.net/rudiedirkx/TqRCw/

(Dabble's editor sucks!!)

It can't be done with only pseudo elements sadly =(

It can be done with only pseudo elements! See pixelass' answer. CSS3 is a requirement though.

Rudie
  • 52,220
  • 42
  • 131
  • 173
  • this can be easily done without any special markup or pseudoelements... trust me it's really simple... home in an hour or two... then I'll give the correct answer to this question... –  Jan 05 '12 at 19:56
  • sorry... of course not without a psudoelement.. since it's intended to vreate the circle. my idea is to use a combination of a background-gradient, background-position and background-size. –  Jan 05 '12 at 20:21
  • +1--I just looked at your answer and discovered it was nearly identical to my own (only you posted much sooner than I did, and yours is slightly more elegant). – ScottS Jan 05 '12 at 21:24
  • Works nice, but I need to put an image or a canvas element inside that little circle. – tripleZee Jan 05 '12 at 21:50
  • You can add a background to, but not an element inside a pseudo element. Obviously you can replace the pseudo element with a real element, but I like semanticity and this isn't it. – Rudie Jan 05 '12 at 22:47
  • what exactly do you mean bay adding an image to the circle? you can put another layer on top (my example) and use an image as background (url). So this way, you have the transparent box with the transparent circle AND an image inside the circle..and all with a single div no other elements needed. PURE CSS... Is that what you want? –  Jan 05 '12 at 23:15
  • sorry for the flow of comments ;)... I added the example with an image to my answer.. Anyways. thanks for this question. I like stuff like this :D +1 for this question... –  Jan 05 '12 at 23:30
2

Revised Answer

This fiddle is compatible with IE9 and resolves the duplication of background needed in my original answer. It does use pseudoelements to generate the circle. This solution spins off pixelass's "pacman" idea, only instead of using the newer background gradient css to generate, it uses the older (and little used or understood) clip property to make the circle in two parts. This solved the issue of your circle not being "centered" at the corner.

#foo {
    height:150px;
    width:250px;
    background: rgba(0, 0, 0, 0.6);
    position:absolute;
    left:40%;
    top:20%;
}

#bar {
    height:40px;
    width:40px;
    position:absolute;
    top:-15px;
    left:-15px;
    line-height: 40px;
}

#bar:before,
#bar:after {
    content: '';
    display: block;
    background: rgba(0, 0, 0, 0.6);
    border-radius: 40px;
    width: 100%;
    height: 100%;
    position: absolute;
    z-index: -1;
    top: 0;
    left: 0;
}

#bar:before {
    clip: rect(0 40px 15px 0);
}

#bar:after {
    clip: rect(15px 15px 40px 0);
}

Original Answer

You can do this (see fiddle). It pushes the circle below and "overlays" the portion that overlaps with a pseudoelement to reestablish the background color of the body:

body{background:green;}

#foo{
height:150px;
width:250px;
background:rgba(0, 0, 0, 0.6);
position:absolute;
left:40%;
top:20%;
}

#bar{
height:40px;
width:40px;
background:rgba(0, 0, 0, 0.6);
border-radius:40px;
position:absolute;
top:-15px;
left:-15px;
z-index: -1;
}

#bar:after {
    content: '';
    display: block;
    background: green;
    position: absolute;
    right: 0;
    bottom: 0;
    width: 25px;
    height: 25px;
}
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • Not bad but the green was just an example. How would you handle it without knowing what the background color is? – tripleZee Jan 08 '12 at 01:48
  • @tripleZee--good question. I've reformulated an answer. It still has a minor issue I need to work out since your circle does not sit centered on the corner. – ScottS Jan 08 '12 at 04:08
  • @tripleZee--I have worked out the issue with the circle being offset of center. – ScottS Jan 09 '12 at 12:49
  • the OP should have mentioned that he's looking for an iPhone compatible way. even though your version supports IE9, it's not compatible to the iPhone (neither is mine). your version has tiny overlaps, mine has tiny gaps... anyways +1 for IE9 support –  Jan 09 '12 at 15:13
  • Yeah, the bit about the iPhone would have been good to know. I'm not sure which version you last looked at, but I'm not seeing tiny overlaps with the latest. – ScottS Jan 09 '12 at 15:32
0

I have created a Q/A to handle this scenario along with the 'hover' of such overlapped elements.

Overlapped elements with opacity and handling the 'hover' on those.

The solution is basically to set the opacity in the parent level instead directly on the children elements and to toggle those while hover, with JS.


HTML

<div class="wrapper">
  <div class="first"></div>
  <div class="second"></div>
</div>

JS

$(".first, .second").hover(function() {
  $(".wrapper, .first, .second").not(this).toggleClass("add-opacity");
});

CODEPEN

Hope this helps.

Gibin Ealias
  • 2,751
  • 5
  • 21
  • 39