I want to convert a page from having tightly-controlled positioning to grid-template. I am able to display the containers in the right places, but I don't know how to properly set grid-template-rows. grid-properties-not-working-on-elements-inside-grid-container hints at an answer, but I don't think my problem involves grandchildren.
I have two fiddles to demonstrate the problem.
The first is the bad example, where the entire page scrolls. I have tried variations of
grid-template-rows: min-content min-content 90%;
but nothing forces my main container to be the only one that scrolls and resizes, even if I play around with the value in the last row. ("min-content" is fine for the first two rows). Here is the CSS for the main container:
main {
overflow: auto;
}
The second is the good example, where the main container scrolls and resizes properly when the browser window size is altered, but I would think that the positioning I applied overrides any benefit gained from using a grid template. Here is the CSS for the main container:
main {
overflow: auto;
position: fixed;
top: 72px;
bottom: 0px;
left: 200px;
right: 0px;
margin-left: 10px;
}
My question:
How do I define the grid-template-rows property while still isolating just the main container in row 3 column 2?
Follow-up: Is there a general resource for grid-templates that I have overlooked and should be reading? I looked at several of the articles SO suggested when I created my original post, but none seemed to address my particular issue.
Scrolling containers is not as hard as it seems, based on this article by Michael X. I studied what he did, and adapted it to use grid templates. Other articles on SO talk about grandparents, parents and children, but with no practical examples.
The solution I found is putting any area you want to scroll in a separate subgrid; one grid will not work for the entire page. For example, if I want to scroll a column in a specific row, that row needs a container with its own grid, and that container needs a subcontainer for the column I want to scroll. The content is a separate tag inside of that.
My original post used a page with full-width header, a full-width navigation bar and another row with a fixed table of contents on the left and scrolling contents on the right.
Here is the HTML, with the first two rows left out for simplicity. It focuses on the row of interest:
<html>
<body>
<div id="grid_container">
...
<div id="body_wrapper">
<div id="toc_wrapper">
</div> <!-- end of toc_wrapper -->
<main>
<article>
...
</article>
</main> <!-- end of main -->
</div> <!-- end of body_wrapper -->
</div> <!-- end of grid_container -->
</body>
</html>
And here is the CSS to make the third column scroll. Note where and how overflow and display:grid are used. Note also that 1fr is for non-specific sizing:
body {
overflow: hidden;
}
#grid_container {
height: 100vh;
width: 100vw;
display: grid;
grid-template-areas:
"pageheader"
"sitenav"
"body"
;
grid-template-columns: 1fr;
grid-template-rows: min-content min-content 1fr;
}
...
#body_wrapper {
grid-area: body;
overflow: hidden;
display: grid;
grid-template-areas:
"toc maincontent"
;
grid-template-columns: 175px 1fr;
}
#toc_wrapper {
grid-area: toc;
}
main {
grid-area: maincontent;
overflow-y: scroll;
}
Related
Pointless but required details:
I could build the software myself as its open source but its server software so i don,t want to
This relates to a self made CSS theme, tho there might be a alternate solution i don't want it
I am open to other solutions that acomplish the same thing and is pure css and is in the same ish scope, unlikely tho they may be.
Actual problem:
create a grid filled with columns of element width spanning 150% of screen or document width
Important info:
I DO NOT have access to the JS or HTML
Element size is determined by code that i don't have access to
Each element is the same size WITCH I DO NOT HAVE see above
I DO want it to overflow to the right of the page that's kinda the point
.homePage .itemsContainer {
display: grid;
grid-template-columns: repeat(calc(100vw/max-content),1fr); /* this is the relevant line */
grid-auto-rows: auto;
}
Attempted:
flex: 1 dimensional it simply wont do
grid: auto minmax calc min-content max-content fill-content fit-content fr vw % none of witch worked
obviously tried several sources for a solution but no dice.
calc could in theory work, unfortunately it wont work with min/max-content
new info:
parent is a emby-scroller
itemContainer is a emby-itemContainer
The program in question is jellyfin
when set to grid-template-columns: repeat(auto-fill,auto); a single column is created covering the entire thing. repeat(auto-fill,min-width);
same result, probly since min-width:150%; to ensure container size
current closest to solution:
.homePage .emby-scroller {
margin-right: 0;
}
.homePage .itemsContainer {
display: grid;
grid-template-columns: repeat(auto-fill,20em);
grid-auto-rows: auto;
min-width:150%;
}
issues:
item container always 150% even with no items
different containers with different objects are all the same size, in this case 20em aka 20*font is used witch means font is same size and unrelated to object.
.homePage .itemsContainer {
display: grid;
grid-template-columns: repeat( auto-fit, minmax(idealsizehere, 1fr) );
grid-auto-rows: auto;
}
Just set the width to 150% then put whatever you want in there.
div {
height: 200px;
width: 150%;
outline: 2px dashed blue;
}
<div>
</div>
"How can I pin the footer to the bottom of the page"
I've been in a sticky situation with footers many times and I always end up with a different result.
What's the simplest way to have a sticky footer using CSS Flexbox?
I want this:
To look like this:
If a web page has a <header>, <main> and a <footer> all inside of the <body>:
body {
min-height: 100vh;
display: flex;
flex-direction: column;
}
footer {
background: grey;
margin-top: auto;
}
Making the body flex column allows all items within to be stacked, the margin-top: auto is the magic piece here. It automatically fills any white space with a margin.
Credit goes to Stephanie Eckles: https://moderncss.dev/keep-the-footer-at-the-bottom-flexbox-vs-grid/
I have a few pages with not a lot of content. The whole website is styled with a grid layout - basic header, main and footer:
The goal is to set the footer onto the bottom of the screen with a whitespace from the content, if there isn't a lot going on on the page like this:
For demonstration purposes I used margin-bottom of 50vh on this page.
But if, for example a blog post is bigger than 100vh, the footer should still appear on the bottom - without the whitespace of course:
The user needs to scroll to see the footer on the bottom of the page.
What's a "best practise"-way of achieving this behaviour (preferred without JS(?))?
Some code for those who might want to have a look into the structure of the webpage:
/* inside this class the content is wrapped into the grid layout */
.container {
display: grid;
grid-template-areas:
"header header header header header"
". recent-posts recent-posts recent-posts ."
"footer footer footer footer footer";
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 10px;
}
/* setting header, main and footer as grid layout */
header {
grid-area: header;
border-bottom: 1px solid;
border-radius: 4px;
margin-bottom: 2vh;
}
main {
grid-area: recent-posts;
}
footer {
grid-area: footer;
margin-top: 1vh;
padding: 0.2vh;
border: 1px solid;
border-radius: 4px;
}
If someone wants to have a look into the whole code, I publish the source code on my GitLab.
I got around with a solution which might help someone else in the future:
Inside the .container class I added:
.container {
[…]
/* this forces the footer to stay at the bottom even if the content doesn't fill up the page */
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
where grid-template-rows equals the amount of rows of the grid layout.
I edited the CSS-file to remove padding around the whole grid-layout which made the page a tiny bit bigger than 100vh and added a scrollbar this way.
Instead I added a margin to the header and footer itself:
footer on low-content pages
footer with more content
On mobile you may need to scroll to see the content due to the URL bar:
landing on mobile startpage
scroll on mobile to see 100vh
I mark this question as solved as this solution does exactly what I want; still, if someone knows a better way, please write an answer!
So this will be how if we use flexbox in this case.
section will act as a container to the whole data except the header and footer. Since the section is defined as flex:1, it will take the entire space except for the header and footer.
In this way, if the content gets overflowed in section, the footer will be pusher further down too. You don't have to worry about any such scenarios.
main {
display: flex;
flex-direction: column;
height: 100vh;
}
header, section, footer {
border: 1px solid #ddd;
padding: 10px;
}
section {
flex: 1;
}
<main>
<header>
Something
</header>
<section class="container">Another thing</section>
<footer>
Footer
</footer>
</main>
I have two full width rows. The first one has top and bottom padding so that it has a height. The other must be full height minus the height of the first one.
I used CSS grid layout (even if I have only one column, I don't want to make use of the flexbox layout, for personal reasons):
.main {
display: grid;
grid-template-rows: auto 1fr;
grid-template-columns: 100%;
grid-template-areas:
'menu'
'section_1';
}
.menu {
grid-area: menu;
}
.section_1 {
grid-area: section_1;
}
I would want to replace 1fr by something that would allow my second row, named section_1, to be full height minus menu's height without using calc(100vh - <menu_height>). Is it possible? I've tried 1fr but it doesn't work for this purpose of course.
to complete comment untill clarification:
fr means fraction , so you need to set the ratio of fractions of both elements, js will help you here ... but if you don't set any row template it will do without. Can you clarify the use with a snippet with enough code to demonstrate your issue . If you set an height on .main, it will also do the job
are you looking for this :
body {
margin: 0;
}
main {
height: 100vh;/* missing in your code */
display: grid;
grid-template-rows: auto 1fr;
grid-template-columns: 100%;
grid-template-areas: 'menu' 'section_1';
}
nav {
grid-area: menu;
}
section {
background: #bee;
grid-area: section_1;
}
<main>
<nav> a nav</nav>
<section> a section </section>
</main>
Struggling to find the right title that isn't just a mixture of "help" and "what, CSS, why?!" so hopefully a couple of you geniuses will find this...!
I have two columns. Each of them has a full-width div inside it which contains a logo. The images are quite different shapes, one being a square and one being a more panoramic aspect ratio. To achieve a balanced look, the images are set to a max-width of 50% and a max-height of 100%. Flexbox is used to center the images both horizontally and vertically.
They look perfectly fine.
// working before wrapping images with links
section.working {
div.flex {
display: flex;
justify-content: center;
align-items: center;
img {
max-width: 50%;
max-height: 100%;
}
}
}
And then I needed to add links.
https://codepen.io/lenoz/pen/VwZyeOG
This is the problem reduced to its most simple, in that the bottom row was the original code I was using to get the perfect layout, and the top row shows what happens when the images were wrapped in tags to make them links. Some points of note:
colours added just to help distinguish boundaries a little - useful for detecting when the link (red background) is no longer constricted to the size of the image inside it (as it ideally should be)
the two columns are separate in the code and not part of a shared container - i.e. one cannot inform the height of the other (want to fix this with CSS not JS)
I should mention that of course there was no way adding links would just work - the <a> tags come in between the flex container and the flex item, so obviously they will mess with the layout.
Much appreciated if you can help me find a CSS solution.
Still here? Read on if you want some more info on my attempts to fix, with a side portion of Chrome weirdness.
It should also go without saying I've spent ages fiddling with this, so here's another link showing some of my efforts that have gotten close: https://codepen.io/lenoz/pen/pozpjVq
The top row (section.help) is my latest attempt, but is a bit of a mess simply because I stopped half way, having suffered frustration sufficient to lead to me making this post.
The middle row, which I'm calling section.weirdness, actually seemed to be a solution for a hot minute. If you're using Chrome, like I am, when you look at the Codepen link you may see nothing on these blue blocks?
But try removing the display: flex attribute from div.flex and, if your Chrome is like my Chrome, you'll see this:
Now, add that same display: flex attribute back on the same div.flex selector and you'll see that suddenly the blue blocks are not blank:
How strange is that? Browser rendering bug or what?
Now find the max-width or max-height attributes on div.image, toggle one of those off and then on again and you'll see that everything suddenly looks right again:
Somehow, without changing any CSS other than toggling it, we've gone from no links showing up at all, to them showing up and looking perfect. You can see how I'd managed to confuse myself into thinking I had got it working!
Just add style="display: contents" to your anchors
"display: contents" causes an element's children to appear as if they were direct children of the element's parent, ignoring the element itself
<div>
<a style="display: contents" href="#">
<img src="https://via.placeholder.com/1000x300.png" />
</a>
</div>
Here's a simple solution:
I've changed the columns to be flex contexts but retained an inner div to serve as the 50% width constraint. When the imgs are allowed to set their own height explicitly all the other constraints around them flow into place without much fuss, and because the anchors don't have any layout rules, they manage to avoid having any clickable areas outside their image.
With the same max-height on the images, they'll match in the same way as your .working class as long as their containers are the same width.
section {
width: 800px;
display: flex;
}
.column {
background-color: blue;
margin: 5px;
width: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.column > div {
max-width: 50%;
}
img {
display: block; /* get rid of bottom gap */
max-width: 100%;
max-height: 80px;
}
<section>
<div class="column">
<div>
<a href="#">
<img src="https://via.placeholder.com/500x500.png" />
</a>
</div>
</div>
<div class="column">
<div>
<a href="#">
<img src="https://via.placeholder.com/1000x300.png" />
</a>
</div>
</div>
</section>
Try adding this to your Codepen example:
.flex > a {
flex: 0 0 50%;
height: 100%;
display: flex;
}
div.flex a > img {
max-width: 100% !important;
max-height: 100% !important;
margin: auto;
}
Any immediate child of a container with display: flex is flex item. To prevent that item from growing or shrinking we must set flex-grow and flex-shrink properties to 0. In my case I used flex: 0 0 50% shorthand for that. That last value of 50% is from your initial image max-width property. That + height:100% will make sure that <a> behaves like images in your original example.
Now the fun part: use display: flex again on <a> to make the image flex item again. Since <a> is already properly sized we can set max-width and max-height to `00% to fill available space.
Using margin: auto is a neat trick to center both horizontally and vertically flex child inside of flex container (works only when there is one child).
sidenote: I used important to override specificity without changing markup but I would advise against it and put new CSS class on both a and img.
UPDATE
working fork (Chrome only): https://codepen.io/teodragovic/pen/wvwpWbx?editors=1100
section.broken {
.flex {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
a {
max-width: 50%;
max-height: 100%;
}
img {
max-width: 100%;
max-height: 100%;
display: block;
}
}