CSS column layout with last elements' heights set equally - css

I have a 3-column layout which I'm trying to show you with this paint illustration.
I want the last divs of each column to take up the remaining space (blue).
The overall height of this layout is not fix, nor the number of divs.
Some of the divs will have fix dimensions, others don't.
Is there a pure CSS solution for this?

The cleanest way to achieve this is to use CSS flexible boxes:
<div class="col1"> ... </div>
<div class="col2"> ... </div>
<div class="col3"> ... </div>
CSS:
body{
display: -ms-flexbox; /* ie 10 (older but working flex implementation) */
display: -webkit-flexbox;
display: flex;
min-height: 100vh; /* optional, forces minimum height to 100% of viewport */
margin: 0;
padding:0;
}
.col1, .col3{
width: 25%;
}
.col2 {
width: 50%;
}
(demo)
The markup is simple, CSS is easy to understand, no "hacks". The only disadvantage right now is the poor browser support (IE 10+). I wouldn't consider it a big one, because you can work around this in IE 9- by using javascript.
Check out "Solved by flexbox" for other uses cases.
Another good solution that I have been using for years is the "The Perfect 3 Column Liquid Layout". The CSS is clean, but a little harder to understand and HTML is a little bulky because it requires wrapper elements for each column. If you need IE 6+ support without resorting to javascript, this is probably the 2nd best choice.
There are other ways to do this:
Table layout (display:table and related properties)
Background images on the body (for solid colors CSS gradients work too)
They are explained in this article (ignore the flex box one, because it uses the old implementation with some unnecessary 99999px margin hack).
But these introduce other limitations that can outweigh the ones from the first two methods. For example, Firefox not positioning absolute elements relative to the table cell. With backgrounds this kind of positioning is not possible at all, because the columns don't have real 100% height

