Center alignment using flex-box without empty spaces - css

Hi everyone, i'm currently working on a note project, i'm trying to center my notes using flex box without any useless spaces, take a look at the photos you will understand what i mean .
bottom space is just fine, the problem is the space that is caused by flex box on the right side , i want the yellow box to resize and fit but stay centered as well, the yellow box is a ul tag and the red boxes are li tags.
here is the css styles : ( container includes the whole page except the header )
.container {
width: 100%;
display: flex;
height: 100vh;
align-items: flex-start;
justify-content: center;
position: relative;
}
ul {
align-content: flex-start;
margin: 40px auto;
max-width: 1400px;
width: fit-content;
height: 80vh;
display: flex;
justify-content: flex-start;
align-items: flex-start;
flex-wrap: wrap;
overflow-y: scroll;
margin-top: 100px;
border: 3px solid yellow;
}
ul li {
border: 2px solid red;
list-style-type: none;
font-size: 20px;
margin: 5px;
background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5));
backdrop-filter: blur(10px);
width: 330px;
height: 200px;
display: flex;
overflow: hidden;
justify-content: space-between;
align-items: flex-start;
flex-direction: column;
padding: 20px;
border-radius: 5px;
position: relative;
transition: height 0.3s;
}
here is the HTML codes : ( sorry it's not clean )
<title>Dashboard</title>
<div class="container">
<ul>
<li class="item">
<div class="priority"></div><span class="title c-title"> title </span>
<span class="content c-content"> Content </span>
<span class="date"> date </span>
<div class="item_buttons">
<button class="detail faint_color"><img class="edit-icon" src="/icons/invisible.svg" alt="see icon"></button></button>
<button class="detail faint_color"><img class="edit-icon" src="/icons/edit.svg" alt="edit icon"></button></button>
<button class="deleteButton detail faint_color"><img class="edit-icon" src="/icons/trash.svg" alt="delete icon"></button>
</div>
</li>
</ul>
</div>
<div class="addButton">
<img class="addButtonImage" src="/add.svg" alt="add new note" />
<div class="smallMenu hide">
<a href="/modify/folders">
<button class="folders_button"><img src="/icons/folder.svg" alt="folder icon"></button>
</a>
<a href="/note/add">
<button class="addNote_button"><img src="/icons/pen.svg" alt="pen icon"></button>
</a>
</div>
</div>

There's a number of solutions for this one, depending which way you want to go,
If the notes don't have to be exactly 330px wide, you can achieve removing the gaps by replacing:
width: 330px;
with
flex: 200px;
This takes advantage of the fluid responsiveness of flexbox.
One issue with this flex solution is the 'leftover' element upon wrapping: e.g. with three elements across, the fourth will wrap and grow to the full width of the parent:
To get around this with flex, you would need to either:
change flex to something like flex: 0 1 50%; with percentage values and flex-grow disabled, which means you would need #media queries to give the lists the fluidity they had before
use a JavaScript solution to dynamically set the width of the last element based on the other lists (like #SnoopFrog's answer)
If you do need the notes to be 330px wide, I would set the parent <ul> to have a set size twice that of the lists width: 785px; and ensure that justify-content: center;
Alternatively, turning to CSS grid or a simple inline-block method may fit your needs but both would need #media queries for responsivity.

As I said in the comment, I don't think you can solve this using pure HTML/CSS, but you could calculate how many elements can fit at given time inside your .container and change width of your ul.
Check this code below:
function totalWidth(element) {
style = window.getComputedStyle(element)
return parseFloat(style.marginLeft) + parseFloat(style.marginLeft) + parseFloat(style.width)
}
function resizeContainer() {
const container = document.querySelector(".container")
const element = document.querySelector(".container ul")
const children = document.querySelector(".container ul li")
const childrenWidth = totalWidth(children)
const amountFits = Math.floor(Math.min(container.offsetWidth, 1400) / childrenWidth)
element.style.width = `${childrenWidth * amountFits}px`
}
resizeContainer()
window.addEventListener("resize", resizeContainer)
.container {
width: 100%;
display: flex;
height: 100vh;
align-items: flex-start;
justify-content: center;
position: relative;
}
ul {
align-content: flex-start;
margin: 40px auto;
max-width: 1400px;
width: fit-content;
height: 80vh;
display: flex;
justify-content: flex-start;
align-items: flex-start;
flex-wrap: wrap;
overflow-y: scroll;
margin-top: 100px;
border: 3px solid yellow;
padding: 0;
}
ul li {
border: 2px solid red;
list-style-type: none;
font-size: 20px;
margin: 5px;
background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5));
backdrop-filter: blur(10px);
width: 330px;
height: 200px;
display: flex;
overflow: hidden;
justify-content: space-between;
align-items: flex-start;
flex-direction: column;
padding: 20px;
border-radius: 5px;
position: relative;
transition: height 0.3s;
box-sizing: border-box;
}
<div class="container">
<ul>
<li>test</li><li>test</li>
<li>test</li><li>test</li>
</ul>
</div>
Mind the fact that I added box-sizing: border-box; to your ul li so it's a bit easier to calculate the actual size of the element. Naturally you could ignore this and change my totalWidth method to calculate it the way you'd like.
I don't think you can do it differently but I'd like to be proven wrong.

