I've noticed the 'input' element does not stretch or shrink to fill a flex container. Does anyone know why and if there is a solution?
My example below shows the container class c being used on Div elements (which stretch properly). And a single class e, used for the right-justified fixed-length end. The row of divs stretch and shrink as expected, the row of inputs do not.
div.c {
display: flex;
flex-direction: row;
align-content: stretch;
}
div.d {
flex: 1;
}
div.e {
display: inline-block;
flex: 0 0 30px;
background-color: red;
}
<div class='c'>
<div class='d'>A</div>
<div class='d'>B</div>
<div class='d'>C</div>
<div class='d'>D</div>
<div class='e'>E</div>
</div>
<div class='c'>
<input class='d'></input>
<input class='d'></input>
<input class='d'></input>
<input class='d'></input>
<div class='e'></div>
</div>
note i am aware of this link:
input / button elements not respecting flex-grow
However using min-width: 0; box-sizing: border-box; has no effect for me.
Because you specified div.d not input.d or div .d or just .d. Also, no need to close the input tag.
div.c {
display: flex;
flex-direction: row;
align-content: stretch;
}
.d {
flex: 1;
}
div.e {
display: inline-block;
flex: 0 0 30px;
background-color: red;
}
<div class='c'>
<div class='d'>A</div>
<div class='d'>B</div>
<div class='d'>C</div>
<div class='d'>D</div>
<div class='e'>E</div>
</div>
<div class='c'>
<input class='d'>
<input class='d'>
<input class='d'>
<input class='d'>
<div class='e'></div>
</div>
Related
My scenario
I have these two flex containers (the difficulty options and the max-score options):
I want the 'easy', 'medium' and 'hard' button to share the same width, but also to fit they're content (in this case, because 'medium' is the longest, they should all equal its width).
I want the same behavior with the bottom buttons (but for them to have a smaller width since they need to accommodate for smaller content).
Right now the flex containers for both of them is set to:
display: flex;
flex-direction: wrap;
flex-wrap: wrap;
And the flex children are each set to their default flex values, with a set height and an auto width.
Approaches I've tried
First approach - flex-basis and flex-grow
Setting the children to flex-basis: 0 and flex-grow: 1, as I've seen in past questions, but then my wrapped child fills the entire width, and the top buttons aren't the same width:
Second approach - -- hardcoded flex-basis
Setting all children to flex-basis: 90px (90px to accommodate for the biggest button, 'medium') which does make them all the same width, but then the width is fixed and doesn't adjust to only fit the content (specifically this is desired so the score buttons can fit in two rows instead of three).
Third approach - max-width
The closest I've got to is to set the children to:
```
max-width: 90px;
flex-basis: 0;
flex-grow: 1;
```
Which makes them behave as wanted:
But when the screen width shrinks, the buttons start to differ in width (the obvious one is the '200' button bigger than the other scores, but also 'medium' is bigger than 'easy' and 'hard'):
My code:
.flex-col,
.flex-row {
display: flex;
flex-wrap: wrap;
gap: 4px;
justify-content: center;
}
.flex-col {
flex-direction: column;
}
.flex-row {
flex-direction: row;
}
.button {
border-style: solid;
padding: 4px;
}
.parent {
height: auto;
width: auto;
}
<div class="parent flex-col">
<div class="flex-col">
<div class="flex-row">
DIFFICULTY
</div>
<div class="flex-row">
<div class="button">EASY</div>
<div class="button">MEDIUM</div>
<div class="button">HARD</div>
</div>
</div>
<div class="flex-col">
<div class="flex-row">
MAX SCORE
</div>
<div class="flex-row">
<div class="button">50</div>
<div class="button">75</div>
<div class="button">100</div>
<div class="button">150</div>
<div class="button">200</div>
</div>
</div>
</div>
Help appreciated, thanks!
The closest way to do this with CSS only, is to use a grid instead of a flexbox for reasons well explained here.
The only way to truly do what you are asking (make all children have the same width as the widest child), is with JavaScript. Loop through the elements to find the biggest width and set them all to have the found width.
Here is a snippet demonstrating both concepts:
const equalizers = document.querySelectorAll('.equalize')
let r = 0
equalizers.forEach(equalizer => {
const widths = []
for (const btn of equalizer.children) {
const w = btn.getBoundingClientRect().width
// Math.ceil() is optional to avoid long floats
widths.push(Math.ceil(w)) // 82
// widths.push(w) // 81.31945037841797
}
const biggest = Math.max(...widths)
console.log(`biggest width found in row[${r++}]:`, biggest)
for (const btn of equalizer.children) {
btn.style.width = `${biggest}px`
}
})
.flex-col,
.flex-row {
display: flex;
flex-wrap: wrap;
gap: 4px;
justify-content: center;
}
.flex-col {
flex-direction: column;
}
.flex-row {
flex-direction: row;
}
.button {
border-style: solid;
padding: 4px;
}
.parent {
height: auto;
width: auto;
}
.grid-row {
display: grid;
gap: 4px;
}
.grid-row>* {
text-align: center;
}
#media (min-width: 25em) {
.grid-row {
grid-auto-flow: column;
grid-auto-columns: 1fr;
}
}
.flex-row>* {
text-align: center;
}
<hr>
<strong>JavaScript</strong> (only ever as wide as the widest sibling, with wrapping)
<hr>
<div class="parent flex-col">
<div class="flex-col">
<div class="flex-row">
DIFFICULTY
</div>
<div class="flex-row equalize">
<div class="button">EASY</div>
<div class="button">MEDIUM</div>
<div class="button">HARD</div>
</div>
</div>
<div class="flex-col">
<div class="flex-row">
MAX SCORE
</div>
<div class="flex-row equalize">
<div class="button">50</div>
<div class="button">75</div>
<div class="button">100</div>
<div class="button">150</div>
<div class="button">200</div>
</div>
</div>
</div>
<hr>
<strong>Grid</strong> (always as wide as posible and no wrapping, either all stacked, or all inline with breakpoint)
<hr>
<div class="parent flex-col">
<div class="flex-col">
<div class="flex-row">
DIFFICULTY
</div>
<div class="grid-row">
<div class="button">EASY</div>
<div class="button">MEDIUM</div>
<div class="button">HARD</div>
</div>
</div>
<div class="flex-col">
<div class="flex-row">
MAX SCORE
</div>
<div class="grid-row">
<div class="button">50</div>
<div class="button">75</div>
<div class="button">100</div>
<div class="button">150</div>
<div class="button">200</div>
</div>
</div>
</div>
<div className={css.title} >
<div className={css.row}>
<div className={css.columnLeft}>
<div className={css.header}>Images</div>
</div>
<div className={css.columnRight}>
<strong>Image 1 of 2</strong>
</div>
</div>
<Icon />
</div>
css
.row {
width: 100%;
display: flex;
align-items: center;
}
.columnLeft {
flex: 1 0 25%;
text-align: left;
}
.columnRight {
flex: 1 0 75%;
}
Currently does
I would like it to be aligned horizontally more so in between left and center.
To keep "Image 1 of 2" (center column) in the middle of the screen:
give left and right 1 columns flex: 1 1 50%
give center column flex: 0 0 auto
This will make the left and right columns start flex calculation from a base of 50% (which gives them equal weight, regardless of unequal content width). The center column will push back against both left and right columns and take an equal amount of empty space from each, to render its contents 2.
If you want the center column to start wrapping at a particular width, give it a max-width and text-align: center.
That's about it.
<div className={css.title}>
<div className={css.row}>
<div className={css.columnLeft}>
<div className={css.header}>Images</div>
</div>
<div className={css.columnCenter}>
<strong>Image 1 of 2</strong>
</div>
<div className={css.columnRight}>
<Icon />
</div>
</div>
</div>
CSS:
.row {
display: flex;
}
.columnLeft,
.columnRight {
flex: 1 1 50%;
}
.columnCenter {
flex: 0 0 auto;
display: flex;
justify-content: center;
}
.columnRight {
display: flex;
flex-direction: row-reverse;
}
HTML demo:
.row {
display: flex;
justify-content: center;
}
.columnLeft, .columnRight {
flex: 0 1 50%;
border: 1px solid red;
}
.columnCenter {
flex: 0 0 auto;
display: flex;
justify-content: center;
}
.columnRight {
display: flex;
flex-direction: row-reverse;
}
.middle {
width: 1px;
height: 2rem;
background-color: red;
}
<div class="row">
<div class="columnLeft">
<div class="header">More content on left side</div>
</div>
<div class="columnCenter">
<strong>I am centered</strong>
</div>
<div class="columnRight">Icon</div>
</div>
<div class="row">
<div class="middle" />
</div>
Notes:
1 - I gave middle flex element columnCenter class and placed a .columnRight wrapper around the <Icon />, because in your example the center element had the class of columnRight, which was confusing (e.g: improper naming), IMHO.
2 - Keep in mind flex is flexible (hence the name). If one of the columns has significantly more content than the other, the equal pushing of center column against the sides won't be so equal anymore. Sides only concede an equal amount of space as long as they have more room than needed to render their contents. If you want to keep the center text centered no matter what, place max-width on the side columns.
I am using Materializecss to create React app. I have already applied flex inside my app class. And now I want to apply flex inside main tag where buttons get fixed at bottom of main tag & above the footer.
I have tried {margin-top: auto;} , justify-content: flex-end which didn't help. The buttons always print after content class. I can set the height of the content class, but small devices render view badly and it's not fixing my problem.
JSX code:
<div className="app">
<header> <header>
<main>
<div className="box">
<div className="content"> Long text less than 100 words <div>
<div className="buttons"> <button> Button-1 </button> <button> Button-2 </button>
<div>
<main>
<footer><footer>
<div>
My css
app {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex: 1 0 auto;
}
I want to stick my button above the footer. My content class has 100 words then the button should stick above the footer not rendered after the content class.
I would appreciate the help.
You haven't applied display:flex etc to the main element. If you do that the margin-top:auto will work.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::before,
::after {
box-sizing: inherit;
}
.app {
display: flex;
min-height: 100vh;
flex-direction: column;
background: ;
}
main {
flex: 1;
display: flex;
flex-direction: column;
}
.buttons {
margin-top: auto;
}
<div class="app">
<header>header </header>
<main>
<div class="box">box</div>
<div class="content"> Long text less than 100 words </div>
<div class="buttons">
<button> Button-1 </button>
<button> Button-2 </button>
</div>
</main>
<footer>footer</footer>
</div>
I receive an dynamic amount of items from the backend.
In case it's an odd number of items the first should be the only one in the first row.
All others should be displayed two per each row. Same if it's an even number of items - no single item in any row then.
I strongly think there is some way to do this with CSS only (i would easily solve this with JS but would prefer a CSS approach) i just hadn't been able to find the right combination.
HTML:
<div class="row">
<div class="col">A</div>
<div class="col">B</div>
<div class="col">C</div>
<div class="col">D</div>
</div>
CSS:
.row {
display: flex;
flex-wrap: wrap;
}
.col {
flex: 0 0 50%;
background: gray;
text-align: center;
}
.col:first-child { // should only hit for an odd amount of items
flex: 0 0 100%;
}
Codepen
Yes, this is possible with the following CSS:
.col:first-child:nth-last-child(odd) {
flex: 0 0 100%;
}
.row {
display: flex;
flex-wrap: wrap;
}
.col {
flex: 0 0 50%;
background: gray;
text-align: center;
}
.col:first-child:nth-last-child(odd) {
flex: 0 0 100%; // should only hit for an odd amount of items
}
<p>Even</p>
<div class="row">
<div class="col">A</div>
<div class="col">B</div>
<div class="col">C</div>
<div class="col">D</div>
</div>
<p>Odd</p>
<div class="row">
<div class="col">A</div>
<div class="col">B</div>
<div class="col">C</div>
<div class="col">D</div>
<div class="col">E</div>
</div>
Also se this related post: Can CSS detect the number of children an element has?
I'm currently making an Electron app with the View powered by Vue.js
I currently have this (for testing purposes)
<template>
<div class="formWrapper">
<div class="inputGroup">
<span class="inputPrepend"><i class="fa fa-user"></i></span>
<input type="text" name="" value="">
</div>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
.formWrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.inputGroup {
align-self: center;
}
</style>
I end up with this result:
But I cannot seem to get the vertical centering to happen.
I have made sure all parent elements have a height: 100%; but still can't get it to go down, also why do I need to specify align-self if the parent flex container formWrapper has specified center for align-items and justify-content
Thanks.
You need to set body to height: 100vh, and formWrapper and all parent elements to height: 100%.
Live example:
body {
height: 100vh;
}
.formWrapper {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
<div class="formWrapper">
<div class="inputGroup">
<span class="inputPrepend"><i class="fa fa-user"></i></span>
<input type="text" name="" value="">
</div>
</div>
There might be a smarter way to do this, but this is the best I could figure out.