Implementing a "Mondrian" pattern using Flexbox - css

The article 5 Really Useful Responsive Web Design Patterns describes a "Mondrian" pattern for layout on the web that arranges one large box on the left (2/3 or 3/4 width) with a few smaller items, stacked vertically on the right — but then in medium-sized viewports, the design shifts to show the main box at full width, with the other boxes side-by-side, horizontally below. (And on small screens, everything is 100% width stacked vertically.)
I have this pattern implemented using floating divs, but I would like to get this implemented using flexbox, so that the boxes can be of equal height no matter what. That's what flexbox is so good at!
Conceptually, I think that this can work, but I am just not having any luck at all with this. I'm surprised that I haven't found any references to this (except for a jsfiddle that's not really what I'm looking for at all.)
I believe that this could be implemented with column wrapping, and the first item's flex basis fairly large so that it takes up all of the vertical space on larger viewports, with the remaining boxes wrapped into a second column, stacking vertically. Using a media query, I think you could then just change the flex-wrap to be row-based so that the remaining smaller boxes get arranged side-by-side below the main full-width image.
And yet, I get nothing. No point even linking to my CodePen work in progress because it's just so pathetic. :-)
Anybody who is super-flexy interested in showing how this might be done?

/* ┌──────────────────────────────────────────────┐
│ These values determine when to switch layout │
└──────────────────────────────────────────────┘ */
.big {
flex-basis: 600px;
}
.outer.flex, .small {
min-width: 300px;
}
/* ┌───────────────────────────────┐
│ This other code makes it work │
└───────────────────────────────┘ */
html, body, .outer.flex {
margin: 0; /* Remove margins */
height: 100%; /* Fill all window */
}
.flex {
display: flex; /* Magic begins */
flex-wrap: wrap; /* Multiline */
}
.big, .small {
overflow: auto; /* In case the content doesn't fit */
box-sizing: border-box; /* Desirable if you want border or paddin */
border: 3px solid; /* Optional */
}
.big {
flex-grow: 2; /* Grow to fill available space, with factor 2 */
min-height: 50%; /* At least 50%, and allow 100% */
background: red; /* Optional */
}
.inner.flex {
flex: 1; /* Grow to fill available space, with factor 1 */
min-width: 33vw; /* At least 33% of the width of the window */
min-height: 50%; /* At least 50%, and allow 100% */
}
.small {
flex: 1 33vw; /* Grow to fill available space, with factor 1 */
/* At least 33% of the width of the window */
background: blue; /* Optional */
}
.small:first-child {
background: green; /* Optional */
}
<div class="outer flex">
<div class="big"></div>
<div class="inner flex">
<div class="small"></div>
<div class="small"></div>
</div>
</div>

Related

How do I vertically center the feature image for all posts in Wordpress?

