I am programming a quantity selector button and want it to be responsive. That is, I want the minus and plus to contain only as much width as the icons need and the input in the middle to be the maximum width.
I am wondering how to approach this using scss.
HTML:
<div class="quantity-select-container">
<div class="btn btn-minus">
<span class="icon icon-minus">
</span>
</div>
<input value="1" type="number" min="1" max="100" step="1" pattern="[0-9]*" class="form-control product-detail-quantity-select">
<div class="btn btn-plus">
<span class="icon icon-plus"></span>
</div>
</div>
SCSS:
.quantity-select-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr;
gap: 0 0;
border: 1px solid black;
grid-auto-flow: row;
grid-template-areas: "minus input plus";
.btn-minus {
grid-area: minus;
}
input {
text-align: center;
grid-area: input;
padding: 2px;
width: 100%;
}
.btn-plus {
grid-area: plus;
}
.btn-minus,
.btn-plus {
cursor: pointer;
display: flex;
justify-content: center;
}
}
grid-template-columns: 45px auto 45px;
can solve this problem, but not effectively because with a narrow screen the buttons overlap and obscure the input, therefore it works with large screens while in doesn't on tiny screens
min-content with clamp are your best friends when it comes to fitting some boxes to its smallest width possible on small screens while maintaining a reasonable width when there's enough space on screen
#grid{
grid-template-columns: min-content 1fr min-content;
display: grid;
font-size:25px;
}
#grid > *{
display: flex;
justify-content:center;
padding-block: 5px;
}
.to-shrink{
background:red;
padding-inline: clamp(2px, 3vw, 30px);
}
<div id="grid">
<div class="to-shrink">smol</div>
<div>bigg</div>
<div class="to-shrink">smol</div>
</div>
For a better illustration what does this combo do, check the gif below and notice how paddings are changing due to clamp:
To go further, you can also apply clamp to the font or, in your case, size of the icon itself, while still keeping min-content on grid layout
Related
The issue
The last column/padding in a grid disappears when overflow is present. We initially attempted to use padding on our grid. Looking into this question, we were able to confirm that it's not just us facing this challenge.
Unfortunately, the way our app is structured, we're unable to use the suggestions made by some of the answers to that question:
Right border: really more of a hack than a solution, does not work for us.
Pseudo-elements: same as above
What we have
We figured, why not try to place our grid inside another grid and "fake" the padding by making the container grid contain surrounding rows/columns to mimic padding?
It works well to ensure items are of correct width across multiple screen sizes:
3 columns, 2 rows on larger screens
2 columns, 3 rows on medium screens
1 column, 6 rows on smaller screens
It fails again, however, to maintain the last column/row in the grid even though it's specified in pixels. To see this effect, you will need to resize the screen (make it smaller) to show the overflow appear and the last column disappear.
html, body {
margin: 0px !important;
}
.gallery {
position: relative;
display: grid;
grid-template-columns: 22px [main] 1fr 22px;
grid-template-rows: 22px [main] 1fr 22px;
box-sizing: border-box;
align-items: stretch;
justify-items: stretch;
height: 100vh;
width: 100vw;
overflow: auto;
}
.visuals {
position: relative;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(32%, 1fr));
grid-area: main;
align-items: stretch;
justify-items: stretch;
width: 100%;
height: 100%;
gap: 22px;
}
.content {
width: 100%;
height: 100%;
background-color: #444;
color: white;
white-space: nowrap;
}
#media only screen and (max-width: 858px) {
.visuals {
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
}
<div class="gallery">
<div class="visuals">
<div class="content">I have some content here that shouldn't be cut off.</div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
</div>
</div>
Our confusion
According to the documentation:
The new fr unit represents a fraction of the available space in the
grid container.
So I would assume here that the explicitly defined 22px row/column would maintain its size and that 1fr would resize according to the remaining space. The last 22px row/column disappears altogether once the overflow appears.
The question
So, how can we ensure that the last column/row in a grid layout remains visible after the scrollbar appears?
Your problem is not that the outer grid isn't working ok.
The second column is dimensioned ok, but the content overflows it.
I have added overflow hidden in the snippet, and as afar as I can tell, it's working
html, body {
margin: 0px !important;
}
.gallery {
position: relative;
display: grid;
grid-template-columns: 22px [main] 1fr 22px;
grid-template-rows: 22px [main] 1fr 22px;
box-sizing: border-box;
align-items: stretch;
justify-items: stretch;
height: 100vh;
width: 300px;
overflow: auto;
box-shadow: inset 0px 0px 0px 22px red;
}
.visuals {
position: relative;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(32%, 1fr));
grid-area: main;
align-items: stretch;
justify-items: stretch;
width: 100%;
height: 100%;
gap: 22px;
opacity: 0.6;
}
.content {
width: 100%;
height: 100%;
background-color: lightgreen;
white-space: nowrap;
}
#media only screen and (max-width: 858px) {
.visuals {
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
}
<div class="gallery">
<div class="visuals">
<div class="content">this is a long sentence that won't wrap and overflow</div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
<div class="content"></div>
</div>
</div>
What it should do:
1 fr is an image of a product, 1fr is a description of the product (positioned on the right side of the image). the whole grid should be centered in the middle but it isnt. It centers but it leaves a huge gap between them.
HTML:
<div class="grid">
<img src="../images/s6.png" alt="photo of the item">
<div class="text">
<h1 class=>V.2</h1>
<h4>$54.00</h4>
<ul>
<li>Biquíni truangular com detalhes franzidos a lilás</li>
<li>Detalhes metálicos dourados</li>
<li>Alças ajustáveis</li>
<li>Cintura subida reversível</li>
<li>Opçāo de colocar copa</li>
</ul>
</div>
</div>
CSS:
.grid img{
width: 450px;
height: 450px;
border: solid 1px rgb(235, 235, 235);
border-radius: 3%;
padding: 6px;
}
.grid{
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
justify-items: center;
}
Both your img and div are equal width maintaining the correct gap between them. Your div's contents need to be justified left if you want to close that gap.
.text {
justify-self: start;
}
Here is some more information: https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self
Why does this:
div {
width: 200px;
display: grid;
grid: "first second" / 1fr 1fr;
background-color: #ccc;
padding: 8px;
}
#first {
grid-area: first;
}
#second {
grid-area: second;
}
<div>
<input id="first" />
<input id="second" />
</div>
Behave differently from this:
div {
width: 200px;
display: grid;
grid: "first first second second" / 1fr 1fr 1fr 1fr;
background-color: #ccc;
padding: 8px;
}
#first {
grid-area: first;
}
#second {
grid-area: second;
}
<div>
<input id="first" />
<input id="second" />
</div>
Note that the only thing I changed was the number of columns and the area each input occupies.
This is an issue with the spec and how 1fr is intepreted.
From a W3C bug/issue report
The "problem" is that 1fr resolves to minmax(auto, 1fr) and this means that we need to know the size of (the parent) before resolving the size of the 1fr track (because the min track sizing function is content sized, it's auto).
There is a quick solution to this issue from the author POV, just replacing 1fr by minmax(0px, 1fr) for example.
..or in this case just setting min-width:0 to the child elements.
I think its a rendering issue casued by the default width set by the browser for the inputs. Its fixed by adding 100% width for the inputs and setting up the border-box box model.
div {
width: 200px;
display: grid;
grid: "first second" / 1fr 1fr;
background-color: #ccc;
padding: 8px;
}
#first {
grid-area: first;
}
#second {
grid-area: second;
}
input {
width: 100%;
}
* {
box-sizing: border-box;
}
<div>
<input id="first" />
<input id="second" />
</div>
Note that this problem is not really a CSS Grid issue. It's more a matter related to input elements.
Here's your code, using input elements:
div {
display: grid;
width: 200px;
background-color: #ccc;
padding: 8px;
}
div[one] {
grid: "first second" / 1fr 1fr;
}
div[two] {
grid: "first first second second" / 1fr 1fr 1fr 1fr;
}
#first {
grid-area: first;
}
#second {
grid-area: second;
}
<div one>
<input id="first" />
<input id="second" />
</div>
<hr>
<div two>
<input id="first" />
<input id="second" />
</div>
There's a difference in the two layouts.
Now here's your code using section elements instead of inputs:
article {
display: grid;
width: 200px;
background-color: #ccc;
}
article[one] {
grid: "first second" / 1fr 1fr;
}
article[two] {
grid: "first first second second" / 1fr 1fr 1fr 1fr;
}
#first {
grid-area: first;
height: 25px;
background-color: green;
}
#second {
grid-area: second;
height: 25px;
background-color: red;
}
<article one>
<section id="first"></section>
<section id="second"></section>
</article>
<hr>
<article two>
<section id="first"></section>
<section id="second"></section>
</article>
There's no difference.
This essentially boils down to the intrinsic width of input elements, which is a standard feature in most browsers. The issue is discussed in more detail here:
input / button elements not shrinking in a flex container
The simple way to disable this feature is by:
overriding the default min-width: auto on grid items by adding min-width: 0 (explanation) or,
by switching from 1fr (which represents minmax(auto, 1fr)) to minmax(0px, 1fr).
There are lots of similar questions, I have reviewed all of them, but none solved my problem.
Premises:
I have a flexbox layout with flex column and the bottom flex-item filling the remainder of the page height. The flex-item gets stretched to the remainder of the page by flex 1.
Goal:
I need my grid (with its children) inside this flex-item to expand to the height of the flex-item.
Problem:
The html wrapper only has a min-height 100vh set. This makes the grid stretch to the flex-item, but not its children!
The only solution I can find is to also set height 100vh on the html wrapper, but I do not want to do this. Is there any way to solve my problem without setting height?
See the codepen here:
https://codepen.io/mesqueeb/pen/aGeKjm
See the animated GIF here to show you what I mean:
You can try this.
remove the flex-direction: column; in the .remaining and it will expand the height.
main{
min-height: calc(100vh - 51px);
display: flex;
flex-direction: column;
}
div{
border: solid goldenrod thick;
padding: 2px;
margin: 2px;
}
.full-page{
display: flex;
flex-direction: column;
height: 100%;
flex: 1;
}
.top-row{
height: 100px;
}
.remaining{
flex: 1;
display: flex;
}
.grid{
border: solid teal thick;
flex: 1;
display: grid;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
}
.key{
border: thin green solid
}
.small{
font-size: .8em
}
<main>
<div class="full-page">
<div class="top-row">
grid below will take full height only if body height is set...
</div>
<div class="remaining">
<div class="grid">
<div class="key">1</div>
<div class="key">2</div>
<div class="key">3</div>
<div class="key">4</div>
<div class="key">5</div>
<div class="key">6</div>
<div class="key">7</div>
<div class="key">8</div>
<div class="key">9</div>
<div class="key">C</div>
<div class="key">0</div>
<div class="key">➕</div>
</div>
</div>
</div>
</main>
Not sure if it solves your problem in the best way, but this works:
.remaining {
flex: 1;
/* display: flex; */
flex-direction: column;
position: relative;
}
.grid {
border: solid #008080 thick;
/* flex: 1; */
display: grid;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
I have a nav at the top of my page.
In it I have 5 market stocks for 5 different companies. I want to display the 5 at full width but as the window gets smaller, I basically want behavior which will cut off the ones that overflow, and resize the remaining ones to fill up the nav container (so let's say at some point it would only show 3 of the stocks and hide the others). Here is the code right now:
.stocks-container {
display: grid;
grid-template-columns: repeat(auto-fit, 150px);
grid-template-rows:1fr;
grid-auto-rows: 0;
overflow-y: hidden;
justify-content: space-between;
width: 75%;
font-size: 11px;
overflow-y: hidden;
}
What this does currently is almost what I need. The problem is that now the stock items that overflow, and should basically create a new row, get mushed on top of the first row. Again, I don't want them to create a new row, or be scrollable. I just don't want them to be showing at all. Any ideas?
You can use CSS max-height and #media queries to achieve this effect:
Give the .stocks-container a max-height which corresponds with the height of a single grid row and declare overflow: hidden
This ensures that there will now only ever be a single row visible (ie. no vertical wrapping of rows).
Now add a short series of break-point media queries to reset grid-template-columns as percentages of the viewport width.
This enables those grid boxes which are still visible to fill the entire horizontal width reserved for the .stocks-container.
Working Example:
.stocks-container {
display: grid;
grid-template-columns: repeat(5, calc(20% - 6px));
grid-template-rows: 92px;
grid-column-gap: 6px;
grid-row-gap: 6px;
max-height: 92px;
font-size: 11px;
overflow: hidden;
}
.stocks-container div {
height: 80px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
#media only screen and (max-width: 900px) {
.stocks-container {
grid-template-columns: repeat(4, calc(25% - 6px));
}
}
#media only screen and (max-width: 750px) {
.stocks-container {
grid-template-columns: repeat(3, calc(33.33% - 6px));
}
}
#media only screen and (max-width: 600px) {
.stocks-container {
grid-template-columns: repeat(3, calc(50% - 6px));
}
}
<div class="stocks-container">
<div>
<h2>Company 1</h2>
<p>Company Stock</p>
</div>
<div>
<h2>Company 2</h2>
<p>Company Stock</p>
</div>
<div>
<h2>Company 3</h2>
<p>Company Stock</p>
</div>
<div>
<h2>Company 4</h2>
<p>Company Stock</p>
</div>
<div>
<h2>Company 5</h2>
<p>Company Stock</p>
</div>
</div>