How to "skip" div in HTML tree when using Flexbox? - html

I am trying to use Flexbox on an existing site, and I need to somehow tell the browser to "skip" several divs in the tree.
Let me explain on a simplified example. I have a HTML like this
<body style="display: flex;
min-height: 100vh;
flex-direction: column;">
<div id="want_to_skip">
<div style="flex: 1;">
</div>
<div id="footer"></div>
</div>
</body>
and I want it to behave as it was like this
<body style="display: flex;
min-height: 100vh;
flex-direction: column;">
<div style="flex: 1;">
</div>
<div id="footer"></div>
</body>
Unfortunately, I need the "skipped" div to be there and cannot remove it. What should I do?

CSS Display L3 introduces display: contents:
The element itself does not generate any boxes, but its children and
pseudo-elements still generate boxes as normal. For the purposes of
box generation and layout, the element must be treated as if it had
been replaced with its children and pseudo-elements in the document
tree.
#want_to_skip {
display: contents;
}
body {
display: flex;
margin: 0;
}
body > div {
flex: 1;
}
.wrapper {
display: flex;
min-height: 100vh;
flex-direction: column;
border: 1px solid;
}
.top {
flex: 1;
}
.want_to_skip {
display: contents;
}
<div>
<div class="wrapper">
<div>
<div class="top"> No skipping - Top </div>
<div class="bottom">No skipping - Bottom</div>
</div>
</div>
</div>
<div>
<div class="wrapper">
<div class="want_to_skip">
<div class="top"> Skipping - Top </div>
<div class="bottom">Skipping - Bottom</div>
</div>
</div>
</div>
<div>
<div class="wrapper">
<div class="top"> Desired - Top </div>
<div class="bottom">Desired - Bottom</div>
</div>
</div>
Currently, it is only supported by Firefox 37.

Related

How do I correctly nest a flexbox to achieve a form layout?

