Sizing a grid column based on a child's aspect ratio - css

My question is similar to this one: I'm trying to contain an aspect-ratio element within its parent element. One difference though, this aspect-ratio element has siblings—a header and a footer—and all this nice family should be center-aligned and share a common width.
Images are worth a thousand words:
GIFs are worth a thousand images:
I'm close to that result, but I'm not quite there yet:
body {
height: 100%;
margin: 0;
}
html {
background-color: lightgrey;
height: 100%;
}
#footer,
#header {
background-color: blue;
height: 50px;
}
#paper {
aspect-ratio: 1;
background-color: red;
margin: auto;
max-height: 100%;
overflow: hidden;
width: 100%;
}
#wrapper {
align-content: center;
display: grid;
height: 100%;
}
<div id="wrapper">
<div id="header"></div>
<div id="paper"></div>
<div id="footer"></div>
</div>
Any CSS wizard to help me out?

Not sure if you can get all the requirements but here is the best I could do (seems to work on chrome only)
body {
background-color: lightgrey;
margin: 0;
}
#footer,
#header {
background-color: blue;
height: 50px;
}
#paper {
aspect-ratio: 1;
background-color: red;
max-height: 100%;
max-width: 100vw;
}
#wrapper {
place-content: center;
display: grid;
height: 100vmin;
margin-block: max(0px,50vh - 50vmin);
grid-template-rows: auto minmax(0, 1fr) auto;
}
<div id="wrapper">
<div id="header"></div>
<div id="paper"></div>
<div id="footer"></div>
</div>
If the 50px is known you can do like below:
body {
background-color: lightgrey;
margin: 0;
--h: 50px; /* the fixed height */
}
#footer,
#header {
background-color: blue;
height: var(--h);
}
#paper {
aspect-ratio: 1;
background-color: red;
width: min(100vw,100vh - 2*var(--h));
}
#wrapper {
place-content: center;
display: grid;
height: min(100vh, 100vw + 2*var(--h));
margin-block: max(0px, (100vh - 100vw - 2*var(--h))/2);
grid-template-rows: auto minmax(0, 1fr) auto;
}
<div id="wrapper">
<div id="header"></div>
<div id="paper"></div>
<div id="footer"></div>
</div>

Try this solution, all the magic happens in grid-template-columns and grid-template-rows.
html {
background-color: lightgrey;
height: 100%;
}
body {
height: 100%;
margin: 0;
}
#wrapper {
--footer-header-height: 50px;
align-content: center;
display: grid;
height: 100vh;
grid-template-columns: 1fr minmax(auto, calc(100vh - var(--footer-header-height) * 2)) 1fr;
grid-template-rows: auto minmax(auto, 100vw) auto;
}
#footer,
#header {
grid-column: 2;
background-color: blue;
height: var(--footer-header-height);
}
#paper {
grid-column: 2;
aspect-ratio: 1 / 1;
background-color: red;
}
<div id="wrapper">
<div id="header"></div>
<div id="paper"></div>
<div id="footer"></div>
</div>

Actually Container Queries enable us to solve this kind of problems elegantly.
Support for this feature is currently very bad (see here), but it's part of Interop 2022 so I guess it'll look different by the end of the year.
I post this as an answer as it might help someone in the future 👽👋
Note that you currently need to turn on a flag on Chrome to be able to test it.
body {
container-type: size;
height: 100%;
margin: 0;
}
html {
background-color: lightgrey;
height: 100%;
}
#footer,
#header {
background-color: blue;
}
#paper {
background-color: red;
}
#wrapper {
align-content: center;
display: grid;
grid-template-columns: min(100cqi, (100cqb - 100px));
grid-template-rows: 50px min(100cqb - 100px, 100cqi) 50px;
justify-content: center;
}
<div id="wrapper">
<div id="header"></div>
<div id="paper"></div>
<div id="footer"></div>
</div>
Here's the same code but relying on viewport units (works in all browsers):
body {
height: 100%;
margin: 0;
}
html {
background-color: lightgrey;
height: 100%;
}
#footer,
#header {
background-color: blue;
}
#paper {
background-color: red;
}
#wrapper {
align-content: center;
display: grid;
grid-template-columns: min(100vw, (100vh - 100px));
grid-template-rows: 50px min(100vh - 100px, 100vw) 50px;
height: 100%;
justify-content: center;
}
<div id="wrapper">
<div id="header"></div>
<div id="paper"></div>
<div id="footer"></div>
</div>

