Why is my CSS grid-template-columns stacking and not being consistent - html

So I have these carousel thumbnails that supposedly keep adding to the right until each of them reached the width of 120px and they'll go into the next row. These thumbnails are wrapped by a wrapper which its width fits its content.
HTML:
<div class="carousel-thumbnail-wrapper">
<div class="carousel-thumbnail mod-active">
<img src="./img/project-slider-1.jpg" alt="">
</div>
<div class="carousel-thumbnail">
<img src="./img/project-slider-2.jpg" alt="">
</div>
</div>
CSS:
.cg-carousel > .carousel-thumbnail-wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
column-gap: 8px;
width: fit-content; /** the width fits its content... */
max-width: 100%; /** ...but can only grow not more than 100% of its parent's */
}
.cg-carousel > .carousel-thumbnail-wrapper > .carousel-thumbnail {
box-sizing: border-box;
border-radius: var(--border-radius-xs);
cursor: pointer;
position: relative;
margin-bottom: 8px;
max-width: 200px; /** each thumbnail has maximum 200px width */
}
Normally, if everything goes right it will show like this: Images keep adding to the right
It does work like that sometimes. But when I refresh the page or go to another page back to back, for some reason they're stacking, like this: Images suddenly stacking
What did I do wrong?

So your code isn't wrong per se, but your selectors are a little off, and your images need a width of 100%, otherwise they will not resize - their parent will, but they will still remain their original size. So if you change your selectors so that they actually target the elements in your html, and set the width of the images to 100%, it should work perfectly. The javascript in my other answer makes your code fully fool-proof as it combats any css issues older browsers may face. But if old browsers are not a problem, then use this answer. Below is a snippet. Here is a jsfiddle link if you want to resize the viewport, add images or play with the code in general: https://jsfiddle.net/258b9x6e/1/
.carousel-thumbnail-wrapper {width: 100%}
.carousel-thumbnail-wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
column-gap: 8px;
width: fit-content; /** the width fits its content... */
max-width: 100%; /** ...but can only grow not more than 100% of its parent's */
}
.carousel-thumbnail {
box-sizing: border-box;
border-radius: var(--border-radius-xs);
cursor: pointer;
position: relative;
margin-bottom: 8px;
max-width: 200px; /** each thumbnail has maximum 200px width */
}
img {
width: 100%;
}
<div class="carousel-thumbnail-wrapper">
<div class="carousel-thumbnail mod-active">
<img src="https://via.placeholder.com/200" alt="">
</div>
<div class="carousel-thumbnail">
<img src="https://via.placeholder.com/200" alt="">
</div>
</div>

The following snippet will resize the images, to make them small enough to be able to fit on one row, until they are 120px in width, which is when they will no longer be shrunk, but moved to the next row. This achieves the same results as my other answer, but also works on older browsers, at the expense of having to use JS. My other answer only works on newer browsers but does not need any JS.
Here, I've used 3 imgs but you can use as many as you would like This is also responsive, so you can resize your browser and the images will still fit well.
document.querySelectorAll("img")[document.querySelectorAll("img").length-1].onload = re_calculate_image_width;
function re_calculate_image_width() {
let count = document.querySelectorAll(".img-wrapper").length;
document.querySelector(".outer-wrapper").style.setProperty("--how-many", (count).toString());
}
alert("Important: Read this: \n If you dynamically add more images, you MUST call the ***re_calculate_image_width*** function when the added images have finished ***loading***.");
.outer-wrapper {
width: 100%;
background: rgba(255,255,0,0.6);
--how-many: 5;
}
.img-wrapper {
display: inline-block;
min-width: 120px;
max-width: 200px;
width: calc(90% / var(--how-many));
height: auto;
}
img {
display: inline-block;
margin: 0px;
padding: 0px;
height: 100%;
width: 100%;
box-shadow: 0px 0px 1px 1px #000;
}
<div class="outer-wrapper">
<div class="img-wrapper">
<img src="https://via.placeholder.com/200" alt="">
</div>
<div class="img-wrapper">
<img src="https://via.placeholder.com/200" alt="">
</div>
<div class="img-wrapper">
<img src="https://via.placeholder.com/200" alt="">
</div>
</div>