* {
/* just for reset and for remove all margins and paddings */
box-sizing: border-box;
margin: 0;
padding: 0;
}
ul {
display: flex;
/*justify-content: flex-start; don't need this, is start by default
align-items: flex-start;*/
/* magical words that they can align internal box(li) */
justify-content: center;
align-items: center;
margin: 40px auto; /*auto <--> both part is ok*/
max-width: 1400px;
/* just for see the center(you can remove this width static of 25rem */
width: 25rem; /* width: fit-content; */
height: 80vh;
overflow-y: scroll;
margin-top: 100px;
border: 3px solid yellow;
}
ul li {
display: flex;
justify-content: space-between;
align-items: flex-start;
flex-direction: column;
border: 2px solid red;
list-style-type: none;
background: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5));
backdrop-filter: blur(10px);
width: min(100%, 330px); /*make it responsive, when shrink down, under 330px, is take 100% of width avaiable, and not overflowing*/
height: 200px;
margin: 10px auto; /*in every elements, you can use margin auto for both parts*/
padding: 20px;
border-radius: 5px;
transition: all 0.3s; /*transition:height 0.3 --> not height, but all inside!*/
/* overflow: hidden; don't need, that not should be overflow */
/* position: relative; Is by default! like height:auto*/
}
/* if you want to style your buttons, write this code all times */
/* remove deafult aspect of a btn and others, beacuse every browser take a different style*/
button, input, a {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
}
<title>Dashboard</title>
<ul>
<div class="wrapper">
<li class="item">
<div class="priority"></div>
<span class="title c-title"> title </span>
<span class="content c-content"> Content </span>
<span class="date"> date </span>
<div class="item_buttons">
<a href="">
<button class="detail faint_color">
<img class="edit-icon" src="/icons/invisible.svg" alt="see icon">
</button>
</a>
<a href="">
<button class="detail faint_color">
<img class="edit-icon" src="/icons/edit.svg" alt="edit icon">
</button>
</a>
<a href="">
<button class="deleteButton detail faint_color">
<img class="edit-icon" src="/icons/trash.svg" alt="delete icon">
</button>
</a>
</div>
</li>
</div>
</ul>
<div class="addButton">
<img class="addButtonImage" src="/add.svg" alt="add new note" />
<div class="smallMenu hide">
<a href="/modify/folders">
<button class="folders_button">
<img src="/icons/folder.svg" alt="folder icon">
</button>
</a>
<a href="/note/add">
<button class="addNote_button">
<img src="/icons/pen.svg" alt="pen icon">
</button>
</a>
</div>
</div>

Related

Vue-Router Flexbox not scrolling properly (or at all)