Related

Positioning of a Absolute Element in relation to a responsive image

I’m trying to create a responsive design where a sections section is always flush to the bottom edge of an image.
The section is a grid divided into three grid-areas:
“section1 section3”
“section2 section3"
I want the bottom of section1 to always align with the bottom of a responsive 3/2 image.
The closest I’ve been able to get to achieve what I’m looking for is by applying padding-bottom: min(50px, 3.5vw);
img{
object-fit: contain;
/* aspect-ratio: 3/2;*/
width: 100%;
padding-bottom: min(50px, 3.5vw);
}
div section{
position: absolute;
bottom: 0;
}
What I’m looking for is something like calc(heightOfTheContainer + XXpx)
I know I can do this in JavaScript document.getElementById("myImg").offsetHeight + XXpx;
Can I achieve what I want with just CSS using calc() minmax() or ??.
main{
height:100%;
width: 100%;
padding: 3.5vh;
}
div{
position: relative;
max-width: 800px;
margin: 0 auto;
}
img{
object-fit: contain;
/* aspect-ratio: 3/2;*/
width: 100%;
padding-bottom: min(50px, 3.5vw);
}
div section{
position: absolute;
display: grid;
grid-template-columns: 30% 70%;
grid-template-rows: 50% 50%;
grid-template-areas:
"section1 section3"
"section2 section3";
bottom: 0;
height:8vw;
width:100%;
}
.section1, .section2, .section3{
width:100%;
height:100%;
font-size: 20px;
font-weight:bold;
color:black;
}
.section1{
grid-area: section1;
background-color: red;
}
.section2{
grid-area: section2;
background-color: blue;
}
.section3{
grid-area: section3;
background-color: green;
opacity: .5;
}
<main>
<div>
<img src="../../images/portfolio/mainbnw.jpg" />
<section>
<div class="section1">
section 1
</div>
<div class="section2">
section 2
</div>
<div class="section3">
section 3
</div>
</section>
</div>
</main>
If you remove any bottom padding from the main and position the grid element relative rather than absolute it will end up immediately below the image.
So then translate it upwards by 50% of its height and the bottom of the first cell will always be aligned with the bottom of the image (whatever height you give the cell).
main {
height: 100%;
width: 100%;
padding: 3.5vh;
}
div {
position: relative;
max-width: 800px;
margin: 0 auto;
}
img {
object-fit: contain;
/* aspect-ratio: 3/2;*/
width: 100%;
}
div section {
position: relative;
transform: translateY(-50%);
display: grid;
grid-template-columns: 30% 70%;
grid-template-rows: 50% 50%;
grid-template-areas: "section1 section3" "section2 section3";
bottom: 0;
height: 8vw;
width: 100%;
}
.section1,
.section2,
.section3 {
width: 100%;
height: 100%;
font-size: 20px;
font-weight: bold;
color: black;
}
.section1 {
grid-area: section1;
background-color: red;
}
.section2 {
grid-area: section2;
background-color: blue;
}
.section3 {
grid-area: section3;
background-color: green;
opacity: .5;
}
<main>
<div>
<img src="https://picsum.photos/id/1015/600/400" />
<section>
<div class="section1">
section 1
</div>
<div class="section2">
section 2
</div>
<div class="section3">
section 3
</div>
</section>
</div>
</main>
If you use grid, you can a set few elements inside the same cell without the need of absolute.
here is an example made of 3 rows to show the idea:
img {
object-fit: contain;
aspect-ratio: 3/2;
}
.section1,
.section2,
.section3 {
font-size: 20px;
font-weight: bold;
color: black;
}
section {
display: grid;
grid-template-columns: 30% 70%;
grid-template-rows: 8fr auto auto;
grid-template-areas: "img img" "sec1 sec3" " sec2 sec3"
}
img {
grid-column: 1/3;
grid-row: 1/3;
width: 100%;
}
.section1 {
grid-area: sec1;
background-color: red;
}
.section2 {
grid-area: sec2;
background-color: blue;
}
.section3 {
grid-area: sec3;
background-color: rgba(0,128,0,0.5);
}
<section>
<img src="https://picsum.photos/id/1015/300/200" />
<div class="section1">
section 1
</div>
<div class="section2">
section 2
</div>
<div class="section3">
section 3
</div>
</section>

