Setting width relatively to the size of the grandparent div - css

I have the structure that currently looks approximately like the snippet below; how can I make div2 to take the width 50% of its grandparent div, rather than 50% of its immediate parent?
<div id="grandParent" style="width: 100%; display: flex; flex-direction: row; flex-wrap: nowrap; background-color: yellow; border-color: yellow">
<div id="div1" style="width: 100px; background-color: aqua">
div1
</div>
<div id="parent" style="width: 100%; background-color: green">
parent<br>
<div id="div2" style="width: 50%; background-color: fuchsia; margin: 0 auto;">
div2
</div>
</div>
</div>

We can do some maths. The width of the parent is P - 100px and you need to have P/2 so if you do X/2 + 50px where X = P - 100px you will have P/2. Also better use flex-grow:1 instead of width:100% to avoid the shrink effect and have the first div always at 100px
console.log($('#div2').width())
console.log($('#grandParent').width())
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="grandParent" style=" display: flex; flex-direction: row; flex-wrap: nowrap; background-color: yellow; border-color: yellow">
<div id="div1" style="width: 100px; background-color: aqua">
div1
</div>
<div id="parent" style="flex-grow:1; background-color: green">
parent<br>
<div id="div2" style="width: calc(50% + 50px); background-color: fuchsia; margin: 0 auto;">
div2
</div>
</div>
</div>
You can consider the use of CSS variable to make this easier:
console.log($('#div2').width())
console.log($('#grandParent').width())
:root {
--w:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="grandParent" style="display: flex; flex-direction: row; flex-wrap: nowrap; background-color: yellow; border-color: yellow">
<div id="div1" style="width: var(--w); background-color: aqua">
div1
</div>
<div id="parent" style="flex-grow:1;background-color: green">
parent<br>
<div id="div2" style="width: calc(50% + var(--w)/2); background-color: fuchsia; margin: 0 auto;">
div2
</div>
</div>
</div>

Related

Pixel-Sized Gap Between Inner and Outer Div

Is this a rendering bug in Chrome?
Using Google Chrome 107.0.5304.32 (Official Build) beta (64-bit)
.meters {
display: grid;
grid-template-columns: 4rem 1fr 3rem;
grid-auto-rows: 1.3rem;
align-items: center;
gap: 0.8rem;
}
.meter {
display: flex;
height: 100%;
border: solid 3px black;
}
.fill {
background: blue;
}
<div class="meters">
<p>0 Sterne</p>
<div class="meter">
<div class="fill" style="width: 100%;"></div>
</div>
<p>27%</p>
<p>1 Sterne</p>
<div class="meter">
<div class="fill" style="width: 10.989%;"></div>
</div>
<p>11%</p>
<p>2 Sterne</p>
<div class="meter">
<div class="fill" style="width: 32.4176%;"></div>
</div>
<p>32%</p>
<p>3 Sterne</p>
<div class="meter">
<div class="fill" style="width: 11.5385%;"></div>
</div>
<p>12%</p>
<p>4 Sterne</p>
<div class="meter">
<div class="fill" style="width: 17.5824%;"></div>
</div>
<p>18%</p>
</div>
I see white around the blue divs:
If I set the border to 4px or more, the white is gone. For 1px, it also works fine. With 2px I see only white at the bottom and with 3px white on top and bottom.
Amaury Hanser in the comments mentioned zoom, so I checked and when zooming in to 110%, the white also disappears.
I even tried setting overflow: hidden; on .meter and height: 150%; on fill, so I can see in the inspector that the fill is larger than the container, but it still shows the white border:
Iam not sure what is wrong but you can use outline instead
.meters {
display: grid;
grid-template-columns: 4rem 1fr 3rem;
grid-auto-rows: 1.3rem;
align-items: center;
gap: 0.8rem;
}
.meter {
display: flex;
height: 100%;
outline: 3px solid black !important;
}
.fill {
background: blue;
}
<div class="meters">
<p>0 Sterne</p>
<div class="meter">
<div class="fill" style="width: 100%;"></div>
</div>
<p>27%</p>
<p>1 Sterne</p>
<div class="meter">
<div class="fill" style="width: 10.989%;"></div>
</div>
<p>11%</p>
<p>2 Sterne</p>
<div class="meter">
<div class="fill" style="width: 32.4176%;"></div>
</div>
<p>32%</p>
<p>3 Sterne</p>
<div class="meter">
<div class="fill" style="width: 11.5385%;"></div>
</div>
<p>12%</p>
<p>4 Sterne</p>
<div class="meter">
<div class="fill" style="width: 17.5824%;"></div>
</div>
<p>18%</p>
</div>

Keep left margin of a div inline with another div when resizing

the problem that I'm having is that when I resize the browser the left margins of both the and my card divs aren't aligning. Is there some sort of css property or maybe some JS that will make them stay aligned when resizing?
here's my sandbox
https://codesandbox.io/s/stupefied-christian-tosys?file=/src/styles.css:0-
Add the .filter margin margin: 0 80px; to your .row. and then remove justify-content: center;. It will loose the centered. But will be align on the left. To aviod the overflow from the body, you can set width: calc(100% - 160px);to your .row:
/* ADDED BELOW */
margin: 0 80px;
justify-content: unset;
width: calc(100% - 160px);
After if you want to keep your card more center, either you use justify-content: space-between; on row, either you use margin: 10px auto; on your card.
DEMO:
body {
margin: 0 auto;
max-width: 1200px;
}
.row {
display: flex;
justify-content: center;
width: 100%;
flex-wrap: wrap;
/*ADDED BELOW */
margin: 0 80px;
justify-content: unset;
width: calc(100% - 160px);
}
.filter {
display: flex;
margin: 0 80px;
}
.filter select {
display: inline;
width: 15rem;
margin: 10px;
border-radius: 5px;
}
.card {
width: 15rem;
margin: 10px;
border-radius: 5px;
border: 1px solid rgba(0, 0, 0, 0.125);
}
.info {
padding: 15px;
}
.img-container {
padding-top: 0;
position: relative;
}
.card img {
width: 100%;
object-fit: cover;
}
.price {
font-weight: bold;
}
<div id="root">
<div class="App">
<div class="filter-container">
<div class="product-listing-wrap">
<div class="filter">
<select class="custom-select" id="priceGroup">
<option value="1">Under $50</option>
<option value="2">$50 to $100</option>
<option value="3">$100 to $250</option>
<option value="4">Over $250</option>
</select>
</div>
<div class="row" style="
margin: 0 80px;
padding: 10px 0;
width: calc(100% - 160px);
">
<div class="card">
<div class="img-container"><img src="https://images.pexels.com/photos/593171/pexels-photo-593171.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="1"></div>
<div class="info">
<p class="info-title"><span><a>placeholder...</a></span></p>
</div>
</div>
<div class="card">
<div class="img-container"><img src="https://images.pexels.com/photos/593171/pexels-photo-593171.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="2"></div>
<div class="info">
<p class="info-title"><span><a>placeholder...</a></span></p>
</div>
</div>
<div class="card">
<div class="img-container"><img src="https://images.pexels.com/photos/593171/pexels-photo-593171.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="3"></div>
<div class="info">
<p class="info-title"><span><a>placeholder...</a></span></p>
</div>
</div>
<div class="card">
<div class="img-container"><img src="https://images.pexels.com/photos/593171/pexels-photo-593171.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="4"></div>
<div class="info">
<p class="info-title"><span><a>placeholder...</a></span></p>
</div>
</div>
<div class="card">
<div class="img-container"><img src="https://images.pexels.com/photos/593171/pexels-photo-593171.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="5"></div>
<div class="info">
<p class="info-title"><span><a>placeholder...</a></span></p>
</div>
</div>
<div class="card">
<div class="img-container"><img src="https://images.pexels.com/photos/593171/pexels-photo-593171.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="6"></div>
<div class="info">
<p class="info-title"><span><a>placeholder...</a></span></p>
</div>
</div>
<div class="card">
<div class="img-container"><img src="https://images.pexels.com/photos/593171/pexels-photo-593171.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="7"></div>
<div class="info">
<p class="info-title"><span><a>placeholder...</a></span></p>
</div>
</div>
<div class="card">
<div class="img-container"><img src="https://images.pexels.com/photos/593171/pexels-photo-593171.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500" alt="8"></div>
<div class="info">
<p class="info-title"><span><a>placeholder...</a></span></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
try it:
.row {
display: flex;
justify-content: space-between;
margin: 0 80px;
max-width: 1040px;
flex-flow: wrap;
}

Css trick for border between blocks but not between container and his blocks

I'm trying to find the ultimate CSS-trick to perform what seems to be a simple thing :
I want to see borders between the different blocks, but not see them between the container border and a block. In other words, I want no space between the container and the blocks, but space between the blocks.
Of course I could set some things like border-left: 0px; for the left blocks in the container for example, but I'd like something than can adapt to every circonstances, no matter how many blocks there are, how many lines they do in the container, etc, without having to apply a specific style to every block in the container.
In the example bellow, all borders are shown, even those I don't want to see (between container's borders and blocks themselves) :
* { box-sizing: border-box; }
.container {
display: flex;
align-items: stretch;
align-content: stretch;
flex-wrap: wrap;
border: 2px solid green;
margin-bottom: 1em;
}
.block {
background-color: yellow;
border: 1px solid red;
}
<div class="container">
<div class="block" style="width: 50%;">Block1</div>
<div class="block" style="width: 50%;">Block2</div>
</div>
<div class="container">
<div class="block" style="width: 75%;">Block1</div>
<div class="block" style="width: 25%;">Block2</div>
<div class="block" style="width: 30%;">Block3</div>
<div class="block" style="width: 70%;">Block4</div>
</div>
Taking the border off the actual element and putting it instead on its after pseudo element, with the pseudo element being 4px less wide and less high (4px being 2x the desired border width) gives the effect by overwriting the red borders adjacent.
This is a bit hacky as paddings, width of the red borders etc needs to be adjusted for in the settings.
* { box-sizing: border-box; }
.container {
display: flex;
align-items: stretch;
align-content: stretch;
flex-wrap: wrap;
rborder: 2px green solid;
margin-bottom: 1em;
box-sizing: border-box;
position: relative;
}
.container::after {
border: 2px green solid;
content: '';
position: absolute;
top: 0;
left: 0;
width: calc(100% - 4px);
height: calc(100% - 4px);
display: inline-block
z-index: 1;
}
.block {
background-color: yellow;
border: 1px solid red;
}
<div class="container">
<div class="block" style="width: 50%;">Block1</div>
<div class="block" style="width: 50%;">Block2</div>
</div>
<div class="container">
<div class="block" style="width: 75%;">Block1</div>
<div class="block" style="width: 25%;">Block2</div>
<div class="block" style="width: 30%;">Block3</div>
<div class="block" style="width: 70%;">Block4</div>
</div>
Use flex property instead of width. Want space between blocks, using gap property.
* {
box-sizing: border-box;
}
.container {
border: 2px solid green;
margin-bottom: 1em;
}
.flexbox {
display: flex;
gap: 0 10px;
}
.block {
background-color: yellow;
border: 1px solid red;
}
<div class="container flexbox">
<div class="block" style="flex: 1;">Block1</div>
<div class="block" style="flex: 1;">Block2</div>
</div>
<div class="container">
<div class="flexbox">
<div class="block" style="flex: 3;">Block1</div>
<div class="block" style="flex: 1;">Block2</div>
</div>
<div class="flexbox">
<div class="block" style="width: 30%;">Block3</div>
<div class="block" style="width: 70%;">Block4</div>
</div>
</div>