I am looking to achieve the following layout:
Here is how I'm picturing it (with grids):
Black bar is the nav (we can ignore this)
A title and subtitle (purple) - these should be aligned and take up approx 70% of width - I think I've done this
A form which has 3 columns (should take up 70ish percent of the 70%, I don't want inputs to be too wide)
Column 1: Heading + text pairs
Column 2: it will have some icon/character - these must be perfectly aligned
Column 3: Heading + input boxes - these must be the same width
Here is my starting HTML:
.title-container {
display: flex;
justify-content: center;
background: red;
}
.title-item {
flex-basis: 75%;
}
.data-container {
display: flex;
justify-content: center;
background: blue;
}
.column-items {
flex-basis: 70%;
display: flex;
flex-direction: row;
}
.column-1-item {
background: green;
flex-grow: 0.5;
}
.column-2-item {
background: yellow;
flex-grow: 0.1;
align-self: center;
}
.column-3-item {
background: orange;
flex-grow: 1;
}
<div class="title-container">
<div class="title-item">
<h2>Title</h2>
<p>This is some text</p>
</div>
</div>
<div class="data-container">
<div class="column-items">
<div class="column-1-item">
<p>Heading1</p>
<p>SomeText</p>
</div>
<div class="column-2-item">
<p>--></p>
</div>
<div class="column-3-item">
<p>Heading1</p>
<input type="text" name="lname">
</div>
</div>
</div>
I have tried to expand on this, but no matter what I try, I end up further away from my design making me think there is something wrong with my initial design (and flex understanding). If I add additional 'row', it breaks my layout. I also think my data-container is wrongly setup, since this will take up far more space than I want it to
Here is a code pen.
Could someone help get me closer to my design?
I would wrap your entire html in a wrapper class so that you can get the general layout of the page like so:
<div class="wrapper">
<div class="title-container">
<h2>Title</h2>
<p>
Subtitle should be aligned with title
</p>
</div>
<div class="form-container">
<div class="item">
<div class="column">
<p>Heading1</p>
<p>Some Text</p>
</div>
<div class="column">
<p>-></p>
</div>
<div class="column">
<p>Heading1</p>
<p>[ input textfield ]</p>
</div>
</div>
<div class="item">
<div class="column">
<p>Heading3</p>
<p>Some Text</p>
</div>
<div class="column">
<p>-></p>
</div>
<div class="column">
<p>Heading2</p>
<p>[ input textfield ]</p>
</div>
</div>
<div class="item">
<div class="column">
<p>Heading3</p>
<p>Some Text</p>
</div>
<div class="column">
<p>-></p>
</div>
<div class="column">
<p>Heading3</p>
<p>[ input textfield ]</p>
</div>
</div>
<div class="item">
<div class="column"></div>
<div class="column"></div>
<div class="column submit-button">
<p>[ Button ]</p>
</div>
</div>
</div>
</div>
Then you can specify the width for the title-container and form-container with the width property. Making each of the item classes in the form container have a display: flex property lets you format the children column classes to have flex-grow: 1 so they can fill up the available space. The css then looks like:
.wrapper {
display: flex;
flex-direction: column;
align-items: center;
outline: 1px solid red;
}
.title-container {
width: 70%;
outline: 1px solid red;
}
.form-container {
width: 50%;
outline: 1px solid red;
}
.item {
display: flex;
outline: 1px solid red;
}
.column {
/* flex-grow: 1; */
flex: 1 1 0px;
outline: 1px solid red;
}
.submit-button {
display: flex;
align-items: flex-end;
justify-content: flex-end;
}
Alternately you can remove the flex-grow: 1 property from the column class and add justify-content: space-between to the item class to get a result similar to your example.
Here is the codepen.
Your .data-container just needs a flex-direction: column; because you want the .column-items to stack.

Layout a flex box similar to a table?

I'm working with a framework developed in-house which depends on a certain structure to our HTML. And one of the tricky things is that each row needs its own container with its own classes and data attributes.
So here's the problem. Without drastically changing the DOM, how can I make the flex box below render essentially like an HTML table would? Or is a table the only way? The solution will have to work in both IE11 and Chrome.
I'm trying to make it look like this...
Column A | Column B | Column C
1 | 2 | 3
section {
display: flex;
flex-wrap: wrap;
}
section .col {
flex: 1 1 auto;
}
section .line-break {
flex-basis: 100%;
width: 0px;
height: 0px;
overflow: hidden;
}
<html>
<head>
</head>
<body>
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="line-break"></div>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
</body>
</html>
header, .row {
display: flex; /* aligns all child elements (flex items) in a row */
}
.col {
flex: 1; /* distributes space on the line equally among items */
}
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
If the content you are going to present is of type tabular data, then a table is the proper way.
HTML 5.1 W3C Recommendation, 1 November 2016, 4.9 Tabular data
Given that you can't, or don't want to, alter the markup, this can be done using CSS Table, and with that easily swap between any display type such as flex, block, etc., or even float, using media query etc.
I also removed the <div class="line-break"></div> element, since you don't need, though if it is rendered by a component or similar, leaving it as is won't cause any problem.
Using CSS Table
section {
display: table;
width: 100%;
}
section > * {
display: table-row;
}
section .col {
display: table-cell;
}
<html>
<head>
</head>
<body>
<section>
<header>
<div class="col">Column A</div>
<div class="col">Column B</div>
<div class="col">Column C</div>
</header>
<div class="row">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
</div>
</section>
</body>
</html>
If you still need, or have to, use Flexbox, this answer of mine mention the difference between CSS Table and Flexbox on two important features:
Can flexbox handle varying sizes of columns but consistent row height?
Updated, a sample showing some useful Flexbox stuff, with varying width's and span columns.
Using Flexbox
.tbl {
display: flex;
flex-direction: column;
}
.row {
display: flex;
min-height: 50px;
}
.cell {
flex: 4;
border: 1px solid red;
}
.cell:nth-child(1) {
flex: 1;
}
.cell:nth-child(2) {
flex: 2;
}
.cell.span4-5 {
flex: 8 24px; /* col 4,5 flex-grow/border/padding */
}
.cell.span3-4 {
flex: 8 24px; /* col 3,4 flex-grow/border/padding */
}
.cell.span3-5 {
flex: 12 36px; /* col 3,4,5 flex-grow/border/padding */
}
.row:first-child .cell {
display: flex;
justify-content: center; /* center horiz. */
align-items: center; /* center vert. */
}
.row .cell {
padding: 5px;
box-sizing: border-box;
}
<div class="tbl">
<div class="row">
<div class="cell">ID </div>
<div class="cell">Nr </div>
<div class="cell">Header 1 </div>
<div class="cell span4-5"> Header 2 </div>
</div>
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
</div>
<div class="row">
<div class="cell">2</div>
<div class="cell">3</div>
<div class="cell span3-5">Content</div>
</div>
<div class="row">
<div class="cell">1</div>
<div class="cell">2</div>
<div class="cell span3-4">Content</div>
<div class="cell">Content</div>
</div>
</div>
This code works for me:
* {
box-sizing: border-box;
}
body, html {
height: 100%;
margin: 0;
}
#container {
width: 400px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
background-color: lightgrey;
padding: 10px;
}
.shelf {
flex: 1 1 auto;
width: 100%;
margin-bottom: 10px;
border: 1px solid black;
background-color: lightgreen;
display: flex;
flex-direction: row;
}
.shelf:last-child {
margin-bottom: 0;
}
.labelbox {
flex: 0 0 35%;
}
.valuebox {
flex: 0 0 65%;
}
<div id="container">
<div class="shelf">
<div class="labelbox">Name: </div> <div class="valuebox">Barry Carter</div>
</div>
<div class="shelf">
<div class="labelbox">DOB:</div><div class="valuebox">10/12/1980</div>
</div>
<div class="shelf">
<div class="labelbox">
Description:
</div>
<div class="valuebox">
This content goes on and on and will force the height to expand. And the label box to the left will
"move" with it. There need not be much of a relation other than that their parent div/flex-container is
getting taller as well.
</div>
</div>
<div class="shelf">
<div class="labelbox">Group:</div><div class="valuebox">Advanced</div>
</div>
<div class="shelf">
<div class="labelbox">End Date:</div><div class="valuebox">2020-09-20</div>
</div>
</div>
Use CSS Grid. You can style any table the way you like.
Keep in mind If your table is more than 700 rows, the fram rate will start to drop, no matter what js framework you use. react, angular, vue or vanila JS. the scrolling will get real laggy.
And the maximum you row can use is 1000. More than that the extra row will create bad graphic. But you wont reach 1000 anyway, because at 700th row, the scrolling speed, starts to get bad.
If somehow you need to display more than 1000 rows, you will visualized lib. Every js framework has a lib to do so. Basically, it will render the rows in the view port. The rows that not in the view port will not be rendered. They will only be rendered when user scrolls.
This is year 2021, chances you read this answer in the future, the browsers vendor might probably fix the performance of 1000 rows, they might even extend that limit. So try it out.

