How to cover all but one div with frosted glass effect? - javascript

Say I have 2 divs, I moved 1 div to hover above all other divs using position: absolute like this:
.wrapper {
display: block;
}
.block1 {
width: 100px;
height: 300px;
background-color: grey;
}
.block2 {
width: 100px;
height: 200px;
background-color: yellow;
}
.block3 {
width: 100px;
height: 50px;
background-color: green;
position: absolute;
top: 10%;
}
<div class='wrapper'>
<div class='block1'>Block 1</>
<div class='block2'>Block 2</>
<div class='block3'>Block 3</>
</div>
Now I'd like to add a frosted glass to all the divs except block3. I know the frosted glass effect can be done by something like filter: blur(10px), but how can I modify block3 class to apply this effect to all other divs? In other words I want block3 to be clear, everywhere else should be blurred. Surely adding filter: blur(10px) to all other divs are not allowed because in reality I could have block4, block5 etc.
EDIT: thanks for all the help, what I wanted was to have any single block unblurred, and all other blocks blurred. So Marc's answer is correct.

Note the new CSS I added, which excludes the <div> with a class of block3.
.wrapper {
display: block;
}
.block1 {
width: 100px;
height: 300px;
background-color: grey;
}
.block2 {
width: 100px;
height: 200px;
background-color: yellow;
}
.block3 {
width: 100px;
height: 50px;
background-color: green;
position: absolute;
top: 10%;
}
div.wrapper > div:not(.block3) {
filter: blur(10px);
}
<div class='wrapper'>
<div class='block1'>Block 1</div>
<div class='block2'>Block 2</div>
<div class='block3'>Block 3</div>
</div>
If you're goal is to hide the last .block element, as others have assumed, then you could use the following instead:
div.wrapper > div:not(:last-child) {
filter: blur(10px);
}

If I understand correctly this is all possible with CSS.
To create your frosted glass effect use a CSS class selector *="class" (equivalent to CSS attribute selector) which selects all elements whose class contains at least one substring "block".
[class*="block"] {
filter: blur(10px);
}
Then when you hover over a div, override the styles with this:
[class*="block"]:hover {
filter: none !important;
}

User hover and target the element
.wrapper {
display: block;
}
.wrapper:hover > .block {
filter: blur(10px);
}
.wrapper:hover > .block:hover {
filter: blur(0px);
}
<div class='wrapper'>
<div class='block'>Block 1</div>
<div class='block'>Block 2</div>
<div class='block'>Block 3</div>
</div>
if you want it hard coded
.wrapper {
display: block;
}
.wrapper > .block {
filter: blur(10px);
}
.wrapper > .block3{
filter: blur(0px);
}
<div class='wrapper'>
<div class='block'>Block 1</div>
<div class='block'>Block 2</div>
<div class='block block3'>Block 3</div>
</div>

Related

Parent component not resizing to fit children

