Adding a class "collapse" to flex grid creates uneven spacing - css

So, I am creating a grid system based on flexbox and everything is going quite swimmingly. The basics of my grid are:
<div class="row">
<div class="column"><p>Column</p></div>
<div class="column"><p>Column</p></div>
<div class="column"><p>Column</p></div>
</div>
And in my css:
.row {
margin: 10px 0;
display: flex;
flex-wrap: wrap;
}
.column {
padding: 10px;
flex: 1 1 0%;
}
Essentially, this makes the columns quite fluid, and they shrink/grow to fill all available space. This is great for me as I need to use this throughout various projects where I can't quite customize the grid for every single one. However, I have run into a small "issue". I was going to create a class called ".collapse" so I could collapse the left/right padding to have some columns fit right next together (for example: If I wanted a div with a background color (by adding a color class to the column=> .column .green) flush to an image in the next column). However, the spacing is all out of wack compared to row/columns above it.
<div class="row">
<div class="column purple collapse"><p>Column</p></div>
<div class="column red collapse"><p>Column</p></div>
<div class="column purple collapse"><p>Column</p></div>
<div class="column red collapse"><p>Column</p></div>
</div>
example screenshot here
As you can see in my little example mockup, they do kinda line up, but the right and left margins have "decreased". Is there any smart way around this? I tried adding "left/right margins" to the first-of-type and last-of-type, but this just gets a bit hacky as then anything added in between start having odd alignment issues.

For this kind of grid system, you usually would discourage using structural styling on the grid cells directly, and it lets you do something like this:
.row {
display: flex;
flex-flow: row wrap;
list-style: none;
padding: 0;
margin-left: -10px;
}
.column {
flex: 1 0 0;
padding-left: 10px;
}
.collapse { margin-left: 0; }
.collapse > .column { padding-left: 0; }
.red,
.purple {
padding: 10px;
margin-bottom: 10px;
}
.red { background-color: red; }
.purple { background-color: purple; }
<div class="row">
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
</div>
<div class="row collapse">
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="purple">
<p>Column</p>
</div>
</div>
<div class="column">
<div class="red">
<p>Column</p>
</div>
</div>
</div>
This approach uses no margins on the outer ends, which I find way more convenient.
It's worth noting that this kind os system is not all that useful anymore, with the advent of CSS Grid Layout, but there you have it.
On a side note, 0 is always 0, and it never needs a unit.

Related

How to make resizable grids based on number of items?

I am working on a questionnaire design, which can have one or more answers, something like this:
This looks alright for 3 or more answers as in the above screenshot. However, when there's a single or couple of answers, they are taking too much space, resulting in this:
How can I make the boxes smaller if there are fewer answers, still making them look good, i.e. centered and with proper spacing, etc.?
Here's a working code sandbox where you can see what I have so far.
Maybe you may need a different approach with only flexbox
/* custom class */
.box {
display: inline-flex;
align-items: center;
justify-content: center;
width: 150px;
height: 150px;
border: 2px solid black;
margin: 2px;
}
/* responsivity class */
.responsive {
width: 100%;
display: flex;
margin: 0 auto;
}
.center-placer {
width: max-content;
margin: 0 auto;
}
<div class="responsive">
<div class="center-placer">
<div class="box">
A
</div>
<div class="box">
B
</div>
<div class="box">
C
</div>
<div class="box">
D
</div>
<div class="box">
E
</div>
</div>
</div>
<div class="responsive">
<div class="center-placer">
<div class="box">
A
</div>
<div class="box">
B
</div>
</div>
</div>
<div class="responsive">
<div class="center-placer">
<div class="box">
C
</div>
</div>
</div>

Reduce the bottom border width

I have two tabs and they have bottom-borders. This is the jsfiddle example.
<div class="component-content">
<div class="tabs-inner">
<ul class="tabs-heading">
<li tabindex="0" class="active">
<div>
<div class="row">
<div class="component content col-12">
<div class="component-content">
<div class="field-heading">TAB 1: STANDARD SMALL</div>
</div>
</div>
</div>
</div>
</li>
<li tabindex="-1">
<div>
<div class="row">
<div class="component content col-12">
<div class="component-content">
<div class="field-heading">TAB 2: STANDARD SMALL</div>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
.tabs-heading {
display: table;
table-layout: fixed;
width:100%;
}
.tabs-heading li {
display: table-cell;
border-bottom: 2px solid red;
}
I want to add padding in the border bottom so that it should look like this
I tried to add padding-bottom but it didn't work.
Any suggestion or help would be appreciated
I am not quite sure if I got your question right ... but maybe you are looking for something like this ...?
If you don't use table and table-cell ... but flexbox instead ... all tabs will get automatically the same height and you are able to work with padding-bottom. If you like you can add margins between tabs as well.
#wrapper {
display: flex;
align-items: stretch;
background-color: Gray;
}
#wrapper div {
padding-bottom: 10px;
border-bottom: 2px solid orange;
}
#one {
background-color: green
}
#two {
background-color: blue
}
#three {
background-color: red
<div id="wrapper">
<div id="one">one one one one one one one one one one one one one one one one one one one one one</div>
<div id="two">two two two two two two</div>
<div id="three">three</div>
</div>