I have a vanilla site and have a lot of posts already. The banner feature image for all of them is set to "top aligned" as a default setting so it looks pretty bad. I'd like ALL banner featured images to simply be vertically center aligned.
I tried this .css from a post, but it doesn't work in style.css, has no affect (maybe it just impacts the main landing page?).
.banner {
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
Does anyone have a simple solution that doesn't require plugins? Thanks.
Following my comment I created a little snippet showcasing what I mean with:
Using display: grid; place-items: center on an elements parent usually horizontally and vertically centers the parent content, whether this is center viewport depends on height/width of the parent...
snippet
* { outline: 1px dashed } /* for debugging */
/********************************/
/* some convenient global rules */
/********************************/
* { box-sizing: border-box }
html, body { width: 100%; max-width: 100% }
/* make room to minimally occupy the full viewport */
body { min-height: 100vh; margin: 0 }
/* ... and kill the default margin */
/* some full page parent */
.parent {
display: grid; place-items: center;
width: 100vw; height: 100vh;
}
.banner {
/* restrict banner size, either 30rem
or full width if less available (mobile) */
max-width: min(30rem, 100%);
}
img {
display: block; /* removes tiny space below image */
width: 100%; /* stretch to fill parent */
height: auto; /* follow where width leads */
object-fit: cover; /* clip if larger than space available */
}
<div class="parent">
<div class="banner">
<!-- retrieve some large picture -->
<img src="https://picsum.photos/1280?random">
</div>
</div>
After exhaustive search, I found the best solution is the show the whole image. This requires an override of the theme settings. To get there, from the control panel, go to: Appearance -> Themes -> Customize. Then at the bottom of the left column, click on Additional CSS. Enter the following and click Publish button at the top of the left column...
.post__thumbnail
{
padding: 29% !important;
}
I would have liked to keep the image frame dynamic and shown on the center sliver of the image as best served for various devices, but for now, this was the best option for me.

Make second div appear above first, without absolute position or changing html

My page is split into 3 slices, as shown in this JFiddle.
In my full source code, I have media queries to help manage sizing between mobile and desktop. When someone accesses the site on mobile mode, Logo should appear at the top, and Items should appear below it. (I set display: none on my picture div to hide it)
Problem:
I can't change the positioning of the divs in HTML, or it'll disturb my current 3 slice layout. Absolute positioning is not an option, since most of my site is already dynamically sized, and I wouldn't want absolute positioning to interfere on a resolution I haven't tested on. This means calculating the margin sizes would be out of the question aswell.
So, absolute positioning is not allowed, nor is changing the orders of the divs. The result I'm looking for would be similar to this, exception without repositioning the divs.
My question is not about media queries, or how to size for mobile using media queries. I am only asking about how to get the layout I want with the restrictions in place (no absolute positing, no calculating margins, no changing div order).
Other questions I looked at:
Reposition div above preceding element - First answer suggests repositioning divs, which I cannot do. Second answer relies on calculating the position, which could interfere with other dynamically sizing elements.
Move The First Div Appear Under the Second One in CSS - Suggests I use absolute positioning, which I cannot do
Flexbox layout is your friend here. display: flex can be used to interchange the elements position on the layout.
#container { display:flex; flex-direction: column; text-align:center;}
#items { order: 2 }
#logo { order: 1 }
#picture { display: none; }
<div id="container">
<div id="items">Items</div>
<div id="logo">Logo</div>
<div id="picture">Picture</div>
</div>
display: flex works only in modern browsers. Check caniuse.
A test on my android mobile shows it working on Firefox and Chrome, but not on the stock Android browser.
I tried to solve the solution using transform: translateY property in percentage value.
Note: This works if and only if the two containers have same height. or if the height is already known, then you can set the transform: translateY value according to the height.
CSS
#media (max-width: 700px) {
#container > div {
width: auto;
display: block;
float: none;
}
#container #picture {
display: none;
}
#logo {
transform: translateY(-100%);
}
#items {
transform: translateY(100%);
}
}
Working Fiddle
Probably the easiest is if you play with minus margins. Note that the below sizes (width and side margins) may need to be adjusted to your specific needs.
#container * {
width: 95vw;
text-align: center;
}
#items {
width: 50%; /* #picture is hidden so we split the screen into 2 */
float: left;
margin-top:30px; /* has to be smaller than the absolute of #logo */
margin-left:25%; /* half of the element's width */
}
#logo {
width: 50%; /* #picture is hidden so we split the screen into 2 */
float: right;
margin-top:-40px; /* its absolute has to be greater than the one of #items */
margin-right:25%; /* half of the element's width */
}
#picture {
width: 33%;
float: right;
display:none; /* Hiding #picture as you said you would */
}
<div id="container">
<div id="items">Items</div>
<div id="logo">Logo</div>
<div id="picture">Picture</div>
</div>

Dynamic size, two column layout with one column vertically and horizontally aligned, legacy browser support