Related

Grid element height affected by content image width percentage [duplicate]

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.

Align image with border 2 column on mobile

I have images where I want to do 5 columns on the desktop and 2 on the mobile, on the desktop it is working however on the mobile being img-responsive is showing only 1 image at a time and I want to show 2.
I've used hidden-xs but I think it's wrong. Two images are not aligned.
<style>
#tudo {
width: 100%;
}
#media screen and (min-width: 980px) {
#tudu {
margin-right: 50px;
}
#tudo1 {
position: relative;
width: 15%;
margin-left: 4%;
float: left;
border: 2px solid #35c9b1;
max-height: 300px;
}
}
#media screen and (max-width: 500px)
/* Mobile */
{
#tudo1 {
position: relative;
width: 46%;
margin: 2%;
float: left;
border: 2px solid #35c9b1;
}
}
</style>
<div id="tudo" align="left">
<div id="tudo1"><img class="img-responsive" src="https://picsum.photos/200"></div>
<div id="tudo1"><img class="img-responsive" src="https://picsum.photos/150"></div>
<div id="tudo1"><img class="img-responsive" src="https://picsum.photos/140"></div>
<div id="tudo1"><img class="img-responsive" src="https://picsum.photos/130"></div>
<div id="tudo1"><img class="img-responsive" src="https://picsum.photos/120"></div>
</div>
I'm not 100% sure what you would like to achieve, but I highly recommend looking into the CSS Grid Layout. You could use it to get the columns easily. One way would be like this.
#tudo {
display: grid;
width: 100%;
grid-template-columns: repeat(5, 1fr);
grid-column-gap: 10px;
grid-row-gap: 15px;
}
#media only screen and (max-width: 600px) {
#tudo {
grid-template-columns: repeat(2, 1fr);
}
}
With the grid-template-columns, you can specify how many columns you want, and you can also set each column to specific widths. The fr is for fractions, but you can also use e.g percentages and fixed widths in px.
E.g. if you want to have the first item in each row fixed and rest take up the available space, you can do the following:
grid-template-columns: 300px repeat(4, 1fr);
With this, the first item in each row will be fixed to 300px and the rest will take up 1/4 of available space.
See more here:
https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns
With grid-column-gap and grid-row-gap you can set the space between the rows and columns.
See this guide here for more info on CSS grid
https://css-tricks.com/snippets/css/complete-guide-grid/
In mobile styling you should decrease #tudo1 width 4px because of 2px left and 2px right border. You can use calc(46% - 4px)
Does this show the behaviour you're looking for?
Use padding instead of margin for spacing
Use box-sizing: border-box to avoid box-model width gotchas with borders and padding
Use max-width: 100% on images so they don't overflow the size of the container
Use inline-block + whitespace fix instead of float but that's up to you, if you use floats you need a clearfix on #tudo!
Do not use ID's multiple times, use classes instead.
Have main styles not wrapped in a media query, either go mobile first (e.g. your global styles are for mobile) or go desktop first and change your stuff for smaller screens selectively (used in below example based on your code)
Of course you could achieve the same thing with flexbox or css-grids, but I tried to stay close to what you provided as code-input.
* {
box-sizing: border-box;
}
#tudo {
font-size: 0;
width: 100%;
}
.tudo1 {
font-size: initial;
display: inline-block;
max-height: 300px;
padding: 4%;
position: relative;
width: 20%;
}
.tudo1 img {
border: 2px solid #35c9b1;
display: block;
max-width: 100%;
}
#media screen and (max-width: 500px)
/* Mobile */
{
.tudo1 {
width: 50%;
padding: 2%;
}
}
<div id="tudo" align="left">
<div class="tudo1"><img class="img-responsive" src="https://via.placeholder.com/300x300"></div>
<div class="tudo1"><img class="img-responsive" src="https://via.placeholder.com/300x300"></div>
<div class="tudo1"><img class="img-responsive" src="https://via.placeholder.com/300x300"></div>
<div class="tudo1"><img class="img-responsive" src="https://via.placeholder.com/300x300"></div>
<div class="tudo1"><img class="img-responsive" src="https://via.placeholder.com/300x300"></div>
</div>

