Reputation: 2709
I have two div
with two different transparent, colored backgrounds. The elements overlap one another.
I would like to customize the color in the overlapped area.
For example I mix red and blue with opacity 0.5 and would like the overlapped area to be black. Is it possible? This solution would simplify the implementation of functionality.
For better understanding, example:
.wrapper{
width: 200px;
height: 500px;
background-color: #fff;
position: relative;
}
.box{
width: 100%;
position: absolute;
}
.box-1{
top: 0px;
height: 250px;
background-color: rgba(181, 226, 163, 0.5);
}
.box-2{
background-color: rgba(183, 222, 241, 0.5);
top: 200px;
height: 300px;
}
<div class="wrapper">
<div class="box box-1">
</div>
<div class="box box-2">
</div>
</div>
UPDATE:
The height of the overlap area is unknown, so it is not an option to add an element rigidly on height 50px
. Question is about
custom mixing colors.
Upvotes: 18
Views: 3014
Reputation: 1
try using this website to make your colours then it gives you the tag you need
http://www.w3schools.com/colors/colors_picker.asp
Upvotes: 0
Reputation: 3733
This is probably a lot more than you would want to do, but I think it is the only way you can get the result that you are looking for.
Using javascript you can basically detect if there is an overlap, and if there is create a div that represents the overlapped area and color that div black. Below is a code snippet showing a very simple example.
UPDATE:
I saw in a comment that this needs to work across multiple elements, not just two elements, so I updated my snippet to work with multiple elements. As long as the element is a class type overlappable-box
then an overlap will be calculated for the element.
clearOverlaps
is not being used in the snippet, but if your page is dynamic at all, then you will need to be able to clear any calculated overlaps which you can do with that function.
function clearOverlaps() {
overlaps = document.getElementsByClassName("box-overlap");
var i = 0;
for (i = 0; i < overlaps.length; i++) {
document.body.removeChild(overlaps[i]);
}
}
function addOverlap(box1, box2) {
var box1Top = box1.offsetTop;
var box1Left = box1.offsetLeft;
var box1Right = box1Left + box1.offsetWidth;
var box1Bottom = box1Top + box1.offsetHeight;
var box2Top = box2.offsetTop;
var box2Left = box2.offsetLeft;
var box2Right = box2Left + box2.offsetWidth;
var box2Bottom = box2Top + box2.offsetHeight;
var isOverlappedVertically = box1Bottom > box2Top && box1Top < box2Bottom;
var isOverlappedHorizontally = box1Right > box2Left && box1Left < box2Right;
if (isOverlappedVertically && isOverlappedHorizontally) {
var overlapTop = Math.max(box1Top, box2Top);
var overlapBottom = Math.min(box1Bottom, box2Bottom);
var overlapLeft = Math.max(box1Left, box2Left);
var overlapRight = Math.min(box1Right, box2Right);
var overlap = document.createElement("div");
overlap.className += "box-overlap";
overlap.style.position = "absolute";
overlap.style.left = overlapLeft + "px";
overlap.style.width = (overlapRight - overlapLeft) + "px";
overlap.style.top = overlapTop + "px";
overlap.style.height = (overlapBottom - overlapTop) + "px";
document.body.appendChild(overlap);
}
}
var overlappableBoxes = document.getElementsByClassName("overlappable-box");
var i = 0;
var j = 0;
var box1;
var box2;
for (i = 0; i < overlappableBoxes.length; i++) {
box1 = overlappableBoxes[i];
for (j = i + 1; j < overlappableBoxes.length; j++) {
box2 = overlappableBoxes[j];
addOverlap(box1, box2);
}
}
.overlappable-box {
position: absolute;
}
.red-box {
top: 0px;
left: 40px;
height: 50px;
width: 50px;
background-color: red;
opacity: .5
}
.blue-box {
background-color: blue;
top: 20px;
left: 25px;
height: 50px;
width: 50px;
opacity: .5
}
.green-box {
background-color: green;
top: 60px;
height: 50px;
width: 50px;
opacity: .5
}
.box-overlap {
background-color: black;
z-index: 99;
}
<div class="overlappable-box red-box"></div>
<div class="overlappable-box blue-box"></div>
<div class="overlappable-box green-box"></div>
Upvotes: 2
Reputation: 11
You can use CSS gradients:
.box-2 {
background-color: blue;
top: 200px;
height: 300px;
background: rgb(0,0,0);
background: -moz-linear-gradient(top, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 12%, rgba(0,0,0,1) 25%, rgba(0,0,0,1) 39%, rgba(44,44,44,1) 50%, rgba(0,0,0,1) 51%, rgba(25,33,255,1) 51%, rgba(25,33,255,1) 65%, rgba(25,33,255,1) 78%, rgba(25,33,255,1) 78%, rgba(25,33,255,1) 100%);
background: -webkit-linear-gradient(top, rgba(0,0,0,1) 0%,rgba(0,0,0,1) 12%,rgba(0,0,0,1) 25%,rgba(0,0,0,1) 39%,rgba(44,44,44,1) 50%,rgba(0,0,0,1) 51%,rgba(25,33,255,1) 51%,rgba(25,33,255,1) 65%,rgba(25,33,255,1) 78%,rgba(25,33,255,1) 78%,rgba(25,33,255,1) 100%);
background: linear-gradient(to bottom, rgba(0,0,0,1) 0%,rgba(0,0,0,1) 12%,rgba(0,0,0,1) 25%,rgba(0,0,0,1) 39%,rgba(44,44,44,1) 50%,rgba(0,0,0,1) 51%,rgba(25,33,255,1) 51%,rgba(25,33,255,1) 65%,rgba(25,33,255,1) 78%,rgba(25,33,255,1) 78%,rgba(25,33,255,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000000', endColorstr='#1921ff',GradientType=0 );
opacity: 0.5;
background: rgb(0,0,0);
background: -moz-linear-gradient(top, rgba(0,0,0,1) 0%, rgba(0,0,0,1) 12%, rgba(0,25,255,1) 25%, rgba(0,25,255,1) 39%, rgba(0,25,255,1) 49%, rgba(0,25,255,1) 50%, rgba(0,25,255,1) 53%, rgba(0,25,255,1) 53%, rgba(25,33,255,1) 54%, rgba(0,25,255,1) 60%, rgba(25,33,255,1) 65%, rgba(25,33,255,1) 78%, rgba(25,33,255,1) 78%, rgba(25,33,255,1) 100%);
background: -webkit-linear-gradient(top, rgba(0,0,0,1) 0%,rgba(0,0,0,1) 12%,rgba(0,25,255,1) 25%,rgba(0,25,255,1) 39%,rgba(0,25,255,1) 49%,rgba(0,25,255,1) 50%,rgba(0,25,255,1) 53%,rgba(0,25,255,1) 53%,rgba(25,33,255,1) 54%,rgba(0,25,255,1) 60%,rgba(25,33,255,1) 65%,rgba(25,33,255,1) 78%,rgba(25,33,255,1) 78%,rgba(25,33,255,1) 100%);
background: linear-gradient(to bottom, rgba(0,0,0,1) 0%,rgba(0,0,0,1) 12%,rgba(0,25,255,1) 25%,rgba(0,25,255,1) 39%,rgba(0,25,255,1) 49%,rgba(0,25,255,1) 50%,rgba(0,25,255,1) 53%,rgba(0,25,255,1) 53%,rgba(25,33,255,1) 54%,rgba(0,25,255,1) 60%,rgba(25,33,255,1) 65%,rgba(25,33,255,1) 78%,rgba(25,33,255,1) 78%,rgba(25,33,255,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#000000', endColorstr='#1921ff',GradientType=0 );
opacity: .8;
}
Upvotes: 0
Reputation: 29453
You can achieve this effect by giving .box-1
an absolutely positioned ::after
pseudo-element (positioned at bottom:0;
) with a height calculated as 100%
of its .box-1
parent minus the vertical offset position of .box-2
.
Eg. If .box-2
has a top:
value of 200px
, then the height of the ::after
pseudo-element on .box-1
should be:
height: calc(100% - 200px); /* 200px is the top: value of .box-2 */
Working Example (with .box-1
at 4 different heights - the last .box-1
is resizable):
.wrapper{
display: inline-block;
width: 200px;
height: 500px;
background-color: #fff;
position: relative;
}
.box{
width: 100%;
position: absolute;
}
.box-1{
top: 0px;
background-color: rgb(128,191,128);
}
.box-2{
top: 200px;
height: 300px;
background-color: rgb(128,128,255);
}
.wrapper .box-1 {
z-index: 6;
}
.wrapper .box-1::after {
content: '';
position: absolute;
left: 0;
bottom: 0px;
width: 100%;
height: calc(100% - 200px); /* 200px is the top: value of .box-2 */
background-color: rgba(0,0,0,1);
}
div:nth-of-type(1).wrapper .box-1 {
height: 250px;
}
div:nth-of-type(2).wrapper .box-1 {
height: 275px;
}
div:nth-of-type(3).wrapper .box-1 {
height: 300px;
}
div:nth-of-type(4).wrapper .box-1 {
height: 325px;
}
div:nth-of-type(4).wrapper .box-1 {
resize: vertical;
overflow: auto;
}
<div class="wrapper">
<div class="box box-1">
</div>
<div class="box box-2">
</div>
</div>
<div class="wrapper">
<div class="box box-1">
</div>
<div class="box box-2">
</div>
</div>
<div class="wrapper">
<div class="box box-1">
</div>
<div class="box box-2">
</div>
</div>
<div class="wrapper">
<div class="box box-1">
</div>
<div class="box box-2">
</div>
</div>
Upvotes: 3
Reputation: 65808
Sure. Although, you can only do this by including another element that is on top of the overlapped area. To show this, I'm changing the widths and heights of the divs so you can see where all the borders are.
See this:
div {position:absolute; border:1px solid black;}
#div1 { background:red; opacity:.5; top:0; height:110px; width:100px;}
#div2 { background:blue; opacity:.5; top:50px; height:100px;width:175px;}
#div3 { background:black; top:50px; height:50px; z-index:99; width:150px;}
<div id="div1">test</div>
<div id="div2">test</div>
<div id="div3">test</div>
For your second issue: "I don't know the height of the overlapped area" This can be solved with JavaScript:
var d1 = document.getElementById("div1");
var d2 = document.getElementById("div2");
var d3 = document.getElementById("div3"); // This is the div that will mask the overlapping area
// Get the height and top of the first element
var d1Height = parseInt(window.getComputedStyle(d1).height.replace("px", ""));
var d1Top = parseInt(window.getComputedStyle(d1).top.replace("px", ""));
console.log("div1 height: " + d1Height, ", div1 top: " + d1Top);
// Get the height and top of the second element
var d2Height = parseInt(window.getComputedStyle(d2).height.replace("px", ""));
var d2Top = parseInt(window.getComputedStyle(d2).top.replace("px", ""));
console.log("div2 height: " + d2Height, "div2 top: " + d2Top);
// Determine where the overlap starts
var overlapTop = d1Height - d2Top;
console.log("Overlap begins at: " + overlapTop);
// Determine the height of the overlap
var overlapHeight = (d1Top + d1Height) - overlapTop;
console.log("overlap height: " + overlapHeight);
// Move the overlapping div into position by setting its style programmatically:
d3.style.top = overlapTop + "px";
d3.style.height = overlapHeight + "px";
div {position:absolute; border:1px solid black;}
#div1 { background:red; opacity:.5; top:0; height:100px; width:100px;}
#div2 { background:blue; opacity:.5; height:100px; top: 50px; width:175px;}
/* This is the div that will mask the overlapping area
Note that a position and height are not set
The only reason the width is set is to show what area
it winds up overlapping, but that would be removed from
this rule and determined in JavaScript, just as the height is */
#div3 { background:black; z-index:99; width:150px;}
<div id="div1">test</div>
<div id="div2">test</div>
<div id="div3">test</div>
Upvotes: 1
Reputation: 3497
This uses the mix-blend-mode CSS property with a value of multiply to achieve the results. Unfortunately this is not supported in IE.
<!DOCTYPE html>
<html>
<head>
<style>
div{
width:100px;
height:100px;
opacity:1;
}
.red{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==);
}
.blue{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg==);
mix-blend-mode: multiply
}
</style>
</head>
<body>
<div class="red">
</div>
<div style="position:absolute;top:90px" class="blue">
</div>
</body>
</html>
Upvotes: 11
Reputation: 4938
Something like this ?
But sure thing it wont be much helpful if the height is dynamic
.wrapper {
width: 200px;
height: 500px;
background-color: #fff;
position: relative;
}
.box {
width: 100%;
position: absolute;
}
.box-1 {
top: 0px;
height: 250px;
background-color: rgba(181, 226, 163, 0.5);
}
.box-2 {
background-color: rgba(183, 222, 241, 0.5);
top: 200px;
height: 300px;
}
.box-2:before {
background-color: black;
height: 50px;
display: block;
content: ' ';
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="wrapper">
<div class="box box-1">
</div>
<div class="box box-2">
</div>
</div>
</body>
</html>
Upvotes: 0
Reputation: 2643
I think you need to set the opacity of the 2 boxes to have their colors mixed instead of setting the opacity on the color. The rgba opacity only lightens or darken the color applied on the div. The divs by default have opacity set to 1 so if both boxes overlap then only the top box will be shown and the bottom box will be hidden. To achieve what you want add opacity:0.5
to the .box-1
and .box-2
classes to apply to the divs as well.
Upvotes: 0