How can I make my grid full height instead of it shrinking some items?

I have 8 items in my grid; items 1 and 8 are the header and footer respectively, and items 2-7 are parts of the main body.
Items 2-7 are in a two-column format. The problem I am encountering is that when I expand the height of my header (item 1) the rest of the items shrink accordingly; I am stuck and would love some help. Thank you.
Here is my code:
html,
body {
max-width: 100%;
margin: 0 auto;
background-color: white;
overflow-x: hidden;
padding: 0px;
height: 100%;
}
.container {
width: 100vw;
height: 100vh;
display: grid;
grid-template-columns: 40% 60%;
grid-template-rows: 50% 50%;
justify-items: stretch;
}
.item1 {
grid-column-start: span 2;
background-color: blue;
}
.item2 {
background-color: pink;
}
.item3 {
background-color: yellow;
}
.item4 {
background-color: orange;
}
.item5 {
background-color: black;
}
.item6 {
background-color: purple;
}
.item7 {
background-color: brown;
}
.item8 {
background-color: green;
grid-column-start: span 2;
}
<div class="container">
<div class="item1">A</div>
<div class="item2">B</div>
<div class="item3">C</div>
<div class="item4">D</div>
<div class="item5">E</div>
<div class="item6">F</div>
<div class="item7">G</div>
<div class="item8">H</div>
</div>
removed the html tag, updated the styling to the body and .container
body {
max-width: 100vw;
margin: 0px;
background-color: white;
padding: 0px;
}
.container {
width: 100%;
height: 100vh;
display: grid;
grid-template-columns: 40% 60%;
grid-template-rows: 81% 50% 30% auto 30%;
justify-items: stretch;
}
The original code only defined the first 2 rows' height, I put in some random values for the other rows. auto also works to define row height

Make element to take 100% of visible empty space without JS