I have a <div className="canvas"> element that contains four <div className="stripe stripe-color"> elements that I will be styling dynamically adding random color classes.
I want to use this canvas element as a 'dynamic background'.
As you can see, I have a <div className="children">{props.children}</div> element among the <div className="stripe"/> elements:
const Canvas = (props) => {
return (
<div className="stripe-container">
<div className="children">{props.children}</div>
<div className="stripe stripe-yellow" />
<div className="stripe stripe-green" />
<div className="stripe stripe-red" />
<div className="stripe stripe-purple" />
</div>
);
};
And SCSS:
.stripe-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
padding: 0;
margin: 3vw;
height: 100vh;
}
.children {
position: absolute;
width: calc(100% - 6vw);
}
.stripe-yellow {
background: #fdc111;
}
.stripe-green {
background: #00ad5e;
}
.stripe-red {
background: #d33136;
}
.stripe-purple {
background: #8f3192;
}
The problem here is that <div className="canvas"> won't grow to fit the children's height so if the content in <div className="children">{props.children}</div> becomes too large or if the user uses a smaller viewport, the children will overflow into the height and allow you to scroll, but canvas won't expand to fit it's children.
As additional information, props.children is a React component that contains a list of "card elements" for a restaurant's menu. The cards and its container use flex to wrap around if they don't have enough space horizontally. This is causing the canvas to become too small on smaller viewports. height:100% and their variants won't work either.
Any ideas into how I can get the desired behavior? I'm also open to refactoring as long as my requirement of achieving dynamic color stripes remains.
Here's a minima reproducible example without React:
.stripe-container {
display: grid;
grid-template-columns: repeat(4, 1fr);
padding: 0;
margin: 3vw;
height: 100vh;
}
.children {
position: absolute;
width: calc(100% - 6vw);
}
.stripe {
height: 100%
}
.stripe-yellow {
background: #fdc111;
}
.stripe-green {
background: #00ad5e;
}
.stripe-red {
background: #d33136;
}
.stripe-purple {
background: #8f3192;
}
.child-container {
display: flex;
flex-wrap: wrap;
}
.child {
border: 1px solid white;
margin: 1rem;
width: 25vw;
height: 25vw;
background: lightgray;
opacity: 80%;
}
<div class="stripe-container">
<div class="children">
<div class="child-container">
<div class="child">one</div>
<div class="child">two</div>
<div class="child">three</div>
<div class="child">four</div>
<div class="child">five</div>
<div class="child">six</div>
<div class="child">seven</div>
<div class="child">eight</div>
<div class="child">nine</div>
</div>
</div>
<div class="stripe stripe-yellow"></div>
<div class="stripe stripe-red"></div>
<div class="stripe stripe-green"></div>
<div class="stripe stripe-purple"></div>
</div>
I'm not sure I understand 100% what you're trying to achieve. But I'll try my best to help you.
Removing the absolute from the children and putting it on the stripes instead might do the trick. Additionally, you'll want to position the stripes on 25% of the width to the left respectively.
I don't think you need CSS grid for this anymore, so I removed it and added some small tweaks as well. Let me know if you have any questions or if I got the question wrong.
.stripe-container {
padding: 0;
margin: 3vw;
position: relative;
}
.children {
position: relative;
z-index: 2;
width: 100%;
}
.stripe {
width: 25%;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
z-index: 1;
}
.stripe-yellow {
left: 0;
background: #fdc111;
}
.stripe-green {
left: 25%;
background: #00ad5e;
}
.stripe-red {
left: 50%;
background: #d33136;
}
.stripe-purple {
left: 75%;
background: #8f3192;
}
.child-container {
display: flex;
flex-wrap: wrap;
}
.child {
border: 1px solid white;
margin: 1rem;
width: 25vw;
height: 25vw;
background: lightgray;
opacity: 80%;
box-sizing: border-box;
}
<div class="stripe-container">
<div class="children">
<div class="child-container">
<div class="child">one</div>
<div class="child">two</div>
<div class="child">three</div>
<div class="child">four</div>
<div class="child">five</div>
<div class="child">six</div>
<div class="child">seven</div>
<div class="child">eight</div>
<div class="child">nine</div>
</div>
</div>
<div class="stripe stripe-yellow"></div>
<div class="stripe stripe-red"></div>
<div class="stripe stripe-green"></div>
<div class="stripe stripe-purple"></div>
</div>
This way, the stripes work as a background for the stripe-container no matter the size, and since the children element is no longer absolute, the container is finally able to have the same size as the children.
Why not use a linear gradient for the striped background? You could accomplish what you're trying to do with simpler CSS and without the extraneous markup.
Optional: If you declared custom properties for the stripe colors you could change them simply by setting different values instead of having to rewrite the gradient each time (although the gradient itself isn't complicated or particularly verbose anyway.)
:root {
/*
Using custom properties here to demonstrate
that you could control the stripe colors without
hard-coding them in the stylesheet. an element
could declare its own colors via another class
or even an inline style, e.g.
<div style="--stripe-1: blue">
This isn't required. Just a suggestion.
*/
--stripe-1: #fdc111; /* yellow */
--stripe-2: #00ad5e; /* green */
--stripe-3: #d33136; /* red */
--stripe-4: #8f3192; /* purple */
}
.container {
padding: 0;
min-height: 100vh;
display: flex;
flex-wrap: wrap;
background: linear-gradient(
to right,
var(--stripe-1) 0 25%,
var(--stripe-2) 25% 50%,
var(--stripe-3) 50% 75%,
var(--stripe-4) 75%
);
}
.container > * {
border: 1px solid white;
margin: 1rem;
width: 25vw;
height: 25vw;
background: lightgray;
opacity: 80%;
}
<div class="container">
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
<div>five</div>
<div>six</div>
<div>seven</div>
<div>eight</div>
<div>nine</div>
</div>

How to prevent cutting off absolute positioned elements and still keep a box-shadow embrace the parent div?

First of all an example:
https://jsfiddle.net/85uqehz5/
The code is just an example, an easier version of my real code. I figured out that I cant't have both: Setting the wrap-div to overflow: visible the menu that shows up isn't cut off but the box shadow doesn't embrace the box; With overflow:auto; the box-shadow is working but the menu cut off. How could I solve this? A fixed height would not be an option.
Example Code:
$('#menu').click(function() {
$('#menu-list').toggleClass('hidden');
});
#wrap {
width: 80%;
height: auto;
overflow: visible;
box-shadow: 0 0 .2rem rgba(0, 0, 0, .4);
}
#content {
width: 200px;
height: 20px;
margin: 0 auto;
}
#content2 {
float: left;
}
.hidden {
display: none;
}
#menu {
position: relative;
height: 20px;
width: 100px;
background-color: #ccc;
float: left;
}
#menu-list {
position: absolute;
top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrap">
<div id="content">
Some Content
</div>
<div id="content2">
Some Content
</div>
<div id="menu">
Open Menu
<div id="menu-list" class="hidden">
<div> bla </div>
<div> bla </div>
<div> bla </div>
</div>
</div>
</div>
It's very simple, in your specific case:
1- Remove overflow: auto; from #wrap
2- Add this to your CSS:
#wrap:after {
display: table;
content: "";
clear: both;
}
This makes the height of #wrap's calculation include the floated element.
If you have multiple uses declare a class like clearfix and use it whenever needed.
Demo: https://jsfiddle.net/85uqehz5/1/
Floats must be cleared: https://jsfiddle.net/85uqehz5/3/
<div id="wrap" class="clearfix">
The reason the menu is cut off is because you haven't clear your float: left and that is done with such piece of code to the container
.clearfix:after {
content: "\0020";
display: block;
height: 0;
clear: both;
visibility: hidden;
}

