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
.
Related
I have 5 images and I would like to stack them one over the other on the left hand side. I have some text that I would like to display beside each image on the right of the respective image and I would like that text to appear beside the middle of the respective image. I have been able to get the images to appear stacked on top of each other but unfortunately, the text also appears beneath the respective image rather than beside it.
And yes, I am trying to make a meme.
My HTML is as follows.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="container">
<div id="floated-imgs">
<div class="image-div"><img src="a.jpeg" /></div>
<div class="text-div">
<div>A</div>
</div>
<div class="image-div"><img src="b.jpeg" /></div>
<div class="text-div">
<div>B</div>
</div>
<div class="image-div"><img src="c.jpeg" /></div>
<div class="text-div">
<div>C</div>
</div>
<div class="image-div"><img src="d.jpeg" /></div>
<div class="text-div">
<div>D</div>
</div>
<div class="image-div"><img src="e" /></div>
<div class="text-div">
<div>E</div>
</div>
</div>
</div>
</body>
</html>
My CSS looks like this
#container { overflow: hidden; background-color:black; }
#floated-imgs { float: left; }
#floated-imgs img {display: block; width:300px;}
.image-div { display:inline-block; vertical-align:top; }
.text-div { display:inline-block; color:white; font-family: Impact; font-size: 50px; text-align: center; display: flex; justify-content: center; align-items: center;}
Can you see what I am doing wrong?
The layout itself can be solved with Flexbox and CSS-Grid. I would solve it with CSS-Grid as it has some advantages in cases where more than 1 direction needs to be controlled.
The vertical alignment of the text at the vertical center can be solved with Flexbox. I advise using flex-direction: column over the default flex-direction: row to not lose the normal block element behavior.
.container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
}
.container img {
width: 100%;
}
.container > div {
display: flex;
flex-direction: column;
justify-content: center;
}
<div class="container">
<img src="https://via.placeholder.com/1920x1080.jpg">
<div>A</div>
<img src="https://via.placeholder.com/1920x1080.jpg">
<div>B</div>
<img src="https://via.placeholder.com/1920x1080.jpg">
<div>C</div>
<img src="https://via.placeholder.com/1920x1080.jpg">
<div>D</div>
<img src="https://via.placeholder.com/1920x1080.jpg">
<div>E</div>
</div>
I think you can use display: flex; and use align-item: center;
I will put here some code for better understanding my need.
.wrap{
display:flex;
flex-direction:row;
align-items: center;
justify-content: flex-start;
width: 100%;
}
.img{
width: 30px;
height: 20px;
background: red;
}
.img1{
width:40px;
}
<div class='wrap'>
<div class='img img1'>
</div>
<p>
Xxxxxxxxxxxxx
</p>
</div>
<div class='wrap'>
<div class='img'>
</div>
<p>
yyyyyyyyy
</p>
</div>
<div class='wrap'>
<div class='img'>
</div>
<p>
zzzzzz
</p>
</div>
So as u can see, we have 3 div & p elements. I want to separate this elements with identical gap between them. I want separate red div from text. As u notice, first element is longer than rest. I wouldn't like to use static margin or padding value. Exist better solution?
You need a container that defines the width of all children. Then, you can set justify-content: space-between on .wrap, so the text and the red rectangle will get away from each other.
Then, add a gap property to .wrap, so you'll have a basic gap between the elements to start with.
Here's your snippet with the new adjustments:
.container {
display: flex;
flex-direction: column;
max-width: fit-content;
}
.wrap {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 1em;
width: 100%;
}
.img {
width: 30px;
height: 20px;
background: red;
}
.img1 {
width: 40px;
}
<div class="container">
<div class='wrap'>
<div class='img img1'>
</div>
<p>
Xxxxxxxxxxxxx
</p>
</div>
<div class='wrap'>
<div class='img'>
</div>
<p>
yyyyyyyyy
</p>
</div>
<div class='wrap'>
<div class='img'>
</div>
<p>
zzzzzz
</p>
</div>
</div>
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.
Given the following CSS:
.row {
padding: 0;
margin: 0;
list-style: none;
display: flex;
justify-content: space-between;
}
.middle {
flex-grow: 1;
margin: 0 1em;
}
And the following HTML:
<div>
<div class="row">
<div>X</div>
<div class="middle">Variable Content</div>
<div>A</div>
</div>
<div class="row">
<div>X</div>
<div class="middle">Content</div>
<div>AB</div>
</div>
<div class="row">
<div>X</div>
<div class="middle">Var Content</div>
<div>ABC</div>
</div>
</div>
This layout which includes rows and three "columns":
"X" The left column contains the same element in every row, so its width is effectively fixed. This column should only use the amount of space necessary for the element.
"Content" The middle column contains variable text. It should occupy the majority of each row.
"ABC" The right column is where I'm having trouble. The content is text and could be 1-5 characters. I want the characters left aligned across the entire "table". Edit: I don't want to declare a fixed width.
Working example: https://codepen.io/anon/pen/bjEKBW
In short: How do I get the "A" in every column to be left aligned down the entire layout? I'm not married to the HTML layout.
What you have here is a table...I'd suggest you use one or CSS-Tables.
.row {
padding: 0;
margin: 0;
list-style: none;
display: table-row;
}
.row div {
display: table-cell;
padding: 0 .25em;
}
.middle {
width: 100%;
}
<div>
<div class="row">
<div>X</div>
<div class="middle">Variable Content</div>
<div>A</div>
</div>
<div class="row">
<div>X</div>
<div class="middle">Content</div>
<div>AB</div>
</div>
<div class="row">
<div>X</div>
<div class="middle">Var Content</div>
<div>ABC</div>
</div>
</div>
Alternatively, you can dispense with the rows and use CSS Grid
.grid {
display: grid;
grid-template-columns: auto 1fr auto;
}
.grid div {
padding: 0 .25em;
}
<div class="grid">
<div>X</div>
<div class="middle">Variable Content</div>
<div>A</div>
<div>X</div>
<div class="middle">Content</div>
<div>AB</div>
<div>X</div>
<div class="middle">Var Content</div>
<div>ABC</div>
</div>
You can give the last column a fixed width, e.g.
.row > div:last-child {
width: 100px;
}
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.