Css column layout - inline block elements, what is percent width relative to? - css

I'm not sure I understand how css column layout is supposed to work.
I have a straightforward html
<div class="container">
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
</div>
and css
.block {
background-color: blue;
width: 50em;
height: 10px;
margin: 2px;
display: inline-block;
}
.container {
border: 1px solid black;
display: inline-block;
column-count: 2;
-moz-column-count: 2;
-webkit-column-count: 2;
}
This works as expected with the elements flowing downwards and then over into a second column.
Now what if I change the width value of .block to a percentage width? All my widths are tiny. They still are clearly relative to something since shrinking and growing the percentages changes the width proportionately but I have no idea what 100% corresponds to.
What is the percentage width relative to?

The width is relative to the column pseudo-element inserted by the browser:
http://www.w3.org/TR/css3-multicol/
In the traditional CSS box model, the content of an element is flowed into the content box of the corresponding element. Multi-column layout introduces a new type of container between the content box and the content, namely the column box (or column for short). The content of a multicol element is flowed into its column boxes.
(Emphasis mine.)
So, the percentage width you're asking for is relative to the implicit column boxes.
Browser Support
As I noted in my comment support for column-count etc is poor today. Except where you really need a specific feature of CSS multicolumn, I find it easier to just use the old inline-block approach. Works in every browser in use today, easy to figure out.
http://jsfiddle.net/b9chris/nt83M/
.block {
background-color: blue;
width: 45%;
height: 10px;
margin: 2px;
display: inline-block;
vertical-align: top;
}
.container {
border: 1px solid black;
width: 200px;
display: inline-block;
}
<span class=container>
<span class=block></span>
<span class=block></span>
<span class=block></span>
<span class=block></span>
<span class=block></span>
</span>
Two important caveats:
For old IE support to work properly you need to use tags that are inline by default, like span. Using a tag that's block by default, like div, will look great in Chrome etc but fail in IE8.
You need to set vertical-align: top in the inner tags to get things to work the way you'd expect them (otherwise everything acts like vertical-align: bottom).

Essentially how column layouts work is you have a container that a width and you split that container into columns. When you decide how many columns you want for your design you assign each of those columns a percentage. Then you float those columns next to each other.
So if you have a 12 column layout the column classes would be as follows:
.col-1 { width: 4.8076923077% }
.col-2 { width: 13.4615384615% }
.col-3 { width: 22.1153846154% }
.col-4 { width: 30.7692307692% }
.col-5 { width: 39.4230769231% }
.col-6 { width: 48.0769230769% }
.col-7 { width: 56.7307692308% }
.col-8 { width: 65.3846153846% }
.col-9 { width: 74.0384615385% }
.col-10 { width: 82.6923076923% }
.col-11 { width: 91.3461538462% }
.col-12 { width: 100%; margin: 0 }
The above columns take into account margins and padding, but here's a fiddle that lays it out.

Parent element width within a content column refers to the column width, a property that defaults to auto. A columnar element is either defined by column-width or column-count (but not both, column-count overrides any column-width value if they are both non-auto). So in your example, providing column-count is causing an automatically generated width to be presented as container width.
source - right above example IX here: http://www.w3.org/TR/2011/CR-css3-multicol-20110412/
Column boxes act as the containing block for their content. That is,
column boxes behave like block-level, table cell, and inline-block
boxes as per CSS 2.1, section 10.1, item 2 [CSS21]. However, column
boxes do not establish containing blocks for elements with ‘position:
fixed’ or ‘position: absolute’.

Related

How do I prevent multiline text from filling the entire width of the parent element

Suppose I have a container element that has a set width. I have a content element with a display inline-block that can contain some text. This text could be so big that it has to be filled over several lines. The problem with this is that default behaviour for multiline text is that it grows the element to the complete width of the parent element.
Imagine the following example:
HTML:
<div class="container">
<div class="content">
Firstreallongword11 Secondalsolongword22 Thirdwordthatisconsiderablylonger
</div>
</div>
CSS:
.container {
width: 260px;
border: solid blue 1px;
}
.content {
display: inline-block;
background: red;
}
Because these are long words, they will be positioned over multiple lines. What I would expect for the .content element, is that it would grow to the maximum width of the largest word on one single row.
But as you can see, because it consists of multiple lines, the element grows to the max width of .container .
FIDDLE
What I want to achieve is, .content gaining the width of the largest item on a single row, as it would with one single lin:
FIDDLE
Is there any way to achieve this with pure css/html?
The simple answer is: No, you can't do that with pure CSS.
But here is a solution anyway, which is a bit of a hack: It uses display: table-cell; for the .content element, and a rather small width value (which will adjust to the actual value of the longest word and acts like a min-width setting in this case):
.container {
width: 260px;
border: solid blue 1px;
}
.content {
display: table-cell;
width: 100px;
background: red;
}
<div class="container">
<div class="content">
Firstreallongword11 Secondalsolongword22 Thirdwordthatisconsiderablylonger
</div>
</div>