I have a component with a router-view inside it that can display a flexbox. I've tried several different solutions to flex-boxes not scrolling properly and they all either result in no scrolling, or scrolling, but it doesn't quite reach the bottom (the last element in the v-for ends up getting cut off.)
Here is the template and relevant styles for the router view
<template>
<div class="modal" ref="modal">
<div class="modalcontent" ref="content">
<p class="goback" #click="closeAnimation" ref="goback">←</p>
<div class="title">
<h1>Questions & Answers</h1>
</div>
<div class="routerview">
<router-view :posts="posts" v-slot="{ Component }">
<transition name="slide-in" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</div>
</div>
</div>
</template>
<style>
.routerview {
position: relative;
width: 80%;
margin: auto;
overflow-y: scroll;
left: 0;
right: 0;
outline: 10px red;
}
</style>
and for the flexbox:
<template>
<div class="container">
<div class="flex-container" ref="flexcontainer">
<div class="question" v-for="post in posts" :key="post._id" #click="this.$router.push(`/forum/question/${post._id}`)">
<h1 class="qTitle">{{ post.title }}</h1>
<p class="qReplyAmt">{{ post.replies.length }} repl<span v-if="!plural(post.replies.length)">y</span><span v-else>ies</span></p>
</div>
</div>
<p>You've reached the end</p>
</div>
</template>
<style scoped>
.question {
width: 98%;
height: fit-content;
min-height: 0;
background-color: whitesmoke;
border-radius: 10px;
padding: 10px 10px 2px 15px;
cursor: pointer;
transition: all 200ms ease-out;
}
.question:hover {
background-color: rgb(255, 107, 107);
color: white;
}
.qTitle {
display: block;
}
.qReplyAmt {
position: relative;
top: -5px;
}
.flex-container {
display: flex;
align-items: center;
flex-direction: column-reverse;
width: 100%;
gap: 15px;
flex: 1;
}
</style>
I've tried:
setting a height on .container, .routerview, .flex-container
setting overflow-y to auto & scroll on .container, .routerview, .flex-container
and a bunch of other answers i've found on how to fix flexboxes not scrolling
I fixed the issue. Here is the updated styles:
.flex-container {
display: flex;
align-items: center;
justify-content: space-between;
flex-direction: column-reverse;
width: 100%;
gap: 15px;
flex: 1;
margin-top: auto;
margin-bottom: 125px;
}
.container {
overflow-y: scroll;
height: 100vh;
}
I added the .container styles to make it actually scroll and added margin-bottom: 125px; to fix the issue with the last item being cut off.

CSS ignores width of children when using aspect ratio

I have encountered an issue regarding CSS's aspect-ratio on child elements.
I've been trying to style an element's width and height (both the same) to be equal to the height of the parent container. Using height: 100%; and aspect-ratio: 1; makes this work, however;
It seems the parent container ignores the children's resized width when using aspect-ratio, meaning the parent container ends up with the wrong width.
I've included a codepen illustrating the issue. Notice how the width does increase with each new element, but the width increase does not correspond to the actual width of the added elements.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
padding: 8px;
}
.container {
border: 1px solid red;
display: flex;
flex-direction: row;
align-items: stretch;
column-gap: 16px;
width: fit-content;
}
.button_container {
display: flex;
column-gap: 8px;
border: 1px solid green;
width: fit-content;
}
.button {
display: flex;
align-items: center;
justify-content: center;
border: 1px solid black;
}
.first_case {
height: 100%;
aspect-ratio: 1 / 1;
}
.second_case {
height: 100%;
width: 56px;
}
<p>Fixed width (this is how it should look)</p>
<div class="container">
<div>
Text<br/>More text<br/>Lots of text
</div>
<div class="button_container">
<div class="button second_case">
A
</div>
<div class="button second_case">
B
</div>
</div>
</div>
<p>Aspect ratio</p>
<div class="container">
<div>
Text<br/>More text<br/>Lots of text
</div>
<div class="button_container">
<div class="button first_case">
A
</div>
<div class="button first_case">
B
</div>
</div>
</div>
https://codepen.io/th3o4or/pen/ZEoqMrm

How do I change the size of the <figure> area?

I have a figure tag for my shopping cart icon, which sits beside the header navigation. The png img inside is the perfect size, and fills the height of the figure tag. But for some reason, the figure tag is too long. I've tried resizing the figure tag width and the image width, but nothing will make it smaller or erase that empty space which is covering my final menu option. I didn't have or notice this problem earlier, but I made some necessary changes to the CSS and since then, I've noticed this issue. No matter what I change, nothing seems to alter the figure size. [It spans across so I cannot hover over the 'help' option].
<div class="header-wrapper">
<div class="header-split">
<a class="home" href="#">Lu Steven</a>
<div class="menu-cart">
<nav>
<ul class="overall-nav">
<li>gallery</li>
<li><span>|</span></li>
<li>about</li>
<li><span>|</span></li>
<li>shop</li>
<li><span>|</span></li>
<li>exhibitions</li>
<li><span>|</span></li>
<li>contact</li>
<li><span>|</span></li>
<li>help</li>
</ul>
</nav>
<figure>
<img src="/images/cart.png"></img>
</figure>
</div>
</div>
</div>
CSS:
/* Header */
header ul{
display: flex;
flex-direction: row;
list-style: none;
justify-content: space-between;
width: 150%;
letter-spacing: 3px;
margin-left: -35%;
}
header a{
text-decoration: none;
color: aliceblue;
}
header a:hover{
color: #9ec8f0;
}
.header-wrapper{
position: absolute;
height: 7vh;
width: 100vw;
background-color: rgb(43, 43, 43);
color: aliceblue;
display: flex;
flex-direction: row;
}
.header-split{
display: flex;
flex-direction: row;
justify-content: space-between;
width: 80%;
margin: auto;
}
.home{
display: flex;
align-items: center;
}
.menu-cart{
display: flex;
flex-direction: row;
align-items: center;
}
/* Cart */
figure{
display: flex;
flex-direction: row;
justify-content: right;
}
header img{
height: auto;
width: 35%;
}
header img:hover{
cursor: pointer;
opacity: 50%;
}
Hi there there is a small error in your code the img is a self closing tag you don't need to close it like this </img> it should be something like this
<img src="" alt=""/>
correct this error and your problem might get solved

