Shift cells in a row upward while maintaining baseline alignment - html

Here is a table built with flexboxes. The cells in the row are aligned with the align-items: baseline property.
.data-row {
display: flex;
align-items: baseline;
border-top: 2px solid blue;
border-bottom: 2px solid blue;
font: bold 14px monospace;
min-height: 75px;
}
.data-row + .data-row {
border-top: none;
}
.data-cell {
padding: 30px 15px 15px;
}
.data-cell--text {
flex-grow: 1;
}
<div class="data-row">
<div class="data-cell">1111111</div>
<div class="data-cell data-cell--text">Usually one line is enough</div>
<div class="data-cell">1111111</div>
<div class="data-cell">1111111</div>
</div>
<div class="data-row">
<div class="data-cell">2222222</div>
<div class="data-cell data-cell--text">But sometimes too long text gets into some cell and goes to the next line</div>
<div class="data-cell">2222222</div>
<div class="data-cell">2222222</div>
</div>
When text in a cell has two lines or more, I would like the contents of all the cells in the row to rise closer to the top of the row, while maintaining their baseline alignment.
Can this be achieved?
The question was suggested by user #Kate B on Russian SO.

You can wrap the cells with data in two nested flexbox-blocks:
The inner flexbox aligns the cells with the text to their baseline.
And the outer flexbox aligns the indoor one with the center axis.
If a new line appears in the text of any cell, then this cell increases the height of the inner block, and it rises inside the outer one.
https://codepen.io/glebkema/pen/XWaZNEP?editors=1100
/* Heart of the matter */
.outer-row {
display: flex;
align-items: center;
}
.inner-row {
display: flex;
align-items: baseline;
flex-grow: 1;
}
/* Appearance */
.outer-row {
border-top: 2px solid blue;
border-bottom: 2px solid blue;
font: bold 14px monospace;
min-height: 72px;
}
.outer-row + .outer-row {
border-top: none;
}
.data-cell {
padding: 0 15px;
}
.data-cell--text {
flex-grow: 1;
}
<div class="outer-row">
<div class="inner-row">
<div class="data-cell">1111111</div>
<div class="data-cell data-cell--text">One line</div>
<div class="data-cell">1111111</div>
<div class="data-cell">1111111</div>
</div>
</div>
<div class="outer-row">
<div class="inner-row">
<div class="data-cell">2222222</div>
<div class="data-cell data-cell--text">Two <br>lines</div>
<div class="data-cell">2222222</div>
<div class="data-cell">2222222</div>
</div>
</div>
<div class="outer-row">
<div class="inner-row">
<div class="data-cell">3333333</div>
<div class="data-cell data-cell--text">And <br>three <br>lines</div>
<div class="data-cell">3333333</div>
<div class="data-cell">3333333</div>
</div>
</div>

Related

center div cutting into floated left div

I'm trying to align three divs horizontally.
The center div is cutting into the left div.
What am I doing wrong?
<div>
<div style={{width:"100px", border:"solid blue", float:"left"}}>Left some text some text some text</div>
<div style={{width:"100px", border:"solid green", float:"right"}}>Right</div>
<div style={{border:"solid red", margin:"0 auto"}}>Center</div>
<div style={{clear:"both"}}></div>
</div>
The center overlaps the right green box as well but the border sizes are the same so you can't see it.
Give the red div margin-left:100px:
<div>
<div style="width:100px;border:1px solid blue;float:left">Left some text some text some text</div>
<div style="width:100px;border:1px solid green;float:right">Right</div>
<div style="border:1px solid red;margin-left:100px">Center</div>
<div style="clear:both"></div>
</div>
Maybe You should use flexbox ? i think it's much more convenient and more modern than "float" conception. This my proposition.I hope You will be content ;-) If you want, you can switch from width to flex properties, they are commented in css.
.wrapper {
display: flex;
align-items: start;
justify-content: space-between;
width: 100%;
text-align: center;
}
.blue {
width: 100px;
/* flex: 1; */
border:1px solid blue;
}
.green {
width: 100px;
/* flex: 1; */
border:1px solid green;
}
.red {
width: 100%;
/* flex: 8; */
border:1px solid red;
margin: 0 auto;
}
<div class="wrapper">
<div class="blue">Left some text some text some text</div>
<div class="red">Center</div>
<div class="green">Right</div>
</div>