Susy might do the trick for you.
It lets you easily make responsive grids in Sass which isn't vanilla css but will compile down to it. Square Market uses susy and if you take a look at their home page, linked previously and included below, they accomplish a similar effect to what your looking for.
Heres a basic example of a responsive grid so you can get a feel for how easy it is:
// Complex AG grid, brought to you by Susy:
.ag1 { #include span-columns(2,10); }
.ag2 { #include span-columns(6,10); }
.ag3 { #include span-columns(2 omega, 10); }
.ag4 { #include span-columns(3,6); }
.ag5 { #include span-columns(3 omega,6); }
.ag6 { #include span-columns(2,6); }
.ag7 { #include span-columns(4 omega,6); }
.ag8 { #include span-columns(2,4); }
.ag9 { #include span-columns(2 omega,4); }
.ag10 { clear: both; }
Like you want, you dont have to specify the overall height of a particular column and can lock the dimensions of a particular column in.

This can be achieved with a combination of CSS Grid and Flexbox:
html,
body {
height: 100%;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
border: solid 2px gray;
padding: 12px;
height: 100%;
grid-gap: 10px;
min-height: 450px;
}
.column {
display: flex;
flex-flow: column;
}
.item {
border: solid 2px orangered;
height: 100%;
margin: 5px 0;
}
.item.fixed1 {
height: 100px;
}
.item.fixed2 {
height: 380px;
}
<div class="grid">
<div class="column">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item fixed1"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item fixed2"></div>
<div class="item"></div>
</div>

Related

Dynamic width of div

I would like my div to have the maximum width available, so that the text inside it will wrap if needed when the page is shrunk (just the text should wrap when div will have his max width instead breaking all structure). I found a solution on the internet, but I can't translate it to my specific case. I have looked everywhere and cannot find a way to solve this problem...
All I know that I have to use display: flex and flex: 1 1 auto; somehow, but I can't find good way to do that.
#####EDIT
The problem was that I was using strings without spaces, what was breaking the structure. Adding word-break: break-all; fixed that. Below I put my code. Maybe will be useful for someone
HTML:
<div class="row">
<div class="div1">
</div>
<div class="div2">
<div class="div21"></div>
<div class="div21auto"> fadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfssfadsfsfadsfssfadsfsfadsfssfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfsfadsfssfadsfsfadsfssfadsfsfadsfssfadsfsfadsfs
</div>
<div class="div21"></div>
</div>
<div class="div1">
</div>
</div>
CSS:
/* important stuff for this example */
.row {
display:flex;
}
.div2 {
display:flex;
flex-direction: column;
}
.div1 {
width: 30px;
height: 90px
}
.div21 {
height: 30px
}
.div21auto {
height: 30px
flex: 1 1 auto;
word-break: break-all;
}
/* other stuff */
div {
padding:1em;
margin:0.2em;
background-color: rgba(0,0,0,0.125)
}
.row {
width:80%;
padding:1em;
overflow:hidden;
}
Maybe set a min-width attribute for that div? That way, that element will always be at least a certain width.

How to move column cell content to a new row using CSS (making an HTML grid responsive)

I have a post grid layout that I'm trying to make responsive and am having some trouble figuring out the best approach for reorganising/reordering the content using CSS.
The original grid looks like this:
So an image on the left, that's the full height of the parent div (for which the recommendations are usually Flexbox or Absolute positioning), and then two rows in the second column for post content).
What I'm trying to figure out is the best way to code it so I can reorder the blocks to the layout below using CSS (i.e. keeping the HTML code/structure the same):
Essentially, I need to figure out the best way to move block 3 (the bottom "cell" in the second column) out of the second column and onto its own new row using CSS.
I've tried Flexbox, but can't make the structure work for both layouts. The first layout seems to require a nested column structure (the second column requiring its own div to dictate the flex-direction) and the second won't work if I have one (I can't "escape" the box 3 content from the column if it's hardcoded).
Same thing for a table layout, the HTML has to dictate what cell goes where/rows and columns.
The closest solution I have so far is three basic HTML divs, one on top of the other, and "absolute" positioning for box 1.
Basic HTML
<div class="container">
<div class="box-1">
<img=full-height-image>
</div>
<div class="box-2">
<post-title-and-meta>
</div>
<div class="box-3">
<post-excerpt-read-more>
</div>
</div>
Basic CSS (Desktop)
.container{
position: relative;
}
.box-1{
height: 100%;
position: absolute;
max-width: 33.333%;
}
.box-1 img{
height:100%;
object-fit:cover;
}
.box-2,
.box-3{
margin-left: 33.333%;
max-width: 66.666%;
}
Basic CSS (Responsive)
.container{
position: relative;
}
.box-1{
display: inline-block;
position: relative;
max-width: 33.333%;
}
.box-1 img{
height:100%;
object-fit:cover;
}
.box-2{
display: inline-block;
}
.box-3{
display:block;
margin-left:0;
max-width:100%;
}
But this doesn't seem like a particularly elegant/foolproof approach.
Based on what I need to do, and the "full height of parent div" image requirement, is there a better way to do this?
you can switch from a table display to a flex display (use mediaquerie to choose when to switch from a layout to another) .
absolute and object-fit can indeed be used for the image.
example of the idea :
div {
/* reset */
border: solid 1px;
box-sizing: border-box;
}
/* table-layout example , first box */
.container {
width: 80%;
margin: 0.25em auto;
display: table;
background: lightblue
}
.container .box-1 {
display: table-cell;/* no need to filter, once parent is flex, it doesn't matter*/
vertical-align: top;/* it won't disturb once a flex-child*/
width: 33%;
position: relative;
}
img {
position: absolute;
object-fit: cover;
height: 100%;
width: 100%;
}
div>div:last-child {
background: lightgreen
}
/* flex layout example, second box */
.bis {
display: flex;
flex-wrap: wrap;
}
.bis>div:nth-child(2) {
flex: 1;
background: tomato;
}
.bis>div:last-child {
min-width: 100%;
}
<div class="container">
<div class="box-1">
<img src=http://dummyimage.com/100>
</div>
<div class="box-2">
<h1>post-title-and-meta</h1>
</div>
<div class="box-3">
<p>post<br>excerpt</p>
<p>read-more</p>
</div>
</div>
<div class="container bis">
<div class="box-1">
<img src=http://dummyimage.com/100>
</div>
<div class="box-2">
<h1>post-title-and-meta</h1>
</div>
<div class="box-3">
<p>post<br>excerpt</p>
<p>read-more</p>
</div>
</div>

CSS Grid - How to make items responsive

I was trying to make the 2 items (box1 and box2) responsive on small screen, but I couldn't seem to figure it out. Please help. Thanks!
<html lang="en">
<head>
<style>
body{
background: lightblue;
}
.container{
padding:10px;
display: grid;
background: lightyellow;
width:100%;
grid-gap:5px;
justify-content:center;
grid-auto-flow: column;
grid-auto-columns: 300px 100px;
}
.box1{
background: lightgray;
min-height:150px;
}
.box2{
background: lightgreen;
min-height:150px;
}
</style>
</head>
<body>
<div class="container">
<div class="box box1">BOX 1</div>
<div class="box box2">BOX 2</div>
</div>
</body>
</html>
You've told the columns to be a fixed width...so they're naturally not responsive.
Use percentage or fractional values instead.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::before,
::after {
box-sizing: inherit;
}
body {
background: lightblue;
}
.container {
padding: 10px;
display: grid;
background: lightyellow;
width: 100%;
grid-gap: 5px;
justify-content: center;
grid-auto-flow: column;
grid-auto-columns: 3fr 1fr;
}
.box1 {
background: lightgray;
min-height: 150px;
}
.box2 {
background: lightgreen;
min-height: 150px;
}
<div class="container">
<div class="box box1">BOX 1</div>
<div class="box box2">BOX 2</div>
</div>
grid-auto-columns: 300px 100px;
in that line above you use ABSOLUTE sizes. If you want them to be responsive use % instead of px.
something like
grid-auto-columns: 30% 10%;
Any time you use fixed pixel widths, your elements will remain at that size and not be responsive.
The quick and easy solution to this is to switch to percentage widths, which tells the element to be a proportion of its container's size. Assuming the container is itself responsive, then this will make your elements change size according to the width of the screens. You need to do this all the way through your CSS, as any fixed sizes further up the element tree could stop everything inside from responding.
However, a naive percentage figure is often not a perfect solution, because things may not look right with the same proportions at lower screen sizes. For example, a three-column layout may shrink down, but it will look very squashed on a small mobile phone screen.
There are a bunch of solutions to this, and the exact answer will depend on your page design and your preferences.
First up, consider using min-width and max-width with pixel sizes to limit the sizes of your elements. These CSS values will override the percentage if the percentage figure causes them to go above or below the max or min width that you specify. This can be helpful for preventing things from getting exessively squashed or stretched out while still responding appropriately within the desired range.
Next, you need to know about Media Queries. This is a CSS feature that allows you to specify CSS that is only applied when the browser size is within a specified range. (Media queries can do a lot more than this, but I'll leave it to you to investigate them further)
An example might help here:
#media(max-width:600px) {
.container {
grid-auto-flow: unset;
grid-auto-columns: unset;
}
}
The example above uses a media query to switch off your columns if the browser width is 600 pixels or less. For narrow browsers, a column-based layout may not be appropriate, so switching away from it at low resolutions is often a good idea.

Adjust child size based on number of children

I want to make a UI that is similar to tabs in a browser.
To this end, I have elements with this CSS:
width: 20%;
max-width: 150px;
Nice and simple, responsive and awesome.
Only supports five tabs, though. If I want to support 10 tabs, it's as easy as changing to width: 10%.
So basically, I want something like:
width: calc(100% / number-of-children)
If such a thing were possible, that'd be amazing.
I'm currently just using JavaScript to set the width to the above expression. Simple, functional, but I figured I'd ask if anyone knows of a CSS-only solution.
with CSS3 you may use display: flex. E.g.
markup
<section>
<div>tab 1</div>
<div>tab 2</div>
<div>tab 3</div>
<div>tab 4</div>
</section>
Css
section {
display: flex;
}
div {
flex-grow: 1;
max-width: 150px;
}
Codepen example: http://codepen.io/anon/pen/EGbpH/
display: table is your friend.
ul {
display: table;
width: 100%;
}
li {
display: table-cell;
}
Demo
In CSS3 there's a function called calc() so you can use
width: calc(100% / 10);
Here you can find documentation and which browser support it ;)

How to float an element left with full height of the wrapper?

HTML:
<div class="wrapper">
<div class="left">
Foo
</div>
<div class="right">
Text row 1
</div>
</div>
<div class="wrapper">
<div class="left">
Foo Bar
</div>
<div class="right">
Text row 1<br>
Text row 2<br>
Text row 3
</div>
</div>
CSS:
.wrapper {
overflow:hidden;
}
.left {
width:80px;
float:left;
height:100%;
}
How can I give the floating div the full height of the wrapper (whose height is varying)?
is it possible without jQuery?
Test: http://jsfiddle.net/Q6B43/
The display: table solution
Within tables each cell of a row has the same height.
.wrapper {
display: table;
width: 100%;
}
.left, .right {
display: table-cell;
}
This is the best solution in my opinion, but is not compatible before IE8.
Here is the Fiddle for this solution.
Using absolute positioning
Absolute positioned elements respect their relative parents height:
.wrapper {
position: relative;
padding-left: 85px;
}
.left {
position: absolute;
left: 0;
top: 0;
}
Normally I would not recommend absolute positioning in most situations. But as you have a fixed width anyway, maybe it does not matter. But be aware of the fact that this will ignore long contents in .left. The height is just controlled by .right.
Here is an update to your Fiddle.
The flexible solution
This is so new I would not recommend using it right now, but just to be complete. You could use CSS3 flex, but be aware of browser compatibility:
.wrapper {
display: flex;
}
The Fiddle (tested in current Chrome and Firefox).
The grid layout
Even newer than flexbox, CSS grid seams to be the perfect answer for layout questions.
.wrapper {
display: grid;
grid-template-areas: 'left right';
}
.left {
grid-area: left;
}
.right {
grid-area: right;
}
Browser compatibility is rare, if you go back a view versions. Besides, it would be overkill for the OP's scenario in my opinion, but for more complex layout troubles in the future, this is a very powerful thing.
See it in the Fiddle.
Add:
body, html { height:100% }
And give your wrapper a fixed height in pixels.

Resources