Is it possible to make flex children align vertically?
Example
In this case, the left "softwaredevelopment" box should increase a little so that the above "react" align with the "react" underneath. The same goes with "web", "software" and so on..? Obviously, the slight misalignment of the boxes in the picture beneath is slightly annoying...
Does a property for flexbox exist that does what I described?
The solution should be dynamic
Flexbox is great for horizontal layout control, but was not designed to handle vertical layout. Consider CSS Grid with a touch of JavaScript for layouts like this. Once we decide on a number of columns (7, in this case), we can add a bit of JavaScript that decides on the span of columns based on text length. This is a simple prototype, but could be further developed to deal with edge-case rules.
let listItems = document.querySelectorAll(".grid li");
listItems.forEach(item => {
const len = item.innerText.length;
if (len > 15 && len < 20) {
item.classList.add('span-2');
} else if (len >= 20) {
item.classList.add('span-3');
} // etc.
});
.grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-auto-rows: 1fr;
margin: 0;
padding: 0;
list-style: none;
}
.grid li {
text-align: center;
border: .5px solid;
display: flex;
align-items: center;
justify-content: center;
font-size: 100%;
padding: .35em;
}
.span-2 {
grid-column: span 2;
}
.full-width {
grid-column: 1 / -1;
}
<ul class="grid">
<li class="full-width">Show all</li>
<li>Python</li>
<li>NodeJS</li>
<li>React</li>
<li>Web</li>
<li>Software</li>
<li>React</li>
<li>Webdev</li>
<li>Sofware Development</li>
<li>React</li>
<li>Crazy Developers</li>
<li>Web</li>
<li>React</li>
<li class="full-width">Sofware Development</li>
</ul>
jsFiddle
Related
I want to display the first item of the <aside> tag centered at the left.
All other items should be displayed on the right.
I'm using a tool (asciidoctor-html5s) to convert asciidoc to html5.
Therefore I cannot change the HTML.
This is the generated HTML:
<aside class="admonition-block tip" role="doc-tip">
<h6 class="block-title">
<span class="title-label">Tip: </span>
Info
</h6>
<p>Go to this URL to learn more about it:</p>
<div class="ulist">
<ul>
<li><a class="bare" href="http://asciidoc.org">http://asciidoc.org</a></li>
</ul>
</div>
<p>Or you could return to the First Steps or Purpose.</p>
</aside>
And this is an example how it should look like:
Is this possible and if yes, how?
Please do not focus on the Info text inside the h6. I know this is not possible. The question is centered around having the first item on the left an all n other items on the right.
You can make use of the float: left and a bit styling to the height and margin-right
.admonition-block .block-title {
float: left;
margin-right: 2rem;
height: 4rem;
}
<aside class="admonition-block tip" role="doc-tip">
<h6 class="block-title">
<span class="title-label">Tip: </span>
Info
</h6>
<p>Go to this URL to learn more about it:</p>
<div class="ulist">
<ul>
<li><a class="bare" href="http://asciidoc.org">http://asciidoc.org</a></li>
</ul>
</div>
<p>Or you could return to the First Steps or Purpose.</p>
</aside>
If your HTML is going to be exactly like that (e.g. an h6, a p, a div, and then another p), then you can hard code it like this using a combination of CSS Grid and CSS Flexbox styles:
aside {
display: grid;
grid-template-columns: 50px 320px; /* picked these sizes at random; feel free to change */
grid-gap: 5px; /* picked these sizes at random; feel free to change */
}
aside > * {
grid-column: 2;
}
h6 {
grid-column: 1;
grid-row: 1 / 5;
display: flex;
visibility: hidden;
align-items: center;
justify-content: center;
}
h6 span {
visibility: visible;
}
p::before {
content:"Info";
position: absolute;
top: 5px;
font-style: italic;
}
aside p:first-of-type {
grid-row: 1;
}
aside div {
grid-row: 2;
}
aside p:last-of-type {
grid-row: 3;
}
<aside class="admonition-block tip" role="doc-tip">
<h6 class="block-title">
<span class="title-label">Tip: </span>
Info
</h6>
<p>Go to this URL to learn more about it:</p>
<div class="ulist">
<ul>
<li><a class="bare" href="http://asciidoc.org">http://asciidoc.org</a></li>
</ul>
</div>
<p>Or you could return to the First Steps or Purpose.</p>
</aside>
I hid the "Info" text node in markup and added it in CSS as a pseudo-element. It's not selectable that way, but the trade of is it can be positioned the way you want it to.
Maybe there is a way in your converter software to disallow naked text nodes like that (it's considered bad practice to have atomic text not wrapped in an element if you want to style/select it).
I am using Next.js and SCSS and trying to locate 5 & 3 rows of images at the center of the page with responsive grid system.
I just need to slightly adjust images location to the right side but contents do not move at all.
here is the code :
Next.js
// So basically ui.container wraps up li.item which are images.
<ul className="container">
{stores.map(store => (
<li onClick={this.open} key={store.id} className="item">
<img
src={store.thumb}
onClick={() => this.storeDetail(store.id)}
/>
</li>
))}
</ul>
SCSS
section {
background: pink;
}
.store-list-title {
text-align: center;
padding-top: 2rem;
font-size: 3rem;
}
.container {
display: grid;
grid-gap: 1rem;
grid-template-columns: repeat(5, 200px);
}
Add justify-content:center for aligining center
.container {
display: grid;
grid-gap: 1rem;
grid-template-columns: repeat(5, 50px);
justify-content: center;
}
So the solution I found on youtube is using mixin function in SCSS.
It needs calculation so I am still looking at it to understand how it works.
I would be appreciated if someone explains how it works
item element and mixin
#mixin grid($cols, $mgn) {
float: left;
margin-right: $mgn;
margin-bottom: $mgn;
width: ((100% - (($cols - 1) * $mgn)) / $cols);
&:nth-child(#{$cols}n) {
margin-right: 0;
}
}
.item {
#include grid(5, 2%);
img {
width: 100%;
}
}
li tags
{stores.map(store => (
<li onClick={this.open} key={store.id} className="item">
<img
src={store.thumb}
onClick={() => this.storeDetail(store.id)}
alt={`${store.name} image`}
/>
</li>
))}
We have an unordered list that will display up to 10 items. How can we setup the list so that it will place the first five items on the left and put the next five items into the next column (splitting equally)?
Here is the current and desired output. We tried to use CSS Flexbox, but cannot find a way to do it. Open to other ideas if flexbox cannot get it done.
Here is the current results and desired outputs.
ul {
display: flex;
flex-direction: column;
flex: 0 1 auto;
}
<div>
<ul>
<li>Assertively mesh</li>
<li>client-centered</li>
<li>niches and covalent networks</li>
<li>Uniquely e-enable</li>
<li>team driven benefits</li>
<li>rather than exceptional</li>
<li>architectures Continually</li>
<li>foster cutting-edge</li>
<li>open-source core</li>
<li>process-centric</li>
</ul>
</div>
To arrange content into predictable columns, each of five items, would seem to be a job for display: grid:
ul {
/* set the layout to grid: */
display: grid;
/* define the number of rows you
require: */
grid-template-rows: repeat(5, 1fr);
/* set the flow of the grid to follow
a columnar layout: */
grid-auto-flow: column;
}
<div>
<ul>
<li>Assertively mesh</li>
<li>client-centered</li>
<li>niches and covalent networks</li>
<li>Uniquely e-enable</li>
<li>team driven benefits</li>
<li>rather than exceptional</li>
<li>architectures Continually</li>
<li>foster cutting-edge</li>
<li>open-source core</li>
<li>process-centric</li>
</ul>
</div>
JS Fiddle demo.
Although, if you really want to use flex-box, you can:
*,
::before,
::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
/* Use the flexbox layout: */
display: flex;
/* set the content direction to
columns: */
flex-direction: column;
/* let the contents wrap to
new columns once the
boundaries of the element are
reached: */
flex-wrap: wrap;
/* set the height of the containing
element, in order for the wrapping
to occur: */
height: 10em;
/* entirely irrelevant: */
list-style: none;
max-width:500px;
}
li {
/* set the height of the individual
'rows' to be 20% of the total height
of the parent, to enforce the five-
items per 'column': */
height: 2em;
line-height: 2em;
width: 45%;
}
/* Irrelevant, but allows 'column-headings'
to be styled: */
li:nth-child(5n + 1) {
font-weight: bold;
border-bottom: 1px solid #000;
}
<div>
<ul>
<li>Assertively mesh</li>
<li>client-centered</li>
<li>niches and covalent networks</li>
<li>Uniquely e-enable</li>
<li>team driven benefits</li>
<li>rather than exceptional</li>
<li>architectures Continually</li>
<li>foster cutting-edge</li>
<li>open-source core</li>
<li>process-centric</li>
</ul>
</div>
JS Fiddle demo.
I would use CSS columns for this:
ul {columns: 2;}
li {list-style-position: inside;}
<ul>
<li>Assertively mesh</li>
<li>client-centered</li>
<li>niches and covalent networks</li>
<li>Uniquely e-enable</li>
<li>team driven benefits</li>
<li>rather than exceptional</li>
<li>architectures Continually</li>
<li>foster cutting-edge</li>
<li>open-source core</li>
<li>process-centric</li>
</ul>
Note that 'display: grid' has pretty bad browser support, while columns (and flexbox) score better.
I am creating a navigation bar in Reactjs with four elements. These items are a simple unordered list with some css using flexbox to align them horizontaly.
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<ul/>
What I want to achieve is: When a list item is selected, align the selected list item to center. I have added a professional picture for clarification. This change will later be animated for a smooth transition, like a carousel.
Following is the css for <ul> tag.
ul {
list-style-type: none;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
}
What I've tried is to use the align-self: center on the one of the <li> items, but with no luck.
Does anyone have any experience with doing something similar? I am open for all types of solutions, even those that does not use flexbox.
Thank You!
Do the list elements have a fixed with, and do you know how many items there are? If so, you can calculate the center of the list, the item offset, and add a CSS transform.
Example:
You have a list of four items.
Each item has width equal to 100px.
The total width of the list is therefore 400px.
The center point of the list is 200px from the left.
The center point of item number two is 150px from the left. We therefore have to move the list 200px - 150px = 50px from the left.
The center point of item number four is 350px from the left. We therefore have to move the list 200px - 350px = -150px from the left.
If your list is dynamic, both regarding to list length and item width, you can use Element.getBoundingClientRect() to find the elements' dimensions, and use the same calculations as above.
Codepen: https://codepen.io/anon/pen/vjJMVL
HTML:
<ul class="selected-2">
<li>1</li>
<li class="selected">2</li>
<li>3</li>
<li>4</li>
</ul>
<ul class="selected-4">
<li>1</li>
<li>2</li>
<li>3</li>
<li class="selected">4</li>
</ul>
CSS:
ul {
display: flex;
justify-content: center;
list-style: none;
}
li {
width: 80px;
height: 80px;
background-color: #eee;
margin: 10px;
}
.selected {
background-color: #ccc;
}
.selected-2 {
transform: translateX(50px)
}
.selected-4 {
transform: translateX(-150px)
}
Calculate the clicked <MenuItem> center by using Element.getBoundingClientRect() to get it's left, and width, and pass it to the parent (<Menu>). In the parent use the <ul>s ref to get it's left and width with Element.getBoundingClientRect(). Calculate the moveTo state, and update the <ul>s style transform: translateX() accordingly:
const { Component } = React;
const items = ['One', 'Two', 'Three', 'Four'];
class MenuItem extends Component {
clickHandler = (e) => {
const { left, width } = e.target.getBoundingClientRect();
const itemCenter = left + width / 2;
this.props.updateCenter(itemCenter);
}
render() {
const { children } = this.props;
return (
<li onClick={this.clickHandler}>{children}</li>
);
}
}
class Menu extends Component {
state = {
moveTo: 0
};
updateCenter = (itemCenter) => {
const { left, width } = this.ul.getBoundingClientRect();
//this.ul.style.transform = `translateX(${center}px)`;
this.setState(() => ({
moveTo: left + width / 2 - itemCenter
}));
};
render() {
const { items } = this.props;
const { moveTo } = this.state;
return (
<nav>
<ul ref={(ul) => this.ul = ul} style={{
transform: `translateX(${moveTo}px)`
}}>
{
items.map((text) => (
<MenuItem key={text}
updateCenter={this.updateCenter}>
{text}
</MenuItem>
))
}
</ul>
</nav>
);
}
}
ReactDOM.render(
<Menu items={items} />,
demo
);
/** demo only - display the center **/
body::before {
position: absolute;
left: 50%;
height: 100vh;
border-right: 1px solid black;
content: '';
}
nav {
overflow: hidden;
}
ul {
list-style-type: none;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
li {
padding: 1em;
border: 1px solid black;
cursor: pointer;
}
ul li:not(:last-child) {
margin: 0 1em 0 0;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="demo"></div>
Since i don't fully get what you want, this is the best i could have came up with, applying absolute positioning to the selected one and have it overlap the others with z-index
document.querySelectorAll('li').forEach(function(li){
li.addEventListener('click',function(e){
document.querySelectorAll('li').forEach(function(obj){
obj.classList.remove('selected');
});
e.target.classList.add("selected");
});
});
ul {
list-style-type: none;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
}
li{
border:1px solid;
padding:10px;
cursor:pointer;
position:relative;
transition:all ease 1s;
margin:0 20px;
}
.selected{
transform:scale(2.1);
background:white;
box-shadow:0px 0px 55px black;
position:absolute;
z-index:5;
}
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
</ul>
I'm trying to create the following header using CSS:
This is my attempt so far using CSS grid:
HTML:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<div class="jumbotron">
<div class="grid">
<div class="a">
28
</div>
<div class="b">
clubs
</div>
<div class="c">
/
</div>
<div class="d">
48
</div>
<div class="e">
virtual
</div>
<div class="f">
gyms
</div>
</div>
CSS:
.jumbotron {
background: linear-gradient(141deg, rgb(0,223,179), rgb(34,198,252));
}
.grid {
display:grid;
grid-template-columns: 50px 50px 50px 50px;
color:white;
}
.a{
grid-column: 1;
grid-row: 1/span 2;
font-size:35px;
}
.b{
grid-column: 2;
grid-row: 2;
}
.c{
grid-column: 3;
grid-row: 1/span 2;
font-size:35px;
}
.d {
grid-column: 4;
grid-row:1/span 2;
font-size:35px;
}
.e {
grid-column:5;
grid-row:1;
}
.f {
grid-column:5;
grid-row:2;
}
https://codepen.io/anon/pen/jGKwEL
I don't know if I'm overthinking it but this is the best solution I can come up with to make the stacked text somewhat align. It's very tedicous however to make look exactly like the picture and it includes a lot of CSS classes. Any other way to approach this or am I on the right track?
Edit: this what I ended up doing with help of the answers to this question: https://codepen.io/anon/pen/jGKwEL
You don't have to use CSS grid: just because it is available does not mean that you have to use it, or that it is relevant for your usecase. In your layout requirement, it is more suitable to use a mix of display: flex and some simple relative positioning to get the baseline of the text to line up.
First, with the markup, you can simply use a <ul>:
<ul>
<li>
<span class="count">28</span>
<span class="text">clubs</span>
</li>
<li>
<span class="count">48</span>
<span class="text">virtual<br />gyms</span>
</li>
</ul>
With regards to styling:
use display: flex on the <ul> parent so that the child elements will be arranged horizontally
the slanted border can simply be emulated using border-right, and we disable it on the last child using the li:last-child selector
the baseline alignment of the text/description next to the number requires manual adjustment, just play around with some values with bottom offset
use transform: skew(...) to slant your text uniformly, instead of relying on italics. This will lead to uniform slanting of the text and the separators :)
The outcome will look something like this:
Here is a quick proof-of-concept I have whipped up, based on the suggested changes listed above:
.jumbotron {
background: linear-gradient(141deg, rgb(0, 223, 179), rgb(34, 198, 252));
}
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
justify-content: flex-end; /* Align to right */
}
ul li {
transform: skew(-10deg);
border-right: 3px solid #fff;
padding: 0 20px;
display: flex;
align-items: flex-end; /* Align to bottom */
}
ul li:last-child {
border: none;
}
ul li span {
color: white;
line-height: 1em;
font-weight: bold;
}
ul li span.count {
font-size: 45px;
margin-right: 10px;
}
ul li span.text {
text-transform: uppercase;
position: relative;
bottom: .35em; /* Adjust this value manually */
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<div class="jumbotron">
<ul>
<li>
<span class="count">28</span>
<span class="text">clubs</span>
</li>
<li>
<span class="count">48</span>
<span class="text">virtual<br />gyms</span>
</li>
<li>
<span class="count">33</span>
<span class="text">active<br />players</span>
</li>
<li>
<span class="count">15</span>
<span class="text">inactive<br />players</span>
</li>
</ul>
</div>
Here's an example using a list, :after for styling the slashes, and spans for the different parts of one item. You can just duplicate the <li>'s to add more items, without the need for futher classes. I hope it's the way you need it :)
You could use flexbox as an alternative, but I personally think there is no need for it in this case.
https://codepen.io/anon/pen/YrvQMp