Image height inside flexbox not working in Chrome

I have a div using flexbox to center its items. Inside this div I have 3 elements, one of them is an image.
<div id="flex-container">
<div id="container1"></div>
<img src="#" alt="">
<div id="container2"></div>
</div>
#container1 and #container2 have their own height, and the img should use the remaining height inside #flex-container.
This snippet works on Firefox, but doesn't work in Chrome. (jsfiddle)
#flex-container{
height: 300px;
width: 500px;
display: flex;
display: -webkit-flex;
flex-flow: column nowrap;
-webkit-flex-flow: column nowrap;
justify-content: center;
-webkit-justify-content: center;
align-items: center;
-webkit-align-items: center;
border: 5px solid black;
}
#container1, #container2{
height: 100px;
width: 300px;
background: orange;
flex: 1 0 auto;
-webkit-flex: 1 0 auto;
}
<div id="flex-container">
<div id="container1">300x100 px</div>
<img src="http://i.imgur.com/RRUe0Mo.png" alt="">
<div id="container2">300x100 px</div>
</div>
Chrome needs -webkit- prefixes for flexbox, but the issue doesn't seem to be this.
What can be happening? Is a browser bug or I'm forgetting something?
There are two problems you need to overcome:
Firefox solves them both on its own, but Chrome needs assistance.
Problem #1
The first problem is that flex items, by default, cannot be smaller than their content. An initial setting on flex items is min-height: auto.
Therefore, a flex item with a replaced element, like an image, will default to the inherent size of the image. The item cannot be made smaller, unless you override the initial setting (use min-height: 0).
#flex-container {
height: 300px;
width: 500px;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
border: 5px solid black;
}
#container1, #container2 {
height: 100px;
width: 300px;
background: orange;
flex: 1 0 auto;
}
img { min-height: 0; } /* NEW */
<div id="flex-container">
<div id="container1">300x100 px</div>
<img src="http://i.imgur.com/RRUe0Mo.png" alt="">
<div id="container2">300x100 px</div>
</div>
A complete explanation of this issue can be found here:
Why doesn't flex item shrink past content size?
Problem #2
Then you hit the second problem: keeping the aspect ratio. This is a common problem in flex containers. One option is to define a height for the image:
#flex-container {
height: 300px;
width: 500px;
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
border: 5px solid black;
}
#container1, #container2 {
height: 100px;
width: 300px;
background: orange;
flex: 1 0 auto;
}
img { min-height: 0; height: 100px; } /* NEW */
<div id="flex-container">
<div id="container1">300x100 px</div>
<img src="http://i.imgur.com/RRUe0Mo.png" alt="">
<div id="container2">300x100 px</div>
</div>

Group of items with responsive equal width in multi-line context, issue with last-line [duplicate]