Wrap a Vertical bar with the Content

i'm trying to wrap the content and a vertical bar.
right now when the Viewport increate the Content and the Bar move away from each other (the Bar to the right and the Content to the left)
But i want them to Seperate to a specific amount and stay like that.
This is my Screendesign:
enter image description here
And that would be my Code right now:
<!DOCTYPE HTML>
<body>
<div id="wrapper">
<div id="header">
</div>
<div id="navhm">
</div>
<div id="space">
</div>
<div id="wrapperres">
<div id="pfosten">
</div>
<div id="contwrap">
<div id="content">
<p>Lorem Ipsum</p>
</div>
</div>
</div>
<div id="footer">
</div>
</div>
</body>
And thats my CSS
http://codepen.io/Blackcan/pen/AXovrL
Any Advices are welcome!
I would use flexbox for this.
Let's say your HTML looks like this:
<div class="container">
<div class="content-left">
<div class="nav-fixed">
</div>
<div class="content">
</div>
</div>
<div class="social-media">
</div>
</div>
Then you could use in your CSS:
.container {
display: flex;
flex-direction: row;
justify-content: space-around;
}
.content-left {
flex: 0 0 60vw;
overflow-y: scroll;
display: flex;
flex-direction: column;
justify-content: space-around;
}
.social-media {
flex: 0 0 20vw;
}
.nav-fixed {
flex: 0 0 40px;
}
.content {
flex: 0 0 300px;
}
Codepen: https://codepen.io/J-DD/pen/QErjLE
More about flexbox:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
http://thenewcode.com/780/A-Designers-Guide-To-Flexbox

Flexbox many nested children