Sticky Header/Footer With 3 columns. Divs that scroll within the columns

I have a JS Fiddle here.
https://jsfiddle.net/h3c6jqfy/
Basically, i am trying to make a UI that has a sticky header and footer. The middle content will have three columns. Each columns will have DIVs in them. These DIVs should have 100% height and not be cut off from the footer. Within the DIV, they will have scrollable divs.
The very basic layout I created has this in it...
d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>this is the end!!
The part where it says this is the end!! is never reached.
You can use flexbox without the need to calculate heights;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::before,
::after {
box-sizing: inherit;
}
body {
display: flex;
flex-direction: column;
height: 100vh;
}
header {
height: 75px;
background: red;
}
main {
flex: 1;
background: lightgreen;
display: flex;
}
.scrolly {
flex: 1 0 33%;
overflow-y: auto;
}
.content {
height: 1000px;
}
footer {
height: 50px;
background: blue;
}
<header></header>
<main>
<div class="scrolly">
<div class="content"></div>
</div>
<div class="scrolly">
<div class="content"></div>
</div>
</div>
<div class="scrolly">
<div class="content"></div>
</div>
</div>
</main>
<footer></footer>
NOTE: See Fiddle in Full Screen
You can try using flexbox instead of defining every unit, calculate the height to avoid using the space where the footer sits, and let the children div inherit its height
<style>
body, head {overflow: hidden;}
#header,#footer,#content { position:absolute; right:0;left:0;}
#header{
height:100px; top:0; background: #4A4A4A;
}
#footer{
height:100px; bottom:0; background: #4A4A4A;
}
#content{
top:100px;
height: calc(100% - 100px);
background:#fff;
display: flex;
align-items: stretch;
}
</style>
<div>
<div id="header">HEADER</div>
<div id="content">
<div style="background-color: #ff0000; min-width: 33%; height: inherit; overflow-y: scroll;">
<div style="background-color: blue;min-height: inherit;max-width: 99%;padding: 20px 40px;">
<div style="overflow: auto; max-height: inherit; padding: 10px;">
<br>d<br>d<br>d<br>d<br>d<br>d<br>d
<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>
d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>
d<br>d<br>d<br>d<br><br>d<br>d<br>d<br>d<br>
d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>d<br>
d<br>d<br>d
<br>d<br>this is the end!!
</div>
</div>
</div>
<div style="background-color: #ff0000; min-height: 100%; min-width: 33%; max-width: 33%;float: left;">
<div style="background-color: red;min-height: 100%;max-width: 99%;padding: 20px 40px;">
middle
</div>
</div>
<div style="background-color: #ff0000; min-height: 100%; min-width: 33%; max-width: 33%;float: left;">
<div style="background-color: pink;min-height: 100%;max-width: 99%;padding: 20px 40px;">
right
</div>
</div>
</div>
<div id="footer">FOOTER</div>
</div>