CSS buttons align for all divs except the last one

I want to display all buttons aligned to fill full div width, except for the last one. My code is below, but the last div is short and is expanding full width, I don't want this for the last one.
NOTE: The buttons are dynamically generated.
.block {
width: 400px;
display: flex;
flex-wrap: wrap;
}
.button {
background-color: #cec;
border: none;
color: white;
margin: 15px;
padding: 15px;
display: inline-block;
font-size: 16px;
flex: 1 0 auto;
}
<div class="block">
<div class="button">#1 - A LONG TEXT GOES HERE
</div>
<div class="button">#2 - ANOTHER LONG TEXT HERE
</div>
<div class="button">#3 - SOME TEXT HERE
</div>
<div class="button">#4 - SHORT TEXT
</div>
<div class="button">#5 - SHORT
</div>
<div class="button">#6 - SHORT
</div>
</div>
You can have separate classes for the short ones.
.block {
width: 400px;
display: flex;
flex-wrap: wrap;
}
.button {
background-color: #cec;
border: none;
color: white;
margin: 15px;
padding: 15px;
display: inline-block;
font-size: 16px;
flex: 1 0 auto;
}
.short {
max-width: 20vw;
}
<div class="block">
<div class="button">#1 - A LONG TEXT GOES HERE
</div>
<div class="button">#2 - ANOTHER LONG TEXT HERE
</div>
<div class="button">#3 - SOME TEXT HERE
</div>
<div class="button">#4 - SHORT TEXT
</div>
<div class="button short">#5 - SHORT
</div>
<div class="button short">#6 - SHORT
</div>
</div>
You can use :last-child selector, it matches every element that is the last child of its parent.
.button:last-child
Or you can also use nth-last-child(1) because nth-last-child(1) equal to last-child selector
.button:nth-last-child(1)
You can use last-child pseudo-class to target the last element only of you button class.
.button:last-child {
max-width: max-content;
}
Working Example:
.block {
width: 400px;
display: flex;
flex-wrap: wrap;
}
.button {
background-color: #cec;
border: none;
color: white;
margin: 15px;
padding: 15px;
display: inline-block;
font-size: 16px;
flex: 1 0 auto;
}
.button:last-child {
max-width: max-content;
}
<div class="block">
<div class="button">#1 - A LONG TEXT GOES HERE
</div>
<div class="button">#2 - ANOTHER LONG TEXT HERE
</div>
<div class="button">#3 - SOME TEXT HERE
</div>
<div class="button">#4 - SHORT TEXT
</div>
<div class="button">#5 - SHORT
</div>
<div class="button">#6 - SHORT
</div>
</div>

Non-direct subchildren of a flex container seem vertically misaligned. Why?

I'm trying to have three (yellow framed) labels: A, B, and C.
I want A to be left-aligned and B and C to be right aligned. As I don't want the frame of A to grow until reaching B, I set A's display: inline. This almost seems to work, but for some reason A is misbehaving: it shows up vertically misaligned. This seems to originate from this being the only p element that is not a direct subchild of the flex container. But why does this happen?
body {
margin: 0px;
}
#main {
display: flex;
}
.node {
margin: 0px;
padding: 16px;
border: 2px dashed yellow;
}
<div id="main" style="background: red;">
<div style="flex-grow: 1;">
<p class="node" style="display: inline;">A</p>
</div>
<p class="node">B</p>
<p class="node">C</p>
</div>
Thanks
Only children (direct descendants) of flex elements have properties of flex-items.
Here you are:
body {
margin: 0px;
}
#main {
display: flex;
background: red;
}
.node {
margin: 0px;
padding: 16px;
border: 2px dashed yellow;
}
.node:first-child {margin-right:auto}
<div id="main" style="background: red;">
<p class="node">A</p>
<p class="node">B</p>
<p class="node">C</p>
</div>