Showing element in front of common backdrop

We want to find a solution to show just the green box in front of the backdrop (#back). And this without modifying the html.
HTML:
<div id="body" style="z-index:1;position:relative;">
<div id="div1" style="z-index:4;position:relative;">
</div>
<div style="z-index:4;background-color: red; width: 70px;position:relative;height: 70px;">
<div id="div2" style="z-index:7;background-color:green;position:relative;">
</div>
</div>
<div id="back" style="z-index:5;">
</div>
</div>
CSS:
#body {
background-color: blue;
width: 500px;
height: 500px;
position: relative;
}
#div1 {
position:relative;
background-color: white;
width: 100px;
height: 100px;
}
#back {
position: absolute;
top:0;
width: 100%;
height: 100%;
opacity: 0.7;
background-color: black;
}
div {
width: 50px;
height: 50px;
}
There is a fiddle of our problem :
https://jsfiddle.net/ruj23c60/3/
<div style="z-index:4;background-color: red; width: 70px;height: 70px;">
<div id="div2" style="z-index:7;background-color:green;position:relative;">
</div>
</div>
Removing the style position: relative from the parent of #div2 is sufficient already
There are two way as i know.
First:
You need to give z-index:3 to #back. (less than #div2 parent div) then you can make it front of #back
But this way whole div come in front of black(#back) div.
Fiddle
Second:
Make position:adsolute; to #div2 and remove position:relative; from it's parent.
Fiddle
Note: I have comment opacity: 0.7; from #back to understand properly.

div always on top of fixed element

what I'm trying to do is simple to tell. There is fixed div on my page on bottom. It must be always shown on bottom, so position fixed is used.
In this div there are 2divs, one small must be always on top of this fixed div, another must be scrollable.
The problem is small div, if I give him position fixed, it is position to top of window, not on top of this fixed div, as you can see in this fiddle
If small div is position absolute, it is on top of fixed div, but if it is scrolled, as you can see in this fiddle
HTML
<div class="bottom">
<div class="top"></div>
<div class="content"></div>
</div>
CSS
.bottom
{
padding:20px;
height: 253px;
position: fixed;
bottom:0px;
width:100%;
background-color: red;
overflow-x: hidden;
overflow-y: scroll;
}
.top
{
height:50px;
width:100%;
background-color: yellow;
position: fixed;
top: 0px;
}
.content
{
height: 1500px;
background: linear-gradient(green, blue);
}
Is is possible to make this work without watching scrolling by jvascript? By pure CSS?
You can use a wrapper <div> for the content and let it scroll - so that the absolutely positioned sibling does not scroll along with it, as follows:
HTML
<div class="bottom">
<div class="top"></div>
<div class='contentWrap'>
<div class="content"></div>
</div>
</div>
CSS
.contentWrap{
height:100%;
overflow-y:auto;
}
* {
margin: 0;
padding: 0;
}
.bottom {
padding: 20px;
height: 253px;
position: fixed;
bottom: 0px;
width: 100%;
background-color: red;
overflow: hidden;
}
.top {
height: 50px;
width: 100%;
background-color: yellow;
position: absolute;
top: 0px;
}
.contentWrap {
height: 100%;
padding-top: 30px; /* .top height - .bottom padding*/
overflow-y: auto;
}
.content {
height: 1500px;
background: linear-gradient(green, blue);
}
<div class="bottom">
<div class="top"></div>
<div class='contentWrap'>
<div class="content"></div>
</div>
</div>
JSFiddle Demo
Your approach using fixed -> absolute is absolutely correct since you can position an element absolute but relative to its parent by doing so. The problem is that the absolute .top always appears on top of .bottom - so if .bottom is scrolled, .top will follow.
My solution would be using position:fixed; on .top, but using bottom instead of top:
.top {
....
position:fixed;
bottom:253px; /*note sure how it should look at the end, try it yourself*/
}
Add div with class top inside div with class content and remove top:0 from .top class:
html
<div class="bottom">
<div class="content" >
<div class="top"></div>
</div>
<div>
css
.top
{
height:50px;
width:100%;
background-color: yellow;
position: fixed;
}
fiddle
Try this, it basically just puts a frame container around your scrollable div to keep everything in place. JSFiddle
<div class="bottom">
<div class="top"></div>
<div class="scroll-container">
<div class="content" ></div>
</div>
<div>
.scroll-container
{
height: 203px;
overflow-y: scroll;
}
Also, remove overflow-y: scroll; from the .bottom class
If you already dealing with fixed heights & positions, why not just position the 'top' section as fixed as well? check the Fiddle Demo
like so:
.top
{
height:50px;
bottom:243px;
width:100%;
background-color: yellow;
position: fixed;
}

With jQuery how can you make all of the parent divs and body expand in height to accommodate content?

Objective
To have the page the page on my website to expand in height according to the dynamic data pushed into the container.
Background
The page has a set of images and text that is populated via a JSON feed. The text is overflowing into the footer because it is not expanding its containing div which would subsequently expand its containing div which would subsequently expand the body. So I need for a specific child div to push its multiple parent divs.
I have searched similar problems on Stackoverflow and attempted various CSS solutions such as giving all of the parent divs a CSS rule of clear:both or even in the HTML inserting a <div style="clear:both"></div> but none of those solutions worked.
So now I am experimenting with jQuery to see if I could find a solution to this problem.
I know I need to create a variable of some sort like
var newHeight = $("#carousel").height();
And that it needs to have push out the height with something like
$(".case").height(newHeight);
This is my current HTML
<body>
<div class="container">
<div class="block push">
<div id="mainContent" class="row">
<div class="large-12 columns">
<h1>Before & After Case Gallery</h1>
<div id="casesContainer">
<div id="carousel"></div>
</div>
<script id="casestpl" type="text/template">
{{#cases}}
<div class="case">
<div class="gallery_images_container">
<div class="item_container">
<div class="gallery_heading">BEFORE</div>
<img src="/assets/img/content/images-bruxzir-zirconia-dental-crown/cases/{{image}}_b_300.jpg" alt="Photo of {{alt}}" />
</div>
<div class="item_container">
<div class="gallery_heading">AFTER</div>
<img src="/assets/img/content/images-bruxzir-zirconia-dental-crown/cases/{{image}}_a_300.jpg" alt="Photo of {{alt}}" />
</div>
</div>
<div class="description_container">
<p>
<span><strong>Case Number {{{number}}} {{version}}:</strong></span>
{{{description}}}
</p>
</div>
</div>
{{/cases}}
</script>
The {{{description}}} in the <p> is overflowing into its parent divs <div class="description_container"> then <div class="case"> then <div id="carousel"> then <div class="casesContainer"> then <div class="large-12"> (which is a container in Foundation) then <div class="mainContent"> and so on.
Here is my CSS
html, body { height: 100%; }
.container { display: table; height: 100%; width: 100%; margin: 0 auto; }
.block { display: table-row; height: 1px; }
.push { height: auto; }
#mainContent {}
#casesContainer {
min-width:310px;
}
.image-navigation {
background: rgb(6,6,6);
color: #fff;
width:100%;
max-width: 640px;
height: 24px;
}
.image-navigation a {
color: #fff;
padding: 6px;
}
.image-navigation-previous, .image-navigation-next{
float:left;
width: 50%;
}
.image-navigation-previous {
text-align: right;
}
.image-navigation-next {
text-align: left;
}
#carousel {
height:auto;
min-height:600px;
overflow-y: auto;
}
.case {
max-width: 640px;
height:auto;
}
.gallery_images_container {
clear: both !important;
}
.item_container{
max-width: 320px;
float: left;
}
.gallery_heading {
background: black;
color: white;
width: 100%;
text-align: center;
}
.description_container {
background: none repeat scroll 0% 0% white;
min-width: 308px;
max-width: 640px;
padding: 6px 6px 12px 6px;
clear: both !important;
}
I realize that #carousel { height:auto; min-height:600px; overflow-y: auto; } is an ugly hack. It was just an experiment.
I hope that I am just completely missing something and this is an easy jQuery fix. Or maybe my HTML and CSS could use a different structure?
Not a complete fix but maybe helpful.
I've used this function but Internet Explore increases the heights on resize.
$(document).on('ready', function() {
// $(window).on('resize', function() {
var height1 = $("#r1c1").height();
if (height1 < $("#r1c2").height()) { height1 = $("#r1c2").height() }
if (height1 < $("#r1c3").height()) { height1 = $("#r1c3").height() }
$("#r1c1").height(height1);
$("#r1c2").height(height1);
$("#r1c3").height(height1);
// }).trigger('resize'); // Trigger resize handlers not working correctly with IE8.
});//ready

Categories

Resources