Vertically center element with dynamic height in scroll container

I have a scroll container that's usually the size of the whole screen. Inside of it I place dynamic content. So I won't know which height it has or how many elements will be inserted.
Now I want to layout it like this:
if there is enough space, I want the whole content vertically centered inside the scroll container
if the total height of the content exceeds the height of the scroll container, I want the container to just scroll the contents like there was no centering.
I created an example where I tried to solve this problem with flexbox. With content height less than the container height it works like intended. But when the content exceeds the container height, due to justify-content, some elements of the content are cut off:
You can see on the image that the scroll container's scrollTop is all the way at the top, yet elements 1 & 2 aren't visible.
I'd like to know if there is a CSS only solution. A JS solution I could do myself but that's not what I'm after. If it's not possible, that's okay too.
.container {
display: inline-block;
width: 300px;
height: 300px;
border: 2px solid red;
overflow-y: auto;
margin: 1rem 0;
display: flex;
flex-direction: column;
justify-content: center;
}
.block {
width: 80%;
height: 3rem;
margin: 1rem auto;
background: blue;
flex-shrink: 0;
color: #fff;
text-align: center;
}
<div class="container">
<div class="block">1</div>
</div>
<div class="container">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
</div>
<div class="container">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
<div class="block">4</div>
<div class="block">5</div>
<div class="block">6</div>
<div class="block">7</div>
<div class="block">8</div>
</div>
Try applying the overflow to an inner containing div like so:
.container {
display: inline-block;
width: 300px;
height: 300px;
border: 2px solid red;
margin: 1rem 0;
display: flex;
flex-direction: column;
justify-content: center;
}
.inner {
overflow-y: auto;
}
.block {
width: 80%;
height: 3rem;
margin: 1rem auto;
background: blue;
flex-shrink: 0;
color: #fff;
text-align: center;
}
<div class="container">
<div class="inner">
<div class="block">1</div>
</div>
</div>
<div class="container">
<div class="inner">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
</div>
</div>
<div class="container">
<div class="inner">
<div class="block">1</div>
<div class="block">2</div>
<div class="block">3</div>
<div class="block">4</div>
<div class="block">5</div>
<div class="block">6</div>
<div class="block">7</div>
<div class="block">8</div>
</div>
</div>

Resources