Spread arbitrary number of divs evenly in a div's rows

I need to achieve an even distribution of pills inside a div for all 4 major screen sizes using flexbox. The smaller the screen size less divs are to be fit to a single row. The rest of the divs should be placed on the next row. The number of divs to distribute is not known beforehand. Each pill is going to receive a word inside so a min guaranteed width is needed.
Here's a picture of what the outcome for various screen sizes might look like for a single row. How do I go about doing smth like this?
something like this:
.row {
display: flex;
flex-flow: row wrap;
list-style: none;
padding-bottom: 12px;
}
.pill {
min-width: 50px;
max-width: 200px;
margin-right: 12px;
margin-bottom: 12px;
text-align: center;
padding: 6px;
border: 2px solid;
border-radius: 50%;
flex: 1 0 0;
}
.pill:last-child {
margin-right: 0;
}
<div class="row">
<div class="pill">foo</div>
<div class="pill">bar</div>
<div class="pill">foobar</div>
<div class="pill">foo</div>
<div class="pill">bar</div>
<div class="pill">foo</div>
<div class="pill">bar</div>
<div class="pill">foobar</div>
<div class="pill">foo</div>
<div class="pill">bar</div>
</div>
<div class="row">
<div class="pill">foo</div>
<div class="pill">bar</div>
<div class="pill">foobar</div>
<div class="pill">foo</div>
<div class="pill">bar</div>
</div>
<div class="row">
<div class="pill">foo</div>
<div class="pill">bar</div>
<div class="pill">foobar</div>
</div>
<div class="row">
<div class="pill">foo</div>
</div>
You can adjust the min and max width of the pill elements according to your needs.

Div to expand vertically, but be scrollable if it has filled its container

