I'm trying to build myself a flexbox with the following design:
My html looks like this (and I would like to NOT change this):
<div class="wrapper">
<div class="page-header">Heading</div>
<h3 class="right_1">right_1</h3>
<div class="right_2">right_2</div>
<div class="left">form element</div>
<h3 class="right_3">right_3</h3>
<div class="right_4">right_4</div>
</div>
This is the standard layout of the joomla contact page. I want to change the design though without altering html/php code.
Is that possible using flexbox?
And can I use #media queries to make right_1 - right_4 to move under left on mobile view (< 800px or example)?
I myself cannot get it to work, I always end up with right_1 - right_4 next to each other instead of them stacking to the total height of the left portion.
The layout you want cannot be achieved with flexbox. The reasons are explained here:
Is it possible for flex items to align tightly to the items above them?
However, the layout is relatively simple with CSS Grid.
There are, in fact, multiple methods for building the layout with Grid. I'll use the grid-template-areas property, which allows you to lay out your elements using ASCII art.
.wrapper {
display: grid;
height: 100vh;
grid-template-columns: 1fr 1fr;
grid-template-areas:
" heading heading "
" left_ right1 "
" left_ right2 "
" left_ right3 "
" left_ right4 "
}
.page-header { grid-area: heading; }
.right_1 { grid-area: right1; }
.right_2 { grid-area: right2; }
.right_3 { grid-area: right3; }
.right_4 { grid-area: right4; }
.left { grid-area: left_; } /* "left" is a pre-defined CSS keyword,
so it may not work */
#media ( max-width: 800px ) {
.wrapper {
grid-template-columns: 1fr;
grid-template-areas:
" heading "
" left_ "
" right1 "
" right2 "
" right3 "
" right4 "
}
}
/* non-essential decorative styles */
.page-header { background-color: red; }
.right_1 { background-color: chartreuse; }
.right_2 { background-color: aqua; }
.right_3 { background-color: skyblue; }
.right_4 { background-color: black; color: white; }
.left { background-color: cornsilk; }
body { margin: 0; }
.wrapper > * {
font-weight: bold;
font-size: 1.5em;
border: 1px solid black;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
<div class="wrapper">
<div class="page-header">Heading</div>
<h3 class="right_1">right_1</h3>
<div class="right_2">right_2</div>
<div class="left">form element</div>
<h3 class="right_3">right_3</h3>
<div class="right_4">right_4</div>
</div>
jsFiddle demo
In essence, here's how it works:
We establish a block-level grid with display: grid.
With grid-template-columns: 1fr 1fr we are telling the grid to create two columns. The fr unit tells the container to consume available space. It's similar to flexbox's flex-grow property. So both columns will share the full width of the container.
The grid-template-areas property allows you to lay out named grid areas (that you have defined) to create a visual representation of your layout using ASCII art.
In the media query for smaller screens, we remove one column and re-order the grid areas.
Browser Support for CSS Grid
Chrome - full support as of March 8, 2017 (version 57)
Firefox - full support as of March 6, 2017 (version 52)
Safari - full support as of March 26, 2017 (version 10.1)
Edge - full support as of October 16, 2017 (version 16)
IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Here is one way to solve that, based on the existing markup and CSS Flexbox.
The left needs to be absolute positioned for desktop view and the page-header need a fixed height.
If you don't want to set a fixed height, you'll need a script that takes care of the height calculation
html, body {
margin: 0;
}
.wrapper {
position: relative;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.wrapper * {
padding: 0 10px;
margin: 0;
border: 1px solid black;
box-sizing: border-box;
}
.page-header {
height: 70px;
width: 100%;
background: red;
}
.right_1, .right_2, .right_3, .right_4 {
flex: 1;
width: 50%;
margin-left: 50%;
background: lightblue;
}
.left {
position: absolute;
left: 0;
top: 70px;
width: 50%;
min-height: calc(100vh - 70px);
background: yellow;
}
#media only screen and (orientation: portrait) {
.wrapper * {
width: 100%;
margin: 0;
}
.left {
position: static;
flex: 1;
min-height: auto;
order: -1
}
.page-header {
order: -2;
}
}
<div class="wrapper">
<div class="page-header">Heading</div>
<h3 class="right_1">right_1</h3>
<div class="right_2">right_2</div>
<div class="left">form element</div>
<h3 class="right_3">right_3</h3>
<div class="right_4">right_4</div>
</div>
Probably the easiest way to change the order of div elements, you can use Jquery for this purpose. For example:
$("#element1").before($("#element2"));
Eventually:
CSS:
#blocks {
display: box;
box-orient: vertical;
}
#b1 {
box-ordinal-group: 2;
}
#b2 {
box-ordinal-group: 3;
}
HTML:
<div id="blocks">
<div id="b1">Block 1</div>
<div id="b2">Block 2</div>
<div id="b3">Block 3</div>
</div>
It should work.
Related
I'm designing a simple webpage using HTML and CSS. I want to design a row at the top of my page which shall have 4 buttons - lets say with content "A", "BB", "CCC", "DDDD". I want to create these 4 buttons such that their width differs according to the length of the content, i.e "A" would be small, but "DDDD" would be a bigger button since it has 4 letters instead of 1.
Can I achieve this using just HTML and CSS or do I need to learn any more technologies for this?
This can be done with HTML alone:
<div class="top-row">
<button>A</button>
<button>BB</button>
<button>CCC</button>
<button>DDDD</button>
</div>
You can absolutely do that with flexbox. For example:
div.header {
position: fixed;
top: 0;
left: 0;
width: 100vw;
display: flex; /* This element is a flexbox */
}
a.button {
background-color: green;
min-width: 50px;
text-align: center;
border: 1px solid white;
}
section {
display: flex; /* This element is a flexbox */
flex-direction: row;
flex-wrap: nowrap;
background: pink;
}
div.column {
border: 1px solid grey;
min-height: 100vh;
}
/* These properties set the column widths within an element that is a flexbox */
.width-1x {
flex-grow: 1;
}
.width-2x {
flex-grow: 2;
}
.width-3x {
flex-grow: 3;
}
.width-4x {
flex-grow: 4;
}
<div class="header">
A
BB
CCC
DDDD
</div>
<section>
<div class="column width-1x"></div>
<div class="column width-2x"></div>
<div class="column width-3x"></div>
<div class="column width-4x"></div>
</section>
By setting the CSS flex-grow property of each button, we can decide what proportion of the width it would take.
Doing this through JavaScript would also work in the case that the columns need to be updated automatically according to their number of characters.
I'm trying to display two columns with the CSS Grid stretched to the bottom of the screen. I used flexbox to achieve it:
html, body {
height: 100%;
}
#root {
display: flex;
flex-direction: column;
min-height: 100%;
color: #fff;
}
#wrapper {
flex: 1;
display: grid;
grid:
"title title" min-content
"divider divider" min-content
"part1 part2" 1fr
/ calc(50% - 5px) calc(50% - 5px);
background-color: #003300;
grid-gap: 10px;
}
#title {
grid-area: title;
}
#divider {
grid-area: divider;
}
#part1 {
grid-area: part1;
}
#part2 {
grid-area: part2;
}
#part1, #part2 {
background-color: #ff0000;
}
<section id="root">
<section id="wrapper">
<div id="title">Title</div>
<div id="divider"><hr></div>
<div id="part1">Part 1</div>
<div id="part2">Part 2</div>
</section>
</section>
If you run this code in Firefox, you can see properly stretching red columns that reach the bottom of the screen. But in the Chrome they do not stretch properly and leave as small as possible. Is there some way to avoid this issue? I would like to save the flexbox-direction: column.
Maybe there is also a link to the chromium bug?
Looks like a bug in Chrome.
Flex and Grid properties don't play nice in this particular scenario.
I know you said you would like to keep flex-direction: column.
But you can get the same behavior with flex-direction: row when you add wrap to the container and make each item width: 100%.
And in this case, that switch in flex-direction solves your problem.
#root {
display: flex;
min-height: 100vh;
color: #fff;
}
#wrapper {
flex: 1;
display: grid;
grid:
"title title" min-content
"divider divider" min-content
"part1 part2" 1fr
/ 1fr 1fr ; /* calc(50% - 5px) calc(50% - 5px) why the added complexity? */
background-color: #003300;
grid-gap: 10px;
}
#title { grid-area: title; }
#divider { grid-area: divider; }
#part1 { grid-area: part1; }
#part2 { grid-area: part2; }
#part1,
#part2 { background-color: #ff0000; }
body { margin: 0; }
<section id="root">
<section id="wrapper">
<div id="title">Title</div>
<div id="divider"><hr></div>
<div id="part1">Part 1</div>
<div id="part2">Part 2</div>
</section>
</section>
jsFiddle demo
More information: Force flex item to span full row width
If you really can't switch from flex-direction: column, here are two options you can try:
move the min-height from #root to #wrapper (jsfiddle demo)
make the overall parent (body, in this case) a flex container (jsfiddle demo)
I'm trying to create this structure using only flexbox.
This is how my html looks like.
<div class="container">
<div class="first_container"></div>
<div class="second_container"></div>
<div class="third_container"></div>
</div>
I know it's really basic problem if i could just change divs order or add additional wrapper for the first line. The problem is it have to stay as it is.
Basic dimensions:
1. first_container - should takes 100% minus third_container width
2. second_container - shoudl takes 100%
I am asking for some tips, because my hands are slowly falling.
You can use flexbox order property
* {
box-sizing: border-box;
}
.container {
display: flex;
flex-wrap: wrap;
}
.container div {
padding: 10px;
border: 5px solid #fff;
background: gray;
text-align: center;
}
.first_container {
width: 70%;
order: 1;
}
.second_container {
width: 100%;
order: 3;
}
.third_container {
width: 30%;
order: 2;
}
<div class="container">
<div class="first_container">1</div>
<div class="second_container">2</div>
<div class="third_container">3</div>
</div>
This question already has answers here:
Is it possible for flex items to align tightly to the items above them?
(5 answers)
Make a div span two rows in a grid
(2 answers)
Closed 5 years ago.
I am trying to have one div on the left and two on the right. The bottomright should always be below the topRight div. The topRight is the only div with a variable height.
I am currently trying to achieve this using flexbox als you can see in my code below.
I would like to have some directions.
.wrapper {
display: flex;
height: 100px;
}
.left {
background-color: green
}
.topRight {
background-color: yellow
}
.bottomright {
background-color: red
}
<div class="wrapper">
<div class="left">Left</div>
<div class="topRight">TopRight</div>
<div class="bottomright">Bottom</div>
</div
With a fixed height on the container, as you have in your code, you can use flex-direction: column and flex-wrap: wrap. The fixed height serves as a break point, telling flex items where to wrap.
.wrapper {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 100px;
}
.left {
flex: 0 0 100%; /* consumes full height of first column; forces siblings to wrap */
background-color: lightgreen
}
/* variable height div */
.topRight {
background-color: yellow
}
.bottomright {
flex: 1; /* consumes remaining space in column */
background-color: red
}
<div class="wrapper">
<div class="left">Left</div>
<div class="topRight">TopRight<br>variable height</div>
<div class="bottomright">Bottom</div>
</div>
On html put a div with a class called right wrapping both topRight and bottomRight and use this css on css:
.wrapper {
display: flex;
height: 100px;
}
.right {
display: flex-flow;
}
.left {
background-color: green
}
.topRight {
background-color: yellow;
height: 50px;
}
.bottomright {
background-color: red;
height: 50px;
}
I hope that helps you :)
For infos
display:grid is made for this .... very soon available for most browsers and yet for a few
A tutorial among others : https://css-tricks.com/snippets/css/complete-guide-grid/
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* any height s */
background-color: green;
}
.leftspan {
grid-row: span 2;/* if 2 rows avalaible */
}
.topRight {
background-color: yellow;
grid-column: 2 /-1
}
.bottomright {
background-color: red;
grid-column: 2 /-1
}
.bottomfull {
background-color: red;
grid-column: 1 /-1
}
<div class="wrapper">
<div class="leftspan">Left spanning 2 rows</div>
<div class="topRight">Top <br/>Right</div>
<div class="bottomright">Bottom <br/>Right</div>
</div>
<p> or did you mean ?
<div class="wrapper">
<div class="left">Left</div>
<div class="topRight">Top Right</div>
<div class="bottomfull">Bottom <br/>Right</div>
</div>
render if your browsers understand grid:
The result I'm looking for is one big block on the left, and then four small blocks on the right, and everything aligns.
I managed to do this in this fiddle but my solution has a couple of problems:
- it's not very clean in terms of code
- it's not responsive
HTML:
<div class="wrapper">
<div class="box big">ONE</div>
<div class="med-wrapper">
<div class="row-1">
<div class="box medium">TWO</div>
<div class="box medium">THREE</div>
</div>
<div class="row-2">
<div class="box medium">FOUR</div>
<div class="box medium">FIVE</div>
</div>
</div>
</div>
CSS:
.wrapper {
display: flex;
flex-direction: row;
flex-flow: row wrap;
justify-content: space-around;
height: 200px;
}
/* #media screen and (max-width: 768px) {
flex-direction: column
} */
.box {
background: #09f;
color: white;
padding: 1em;
margin: 5px;
text-align: center;
}
.big {
flex: 5;
}
.medium {
flex: 5;
height: 100px;
}
.med-wrapper {
display: flex;
}
Also, you might notice that I have set the flex on both .big and .medium to 5, because I want the total width of the big box and the total width of two medium boxes to be equal, but it didn't work.
Is there a better way to do this?
It's tricky to have everything to align without getting into a lot of constraints, but using flexbox wrapping in the column direction on the right part could work.
Here's a quick version that uses a flex-flow: column wrap on the right part (.med-wrapper) and gets rid of the wrapper element on the two column wrappers inside it -
<div class="wrapper">
<div class="box big">
ONE
</div>
<div class="med-wrapper">
<div class="box medium">TWO</div>
<div class="box medium">THREE</div>
<div class="box medium">FOUR</div>
<div class="box medium">FIVE</div>
</div><!-- /.med-wrapper -->
</div><!-- /.wrapper -->
...and then the CSS:
body {
font-family: 'calibri', sans-serif;
margin: 0;
}
.wrapper {
display: flex;
justify-content: space-around;
height: 200px;
}
.box {
background: #09f;
color: white;
padding: 1em;
margin: 0 5px;
text-align: center;
box-sizing: border-box;
}
.big {
flex: 1;
height: 100%;
}
.med-wrapper {
flex: 1;
display: flex;
height: 100%;
flex-flow: column wrap;
justify-content: space-between;
overflow: auto;
}
.medium {
/* exact sizing for the medium boxes (i.e. get it from main sizing.) */
flex: 0 0 auto;
/* adjust for margins: */
width: calc(50% - 10px);
height: calc(50% - 5px);
}
/* some theoretical adjustments for smaller screens */
#media screen and (max-width: 768px) {
/* switch the wrapper to column dir, and remove fixed height. */
.wrapper {
flex-direction: column;
height: auto;
}
/* just a min height for demo purposes. */
.big {
min-height: 200px;
}
/* Now we need to re-set a height on this one, if we
want to keep the 2x2 square thing. */
.med-wrapper {
margin-top: 10px;
height: 200px;
}
}
Live demo at http://jsbin.com/kasez/5/edit
I've used calc()for the size calculations to counter margins, but hey, if you're already depending on flexbox, you probably need a fallback anyway. :-)
It should work with just the one explicit height on the .wrapper element, but the rest of the items should adjust accordingly - the downside is that overflow handling gets hard.
This is, incidentally, the type of "2D" situation (vs flexbox's 1D) that Grid Layout is meant to help with, but it'll be a while before that is a viable option.