Creating a resizable and scalable image grid using flexbox

I am trying to make a resizable/scalable image grid using FlexBox.
The problem is that whenever the image's proportions are too thin due to resizing the window, the FlexBox will place additional images on previous rows to fill out the space.
It looks good under some window proportions. But, if the window is too short in height and too long in width, then images from lower rows will move to upper rows.
I have tried using flexboxes and tables. When using FlexBox, I have also tried to set the width of flex items using the flex property for images. The issue with this is that images will stretch and distort in order to fill up the required space.
Here is code that I am working with:
html, body {
height: 100%;
width: 100%;
margin: 0;
}
#flex-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
background-color: blue;
height: 100%;
}
#flex-container>img {
width: auto;
height: auto;
max-width: 25%;
max-height: 50%;
margin: auto;
}
<div id="flex-container">
<img src="https://via.placeholder.com/150C/O https://placeholder.com/">
<img src="https://via.placeholder.com/150C/O https://placeholder.com/">
<img src="https://via.placeholder.com/150C/O https://placeholder.com/">
<img src="https://via.placeholder.com/150C/O https://placeholder.com/">
<img src="https://via.placeholder.com/150C/O https://placeholder.com/">
<img src="https://via.placeholder.com/150C/O https://placeholder.com/">
<img src="https://via.placeholder.com/150C/O https://placeholder.com/">
<img src="https://via.placeholder.com/150C/O https://placeholder.com/">
</div>
I want to make the images stay on the same row and column, only resizing themselves in accordance to how large the page is.
I don't need to use FlexBox, but it seems to be the best way to accomplish this task.
Flexbox is a good choice for this layout but there are some tricky side effects when images are the flex items. In order to make this more straightforward, I find it very helpful to put the images inside wrapper divs.
Control the number of items per row now with the width, you can use media queries to change the width as the screen gets smaller but you will need to reconsider the 100% fixed height of the container at that point.
I have put comments in the CSS to highlight the important bits.
* {
box-sizing: border-box; /* so borders and padding dont get in the way */
}
html,
body {
height: 100%; /* you didint need width 100% here */
margin: 0;
}
#flex-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
background-color: blue;
height: 100%;
}
.img-wrap {
width: 25%;
height: 50%;
display: flex; /* flexbox layout for the image wrappers, allows for... */
align-items: center; /* ...easy centering */
justify-content: center;
padding: 10px; /* just some spacing so the images can breathe, remove if you want them edge to edge */
border: 1px solid red; /* so you can easily see the bounds of the wrapper divs, remove this */
}
.img-wrap img {
max-width: 100%; /* max dimensions on the images so they always fit */
max-height: 100%;
height: auto; /* maintain aspect ratio */
width: auto;
}
<div id="flex-container">
<div class="img-wrap"><img src="https://picsum.photos/200"></div>
<div class="img-wrap"><img src="https://picsum.photos/300/200"></div>
<div class="img-wrap"><img src="https://picsum.photos/400/800"></div>
<div class="img-wrap"><img src="https://picsum.photos/500/250"></div>
<div class="img-wrap"><img src="https://picsum.photos/450/505"></div>
<div class="img-wrap"><img src="https://picsum.photos/350/520"></div>
<div class="img-wrap"><img src="https://picsum.photos/250/300"></div>
<div class="img-wrap"><img src="https://picsum.photos/550/200"></div>
</div>

How do I scale the height of a div the same way that a div with an image does?