UPDATE:
I made a fiddle for testing.
An illustration of what I'd like to achieve: (Rows and columns are Bootstrap 4 rows and columns.)
The page should only have scrollbars if the second row is already
"fully compressed" (0 height) and still the header + first row +
footer can't fit in the viewport.
The second row doesn't have to fill
in all remaining pale green place. It's height can be flexible.
Flexbox? Max-width? Overflow... How should I start? What could be a good solution?
HTML:
<div class="page">
<div class="header">
...<br>...
</div>
<div class="main">
<div class="container-fluid">
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body"> .... </div>
</div>
</div>
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body"> .... </div>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body scrollable"> THIS <br> SHOULD <br> BE <br> THE <br> SCROLLABLE <br> CONTENT </div>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
...
</div>
</div>
CSS:
div.page {
background-color: palegreen;
display: flex;
flex-direction: column;
min-height: 100vh;
max-height: 100vh;
}
div.header,
div.footer {
background-color: grey;
padding: 0.5em;
}
div.main {
display: flex;
flex-grow: 1;
}
div.row {
margin-top: 1em;
}
div.scrollable {
/* ??? */
}
The key is how you calculate the height for the <main> and usage of flex, esp. flex-grow, flex-shrink.
<header>, <main> and <footer>
The second row doesn't have to fill in all remaining pale green place. It's height can be flexible.
So I assume you want the <header> and <footer> always stay on top and bottom. Instead of regular absolute positioning approach, I want to explicitly set the heights for them, as well as for <main>.
HTML
<header>header</header>
<main class="container-fluid"></main>
<footer>footer</footer>
SCSS
$custom-header-height: 3rem;
$custom-footer-height: 2rem;
header, footer {
background-color: var(--gray);
// In order to position the text to the center, like your picture
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
}
header {
height: $custom-header-height;
}
footer {
height: $custom-footer-height;
}
main {
// Calculate the height for main, which is 100% viewport height -
// height of header - height of footer
height: calc(100vh - #{$custom-header-height} - #{$custom-footer-height});
background-color: var(--teal);
}
Result
This gives you the playground you can build stuff on.
First Row
The first row is free to expand as high as its contents, but you don't want it to take up any free space. That's why you set flex-grow: 0;. Also when you resize the window and the space for first row is shrinking, you don't want the cards go over the row. That's why you set flex-shrink: 0;. We might as well use the shortcut flex: 0 0 auto; for those 2.
But in order to set that, the first row (as well as the second row) needs to be flexbox children. So we set display:flex; on its parent - <main>.
HTML
<header>header</header>
<main class="container-fluid">
<div class="row first-row">
<div class="col-6">
<div class="card">...</div>
</div>
<div class="col-6">
<div class="card">...</div>
</div>
</div>
</main>
<footer>footer</footer>
SCSS (In addition)
main {
display: flex;
flex-flow: column nowrap;
}
.first-row {
// I purposely make first row's background yellow so that you can see it
background-color: var(--yellow);
flex: 0 0 auto;
}
Result
Second Row
The key here is to make the <card> not to grow when there is space, but shrink on limited space, which is the default of flexbox children: flex: 0 1 auto;
But again, in order to use that, its parent needs to display: flex;. Here the parent is col-6 since we want to use bootstrap grid system.
HTML
<header>header</header>
<main class="container-fluid">
<div class="row first-row">
<div class="col-6">
<div class="card">...</div>
</div>
<div class="col-6">
<div class="card">...</div>
</div>
</div>
<div class="row second-row">
<div class="col-6">
<div class="card">
...
...
...
</div>
</div>
</div>
</main>
<footer>footer</footer>
SCSS (In addition)
.second-row {
// I purposely make second row's background to be blue so that you can see it
background-color: var(--blue);
// Any column, class name starts as "col-"
[class*="col-"] {
display: flex;
flex-flow: column nowrap;
// So that when the second row is compressed to 0, it doesn't show
// the row completely.
min-height: 0;
.card {
// flex-grow: 0;
// flex-shrink: 1;
// Might as well just set it
// flex: 0 1 auto;
// But this is the default of flexbox children so we don't need to set
// it here.
.card-body {
overflow-y: auto;
}
}
}
}
Result
The second row doesn't have to fill in all remaining pale green place. It's height can be flexible.
An illustration of what I'd like to achieve
The page should only have scrollbars if the second row is already "fully compressed" (0 height) and still the header + first row + footer can't fit in the viewport
Notes
There is still a funkiness when the second row is fully compressed. The scrollbar is still hanging there and I don't know how to get rid of it.
The code can be simplified a little bit without usage of bootstrap grid system.
Demo
https://codepen.io/anon/pen/XBqyxZ
Sorry for this lengthy post. If you want to know more about flexbox, here is a great guide: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
I would but a set the height (or max-height if you prefer) on the card and then set overflow to scroll.
<html>
<div class="box">
<div class="content">
Dispassionate extraterrestrial observer citizens of distant epochs
permanence of the stars billions upon billions vastness is bearable only
through love brain is the seed of intelligence.
</div>
</div>
</html>
<style>
.box {
width: 500px;
overflow: scroll;
}
</style>

Horizontally centered Bootstrap columns

JSFIDDLE
I have a case where I want my bootstrap columns to horizontally center themselves.
To achieve this, I have used the following rules
CSS:
div[class^=col-] {
float: none;/* Overwrites float left */
display: inline-block;
vertical-align: top;
width: 25%;
}
Then If 4 columns are there they should come in a line. And if there are 3 columns then they should be centered.
HTML:
<!-- The fourth column falls down -->
<div class='row text-center'>
<div class="col-xs-3 col-1">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
</div>
<!-- Works Fine and centers the columns -->
<div class='row text-center'>
<div class="col-xs-3 col-1">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
</div>
It works fine if I have just 1,2 or 3 columns but when I get 4 columns, one of the columns falls down to a new line. To solve this issue, I have tried reducing the width to say 24.7%. But again this does not work in all screens. So I have to keep changing the width.
I would love to know why width 25% is not taking the 25% width and falling down. And how to solve this issue and keep them always in the center.
JSFIDDLE
You should create a special class (ie: row-centered) for this case, and not override the Bootstrap grid.
.row-centered > div {
display: inline-block;
float: none;
}
http://www.codeply.com/go/EXmotvfGtG
Please remove:
div[class^=col-] {
float: none;/* Overwrites float left */
display: inline-block;
vertical-align: top;
width: 25%;
}
and you can add to the .row class:
.row {
display: flex;
justify-content: center;
}
If you're using bootstrap v4 there are added flexbox classes, which you can use:
https://v4-alpha.getbootstrap.com/utilities/flexbox/
Give display: flex to the row. Using this method will work in all screens.
Fiddle
div[class^=col-] {
float: none;
display: inline-block;
vertical-align: top;
width: 25%;
}
body {
color: white;
}
.row {
margin-bottom: 50px;
display: flex;
}
.col-1 {
background: red;
}
.col-2 {
background: blue;
}
<!-- The fourth column falls down -->
<div class='row row-1 text-center'>
<div class="col-xs-3 col-1">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
</div>
<!-- Works Fine and centers the columns -->
<div class='row text-center'>
<div class="col-xs-3 col-1">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
<div class="col-xs-3 col-2">Hi</div>
</div>
<!-- Post Info -->
<div style='position:fixed;bottom:0;left:0;
background:lightgray;width:100%;'>
About this SO Question: <a href='http://stackoverflow.com/q/23502342/1366033'>Bootstrap 3 grid, does it *really* matter how many columns are in a row?</a><br/>
Fork This Skeleton Here <a href='http://jsfiddle.net/KyleMit/kcpma/'>Bootrsap 3.0 Skeleton</a><br/>
<div>

Resources