I am trying to create a two column layout, with content in column 1 both horizontally and vertically aligned in the middle, whereby the content of column 2 will vary in size. The width of both columns is fixed to 50% of the width of the screen.
In modern CSS complaint browsers I can simply do the following:
CSS:
#wrapper
{
display: table;
width: 100%;
/* for illustration purposes */
background: #ddd;
}
#left-column
{
display: table-cell;
width: 50%;
text-align: center;
vertical-align: middle;
/* for illustration purposes */
background: #fdd;
}
#right-column
{
display: table-cell;
/* for illustration purposes */
background: #ddf;
}
HTML:
<div id="wrapper">
<div id="left-column">
<p>I am both horizontally and vertically centered in column 1</p>
</div>
<div id="right-column">
<p>I am dynamic content in column 2, i.e. my size will vary</p>
<p>I am dynamic content in column 2, i.e. my size will vary</p>
<p>I am dynamic content in column 2, i.e. my size will vary</p>
<p>I am dynamic content in column 2, i.e. my size will vary</p>
<p>I am dynamic content in column 2, i.e. my size will vary</p>
</div>
</div>
However, the bad news is I also need this to work in IE6, and IE7...
The solutions I've seen so far are quite ugly and involve lots of nested divs. What's the cleanest way to achieve this so that it will work in all browsers? I've experimented with float: left, for the two column layout, but my main problem is the vertical alignment in the first column.
PS. I don't want to use tables for the layout, although it does work, it's bad for screen readers and therefore breaks my accessibility guidelines.
Thanks in advance!
With static content on the left-hand column, your solution is simple: use fixed heights and padding.
CSS
#left-column {
height: 50%; /* adjust height dependent on N&S padding */
padding: 20% 0; /* adds north and south padding to "center" #left-content */
}
#left-content {
height: 10%; /* adjust to exactly fit content */
text-align: center;
/* basically for testing, this will help us find the ideal
* percentage for our #left-content height. */
overflow: hidden;
background-color: red;
}
HTML
<div id="left-column">
<div id="left-content">
your image and text goes here
</div><!-- /left-content -->
</div><!-- /left-column -->
In your CSS, you will need to adjust the heights and paddings to achieve your desired result.
I would suggest ensuring the content in #left-content is 100% responsive. This may not be a 100% solution, but with some work on it (#media queries, etc), you should be able to achieve your goal in every browser and viewport size. The only thing I can think of off the top of my head that might break something like this is user-increased font size.
Unfortunately vertically centering something is either going to take javascript or a few ugly nested divs. If you are a maniacal purist I would recommend a float left, top aligned left column and enhance with javascript to be pushed to center.
That said, a couple wrapper divs never killed anyone.
Cracked it, I think... Html as in the original post, and CSS as follows:
#wrapper
{
width: 100%;
overflow: hidden;
position: relative;
/* for illustration purposes */
background: #ddd;
}
#wrapper p { font-size:1em; margin: .5em; }
#right-column
{
margin-left: 50%;
overflow: hidden;
/* for illustration purposes */
background: #ddf;
}
#left-column
{
width: 50%;
height: 2em;
position: absolute;
left: 0;
top: 50%;
margin-top: -1em;
text-align: center;
/* for illustration purposes */
background: #fdd;
}
The margin on the inner <p> tag needs setting so that we know what the height will be (the different browsers seem to default the margin of a <p> differently if you don't explicitly set it), I used em so that it scales nicely on different displays.
It's funny how something this simple can be such a pain to achieve... I'm still not 100% happy with it as if the content of column 1 wraps on a small display (or minimised window), then it won't be vertically aligned properly...

Incorrect width on iPad

After starting work for a new company, I've been charged with building a new site for them. This is what I've got so far:
http://ghostevolution.com/ghostds/
The problem is that it isn't working correctly on the iPad - the header background colour doesn't stretch across the full width of the screen like it is meant to - this is also true of the mid-section light-grey background colour on pages such as http://ghostevolution.com/ghostds/?page_id=160
Does anyone know why this is? Thank you.
The half-assed proper way to do this is to wrap your contents in a container that spans 100% of the screen width. For example:
CSS
.wrapper {
display: block;
width: 100%;
padding: 10px 0; /* add some top + bottom padding */
background-color: #252525;
}
.aligner {
display: block;
width: 960px;
margin: 0 auto;
}
.container {
display: inline-block;
}
HTML
<div class="wrapper">
<div class="aligner">
<div class="container">
// stuff
</div><!-- /container -->
</div><!-- /aligner -->
</div><!-- /wrapper -->
It's not the prettiest, but it allows you to throw 100% width background-colors on any section, and works in < IE8. You can do whatever you need to within div.container (float, position, etc) and it will expand the .wrapper element (thus expanding your background color).
Each div.wrapper should be treated as a "section" - 'header', 'feature', 'content', 'footer', etc...
Another alternative is to start using #media queries, which would allow you to essentially plug in code for specific screen widths (880/1024px for iPad, portrait/landscape).
#media screen and (max-width: 880px) {
.my_element {
/* attributes */
}
}
This is due to issue that is often forgotten (in desktop browsers as well). I'm pretty sure..
You see, with any desktop browser. Change the width of the window less than your wrapper width and scroll to the right. That would show the page as cut off.
This can be fixed quite easily.
removed csspivot site since its no longer running
The basic idea is to add the same background that gets cut off into element that has fixed width since browser can't do anything to that.
Add CSS:
#auxiliary .wrap {
background-color: #bbb; /* Same as the #auxiliary bg color*/
}
#branding .wrap {
border-top: 6px #92C201 solid; /* Same as #branding border and bg and height*/
background-color: #333;
height: 60px;
margin-top: -6px; /* I wouldnt necessarily use this to get it to top but works as well. */
}

CSS Dynamic Vertical Height

I'm working on a new layout for my website and I want the user to be able to change views. One view is a static 540 pixels tall and horizontally/vertically centered. The second is no longer vertically centered and allows the content to define the height.
It's currently working with the first option, but in the second option, the utility column (2011 Browsers Usage Stats) does not fill the entire height. Is there a solution to this?
I don't know how much source code you want. I've listed a link to my website and the differences in CSS code below.
My Website
The first option (currently working):
#floater {
margin-bottom: -27em; /* vertical center - half of container's height */
height: 50%; /* vertical center */
}
#wrapper {
height: 54em; /* vertical center */
}
#content {
height: 33em; /* static height */
}
The second option (not working):
#floater {
margin-bottom: 0em; /* vertical top */
height: auto; /* vertical top */
}
#wrapper {
height: auto; /* vertical 100% */
}
#content {
height: 100%; /* dynamic height */
}
Consider what you're doing versus what you're saying:
#content {
height: 100%; /* dynamic height */
}
but in the second option, the utility column (2011 Browsers Usage Stats) does not fill the entire height
You can only pick one. Do you want it to fill the entire height or be dynamic?

Resources