Centering an image in CSS grid - html

I am trying to fix my grid layout.
Firstly, the image should be at the center of .container. I tried using align-self: center;, but that did not work.
The headers and paragraph are really messed up. Before this, the paragraph was pushing down the image so I thought if I gave both of them (and the headers) custom grid-row value, they'd be fixed, but instead, I have all of these elements overlap each other. I need them to be ordered correctly. The paragraph under H3 and H3 below H1.
.container {
display: grid;
grid-template-columns: auto auto auto;
grid-template-rows: 100%;
}
.container img {
grid-column: 1 / 2;
grid-row: 1;
}
.container h1,
h3 {
grid-column: 3;
grid-row: 1;
line-height: 0.35;
}
.container p {
grid-column: 3;
grid-row: 1;
width: 350px;
}
<div class="container">
<h1>-[IFwsI]- Jail</h1>
<h3>More than 40 000 registered players</h3>
<p>The most active, and one of the most successful servers. Jail has a set of rules players need to follow and enjoy the roleplay of inmates vs. CTs scenario</p>
<img src="https://i.imgur.com/epqMIJv.jpg" height="418" width="740" />
</div>

Create columns for the text and image to make it easier to manage the columns.
Take a look at grid-template-columns you can control the widths of each column in myriad ways. I have just set them to 33% width;
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
justify-content: center puts the columns in the horizontal center.
align-items: center aligns the items vertically.
To change the order I've created a new class .column--left with grid-row: 1 to put move it to the first column.
.container {
display: grid;
grid-template-columns: 33% 33%;
justify-content: center;
align-items: center;
grid-gap: 10px;
height: 100vh;
}
.column.column--left {
grid-row: 1;
}
img {
max-width: 100%;
height: auto;
}
<div class="container">
<div class="column">
<h1>-[IFwsI]- Jail</h1>
<h3>More than 40 000 registered players</h3>
<p>The most active, and one of the most successful servers. Jail has a set of rules players need to follow and enjoy the roleplay of inmates vs. CTs scenario</p>
</div>
<div class="column column--left">
<img src="https://i.imgur.com/epqMIJv.jpg" height="418" width="740" />
</div>
</div>

...but instead, I have all of these elements overlap each other.
In your code, you are specifically telling them to overlap each other.
.container h1, h3 {
grid-column: 3;
grid-row: 1;
line-height: 0.35;
}
.container p {
grid-column: 3;
grid-row: 1;
width: 350px;
}
The h1, h3 and p are all placed in column 3, row 1. Why wouldn't they overlap?
Here's another approach that may be useful to you:
.container {
display: grid;
height: 100vh;
align-items: center;
grid-column-gap: 20px;
grid-template-columns: 1fr 2fr 2fr 1fr;
grid-template-areas: " . pic header1 . "
" . pic header3 . "
" . pic ptext . "
" . pic ptext . "
}
.container > h1 { grid-area: header1; }
.container > h3 { grid-area: header3; }
.container > p { grid-area: ptext; }
.container > div { grid-area: pic; }
.container img { width: 100%; object-fit: contain; }
* { margin: 0; }
<div class="container">
<h1>-[IFwsI]- Jail</h1>
<h3>More than 40 000 registered players</h3>
<p>The most active, and one of the most successful servers. Jail has a set of rules players need to follow and enjoy the roleplay of inmates vs. CTs scenario</p>
<div>
<img src="https://i.imgur.com/epqMIJv.jpg" height="418" width="740" />
</div>
</div>
jsFiddle demo
Here's a visualization of the code using Firefox's grid overlay tool.

Related

How can I shrink the height of a flex child to 50% only?