CSS Grid auto rows height issue in Firefox ESR [duplicate]

I want to have a square div inside a flexbox. So I use:
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
padding-bottom: 50%;
}
<div class="outer">
<div class="inner">
<a>hehe</a>
</div>
</div>
This works fine in Chrome. But in Firefox, the parent squeezes to just one line.
How do I solve this in Firefox? I use version 44.
You can also view the code at https://jsbin.com/lakoxi/edit?html,css
2018 Update
The flexbox specification has been updated.
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items, like those on block
boxes, are resolved against the inline size of their containing block,
e.g. left/right/top/bottom percentages all resolve against their
containing block’s width in horizontal writing modes.
Original Answer - applies to FF and Edge versions released before 2018
From the flexbox specification:
Authors should avoid using percentages in paddings or margins on flex items entirely, as they will get different behavior in different browsers.
Here's some more:
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items can be resolved against either:
their own axis (left/right percentages resolve against width, top/bottom resolve against height), or,
the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
Note: This variance sucks, but it accurately captures the current state of the world (no consensus among implementations, and no consensus within the CSSWG). It is the CSSWG’s intention that browsers will converge on one of the behaviors, at which time the spec will be amended.
In addition to Michael_B's answer, here is a possible workaround.
When using percent we often relate that to the viewport width, so with that in mind, viewport units vw/vh can be an option, since it works similar (responsive).
Stack snippet
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
padding-bottom: 50vw;
}
<div class="outer">
<div class="inner">
<a>hehe</a>
</div>
</div>
Updated based on a comment
If a square is a must, and viewport units or script can't be used, here is another trick using a dummy image.
Note, as image also a SVG or a Base64 could be used as a datauri to save an extra round trip to the server
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
}
.inner img {
display: block;
width: 100%;
visibility: hidden;
}
<div class="outer">
<div class="inner">
<img src="http://placehold.it/10" alt="">
</div>
</div>

Maintaining height of element relative to its width [duplicate]

I want to have a square div inside a flexbox. So I use:
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
padding-bottom: 50%;
}
<div class="outer">
<div class="inner">
<a>hehe</a>
</div>
</div>
This works fine in Chrome. But in Firefox, the parent squeezes to just one line.
How do I solve this in Firefox? I use version 44.
You can also view the code at https://jsbin.com/lakoxi/edit?html,css
2018 Update
The flexbox specification has been updated.
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items, like those on block
boxes, are resolved against the inline size of their containing block,
e.g. left/right/top/bottom percentages all resolve against their
containing block’s width in horizontal writing modes.
Original Answer - applies to FF and Edge versions released before 2018
From the flexbox specification:
Authors should avoid using percentages in paddings or margins on flex items entirely, as they will get different behavior in different browsers.
Here's some more:
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items can be resolved against either:
their own axis (left/right percentages resolve against width, top/bottom resolve against height), or,
the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
Note: This variance sucks, but it accurately captures the current state of the world (no consensus among implementations, and no consensus within the CSSWG). It is the CSSWG’s intention that browsers will converge on one of the behaviors, at which time the spec will be amended.
In addition to Michael_B's answer, here is a possible workaround.
When using percent we often relate that to the viewport width, so with that in mind, viewport units vw/vh can be an option, since it works similar (responsive).
Stack snippet
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
padding-bottom: 50vw;
}
<div class="outer">
<div class="inner">
<a>hehe</a>
</div>
</div>
Updated based on a comment
If a square is a must, and viewport units or script can't be used, here is another trick using a dummy image.
Note, as image also a SVG or a Base64 could be used as a datauri to save an extra round trip to the server
.outer {
display: flex;
width: 100%;
background: blue;
}
.inner {
width: 50%;
background: yellow;
}
.inner img {
display: block;
width: 100%;
visibility: hidden;
}
<div class="outer">
<div class="inner">
<img src="http://placehold.it/10" alt="">
</div>
</div>

Simulating 2 columns for 4 successive divs