So... How I do something like this with CSS only? Watch red element, it scales not scrolls:
Currently it works via JS, I catch onscroll and update size of the element according to calculated free space.
This is how it works now:
https://codepen.io/bswan-the-decoder/pen/OJPVxZj
<div class="header">
Header
</div>
<div class="header-spacer">
</div>
<div class="content">
<div class="sidebar">
</div>
<div class="page">
</div>
</div>
<div class="footer">
Footer
</div>
body {
background-color: black;
}
.header {
position: fixed;
width: 100%;
top: 0px;
left: 0px;
min-height: 80px;
background-color: #FFF;
z-index: 500;
}
.footer {
min-height: 50px;
bottom: 0px;
background-color: #FFF;
left: 0px;
}
.page {
min-height: 1000px;
width: 50%;
margin: 15px;
margin-left: auto;
margin-right: auto;
background-color: #AAA;
}
.sidebar {
position: fixed;
background-color: #F66;
left: 10px;
top: 105px;
width: 100px;
height: 200px;
}
let header = document.querySelector('.header');
let footer = document.querySelector('.footer');
let sidebar = document.querySelector('.sidebar');
let header_spacer = document.querySelector('.header-spacer');
header_spacer.style.height = header.clientHeight+'px';
document.addEventListener('scroll',(event)=>{
let height = window.innerHeight - header.clientHeight - 35;
let scroll = this.scrollY;
if(scroll+window.innerHeight+footer.clientHeight>=document.body.clientHeight)
{
height = (height - (
(scroll+window.innerHeight+footer.clientHeight)
- document.body.clientHeight));
}
sidebar.style.height = height+'px';
});
This my new layout:
https://codepen.io/bswan-the-decoder/pen/wvBapvV
<body>
<div class="header">
</div>
<div class="content">
<div class="sidebar_holder">
<div class="sidebar"></div>
</div>
<div class="page_holder">
<div class="page"></div>
</div>
</div>
<div class="footer">
</div>
</body>
body{
display: grid;
grid-template-rows: min-content auto min-content;
grid-template-columns: auto;
grid-template-areas: "header" "content" "footer";
background-color: #000;
min-height: 100vh;
}
.header{
grid-area: header;
background-color: #FFF;
min-height: 80px;
position: sticky;
top: 0px;
z-index: 5;
}
.footer{
grid-area: footer;
background-color: #FFF;
min-height: 40px;
}
.content{
grid-area: content;
display: grid;
grid-template-rows: auto;
grid-template-columns: min-content auto;
grid-template-areas: "sidebar page";
}
.sidebar_holder {
grid-area: sidebar;
}
.page_holder {
grid-area: page;
}
.sidebar {
width: 100px;
position: sticky;
top: 105px; /*how to make it (header height+20px) ?*/
height: 100px; /*How to make it (100vh - header height - visible height of footer)?*/
background-color: #F66;
}
.page {
height: 1000px;
width: 50%;
background-color: #AAA;
margin: 25px;
margin-left:auto;
margin-right:auto;
}
Update:
#Roddy - I tried but my knowledge is lacking so there was nothing of use pruduced by me.
To fill out the whole space with a div, you can use ViewHeight and ViewWidth units like:
vw and vh takes the percentage of the screensize and applies it,
100vw means 100% of the width
.whole-area {
height: 100vh;
width: 100vw;
background: orange;
}
<div class="whole-area">
<span>Text</span>
</div>

Grid template with an inner overflow-x element break layout in chrome but not in firefox [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I’m having issues tracking the problem of a div that contains a big table (a green div in the fiddle). I want this div to have a working overflow-x: auto.
On firefox I don’t see any issues, the table container when the windows is too little adds a scrollbar, with chrome or opera the browser scrollbar is shown alongside the block scrollbar, and the page content extends over the window length.
If I don’t use Grid, all browsers show the same behavior, with a scrollbar only in the parent block of the table.
Here's a fiddle and snippet:
.content {
grid-area: content;
display: block;
max-width: 1200px;
margin: 0 auto;
width: 100%;
box-sizing: border-box;
min-height: calc(100vh - 6em);
overflow: hidden;
}
.footer {
grid-area: footer;
height: 3em;
background-color: grey;
}
.sidemenu {
height: 3em;
grid-area: sidemenu;
background-color: grey;
}
.wrapper {
display: grid;
grid-template-areas:
"sidemenu"
"content"
"footer";
}
.big {
background-color: green;
width: 2980px;
height: 20px;
}
.blockWrapper { overflow-x: auto; }
#media (min-width: 500px) {
.wrapper {
grid-template-columns: 3em 1fr;
grid-template-areas:
"sidemenu content"
"sidemenu footer";
}
.sidemenu { height: 100%; }
}
<div class="wrapper">
<div class="sidemenu"></div>
<div class="content">
<div class="blockWrapper">
<div class="big"></div>
</div>
</div>
<div class="footer"></div>
</div>
You can remove width: 100% and margin: 0 auto on .content to get the same behavior in Chrome & Firefox - see demo below:
.content {
grid-area: content;
display: block;
max-width: 1200px;
/*margin: 0 auto;
width: 100%;*/
box-sizing: border-box;
min-height: calc(100vh - 6em);
overflow: hidden;
}
.footer {
grid-area: footer;
height: 3em;
background-color: grey;
}
.sidemenu {
height: 3em;
grid-area: sidemenu;
background-color: grey;
}
.wrapper {
display: grid;
grid-template-areas: "sidemenu" "content" "footer";
}
.big {
background-color: green;
width: 2980px;
height: 20px;
}
.blockWrapper {
overflow-x: auto;
}
#media (min-width: 500px) {
.wrapper {
grid-template-columns: 3em 1fr;
grid-template-areas: "sidemenu content" "sidemenu footer";
}
.sidemenu {
height: 100%;
}
}
<div class="wrapper">
<div class="sidemenu"></div>
<div class="content">
<div class="blockWrapper">
<div class="big"></div>
</div>
</div>
<div class="footer"></div>
</div>
Another fix can be to specify grid-template-columns: 100% and grid-template-columns: 3em calc(100% - 3em) for the media query above 500px - see demo below:
.content {
grid-area: content;
display: block;
max-width: 1200px;
margin: 0 auto;
width: 100%;
box-sizing: border-box;
min-height: calc(100vh - 6em);
overflow: hidden;
}
.footer {
grid-area: footer;
height: 3em;
background-color: grey;
}
.sidemenu {
height: 3em;
grid-area: sidemenu;
background-color: grey;
}
.wrapper {
display: grid;
grid-template-areas: "sidemenu" "content" "footer";
grid-template-columns: 100%; /* added */
}
.big {
background-color: green;
width: 2980px;
height: 20px;
}
.blockWrapper {
overflow-x: auto;
}
#media (min-width: 500px) {
.wrapper {
grid-template-columns: 3em 1fr;
grid-template-areas: "sidemenu content" "sidemenu footer";
grid-template-columns: 3em calc(100% - 3em); /* added */
}
.sidemenu {
height: 100%;
}
}
<div class="wrapper">
<div class="sidemenu"></div>
<div class="content">
<div class="blockWrapper">
<div class="big"></div>
</div>
</div>
<div class="footer"></div>
</div>

