Flexbox + calc() - possible bug in flexbox? - css

The Goal
I'm working on a flexbox + calc() based grid system with gutters in SASS.
You define your grid via mixins like so:
.box {
#include column('1/3', $gutter: 20px);
}
Compiled this will be:
.box {
width: calc(99.999999% * 1/3 - 13.33333px);
}
The Problem (please read the updates further down)
I'm trying to find a way get rid of the classic .row containers.
In my mind this should be super simple with flexbox + calc() but I have this strange bug (or an error in my caculations?) which sometimes break the layout when multiple rows should be created.
As an example: I want a grid with a 20px gutter between the columns.
The rest is best explained in code, so here's a pen:
http://codepen.io/NilsDannemann/pen/OMBVry?editors=1100
Why is the last example (1/8 - multi row) breaking?
Update #1
Okay, heres whats happening: the Problem is not rooted in the flexbox space-between property, but comes from flexbox' behavior in general.
Flexbox always sees the gutters as available space. So in the last example it combines them (7 * 20px = 140px) and concludes that there is enough space to fit another item (width after calc() = 107.5px) on the first row.
This is were the whole thing falls.
space-betweenthen does it's job as intended.
Update #2
I think the only way around that is (as #Siguza pointed out) to add margins to fill the gutters. Then use an :nth-child selector to set the last margin of a row to 0.
In SASS this would look something like this:
.box {
#include column('1/8', $gutter: 20px);
margin-right: 20px;
&:nth-child(8n) {
margin-right: 0;
}
}
Now it becomes a SASS challenge:
How do I get the :nth-child (whole number) from the passed fraction?
With some effort I have solved this. :-)
Heres the pen with the current SASS version of the grid:
http://codepen.io/NilsDannemann/pen/OMaOvX?editors=1100
Wow! This works great!
A multi-column grid with a completely clean DOM!
No .row classes or .eigth classes. Feel free to play around with the mixin (change the fraction or the gutter).
Heres the sad part though:
Try uneven grids like this:
.box1 {
#include column('2/8', $gutter: 20px);;
}
.box2 {
#include column('4/8', $gutter: 20px);;
}
.box3 {
#include column('2/8', $gutter: 20px);;
}
Now the :nth-child is wrong and the whole thing breaks. :-(
If we can solve this (without introducing another variable to the mixin) we would have one of the cleanest any intuitive grids I have seen to date. But this last problem is a tough one.
I'm not sure if it can be done at all.
Any SASS-Genius out there to help?

The problem boils down to the definition of justify-content: space-between.
8.2. Axis Alignment: the justify-content property
The justify-content property aligns flex items along the main axis
of the current line of the flex container.
space-between
Flex items are evenly distributed in the line.
source:
https://www.w3.org/TR/css-flexbox-1/#justify-content-property
So, in your code, flex items will align per the rules of space-between, even when they wrap.
Extra space will be distributed differently depending on how many flex items exist on the line.
In your example illustrating the problem, you have nine flex items on the first row, and seven flex items on the second row. The second row has more extra space to distribute. Hence, the gutters are wider.
There are a total of 16 flex items in that container. Add two more, and everything aligns perfectly.
Revised Codepen
A few more considerations:
Flexbox is not built to serve as a grid system. The W3C is developing the CSS Grid Layout Module for this purpose.
Instead of width for defining the size of your flex items, consider using the flex property, which will enable you to control the width, as well as the flex-grow and flex-shrink factors.
Although it doesn't seem to be causing a problem in the codepen, using line comment syntax (\\ comments) is invalid in CSS and has the potential to break your code. It's safer to use the standard CSS commenting method (/* comments */). More details here: https://stackoverflow.com/a/34799134/3597276

The core issue seems to be that space-between doesn't like multiline:
#a
{
display: flex;
width: 190px;
border: solid 1px #999;
flex-wrap: wrap;
justify-content: space-between;
}
#a > div
{
height: 30px;
width: 50px;
background: #EFE;
border: solid 1px #EEE;
}
<div id="a">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
This would also happen with your 1/4 boxes, if a fifth box could fit on the first row, and it does indeed happen if you make your browser window extremely narrow.
But believe that this is seen as a feature rather than a bug:
Flexbox tries to fit as many items as possible in a row.
(But I have no source to confirm this.)
What I do have though, is a workaround.
It's a little ugly, but you can give .box a margin-right of 20px, and then take it off again every 4th .fourth box, every 8th .eight, and so on, using :nth-child():
.box {
background: #eee;
text-align: center;
padding: 20px;
margin-right: 20px;
}
// Widths: 1/4
.box.fourth {
width: calc(100% * 1/4 - (20px - 20px * 1/4));
}
.box.fourth:nth-child(4n) {
margin-right: 0;
}
// Widths: 1/8
.box.eigth {
width: calc(100% * 1/8 - (20px - 20px * 1/8));
}
.box.eigth:nth-child(8n) {
margin-right: 0;
}
[ Updated Pen ]

TL;DR flexbox is overhyped garbage and here's a grid that kind of solves this unsolvable problem.
Any SASS-Genius out there to help?
Hi. I wouldn't consider myself a "genius of Sass" or anything. I know it pretty well, but Hugo and a few others have that title.
I have been called a "grid master" by a few people. It's pretty much the only thing in life I'm good at.
I made Jeet and Lost and have literally spent hundreds of hours fighting with what you're fighting with now. It haunts me. I wake up in the morning thinking about this problem and go to bed at night thinking about this problem. I've done this for years.
Flexbox won't save you on this one. In fact, the whole "flexbox will save grid systems" meme is really sad to witness because it just doesn't have the power to be any more useful than non-flexbox CSS.
Your original problem, as Michael_B pointed out, is that you're trying to use space-between. This will never work unless you have a very specific number of elements on every line. It isn't practical to expect anyone to always have x number of elements on every line.
Then you moved onto the whole "tons of markup" (a la Bootstrap) vs. margin-right grids and it seems like you opted for the margin-right grids. I tend to lean towards these as well because I care about what my markup looks like. Bootstrap grids get confusing quickly and I've worked on countless teams where some dev went to add something and screwed up the grid by forgetting a row or trying to nest something other than a column in a row. No one notices it at first, but then out of the blue you'll see an entire chunk of the site is offset by 15px or so. Rewriting it can be a pain. I've even seen this a few times by self-proclaimed Bootstrap experts on ThemeForest.
<!-- Bootstrap markup -->
<div class="container">
<div class="row">
<div class="col-md-6">1</div>
<div class="col-md-6">
<div class="row">
<div class="col-md-6">1a</div>
<div class="col-md-6">
<div class="row">
<div class="col-md-6">1b</div>
<div class="col-md-6">2b</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Margin-right grid markup -->
<div class="row">
<div class="col-6">1</div>
<div class="col-6">
<div class="col-6">1a</div>
<div class="col-6">
<div class="col-6">1b</div>
<div class="col-6">2b</div>
</div>
</div>
</div>
https://youtu.be/ueZ6tvqhk8U?t=18
The downside to margin-right grids is you need to get rid of the last element in a row's margin-right, which can be tricky, especially for preprocessors. This can be done by forcing the user to specify what element they want as their last one, but that introduces a whole new range of problems when you're dealing with uneven grids.
For instance, if I make a mixin that removes the margin-right from every 3rd element, but I want an assortment of sizes and shapes for my elements inside my grid, then I'm totally screwed. The only way I've found to mitigate this somewhat rare problem is to use disgusting Bootstrap markup.
This is the point where you go back to the flexbox wishing well and come up empty handed.
A week or so ago I decided to see if the Bootstrap/Foundation folks were interested in a grid that wasn't built on a markup house of cards. They declined but I put a decent amount of work into what I think is the best solution to this problem.
Here's the any-size elements with no extra markup grid Bootstrap and Foundation shot down: http://codepen.io/corysimmons/pen/MKzPWW?editors=1100
Anyway, if you like grids, stay tuned for my next big grid system set to launch early next month (I'll spam it on reddit and Hacker News). It doesn't solve this particular problem, but it will be pretty revolutionary.
If anyone is as obsessed with solving this problem as I am, I would love to chat with you about it. I'm sure I haven't thought of everything and there's some clever bastard out there just sitting on the answer.

Related

Adjustable box widths based on content

I'm new to flexbox, but I'm assuming it's the best tool for what I'm trying to do. (If not, I'm open to other ideas.) I have a set of features of a "product" - something like this:
<div class="flexbox-container">
<div class="borderbox flexbox">A paragraph of content about the first feature...</div>
<div class="borderbox flexbox">Another paragraph of content about the second feature...</div>
<div class="borderbox flexbox">The third feature...</div>
</div>
...with 12 boxes in all. See http://codepen.io/OsakaWebbie/pen/kkyYOp to see my real content with a klugey way of getting something close to what I want. What I really want is to define a common height for the boxes and then let flexbox adjust the widths based on the content (minimizing dead space after shorter paragraphs), but I can't figure out how. flex-basis:auto sounds relevant, but it didn't have any effect on the layout. I tried this CSS:
.flexbox {
height: 8em;
min-width: 8em;
max-width: 20em;
}
But it ignored the min-width and made everything the max. Currently I'm having to tweak the markup and specify a width (or a class equating to a width) for each box based on its content, but I'm hoping to get the power of flexbox to do that automatically. Is it possible?

Do inline-block divs work when printing?

I have a pretty complex single-page application for managing data. Among other things, it of course needs to be able to print that data. For the most part I have my hands around what does and doesn't actually work when printing from the browser, and the tricks you can play in CSS using the #page directive.
I hit a problem last week that I'm finding a bit mystifying, though. I'm trying to print data onto cardstock forms -- for example, printing name badges on cardstock that might be 2 columns by 4 rows per page. I'm trying to do this using fixed-side divs, where the div's CSS looks something like this:
.badge {
display: inline-block;
width: 3.5in;
height: 2.5in;
}
That displays fine on-screen, but when I go to print it, it is coming out with each badge on a separate line -- the divs don't seem to be inlining properly. Margins are minimal, so I don't think that's the issue.
I'm at a loss here. Does fixed-size inline-block not work when printing? I'm using Chrome, if that's relevant. I am hoping that's it's possible to make this work without, eg, resorting to generating the pages as PDF on the server.
This should work:
<style>
.container {
width: 7in; /* This guarantees there will be enough room for 2 badges side-by-side */
}
.badge {
box-sizing: border-box; /* You only need this if you add padding or borders */
display: inline-block;
width: 3.5in;
height: 2.5in;
}
</style>
<div class="container">
<div class="badge">
Badge 1
</div><div class="badge"> <!-- DO NOT put line breaks between the badge divs! -->
Badge 2
</div><div class="badge">
Badge 3
</div><div class="badge">
Badge 4
</div>
</div>
In short, the 7in wide container div guarantees you'll have enough width to fit two badges side-by-side. Also, there are no line breaks between the badge divs, because line breaks would turn into spaces, which would prevent the badges from fitting beside eachother. Finally, I added box-sizing: border-box to the badge CSS to ensure that the width won't exceed 3.5in if you add borders or padding.
The number of depends on your screen size.
so when the resolution of the screen change or the printed page has another size, The number of rows and columns.
so i suggest to you to use % as unit instead of in to re-size width and height or make an css style for each resolution. Or you can Use the HTML table tag.
Because the inline-block Just treats the element like other "inline elements" and allows the use of block properties. it does not precise how many column and row.

Bootstrap delete gutter-width in row and respect width

Im making a page with bootstrap 2 due to job requirements and facing the following challenge, please understand Im learning it ;)
I have one #mainDiv below a div with my namespace for bootstrap .bootstrapDiv
Below that I have one .row-fluid, under them 2 .span12, here is my problem;
I need to be able to put together with margin-right:0 first one and margin-left:0 second one, these two divs should fill the row respecting the general layout of the rest of rows.
How I see them is ok in the left but at right is missing this gutter width and doesnt looks nice at all, is there any special class that expands the row and its contents horizontally if you take out the iner horizontal margins of the elements in it?
How should you solve this problem normally?
EDIT
Here is my fiddle:
http://jsfiddle.net/qdb74/
im refering to the black space
I usually solve problems like this by creating my own CSS or extending Bootstrap. That is because Bootstrap doesn't have an option to modify the gutter for .row-fluid. Here is an example on how to extend Bootstrap:
.row-fluid [class*="span"].no-gutter {
margin: 0;
}
.row-fluid .span6.no-gutter {
width: 50%;
}
.row-fluid .span5.no-gutter {
width: 41.666666666666666%
}
...
And you can decorate your element like this:
<div class="firstDiv span6 no-gutter"></div>
However if you decide to extend Bootstrap and a new version of the framework comes out this might break. If that is a concern it might be better to create your own fluid grid without gutters. That option will require you to write a bit more CSS than this.

How to get rid of unwanted space between inline-block columns? [duplicate]

This question already has answers here:
How to remove the space between inline/inline-block elements?
(41 answers)
Closed 7 years ago.
I'm attempting to use a css grid with widths set in % (so I can use it responsively) and without using floats (personal dislike!).
In this instance, I'm using csswizardry-grids with the appropriate variables added in. You can view the demo linked on the github page.
There is no mention of a "container" class to assign a width to the grid, so I added .container (which is also what the csswizardry-grids demo has) with a max-width (in prep for other breakpoints later). The container has left and right padding to allow for the padding:left on the .grid__item within.
.container {
margin: 0 auto;
padding: 0 $gutter;
max-width: 960px;
}
The scss:
.grid__item {
display: inline-block;
padding-left: 32px;
vertical-align: top;
width: 100%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.desk--one-third { width: 33.333%; }
Also note that the box-sizing:border-box is not on any other element except that which is spec'd by the csswizardry-grids.scss.
My markup:
<div class="container">
<div class="grid">
<div class="grid__item desk--one-third">
<h1>Column 1</h1>
</div>
<div class="grid__item desk--one-third">
<h1>Column 2</h1>
</div>
<div class="grid__item desk--one-third">
<h1>Column 3</h1>
</div>
</div>
</div>
The problem: in firefox, safari & chrome, the last .grid__item falls away.
What I see: a mysterious gap between '.grid__item's of at least a few pixels. See attached screenshot:
!(http://dl.getdropbox.com/u/7408773/Screen%20Shot%202013-05-10%20at%2012.51.06%20AM.png)
Can anyone shed some light on this for me please?
Whitespace between inline-block elements
It sounds like you're using display: inline-block for the columns, rather than floating them.
The problem with using inline-block for layout is that if there's any whitespace in the HTML source code between the HTML tags (in this case, the grid__item divs), there will be 3-4 pixels of horizontal spacing added between the displayed elements.
inline-block was intended for adding block content to the flow of a paragraph. The reason this spacing occurs is the same reason that 3-4 px are added between 2 words in a paragraph: It gives a series of inline elements in a paragraph the amount of spacing they're usually expected to have.
There's no CSS solution for this that's truly cross-browser and safe (though negative left margins come the closest). There are ways to edit the HTML code to prevent this (removing the whitespace between the tags in the source code), but they present maintainability issues (with a high risk of difficult-to-identify issues turning up later on when someone else works on the code), and it significantly compromises the separation of content and presentation (given that changes to the formatting of the source code can affect the formatting of the displayed pages).
Comparison of inline-block and floats
Both floats and inline-block have the disadvantage of not having been intended for general layout (e.g., creating variable-height columns in the flow of a page). It could be argued that CSS positioning and HTML tables were not intended for general layout either (or at least are not well suited for it).
The natural uses for each:
Floats: Allowing a paragraph of text to flow around an element (usually an image)
inline-block: Adding block content inside a paragraph (like an image), as part of the paragraph
CSS positioning: Overlaying one element on top of another (usually a pop-up or dropdown)
HTML tables: Data grids
Historically, each of these has been forced into use for layout, due to the lack of other options. As Eric Meyer pointed out here and here, the reason floats wound up being used for layout was because of the ability to clear a float (which allows it to be used in a wider variety of ways).
Choosing the right tool
So if neither one was intended for general layout, how do you choose the best one to use?
The strongest argument against inline-block, on the whole, is that if it were truly suitable for general layout, there wouldn't be such a fundamental issue as the 3-4 px of horizontal spacing added between elements (which is almost never desired when laying out the main regions of a page -- columns shouldn't behave the same as words in a paragraph of text).
In specific situations, a simple rule can be applied: For cases where that 3-4 px creates a problem, that indicates that the use of inline-block is inappropriate. Likewise, for cases where the 3-4 px does not create a problem, that suggests that it may be a reasonable option.
In practice, I've found floats to be far more reliable and predictable than inline-block, especially on earlier versions of IE. The main hassle with floats is having to manually clear them. Adding a reliable clearfix to the CSS file makes doing so relatively manageable though. Even on modern CSS grid systems, the preferred layout mechanism for establishing columns is typically floats (based on what I've seen so far).
This was the first link when I searched "space between inline": http://css-tricks.com/fighting-the-space-between-inline-block-elements/
tl;dr remove any spaces between your columns.
This issue is caused by inline-block elements being considered as words - so it can be simulated by giving a negative word-spacing to the wrapping element. About word-spacing: -4px; worked for me Chrome/IE9/FF :) - However - remember - this is a workaround.
HTML:
<div class="wrapper">
<div class="inliner">01</div>
<div class="inliner">01</div>
<div class="inliner">01</div>
</div>
CSS:
.inliner{ display: inline-block; }
.wrapper{ word-spacing: -4px; }

Is there a 0-width way to prevent floated divs from collapsing

First, this issue is not about block elements collapsing when their children are floated. In fact the issue has nothing to do with clearing at all.
The issue is this. Suppose I have a series of floated divs like:
<div class="column">Column 1</div>
<div class="column"></div>
<div class="column">Column 3</div>
With css:
div.column { float: left; width: 200px; }
The middle column will collapse in recent versions of Firefox and Safari, although apparently not IE7. What I want is the IE7 behavior.
I realize I can add an and it will hold the div open, but that doesn't work for me in this case because I also have have a declaration like this:
div.column input { width: 100% }
I have a series of columns layed in a table-like format, with certain conditions causing the input fields to disappear. The problem is when the input disappears the field collapses. If I add an it causes the div to wrap. Just to head off the initial questions:
Why don't I use a table instead? Because I'm using Scriptaculous Sortable to drag and drop rows, which doesn't work with tables
Why don't I use a shorter pixel width to leave room for an ? Because width: 100% is more accurate across browsers.
Why don't I add a when I hide the input I may end up resorting to this, but it would be kind of ugly in the JS, so I'm hoping for a better way.
Does anyone have any clever hacks here? Since both Safari and Firefox behave this way I assume this is officially sanctioned behavior. Where is this discussed in the W3C specs?
Eh? Shouldn't you just give it a random height? Can you show a demo?

Resources