I have 4 successive divs:
<div class="container">
<div class="child">A</div>
<div class="child">B</div>
<div class="child">C</div>
<div class="child">D</div>
</div>
Assuming each child div has varying content, of different heights, and a margin added for clarity, it displays as follows:
Without changing the HTML in any way (no adding classes to the divs, no adding intermediary column divs), I would like to achieve this layout:
The order in which the divs are placed does not matter much.
I've tried things along the lines of:
.child { width: 50%; }
.child:nth-child(even) { float: left; }
.child:nth-child(odd) { float: right; }
But the alignnments are off. Does any CSS wizard have an idea?
Does this work?
DEMO
.container {
width:220px; /* (child width)x2 + (child margin)x4 */
}
.child {
margin:5px;
background-color:#FF0080;
width:100px;
}
.child:nth-child(even) {
float: left;
}
.child:nth-child(odd) {
float: right;
}
Well you could use CSS columns, which has good partial support across browsers (primarily prefixed though), but full support is not so great.
Give them a try:
.container {
-webkit-column-width: 250px;
-moz-column-width: 250px;
column-width: 250px;
width: 520px;
background: yellow;
}
.child {
background: red;
margin-bottom: 10px;
display: inline-block;
width: 100%;
}
Take a look at this jsfiddle for a demonstration: http://jsfiddle.net/xwwe3/ (complete with My First Colours to demonstrate what is happening).
The columns are set to 250px wide, which I found the .child didn't obey until given display: inline-block; width: 100%;. Then the width of .container is set to 520px to give the columns a gutter width of 10px with two columns (250 * 2 + 10 = 520)
So depending on whether you think the support is acceptable for your use case is up to you. Tweaking the heights of the .child elements does make some weird stuff happen, but I'd suggest you read up further on CSS columns and try and work out what is going there.
Alternatively, jQuery masonry is a popular way of achieving this.

Fixed width columns with fluid gutters

I know this can be done with columns, but I have to support IE.
I'm trying to get to a layout whose columns are all fixed width, with the gutters being fluid.
I couldn't get this to work with floats, so I settled on using justified inline-block items:
HTML
<div class="wrapper">
<div></div>
<div></div>
<div></div>
<!-- more divs... -->
</div>
CSS
.wrapper {
text-align: justify;
}
.wrapper div {
width: 100px;
display: inline-block;
}
This works wonderfully, but the last row of divs are all aligned to the left: http://jsfiddle.net/EsHh3/
The only solution I found is to add additional unnecessary divs: http://jsfiddle.net/EsHh3/1/
I feel uncomfortable about this, so I'd like to know if there are any other options.
Please don't tell me not to re-invent the wheel. I have not found any fluid grid system that supports fluid gutters.
For what you want to do, I'm afraid a CSS only solution is not available at the moment, much less if you want it to work in IE8.
Since you want to have (a) items that are in the HTML source as a list (b) a variable number of columns depending on available space (c) column spacing depending on width of container I think the solution you'll need would have to employ at least a bit of javascript.
Consider on of the frameworks proposed in the other answers. One I've worked with and could do what you want is Masonry (or the for-pay bigger brother Isotope). (There's also a non-jQuery version of Masonry). You'll have to come up with a function that when the page is resized, recalculates the desired gutter and reconfigures the framework. Something along the lines of calculating x = how many items would fit per line based on the container width and item width and then dividing the remaining space by x-1.
If you want to stick with the idea of adding extra DIV's to the markup, an alternative would be to listen to resize events, and add DIVs as needed based on the width and how many items would fit per line.
ORIGINAL ANSWER, which failed to fit all the criteria.
Since you're relying on text-align: justified the reason the last line doesn't expand to the full width is because there's no line break at the end of it. So to accomplish that we add an extra element with an wrapper:after {} rule, that is also an inline block with a width of 100% so it guaranties a line break.
See fiddle
The CSS ends up something like:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
}
.wrapper div {
width: 100px;
display: inline-block;
}
.wrapper:after {content: ''; width: 100%; display: inline-block; background: pink; height: 2px; overflow: hidden}
Note that the pink background is there so that you can see where the element is. You might need to play with the border/margin/padding of that extra element or the wrapper so that content that comes after wrapper doesn't gain extra margin. In chrome unfortunately there's a slight missalignment of the last row items, possibly because of the extra space between the last DIV and the fake element.
Hey I don't know why you want a fluid gutter, but I have a simple grid sample which you might want to have a look and if you want to see the css then click the SCSS on the codepen site. Also, if you are learning then this sample is very good start point for how to make your own grid. Also, to avoid yourself reinventing the wheel you might want to try different grid frameworks out there. Just google css grid frameworks.
you can try this:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
moz-column-count: 3;
-moz-column-gap: 20px;
-webkit-column-count: 3;
-webkit-column-gap: 20px;
column-count: 3;
column-gap: 20px;
}
Updated URL
This is how I would go about it: http://codepen.io/jeremychurch/pen/wmtJz
.container {
display: table;
width: 100%; }
.cell {
display: table-cell; }
.content {
width: 15em;
margin: 0 auto; }
<div class="container">
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
</div>

Resources