What is the best way to fill the screen without jQuery [duplicate]

This question already has answers here:
Expand a div to fill the remaining width
(21 answers)
How to make a div fill a remaining horizontal space?
(26 answers)
Closed 4 years ago.
I have two divs side by side.
Div1 width is 200px
and Div2 should fill the screen.
To do this, I use jQuery and detect the screen with and then substuct 200 from it.
But if I use this way, jQuery slows down the browser.
So I'm searching a better way rather than using jQuery.
What is the best way to do this?
Update :
I forgot to write that float did not fixed my solution.
Thank you I'm going to check the answers.
float solution
body { margin: 0; }
#a {
background-color: lime;
width: 200px;
float: left;
height: 100vh
}
#b {
background-color: blue;
margin-left: 200px;
height: 100vh;
}
<div id="a"></div>
<div id="b"></div>
css grid
body {
margin: 0;
}
.gridcontainer {
display: grid;
grid-template-columns: 200px 1fr;
height: 100vh;
}
#a {
background-color: lime;
height: 100vh;
}
#b {
background-color: blue;
height: 100vh;
}
<div class="gridcontainer">
<div id="a"></div>
<div id="b"></div>
</div>
flexbox
body {
margin: 0;
}
.flexcontainer {
display: flex;
}
#a {
background-color: lime;
width: 200px;
height: 100vh;
}
#b {
background-color: blue;
height: 100vh;
width: calc(100% - 200px);
}
<div class="flexcontainer">
<div id="a"></div>
<div id="b"></div>
</div>
inline-block solution
body {
margin: 0;
}
.inlineblockcontainer {
font-size: 0;
}
.inlineblockcontainer>div {
display: inline-block;
}
#a {
background-color: lime;
font-size: 16px;
width: 200px;
height: 100vh;
}
#b {
background-color: blue;
font-size: 16px;
height: 100vh;
width: calc(100% - 200px);
}
<div class="inlineblockcontainer">
<div id="a"></div>
<div id="b"></div>
</div>
html,
body,
#container {
height: 100%;
}
#left {
width: 200px;
float: left;
min-height: 100%;
background-color: blue;
}
#right {
width: 100%;
min-height: 100%;
background-color: red;
}
<div id="container">
<div id="left"></div>
<div id="right"></div>
</div>
https://jsfiddle.net/832ahuqc/6/

Resources