I've read many posts on flexbox but still have an issue that bugs me.
I want to have a sticky footer using flexbox as per this guide.
But then, inside my page content I would like to have as many nested divs I like and have them taking the same height of the parent.
The problem is, setting height: 100% on each child (as I would do in a non-flexbox scenario) works differently when flexbox is enabled. This results in the children getting more height (overflow the parent).
To make this more clear here's a codepen without flexbox
and a codepen with flexbox
You can see in the flexbox scenario the footer gets the green bakground even if I don't want that.
HTML:
<div class="sticky-footer-container">
<div class="sticky-footer-content">
<div class="page-container">
<div class="main-menu">
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sticky-footer">
Some footer content
</div>
</div>
SCSS:
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
background: silver;
padding: 0;
margin: 0;
}
.sticky-footer-container {
height: 100%;
display: flex;
flex-direction: column;
.sticky-footer-content {
height: 100%;
background: blue;
flex: 1;
div {
height: 100%;
}
.main-menu-selection {
height: 50%;
}
}
}
.some-other-class {
background: green;
}
In order to solve this, ANY nested div has to become a flex-container ?
In other words, is there any way to "stop the flex propagation" at some point of the tree, so all the divs gets the parent height without overflow?
display:flexbox is not really a valid value :)
you need to set height as well and eventually inherit it from html :
.sticky-footer-container {
display: flex;
flex-direction: column;
}
.sticky-footer-content {
flex: 1;
}
/* let's inherit some height to pull the footer down */
html,
body,
.sticky-footer-container {
height: 100%;
margin: 0;
}
.sticky-footer {
display: flex;/* flex item can be flexboxes as well */
background: turquoise;
align-items: center;
justify-content: center;
min-height: 3em;
}
<div class="sticky-footer-container">
<div class="sticky-footer-content">
<div class="page-container">
<div class="main-menu">
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
<div class="main-menu-selection">
<div class="main-menu-selection-text">
<div class="some-other-class">
Some text
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sticky-footer">
Here my footer
</div>
</div>

Set baseline of flexbox elements

Consider this HTML
<div class="container">
<div class="element">
<div class="top">
<div>A</div>
<div>B</div>
</div>
<hr/>
<div class="bottom">
<div>C</div>
</div>
</div>
<div class="element">
<div class="top">
<div>A</div>
</div>
<hr/>
<div class="bottom">
<div>B</div>
<div>C</div>
</div>
</div>
<div class="element">
<div class="top">
<div>A</div>
</div>
<hr/>
<div class="bottom">
<div>B</div>
</div>
</div>
</div>
I want to line the elements up horizontally using flexbox, such that the horizontal rules align. It seems that align-items: baseline would do the right thing – if I could make sure the element divs have their baseline at the horizontal bar.
See this codepen link for something to play around with.
How can I control the baseline of such a block element?
You could use multiple stacked flexboxes to achieve this, however HTML gets more complex, but it looks like the only way to pretend you set the baseline yourself.
Demo : https://jsfiddle.net/Paf_Sebastien/tLk1jajo/
The content over the line is in one flexbox with :
.overline {
align-items: flex-end;
}
The content under the line in another with :
.underline {
align-items: flex-start;
}
I want to line the elements up horizontally using flexbox, such that
the horizontal rules align. It seems that align-items: baseline would
do the right thing
align-items: baseline is not going to help you here, because you want to align different elements with respect to another element (the hr as opposed to aligning same elements based on the text baseline).
If you can work with fixed heights of your .elements, then without changing your markup, you could do a nested flex and equalize your .top and .bottom, like this:
.top, .bottom {
height: 49%;
display: flex; flex-direction: column;
align-items: center;
}
.top > div, .bottom > div { flex: 0 0 auto; }
And then, to align the .top one to the bottom (i.e. close to the hr), you would do a margin-top: auto, like this:
.top > div { margin-top: auto; }
This will also play along nicely with your flex-wrap: wrap. Try changing the width of the fiddle pane, or window size in the examples below.
Complete Example Snippet:
* { box-sizing: border-box; padding: 0; margin: 0; }
.container {
height: 320px; border: 1px solid #ddd;
display: flex; flex-wrap: wrap;
align-items: center;
}
.element {
flex: 1 1 auto;
height: 120px; width: 200px;
padding: 0.5em;
}
.top, .bottom {
height: 49%;
display: flex; flex-direction: column;
align-items: center;
}
.top > div, .bottom > div { flex: 0 0 auto; }
.top > div { margin-top: auto; }
<div class="container">
<div class="element">
<div class="top">
<div>A</div>
<div>B</div>
</div>
<hr/>
<div class="bottom">
<div>C</div>
</div>
</div>
<div class="element">
<div class="top">
<div>A</div>
</div>
<hr/>
<div class="bottom">
<div>B</div>
<div>C</div>
</div>
</div>
<div class="element">
<div class="top">
<div>A</div>
</div>
<hr/>
<div class="bottom">
<div>B</div>
</div>
</div>
</div>
Fiddle: http://jsfiddle.net/abhitalks/vym76nyn/
Codepen: http://codepen.io/anon/pen/ZbOyzE
.