I am trying to have a UI like this :
This is how I have tried doing it :
A div at the top as cover Image
The next div containing two child divs as profile photo & UI details as -
<div>Image Cover photos<div>
<div style="display : flex;">
<div>profile photo</div>
<div>UI Details Card</div>
</div>
Then I'm using the transform : translateY(-50%) to the profile photo div to move 50 percent of the portion on top of the background cover photo.
This, however creates a problem, the UI details remains at the same place(which is ideal), but the baseline has been changed.I want it to have only 50% of the height, so the baseline matches with the profile photo as well, and also UI details wcard will have some text, I do not want it to overlap on the Cover Image background as well(as that of profile photo). How can I achieve this?
One way to solve this problem is to use CSS grid to place everything.
body {
padding: 100px;
}
.card {
height: 300px;
width: 300px;
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-rows: repeat(3, 1fr);
outline: 1px solid;
}
.details {
background-color: blanchedalmond;
grid-area: 3/2/4/3;
}
.photo {
background-color: aquamarine;
grid-area: 2/1/4/2;
}
.cover {
grid-area: 1/1/3/3;
background-color: grey;
}
.cover img,
.photo img {
height: 100%;
width: 100%;
}
<div class="card">
<div class="cover">
<img src="https://source.unsplash.com/random/?1" alt="">
</div>
<div class="photo">
<img src="https://source.unsplash.com/random/" alt="">
</div>
<div class="details">Details here</div>
</div>
Here's a diagram showing the different grid areas :
Notice the overlap region between the blue box (photo) and the red box (cover). Since the photo div appears after the cover div in the DOM, the photo div will have higher priority and will occupy this overlap region.
You can make a 2 column, 3 row grid and place items where you want them.
Here's a simple example:
.container {
display: grid;
grid-template-columns: 1fr 4fr;
grid-template-rows: 1fr 1fr 1fr;
width: 30vw;
height: 20vw;
}
.container :nth-child(1) {
grid-column: 1 / span 2;
grid-row: 1 / span 2;
background: red;
}
.container :nth-child(2) {
grid-column: 1;
grid-row: 2 / span 2;
background: green;
}
.container :nth-child(3) {
background: blue;
}
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
Obviously you will want to alter the relative sizes of the grid to suit your particular case.
Note: it depends on whether you want to put some text in the first item so that it comes directly above the second item or not as to whether you start the first div in the first column or the second column.

Is there really no way to put any element truely anywhere inside grid if I assign the subelement grid-row and grid-column?

I was trying to use the code below, but it did not work. I wanted to use the grid to define the whole webpage layout on every page I make. It seems like it is not that simple, because it seems like the grid accepts only a simpler flow of elements like this one:
The layout that the grid won't accept:
header just row one and column one
"right div element" row 2/3 and column 2/3
that is what I wanted.
I wanted to achieve that with this code:
<html>
<head>
<style>
body,
html {
margin: 0;
height: 100%;
width: 100%;
}
.main {
width: 100%;
height: 100%;
display: grid;
grid-template-rows: 120px 1fr 120px;
grid-template-columns: 200px 1fr auto;
}
.main footer {
grid-column: 1/3;
grid-row-start: 3;
background: #949994;
}
.main .header {
grid-column-start: 1;
grid-row-start: 1;
background: #034f84;
}
.main .right {
grid-row: 1/2;
grid-column: 2/3;
text-align: center;
background-color: aquamarine;
}
</style>
</head>
<body>
<div class="main">
<header>
</header>
<div class="right">
</div>
<footer>
</footer>
</div>
</body>
</html>

I'm trying to center text within each of my grid cells

I'm working on a website and I have 4 grid cells which take up a section of my webpage. The issue is that all of my text is in random places, I want it to be centered within each grid item (one is gray, one is blue, one is black, one is yellow).
I've tried every combination of justify, align, self, any idea how I can do this? Any help would be very much appreciated.
Here's my jsfiddle documenting the problem: https://jsfiddle.net/RomelF/jd8L7a6n/3/
And here's my HTML:
<div class="container">
<section id="welcome-section"><h1 id="name">My name's Romel, here are some of my projects:</h1>
</section>
<section id="projects">
<div class="project-tile" id="p1"><p class="ptext"><a href="#">Tribute Page<a></p></div>
<div class="project-tile" id="p2"><p class="ptext"><a href="#">Political Questionnaire<a></p></div>
<div class="project-tile" id="p3"><p class="ptext"><a href="#">Landing Page<a></p></div>
<div class="project-tile" id="p4"><p class="ptext"><a href="#">Technical Documentation<a></p></div>
</section>
And here's my CSS:
#projects {
width: 70%;
display: grid;
}
...
.project-tile {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
place-items: stretch;
height: 50vh
}
#p1 {
background: rgb(255,253,254);
background: radial-gradient(circle, rgba(255,253,254,1) 0%, rgba(74,75,75,0.4) 100%);
grid-column: 1 / 2;
grid-row: 1 / 2;
}
#p2 {
background-color: black;
grid-column: 1 / 2;
grid-row: 2 / 3;
}
#p3 {
background-color: blue;
grid-column: 2 / 3;
grid-row: 1 / 2;
}
#p4 {
background-color: yellow;
grid-column: 2 / 3;
grid-row: 2 / 3;
}
.project-tile a {
text-decoration: none;
}
.ptext {
align-self: center;
}
your .project-tile doesn't need to be a grid itself. Using flexbox gives you all the tools you need to center an element.
.project-tile {
display: flex;
place-items: center;
height: 50vh;
}
.ptext {
margin: auto
}
This will give you centred text as long as the text fits inside the boundaries of the parent.
Please remove this style
.project-tile{
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}