This question already has answers here:
Managing CSS flex-box growth in multi-line to create a grid of equal blocks
(2 answers)
Closed 6 years ago.
After researching the question for a while and considering all the float and text-align alternatives, I'm mostly happy with the solution that I've found using flexbox but there is an issue with the last line (when it overflows) in that the items are not the same width as those in the previous lines because they are allowed to stretch more (up to max-width) in order to try to fill the remaining empty space.
My requirements are simple:
1. All items must have the same width (including on the last line);
2. All items must be equallys spaced if the line is full or aligned left if not (typically last line);
3. Items can (must) overflow when min-width is reached (responsive resizing);
4. CSS-only solution and possibly avoiding media queries;
5. I'd rather use flex-basis: 0 for true same width (last line issue standing);
6. Non-flexbox solution considered as long as meet other requirements;
I've removed vendor prefixes for clarity but I'm using them on the actual page.
CSS
nav {
margin: 20px 0px;
}
nav #linkgroup {
display: flex;
flex-wrap: wrap;
justify-content: flex-start; /* aligns left when not full */
align-items: center;
align-content: space-around;
}
nav #linkgroup .link {
min-width: 120px;
width: 120px; /* only used because of Safari issue below */
max-width: 160px;
height: 30px;
margin: 5px;
flex-grow: 1;
flex-basis: auto; /* 0 gives all exact same size but have to use auto and set 'width' for Safari issue https://bugs.webkit.org/show_bug.cgi?id=136041 */
line-height: 30px; /* set equal to height, for vertical align trick */
text-align: center;
}
nav #linkgroup .link a.btn {
display: block;
vertical-align: middle;
line-height: normal;
border-radius: 2px;
padding: 5px 10px 5px 10px;
border: solid #1f628d 2px;
text-decoration: none;
}
HTML
<nav>
<div id="linkgroup">
<div class="link"><a class="btn" href="#">A</a></div>
<div class="link"><a class="btn" href="#">AB</a></div>
<div class="link"><a class="btn" href="#">ABC</a></div>
<div class="link"><a class="btn" href="#">ABCD</a></div>
<div class="link"><a class="btn" href="#">ABCDE</a></div>
<div class="link"><a class="btn" href="#">ABCDEF</a></div>
<div class="link"><a class="btn" href="#">ABCDEFG</a></div>
</div>
</nav>
nav {
margin: 20px 0px;
padding: 0px 0px 5px 0px; /* to space when multi-line */
}
nav #linkgroup {
display: flex;
flex-wrap: wrap;
justify-content: flex-start; /* aligns left when not full */
align-items: center;
align-content: space-around;
}
nav #linkgroup .link {
min-width: 120px;
width: 120px; /* only used because of Safari issue below */
max-width: 160px;
height: 30px;
margin: 5px;
flex-grow: 1;
flex-basis: auto; /* 0 gives all exact same size but have to use auto and set 'width' for Safari issue https://bugs.webkit.org/show_bug.cgi?id=136041 */
line-height: 30px; /* set equal to height, for vertical align trick */
text-align: center;
}
nav #linkgroup .link a.btn {
display: block;
vertical-align: middle;
line-height: normal;
border-radius: 2px;
padding: 5px 10px 5px 10px;
border: solid #1f628d 2px;
text-decoration: none;
}
<nav>
<div id="linkgroup">
<div class="link"><a class="btn" href="#">A</a></div>
<div class="link"><a class="btn" href="#">AB</a></div>
<div class="link"><a class="btn" href="#">ABC</a></div>
<div class="link"><a class="btn" href="#">ABCD</a></div>
<div class="link"><a class="btn" href="#">ABCDE</a></div>
<div class="link"><a class="btn" href="#">ABCDEF</a></div>
<div class="link"><a class="btn" href="#">ABCDEFG</a></div>
</div>
</nav>
Try to set flex-grow property to 0 in nav #linkgroup .link:
flex-grow: 0;
It will avoid the unwanted growing of divs on the last line.
Found a solution:
Simply add as many "empty" items as you expect the maximum on a line to be (a few more don't hurt but have at least enough for a full line) and then add the two bits relating to div:empty from the CSS below.
CSS
nav {
margin: 20px 0px;
}
nav #linkgroup {
display: flex;
flex-wrap: wrap;
justify-content: flex-start; /* aligns left when not full */
align-items: center;
align-content: space-around;
}
nav #linkgroup .link {
min-width: 120px;
width: 120px; /* only used because of Safari issue below */
max-width: 160px;
height: 30px;
margin: 5px;
flex-grow: 1;
flex-basis: auto; /* 0 gives all exact same size but have to use auto and set 'width' for Safari issue https://bugs.webkit.org/show_bug.cgi?id=136041 */
line-height: 30px; /* set equal to height, for vertical align trick */
text-align: center;
}
nav #linkgroup .link a.btn {
display: block;
vertical-align: middle;
line-height: normal;
border-radius: 2px;
padding: 5px 10px 5px 10px;
border: solid #1f628d 2px;
text-decoration: none;
}
#linkgroup > div:empty {
height: 0; /* I think visibility: hidden; would do the same */
}
#media only screen
and (min-width: 1030px) {
#linkgroup > div:empty {
display: none;
}
}
HTML
<nav>
<div id="linkgroup">
<div class="link"><a class="btn" href="#">A</a></div>
<div class="link"><a class="btn" href="#">AB</a></div>
<div class="link"><a class="btn" href="#">ABC</a></div>
<div class="link"><a class="btn" href="#">ABCD</a></div>
<div class="link"><a class="btn" href="#">ABCDE</a></div>
<div class="link"><a class="btn" href="#">ABCDEF</a></div>
<div class="link"><a class="btn" href="#">ABCDEFG</a></div>
<div class="link"></div>
<div class="link"></div>
<div class="link"></div>
<div class="link"></div>
<div class="link"></div>
<div class="link"></div>
</div>
</nav>

Resources