How to use `flex: grow` on floating content?

I have a header with 2 rows of 2 Foundation columns of content, as below:
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
HEADER
</div>
<div class="large-6 columns">
menu
</div>
</div>
<div class="row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
The .header height is dynamic and not set. I want the .image element to take up 100% of the remaining vertical space.
eg:
To that affect I have tried using flex and flex-grow, eg:
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
}
.image-container {
flex-grow: 1;
}
but had no luck, see fiddle: https://jsfiddle.net/9kkb2bxu/46/
Would anyone know how I could negate the dynamic height of the header from the 100vh of the image container?
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
border: 1px solid black;
background-color: #ccc;
}
.row {
width: 100%;
}
.header {
background-color: green;
}
.info {
background-color: yellow;
border: 1px solid #ccc;
}
.image-container {
border: 1px solid black;
display: flex;
}
.image {
background-color: red;
flex-grow: 1;
width: 100%;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css" rel="stylesheet"/>
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
<h1>
HEADER
</h1>
</div>
<div class="large-6 columns">
<h1>
menu
</h1>
</div>
</div>
<div class="row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
Set the second row to take up the rest of the remaining height with flex: 1 and make sure you nest that flex with display: flex:
.row.target-row {
flex: 1;
display: flex;
}
Set the .image-container to 100% height of its column parent.
.image-container {
height: 100%;
}
By default both columns will expand. Stop the left column from expanding with:
.large-5 {
align-self: flex-start;
}
(flex-start reference: https://stackoverflow.com/a/40156422/2930477)
Complete Example
.wrapper {
display: flex;
flex-direction: column;
min-height: 100vh;
width: 100%;
border: 1px solid black;
background-color: #ccc;
}
.row {
width: 100%;
}
.header {
background-color: green;
}
.info {
background-color: yellow;
border: 1px solid #ccc;
}
.image-container {
height: 100%;
background-color: red;
}
.large-5 {
align-self: flex-start;
}
.row.target-row {
flex: 1;
display: flex;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.3.1/css/foundation.min.css" rel="stylesheet" />
<div class="wrapper">
<div class="header row">
<div class="large-6 columns">
<h1>
HEADER
</h1>
</div>
<div class="large-6 columns">
<h1>
menu
</h1>
</div>
</div>
<div class="row target-row">
<div class="large-5 none show-for-medium columns info">
Some information to the left
</div>
<div class="large-7 columns">
<div class="image-container">
<div class="image">
image to the right
</div>
</div>
</div>
</div>
</div>
flex-grow only applies to flex children.
.image-container isn't a direct child of a display: flex element, so that property has no effect.
Plus, it affects the flex axis, which is not what you want.
Instead, you need to put those two elements in their own flex row, and use align-items (on the parent) and align-self (on either child) so that the first one aligns (on the cross axis) to flex-start (stick to top) and the second one to stretch.
You'll also want that flex row (parent) to have flex-grow: 1 so that it stretches along the vertical flex axis of its parent (.wrapper) to fill the rest of the page (otherwise, the grandchild will have nothing to stretch to).
For more information, read a good flex tutorial.
div.wrapper > div:not(.header).row {
flex: 1; /* 1 */
display: flex; /* 1 */
}
div.large-7.columns {
display: flex; /* 2 */
}
div.image-container { /* 3 */
flex: 1;
}
div.large-5.show-for-medium { /* 4 */
align-self: flex-start;
}
jsFiddle
Notes:
flex container and items consume all remaining height of respective parents
give children full height (via align-items: stretch initial setting)
flex item consumes all available width
yellow box does not need to expand to full height; now set to content height

Center one element along with multiple siblings

I have a div with some number of spans in it, that may or may not be of equal width. I know I can use text-align: center to make all the content within a div be centered. However, I want to pick a particular span, and designate that as the true center, rather than the center being the midpoint of the sequence of spans.
One idea I had to simulate this effect was: I'd have my desired middle element with two containers to its left and right; the left one would be right-justified, and vice-versa. These containers would hold the other content in the div. If I could get these two containers to fill up the remaining space in equal amounts, this would have the effect of centering the middle element while keeping the left and right content aligned with the center. Basically, this would require the two containers' width to be set to exactly half the remaining space in the div. (I don't want to change the size of the middle div.) Is this possible to do with just CSS?
Example: with 4 spans, how to I designate span 2 as the true center?
div {
width: 500px;
padding: 4px;
border: 1px dotted black;
}
span {
display: inline-block;
width: 100px;
text-align: center;
margin: 4px;
box-sizing: border-box;
border: 1px dotted black;
}
#b {
/* ??? */
}
<div>
<span id="a">1</span>
<span id="b">2</span>
<span id="c">3</span>
<span id="d">4</span>
</div>
You can use flexbox. Based on this answer,
.outer-wrapper {
display: flex;
padding: 4px;
border: 1px dotted black;
}
.item {
margin: 4px;
text-align: center;
border: 1px dotted black;
}
.left.inner-wrapper, .right.inner-wrapper {
flex: 1;
display: flex;
align-items: flex-start;
min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.left.inner-wrapper {
justify-content: flex-end;
}
.animate {
animation: anim 5s infinite alternate;
}
#keyframes anim {
from { min-width: 0 }
to { min-width: 50vw; }
}
<div class="outer-wrapper">
<div class="left inner-wrapper">
<div class="item animate">1. Left</div>
</div>
<div class="center inner-wrapper">
<div class="item">2. Center</div>
</div>
<div class="right inner-wrapper">
<div class="item">3. Right</div>
<div class="item">4. Right</div>
</div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item animate">2. Center</div></div><div class="right inner-wrapper"><div class="item">3. Right</div><div class="item">4. Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item">2. Center</div></div><div class="right inner-wrapper"><div class="item animate">3. Right</div><div class="item">4. Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item">2. Center</div></div><div class="right inner-wrapper"><div class="item">3. Right</div><div class="item animate">4. Right</div></div></div>
This will attempt to center the desired element, but it will be pushed in case one side doesn't fit, to prevent overlapping.
This can be done using flexbox. You can use display:flex; on the div, and use flex-grow:1; on the 2nd span. That way you can cover the whole div with that span.
Since the 1st and 3rd spans are already equal in width, you'll have the 2nd span in dead center. And then use flex-basis on the 2nd to get it's desired width.
div.container{
width: 500px;
padding: 4px;
border: 1px dotted black;
}
div.row{
display:flex;
align-items:center;
justify-content:center;
}
span {
display: inline-block;
width: 70px;
text-align: center;
margin: 4px;
box-sizing: border-box;
border: 1px dotted black;
transform:translate(50%,0);
}
#b {
}
<html>
<head></head>
<body>
<div class='container'>
<div class="row">
<span id="a">1</span>
<span id="b">2</span>
<span id="c">3</span>
<span id="d">4</span>
</div>
</div>
</body>
</html>
I suggest to do it with a 3 column layout, and use CSS table structure. Make the 1st and 3rd columns to take 50% of total width, and middle column will have only 0, but it will recalculate the width to fit the content and remains center since it's in a table.
Also put white-space: nowrap; there in case there are multiple words inside, but remove it as needed if there is only one word or fixed width.
.container {
display: table;
border-collapse: collapse;
width: 100%;
}
.item {
display: table-cell;
vertical-align: top;
padding: 4px;
border: 1px solid grey;
}
.item-a {
width: 50%;
text-align: right;
}
.item-b {
text-align: center;
white-space: nowrap; /* remove as needed */
}
.item-c {
width: 50%;
}
.item span {
display: inline-block;
border: 1px solid red;
}
.item-b span {
padding: 0 50px; /* for demo only */
}
<div class="container">
<span class="item item-a">
<span>1</span>
</span>
<span class="item item-b">
<span>2</span>
</span>
<span class="item item-c">
<span>3</span>
<span>4</span>
</span>
</div>
jsFiddle