I have 2 divs that are floated next to each other. In one of the divs I have an image that scales (both it´s height and width) when I decrease the size of the browser window. In the other div I have some other content, but this is only being scaled in width when I decrease the size of the browser window. I want both of the divs to have the same height at all times, even when they are being scaled. Is this possible?
If you want a live preview, please check out this link:
http://jjberg.com/cipher/index.html
I know part of the problem is that I´ve actually set a height of 500px to the cipherSide div. This is because so far I haven´t been able to make the height of this div closer to the height of the pinupSide div in any other way.
I tried to copy the declarations from the pinupSide and pinUpGirl to the cipherSide and verticalAlign divs, but to no avail. This only pushed the content in the cipherSide div all the way to the top.
<div class="container">
<div class="pinupSide">
<img class="pinUpGirl" src="images/pin_up_edited_x2.png" alt="Pin up girl">
</div>
<div class="cipherSide">
<div class="verticalAlign">
<h1> Dirty Diana </h1>
<p>Dirty Diana wants to send dirty love messages to her husband, but she does not want Big Brother to know about it. Try out the tool I made for her!</p>
<textarea rows="10" placeholder="Insert the text you want to cipher or decipher here!" required></textarea>
<button id="cipherIT">Cipher It!</button>
<button id="deCipher">Decipher!</button>
<p id="newOne"></p>
</div><!-- verticalAlign -->
</div><!-- cipherSide -->
</div><!-- container -->
.container {
max-width: 992px;
height: 100%;
margin: 0 auto;
background: blue;
}
.pinupSide {
background: green;
width: 50%;
height: 100%;
float: left;
}
.pinUpGirl {
max-width: 100%;
max-height: 100%;
background: black;
}
.cipherSide {
position: relative;
background: red;
width: 50%;
height: 500px;
float: left;
}
.verticalAlign {
position: absolute;
top: 25%;
height: 50%;
width: 100%;
background: yellow;
}
I want both of the divs to have the same height at all times, no matter how I´m scaling the width of the browser window.
Considering you code I assume you want the two elements to have the same height but also the same width at all time. I also assume you want the image to be as big as possible inside the left element without being distorted. Is that right?
If you can use CSS Grid, you can achieve that layout with a grid made up of two columns of each 1fr, which represent one fraction of the available space. See the following code:
The <img> element has its width set to 100% so that it is as big as possible inside its parent element, and its parent element has the font-size set to 0 to remove an unwanted space below the image.
body {
margin: 0;
background-color: #3ff4fe;
}
.container {
max-width: 992px;
margin: auto;
display: grid;
grid-template-columns: 1fr 1fr;
}
.image {
background-color: black;
font-size: 0;
}
.image img {
width: 100%;
}
.text {
background-color: red;
}
<div class="container">
<div class="image">
<img src="http://jjberg.com/cipher/images/pin_up_edited_x2.png" alt="Pin up girl">
</div>
<div class="text">
Some text
</div>
</div>
Does this help?
I second the use of grid like Auguste said. You could also use flex-box instead of floats and absolute positioning. Here is one possible implementation.
You'll probably have to play with object-fit on the image. Or just set the background of the pinup side to be the image and change the positioning through background properties. Either way it should work out.
You can also set hard heights and widths if you want to and just you the flex-box for positioning.
If you run the code snippet be sure to view it full screen because it uses view-port units for the height of the container.
* {
box-sizing: border-box;
}
.container {
padding: 2rem;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.pinupSide,
.cipherSide {
flex: 1 1;
height: 100%;
display: flex;
justify-content: center;
flex-direction: column;
}
.pinupSide {
align-items: center;
background: rgba(0,0,0,.6);
}
.pinUpGirl {
width: 100%;
object-fit: cover;
object-position: 50% 50%;
}
.cipherSide {
align-items: flex-start;
background: rgba(231, 76, 60, 1)
}
.heading-group {
background: rgba(241, 196, 15, 1);
}
textarea {
width: 100%;
}
.button-group {
width: 100%;
}
<div class="container">
<div class="pinupSide">
<img class="pinUpGirl" src="https://images.unsplash.com/photo-1530650819615-f14c8a735dd8?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1055&q=80" alt="Pin up girl">
</div>
<div class="cipherSide">
<div class="heading-group">
<h1> Dirty Diana </h1>
<p>Dirty Diana wants to send dirty love messages to her husband, but she does not want Big Brother to know about it. Try out the tool I made for her!</p>
</div>
<textarea rows="10" placeholder="Insert the text you want to cipher or decipher here!" required></textarea>
<div class="button-group">
<button id="cipherIT">Cipher It!</button>
<button id="deCipher">Decipher!</button>
</div>
<p id="newOne"></p>
</div><!-- cipherSide -->
</div><!-- container -->

CSS Grid template with image breaks Firefox

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