I'm interested in making responsive design with CSS grids, it looks promising. I've determined my dimensions as follows (to see if I can get the grid to do what I want):
.product-page-container {
display:grid;
grid-template-columns:2fr 2fr;
grid-template-rows:150px minmax(674px,675px) minmax(724px,725px) minmax(599px,600px) minmax(399px,400px) 150px;
grid-template-areas:
"banner banner"
"productHero productDetails"
"video video"
"features features"
"meta meta"
"footerBanner footerBanner"
}
In putting 'minmax' I assumed this would force my content to stay within this size. Which, in development, the rest of my website does not seem to be the case at all. The rows grow and shrink much past those limits or less. I
I'm fairly lost on how to achieve this. For example, my features area has a script that swaps out content. One block of contents ends up being 500px in height, and the next block of content ends up being 1200px in height, and the grid expands so it still is in the 'features' area, it's just the features area has expanded.
Is this just how grids work?
I'm having trouble observing what you're observing. Super ugly preview, I know, but scroll down to the green div. That's your features section. White div on the left is 500px height, and white div on the right is 1200px height (but you wouldn't know it since it's limited by the size of the .features div.
.product-page-container {
display:grid;
grid-template-columns:2fr 2fr;
grid-template-rows:150px 675px 725px 600px 400px 150px;
grid-template-areas:
"banner banner"
"productHero productDetails"
"video video"
"features features"
"meta meta"
"footerBanner footerBanner"
}
.banner {
grid-area: banner;
background-color: black;
}
.product-hero {
grid-area: productHero;
background-color: red;
}
.product-details {
grid-area: productDetails;
background-color: purple;
}
.video {
grid-area: video;
background-color: blue;
}
.features {
grid-area: features;
background-color: green;
}
.meta {
grid-area: meta;
background-color: yellow;
}
.footer-banner {
grid-area: footerBanner;
background-color: brown;
}
.small-content,
.large-content {
display: inline-block;
vertical-align: top;
margin: 20px;
width: 50px;
background-color: white;
}
.small-content {
height: 500px;
}
.large-content {
height: 1200px;
}
<div class="product-page-container">
<div class="banner"></div>
<div class="product-hero"></div>
<div class="product-details"></div>
<div class="video"></div>
<div class="features">
<div class="small-content"></div>
<div class="large-content"></div>
</div>
<div class="meta"></div>
<div class="footer-banner"></div>
</div>
Without more details it would be hard to replicate and debug, but alas:
THERE ARE SOME REASONS why your grid would behave in unexpected ways (including <pre> tags and large images). Chris Coyier wrote a great article on these problems and how to solve them here: https://css-tricks.com/preventing-a-grid-blowout/
I have a feeling that that article ^^ could contain your solution. Otherwise, try giving us more code to work from here. Good luck!
Related
This question already has answers here:
Prevent content from expanding grid items
(3 answers)
Why does minmax(0, 1fr) work for long elements while 1fr doesn't?
(1 answer)
Closed 2 years ago.
Edit: Let me clarify! I'm not asking about how to keep the content from flowing out by restricting the size of the container, what I'm looking for is how to properly adjust the size of the content based on the container and why a div with a background image set to cover works, while and img element does not.
I am trying to achieve a standard grid layout with a header, sidebar, content and footer, where the content element would have only a single image as a child, that should fill the entire remaining space. I thought that applying
img {
width: 100%;
height: 100%;
object-fit: cover;
}
would be enough to get the desired result, but it unexpectedly increased the height of the content element. What's even more absurd is that no matter how much I reduce the height of the image, as long as it is measured in percentages, the height of the container keeps depending on the width of the image. See the following pen (or look at the snippets below, but the issue is more apparent in the pen, since there the boxes are visible side-by-side) for example.
https://codepen.io/Isti115/pen/vYGRNpg
Try adjusting the .a img { widht: 100%; } and see how it affects the overall height.
.container {
display: inline-grid;
width: 400px;
height: 300px;
margin: 50px;
grid-template-rows: 75px 1fr 50px;
/* grid-template-rows: 75px minmax(0, 1fr) 50px; */
grid-template-columns: 100px 1fr;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
}
.header {
grid-area: header;
background-color: red;
}
.sidebar {
grid-area: sidebar;
background-color: yellow;
}
.content {
grid-area: content;
background-color: green;
}
.footer {
grid-area: footer;
background-color: blue;
}
.a .content {
/* min-height: 0; */
}
.a img {
width: 100%;
height: 20%;
/* object-fit: cover; */
/* height: 100%; */
}
.b img {
width: 100%;
height: 50px;
/* object-fit: cover; */
}
.c .placeholder {
width: 100%;
height: 100%;
/* background-color: purple; */
background: url("http://lorempixel.com/200/150/cats");
background-size: cover;
}
<div class="container a">
<div class="header"></div>
<div class="sidebar"></div>
<div class="content">
<img src="http://lorempixel.com/200/150/cats">
</div>
<div class="footer"></div>
</div>
<div class="container b">
<div class="header"></div>
<div class="sidebar"></div>
<div class="content">
<img src="http://lorempixel.com/200/150/cats">
</div>
<div class="footer"></div>
</div>
<div class="container c">
<div class="header"></div>
<div class="sidebar"></div>
<div class="content">
<div class="placeholder"></div>
</div>
<div class="footer"></div>
</div>
I have since found a solution by either adding min-height: 0 or using minmax(0, 1fr), but I don't consider those ideal solutions, since I don't see why I couldn't simply take the remaining space that gets assigned to the content div element and place an image inside it that fills it completely without expanding the containers size. For example using a simple div instead of the image and giving it a background works perfectly as intended.
ps.: I know that this might sound similar to some other questions that got answered with max-height: 100%, but I think that there is a more complicated underlying issue that I would like to explore.
I need to display an image as large as possible in my layout. The image can be of any size and/or ratio, and it must work with landscape or portrait device orientation (responsive).
Actual CSS layout description
My layout is a simple CSS grid with:
a header on the top,
the main content where the image must fit (with a commands area on the bottom),
and a nav bar on the bottom.
The actual main area is a display:flex, in order to display some photo commands on the bottom, and the real img tag is wrapped into a div.photo-frame element, in order to display a large white border around the image.
Note: This border could have been rendered by a CSS border property on the image, but I would like to keep it as a <div>, in case if extra elements should be added into the white frame, below the image (e.g.: image caption, links...).
What I tried
I tried many things, but the div.photo-frame element causes problems because ~ it doesn't know the size of the image ~ (#forgivethenoob).
What I need
It would be really great if someone could adapt the one-file code I give just below to a working version.
I guess it is a trivial task for a CSS expert; sorry for duplicate.
Single file code (html+css)
Here is a full example (as minimal as possible, only the cat image is missing):
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title></title>
<style>
body, html {
width: 100%;
height: 100%;
margin: 0;
color: #aaa;
background-color: black;
}
.layout {
display: grid;
grid-template-rows:
4rem
auto
4rem;
grid-template-areas: "header" "main" "nav";
width: 100%;
height: 100%;
}
header {
grid-area: header;
background-color: #330;
}
main {
grid-area: main;
background-color: #033;
}
nav {
grid-area: nav;
background-color: #303;
}
#page-1 {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
#page-1 .photo-zone {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
}
/* I prefer to use this class (.photo-frame) instead of a simple border property on the image,
* because some stuff might be added inside the white frame, below the image: */
#page-1 .photo-zone .photo-frame {
display: flex;
padding: 4px;
background-color: white;
border-radius: 0.2rem;
}
#page-1 .photo-commands {
background-color: rgba(255,255,255,0.1);
}
#cat {
width: 200px; /* This needs to be removed in order to answer the question */
}
</style>
</head>
<body>
<div class="layout">
<header>Header (fixed height)</header>
<main>
<div id="page-1">
<div class="photo-zone">
<div class="photo-frame">
<img id="cat" src="cat.jpg" />
</div>
</div>
<div class="photo-commands">
Photo commands
</div>
</div>
<div id="page-2" style="display:none"></div>
<div id="page-3" style="display:none"></div>
</main>
<nav>Nav bar (fixed height)</nav>
</div>
</body>
</html>
Here is a rendering of the above code (fixed size image: width=200px)
Here is what I would like in a landscape orientation
Here is what I would like in a portrait orientation
I need to do this :
div container 800x600 px
div header 800x150 px
div under header 800x50 px
div menu 200x350 px
div content 600x350 px
div footer 800x50 px
I need to put all this 5 divs inside 1 div, each div must have different colors.
By default, block-level elements expand to 100% of the width of the containing element and their height is determined by their contents. So most of the work here is done for you already by default.
You can set a width for the containing element and heights for the inner element. That gets you almost all of the way there. You just need to make the menu and content sit side by side. You can do this with CSS grid, flexbox, display: table, or floats.
Also, <div> elements are the wrong choice here. HTML includes a lot of different element types, such as <header>, <footer>, <nav>, and <main> that you should consider using.
All you need to do is just assign height to each element and width as per your need, rest give display:flex; flex-wrap: wrap to its parent, and it will handle everything
* {margin: 0; padding:0; box-sizing: border-box;}
.wrapper {max-width: 800px; width: 100%; margin: 0 auto;display: flex;flex-wrap: wrap;}
header {
height: 150px;
background-color: #FF009C;
width: 100%;
}
.yellow50 {
height: 50px;
background-color: #D8FF00;
width: 100%;
}
.blue350, .orange350 {height: 350px; width: 50%;}
.blue350 {
background-color: #03907A;
}
.orange350 {
background-color: #FF7E00;
}
footer {
height: 50px;
background-color: #0B561B;
width: 100%;
}
<section class="wrapper">
<header></header>
<div class="yellow50"></div>
<div class="blue350"></div>
<div class="orange350"></div>
<footer>
</section>
CSS grid layout is one option here:
<!DOCTYPE html>
<html>
<head>
<title>SO 61631033: how-to-put-3-divs-inside-1-div</title>
<style type="text/css">
#container {
display: grid;
grid-template-areas:
"h h"
"sh sh"
"m c"
"f f";
grid-template-rows: 150px 50px 350px 50px;
grid-template-columns: 200px 600px;
width: 800px;
height: 600px;
}
#content {
background-color: darkgreen;
grid-area: c;
}
#footer {
background-color: orange;
grid-area: f;
}
#header {
background-color: pink;
grid-area: h;
}
#menu {
background-color: green;
grid-area: m;
}
#subheader {
background-color: yellow;
grid-area: sh;
}
</style>
</head>
<body>
<div id="container">
<div id="header"></div>
<div id="subheader"></div>
<div id="footer"></div>
<div id="menu"></div>
<div id="content"></div>
</div>
</body>
</html>
Develop this design by starting with a rectangular tesselation of the screen estate. Each rectangle represents a container element in html. Superimpose a grid with all tile borders on grid lines. The grid does not need to be equi-spaced in any dimension. This grid is the base for the grid-template-areas CSS property that mirrors the tesselation in an obvious way.
There are a host of additional options how to specify a grid layout, especially tuned to more regular tilings. MDN has their own section on layouting with this methodology.
If support of different devices and responsive design is of primary concern, flex layout will suit the task better.
I am trying to use a media query so that once my layout gets below 800px wide, it goes into one column with the relevant description underneath the image.
But the order is incorrect and I get the images first and then the descriptions.
Where am I going wrong?
.container {
display: grid;
grid-template-columns: 2fr 1fr;
}
.one img {
height: 100%;
width: 100%;
object-fit: cover;
}
.two img {
height: 100%;
width: 100%;
object-fit: cover;
}
.three {
padding: 20px;
background: wheat;
}
.four {
padding: 20px;
background: gray;
}
#media only screen and (max-width: 900px) {
.container {
display: grid;
grid-template-columns: 1fr;
}
}
<div class="container">
<div class="one">
<img src="https://picsum.photos/id/600/600/300">
</div>
<div class="two">
<img src="https://picsum.photos/id/600/601/300">
</div>
<div class="three">
This is the description for the first image
</div>
<div class="four">
This is the description for the second image
</div>
</div>
By default the grid items will be place one below the other (as per the order the grid items appear in the markup) if you specify grid-template-columns: 1fr. You can use grid-row: 2 to the description to the first image (three) - this places it correctly.
See demo below:
.container {
display: grid;
grid-template-columns: 2fr 1fr;
}
.one img {
height: 100%;
width: 100%;
object-fit: cover;
}
.two img {
height: 100%;
width: 100%;
object-fit: cover;
}
.three {
padding: 20px;
background: wheat;
}
.four {
padding: 20px;
background: gray;
}
#media only screen and (max-width: 900px) {
.container {
display: grid;
grid-template-columns: 1fr;
}
.three {
grid-row: 2; /* added */
}
}
<div class="container">
<div class="one">
<img src="https://picsum.photos/id/600/600/300">
</div>
<div class="two">
<img src="https://picsum.photos/id/600/601/300">
</div>
<div class="three">
This is the description for the first image
</div>
<div class="four">
This is the description for the second image
</div>
</div>
From my comment and maybe not the kind of answer you look for ( I was waiting for a feed back, so i go with the idea ... too long to be just a comment).
When you run your HTML witout style, img and description do not match.
You could use figure and figcaption to describe the content and link image with its description , img and description in the same container is enough , a div + a p is fine too.
Default, will let them stack on top of each others, this is what you expect when the screen is less than 900px wide. nothing to do there .
You need to mind when it is wider.that's where your mediaquerie comes usefull.
Here is the demo of the coding idea :
/* commun style */
img {
box-sizing:border-box;
display:block;
width: 100%;
height: 100%;
object-fit: cover;
padding: 1em 1em 0 1em ;
}
figure figcaption{
display:block;
margin:0 1em;
background: wheat;
}
figure:nth-child(even) figcaption{
background:gray
}
/* reordering visual layout when window is wider than 900px */
#media only screen and (min-width: 901px) {
/* grid , what you want to use */
.container {
display:grid;
grid-template-columns:2fr 1fr;
}
/* not the best , we will try to make figure side by side looking like 2 rows .... */
figure {
display:flex;
flex-direction:column;
}
/* to fake the rows, trying to set heights each should fill */
img {
flex:10
}
/* works for about 2 1em lines, then visual breaks */
figcaption {
flex:1
}
/* use of supports in case browser is able to get rid of figure in the way for the grid sytem set on container, This your initial idea, to use the grid model for img and text and draw a grid with cell alignement */
#supports (display:contents) {
figure {
display:contents
}
img {
grid-row:1;
}
}
}
<div class="container">
<figure>
<img src="https://picsum.photos/id/600/600/300">
<figcaption>
This is the description for the first image<br>another line
</figcaption>
</figure>
<figure>
<img src="https://picsum.photos/id/600/601/300">
<figcaption>
This is the description for the second image
</figcaption>
</figure>
</div>
A different structure and the use of display:contents is surely not what you expected , i hope it brings you to learn something instead your answer. See links to usefull ressources below.
The codepen to play with : https://codepen.io/gc-nomade/pen/EJBmee
about display :
https://css-tricks.com/get-ready-for-display-contents/
The issue is that the only way for elements to participate in the same CSS grid together (or flexbox for that matter) is for them to be siblings. So, in some cases we might be incentivized to forego HTML semantics for the benefit of layout (not great).
One answer to this is display: contents;—a magical new display value that essentially makes the container disappear, making the child elements children of the element the next level up in the DOM.
about figure :
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure
The HTML <figure> (Figure With Optional Caption) element represents self-contained content, potentially with an optional caption, which is specified using the (<figcaption>) element. The figure, its caption, and its contents are referenced as a single unit.
about #supports :
https://developer.mozilla.org/en-US/docs/Web/CSS/#supports
The #supports CSS at-rule lets you specify declarations that depend on a browser's support for one or more specific CSS features. This is called a feature query. The rule may be placed at the top level of your code or nested inside any other conditional group at-rule.
The elements in one column are showing up in the order they appear in your code. You have not created any reason for them to appear in any other order.
You could re-order the HTML so they appear in your preferred order.
Or, here's one CSS method – using grid-template-areas – that may work for you:
.container {
display: grid;
grid-template-columns: 2fr 1fr;
grid-template-areas: "one two"
"three four";
}
.one { grid-area: one; }
.two { grid-area: two; }
.three { grid-area: three; }
.four { grid-area: four; }
img {
height: 100%;
width: 100%;
object-fit: cover;
}
.three {
padding: 20px;
background: wheat;
}
.four {
padding: 20px;
background: gray;
}
#media only screen and (max-width: 900px) {
.container {
display: grid;
grid-template-columns: 1fr;
grid-template-areas: "one"
"three"
"two"
"four";
}
}
<div class="container">
<div class="one">
<img src="https://picsum.photos/id/600/600/300">
</div>
<div class="two">
<img src="https://picsum.photos/id/600/601/300">
</div>
<div class="three">
This is the description for the first image
</div>
<div class="four">
This is the description for the second image
</div>
</div>
I have two lines of text on top of another, each using different font-sizes.
To the left of these text lines, I would like to display an image, automatically scaled in width and height to fit the height of both of these text lines combined, while keeping the original aspect ratio.
I am using css grid trying to achieve this. It does work in chrome, but in firefox, it breaks.
Chrome:
Firefox:
As you can see, firefox fails to properly adjust the image grid area to fit the images size.
How could this be fixed?
The relevant code can be found here:
Jsfiddle: https://jsfiddle.net/5z6grjp2/
.parent {
width: 200px;
display: grid;
border: 1px solid #000;
grid-template-columns: auto 1fr;
grid-template-areas: "image textA" "image textB";
}
.image {
grid-area: image;
height: 100%;
}
.textA {
font-size: 20px;
background-color: #f99;
grid-area: textA;
}
.textB {
font-size: 15px;
background-color: #9f9;
grid-area: textB;
}
<div class="parent">
<img class="image" src="/archer.png">
<div class="textA">Text A</div>
<div class="textB">Text B</div>
</div>
This looks like a bug in Firefox.
The layout renders with the image at its inherent size. The sibling items, sizing to 1fr, don't use the actual remaining space. They use the space available when the image was rendered at its original size. So there's an overlap when the image expands. That's what appears to be happening.
The workaround is to force the image area to expand. A fixed width does this, although I know it may not be what you want.
.parent {
width: 200px;
display: grid;
border: 1px solid #000;
grid-template-columns: auto 1fr;
grid-template-areas: "image textA" "image textB";
}
.image {
grid-area: image;
width: 40px;
height: auto;
}
.textA {
grid-area: textA;
font-size: 20px;
background-color: #f99;
}
.textB {
grid-area: textB;
font-size: 15px;
background-color: #9f9;
}
<div class="parent">
<img class="image" src="http://hordes.io/data/archer.png">
<div class="textA">Text A</div>
<div class="textB">Text B</div>
</div>
jsFiddle demo