Change order of grid items on smaller screens

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>

How to make CSS Grid items take up remaining space?

I have a card built with CSS Grid layout. There might be an image to the left, some text to the right top and maybe a button or a link at the right bottom.
In the code below, how can I make the green area take up as much space as possible and at the same time make the blue area take up as little space as possible?
The green should push the blue area down as far as possible.
https://jsfiddle.net/9nxpvs5m/
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas:
"one two"
"one three"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.two {
background: green;
grid-area: two;
}
.three {
background: blue;
grid-area: three;
}
<div class="grid">
<div class="one">
One
</div>
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
Adding grid-template-rows: 1fr min-content; to your .grid will get you exactly what you're after :).
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: 1fr min-content;
grid-template-areas:
"one two"
"one three"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.two {
background: green;
grid-area: two;
}
.three {
background: blue;
grid-area: three;
}
<div class="grid">
<div class="one">
One
</div>
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
Jens edits: For better browser support this can be used instead: grid-template-rows: 1fr auto;, at least in this exact case.
A grid is a series of intersecting rows and columns.
You want the two items in the second column to automatically adjust their row height based on their content height.
That's not how a grid works. Such changes to the row height in the second column would also affect the first column.
If you must use CSS Grid, then what I would do is give the container, let's say, 12 rows, then have items span rows as necessary.
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: repeat(12, 15px);
}
.one {
grid-row: 1 / -1;
background: red;
}
.two {
grid-row: span 10;
background: lightgreen;
}
.three {
grid-row: span 2;
background: aqua;
}
.grid > div {
display: flex;
align-items: center;
justify-content: center;
}
<div class="grid">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
Otherwise, you can try a flexbox solution.
.grid {
display: flex;
flex-flow: column wrap;
height: 200px;
}
.one {
flex: 0 0 100%;
width: 30%;
background: red;
}
.two {
flex: 1 0 1px;
width: 70%;
background: lightgreen;
}
.three {
background: aqua;
}
.grid>div {
display: flex;
align-items: center;
justify-content: center;
}
<div class="grid">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
When using grid, and you have grid template area used, and by chance you gave a particular area a width, you are left with a space grid does automatically.
In this situation, let grid-template-columns be either min-content or max-content, so that it adjusts its position automatically.
A possible approach might be grouping two and three together, and using flexbox:
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas: "one two"
}
.one {
background: red;
grid-area: one;
padding: 50px 0;
}
.wrap {
grid-area: two;
display: flex;
flex-direction: column;
}
.two {
background: green;
flex: 1;
}
.three {
background: blue;
}
<div class="grid">
<div class="one">
One
</div>
<div class="wrap">
<div class="two">
Two
</div>
<div class="three">
Three
</div>
</div>
</div>
Definitely not the most elegant solution and probably not best practice, but you could always add more lines of
"one two"
before the part where you have
"one three"
so it ends up looking like
.grid {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas:
"one two"
"one two"
"one two"
"one three"
}
Again, pretty sure this is just a work around and there's better solutions out there... But this does work, to be fair.
Just use width: 100% and height: 100% in the CSS class of the item you want to fill the grid. Join a max-width property and a max-height property if you don't want a grid item inside a grid container to grow more than some size.