inline part of a list with flexbox - css

It is possible to inline part of a list with flex box? Here is what I have tried...
The HTML
<ul>
<li>Connect With Me</li>
<li>Facebook</li>
<li>Twitter</li>
<li>LinkedIn</li>
</ul>
The CSS
ul {
display: flex;
flex-direction: column;
}
/*obviously does not work, but hopefully gets my point across*/
ul li:not(:first-child) {
flex-direction:row;
}
So the end result is
Connect With Me
Facebook Twitter LinkedIn

You can use flex wrapping to do this. Setting the first list element to 100% width and enabling wrapping causes it to fill the full top line and wrap the other elements down below. Then, setting the remaining list elements as flex: 1; makes them all share the remaining space evenly between them.
Below is a snippet, along with a CodePen demonstrating this behaviour.
ul {
display: flex;
flex-wrap: wrap;
/* just to make it look cleaner */
list-style-type: none;
margin: 0;
padding: 0;
}
li:first-of-type {
width: 100%;
}
li:not(:first-of-type) {
flex: 1;
}
<!-- background just on li's so they stand out -->
<ul>
<li style="background: red;">Connect With Me</li>
<li style="background: aqua;">Facebook</li>
<li style="background: green;">Twitter</li>
<li style="background: yellow;">LinkedIn</li>
</ul>
CodePen: https://codepen.io/Kxrl/pen/zYBvZmw

Related

Vertical list of items with gap size as percentage of item size

I have a vertical list of items of equal but implicit size. I want a gap between the items to be a percentage relative to this implicit size.
The main problem is that vertical margins are relative to widths, not heights, so they can't be used for this. (Otherwise, one could have a child in the item add the gap as a margin.)
The gap property of flex boxes and grids is in relation to the entire container.
I think this is likely impossible but I wanted to check with the community to verify.
I'm not sure it can be done with pure css, but here is a simple version with javascript, I just looped through a lists children and dynamically set the margin in this case as 10% of its height.
var list = document.getElementById('list');
var children = list.children;
for (var i = 0; i < children.length; i++) {
children[i].style.marginTop = (parseInt(children[i].clientHeight) * .1).toString() + "px";
}
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
background-color: gray;
padding: 10px;
}
.list{
background-color: lightgray;
display: flex;
flex-direction: column;
list-style: none;
}
.list-item{
background-color: lightblue;
}
#li1{
height: 25px;
}
#li2{
height: 50px;
}
#li3{
height: 75px;
}
<div class="container">
<ul class="list" id="list">
<li class="list-item" id='li1'>Item 1</li>
<li class="list-item" id='li2'>Item 2</li>
<li class="list-item" id='li3'>Item 3</li>
</ul>
</div>

Align child elements at inner grid lines

I have a simple CSS Grid Layout with three columns. I need to have the first row's background stretch across the entire track, yet align the child elements at inner grid lines, like a standard navbar aligned with the content following it. I'm using the following code, but can accomplish only one of my requirements at a time (either have the background color stretch across, moving child elements to the left, or have the child elements in the right position, but failing to have the background color run across):
body {
display: grid;
grid-template:
"nav nav nav"
" . content . "
}
nav {
background-color: lightblue;
grid-area: nav;
}
nav ul {
display: flex;
list-style: none;
}
main {
grid-area: content;
}
<nav>
<ul>
<li>item 1</li>
<li>item 2</li>
</ul>
</nav>
<main>
<h1>content</h1>
</main>
As far as I understand, I can only place immediate child elements of a grid container when using CSS Grid Layout. In other words, I can place nav but not nav ul. Presumably, CSS Grid Layout Module Level 2 will lift this restriction, and make this embarrassingly trivial. But I need a solution that works today.
How would I go about this, given the following restrictions:
A solution must be CSS-only (no JavaScript or frameworks).
It must be maintainable, e.g. if I decide to change the first column's width, I do not want to change two (or more) pieces of code.
A solution need not be generic; I really just need to span a single solid color across a row, in case that makes a difference.
Update:
Reading the answers I realize, that my wording was too sloppy. What I asked for did not coincide with what I meant to ask. I'm looking for a CSS Grid Layout based solution replicating the following 'traditional' implementation:
nav {
background-color: lightblue;
}
.container {
margin: auto;
width: 80vw;
}
<nav>
<div class="container">
<a>item</a>
<a>item</a>
</div>
</nav>
<main>
<div class="container">
<p>content</p>
</div>
</main>
I need the background color of the navigation bar to cover the entire width of the parent element, but have the actual content of <nav> and <main> be left-aligned at the same horizontal position.
Notice how your main element, an HTML5 semantically-meaningful container, eliminates the need for a div container, which was common prior to HTML5.
<!-- valid and efficient structure -->
<main>
<h1>content</h1>
</main>
<!-- valid but inefficient structure -->
<main>
<div>
<h1>content</h1>
</div>
</main>
Why aren't you applying this same principle to your navigation bar?
With the HTML5 nav tag available, why use list items?
Instead of this:
<nav>
<ul>
<li>item 1</li>
<li>item 2</li>
</ul>
</nav>
Just do this:
<nav>
<a>item 1</a>
<a>item 2</a>
</nav>
This offers you at least three benefits:
a clean and semantically-meaningful element,
an HTML structure that falls within the scope of Grid's parent-child relationship, and
with one nested grid, that occupies the same space as the parent grid, you can align your items along grid lines.
body {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-areas: " nav nav nav "
" . content . "
}
nav {
grid-area: nav;
display: grid;
grid-template-columns: repeat(3, 1fr);
background-color: lightblue;
}
main {
grid-area: content;
}
<nav>
<a>item 1</a>
<a>item 2</a>
<a>item 3</a>
</nav>
<main>
<h1>content</h1>
</main>
There are other ways to achieve your layout, and the code concept above could be applied to your original HTML structure (just add another nested grid). I'm just putting this forward as one hopefully useful method.
Your problem comes from having your grid styles on the body tag. Move them down to the individual sections you want to format:
main,
header ul.menu {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
main .content {
grid-column: 2/3;
}
header ul.menu {
list-style: none;
padding: 0;
margin: 0;
background-color: lightblue;
}
header ul.menu li {
margin: 1em;
}
header ul.menu li:not(:first-child){
margin-left: 0;
}
<header>
<nav>
<ul class="menu">
<li>item 1</li>
<li>item 2</li>
</ul>
</nav>
</header>
<main>
<div class="content">
<h1>content</h1>
</div>
</main>

Pure css tabs without radio button

I'm trying to adapt this jsfiddle to work without radio button since I cannot use any <form> related tags, and neither javascript!
I "transformed" the <input type='radio'> into <a> tags, and transform the :checked pseudo class into :target
as you can see in this CodePen.
but it does not work :-(
And also solution I used to show first Tab is not usable
Can suggest what's wrong?
Thanks
Joe
Alright, using the :target pseudo-class we can achieve this.
EDIT: I added a wrapper div so you can use position absolute on the panels. This allows you to have the first panel open and switch between them.
.wrapper {
position: relative;
}
.tab-container {
display: none;
position: absolute;
top: 0;
left: 0;
background: red;
}
.tab-container:first-child { display: block }
:target { display: block }
/* just for demo */
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
display: inline-block;
margin-right: 1rem;
}
<ul>
<li>Tab 1</li>
<li>Tab 2</li>
<li>Tab 3</li>
</ul>
<div class="wrapper">
<div id="tab-1-container" class="tab-container">
Tab 1 content
</div>
<div id="tab-2-container" class="tab-container">
Tab 2 content
</div>
<div id="tab-3-container" class="tab-container">
Tab 3 content
</div>
</div>

Hide div and show it when target

I have this in my html:
<div>
<ul id="tabs">
<li id="h1">
Home
<div>
text here
</div>
</li>
<li id="h2">
Services
<div>
text here
</div>
</li>
</ul>
</div>
What I want to do is make the list items inline, while hiding their contents. And the contents would only be visible when I press the list item link. This is what I've tried so far on the css:
li {
display: inline;
}
li div {
display: none;
}
li:target {
display: block;
}
However, this doest not work. The display: block; is not overriding the display: none;
Thanks in advance!
li:target only refers to the li element itself that is targeted. Setting that li’s display property to block will not affect the containing div which display property is set to none. In fact, it will only overwrite the display: inline that’s defined on li.
When you want to display the div that’s inside the targeted li element, then you need to adjust the selector to actually match that div. For example using li:target div to match the specificity of the original rule:
li {
display: inline;
}
li div {
display: none;
}
li:target div {
display: block;
}
<div>
<ul id="tabs">
<li id="h1">
Home
<div>
text here
</div>
</li>
<li id="h2">
Services
<div>
text here 2
</div>
</li>
</ul>
</div>

How to display a list in two rows?

I have a list of items that I want to fit in a space that is constrained vertically:
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
<li>Six</li>
</ul>
Since I don't want the list to have more than a specific height, but I'm free to expan it horizontally, I want to divide the list into columns, like this:
One Two Three
Four Five Six
Or, alternatively (in my case order is not important)
One Three Five
Two Four Six
The css property column-count allows to break a list into columns, but it only accepts a fixed number of columns. I don't know the number of items I am going to have (it can go from 1 to more than 40), so if I set the number of columns to 3, any list with more than 6 items will be too high, and if there is only 4 items, then only the first column will have two items and it will look uneven.
So, ideally I would need a row-count property, but it doesn't exist. I guess I can do that in Javascript too but I'm looking for a CSS-only solution.
I tried something: float:left on every li puts the list in one row. To break it into two rows, I would need to not apply float:left to the N/2 element. I don't know how to do that.
I know also that I can do it by breaking it into multiple ul, each one with two li, and float:left them, but I would like to avoid messing the HTML for something entirely presentational.
Does someone has a solution for this problem?
Edit: I think I have not been clear in explaining my requirements. I want the list to be sorted into columns without knowing how many items I'm going to have, and so that I will always have two rows.
So for example with 7 items, I want to have:
One Two Three Four
Five Six Seven
And with 3 items:
One Two
Three
Here is a simple way to do it using jquery. I know it is mentioned that a CSS way is needed, but this is just for future reference if anyone wants to refer to this question.
Get the number of LI items and divide it by the number of rows and set that value to column-count property.
Jquery
$(document).ready(function() {
var numitems = $("#myList li").length;
$("ul#myList").css("column-count",Math.round(numitems/2));
});
CSS
ul {
width: 900px;
}
li {
width: 75px;
height: 75px;
margin-top: 10px;
margin-right: 10px;
display: inline-block;
}
HTML
<ul id="myList">
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
<li>Six</li>
<li>Seven</li>
<li>Eight</li>
<li>Nine</li>
</ul>
Fiddle here
EDIT:
Same implementation using simple javascript.
var ul = document.getElementById("myList");
var li = ul.getElementsByTagName("li");
var numItems = li.length;
var css = document.createElement("style");
css.type = "text/css";
css.innerHTML = "ul { column-count: " + Math.round(numItems/2) + "; }";
document.body.appendChild(css);
You need to set the width of UL, because number of rows will depend on the width also even after setting the column-count. You can set it to 100% too, but then the number of rows will change based on the window size. To restrict the number of rows to 2, fixed width for UL may be required.
You could set your li at 33% width and floating against each other, once there isn't enough room in a row they will be pushed down in rows of 3 of equal width.
ul li{
width: 33%;
float: left;
}
I know this question is 7 years old but if anyone has similar problem today, then here's a solution using CSS Grid Layout (https://www.w3.org/TR/css-grid-1/)
ul {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
Why not give it a max-width?
ul {
max-width: somevalue; // which would last when the third item ends
}
Or, you can add class to them as
<ul>
<li class="one">One</li>
<li class="one">Two</li>
<li class="one">Three</li>
<li class="two">Four</li>
<li class="two">Five</li>
<li class="two">Six</li>
</ul>
Now CSS as:
.one {
display: inline;
}
.two {
display: inline;
}
The last thing of the padding is as
ul li {
padding: somevalue;
}
And for slicing:
ul {
max-width: 200px; // to break the list
}
The good luck for you would be that you can first check the width of the list! And then slice it into two equal parts using JS, and then applying it.
If you want to get the CSS calucator, then use this:
width: calc(var1 + var2); // calc will do the math..
Here is the fiddle for this situation: http://jsfiddle.net/afzaal_ahmad_zeeshan/xN87Q/
you can use
li:nth-child(even)
li:nth-child(odd)
http://jsfiddle.net/nCmZT/
Source: Creating a two column Unordered List
Fiddle : Demo provided in the link
HMTL
<ul class="two-col-special">
<li>First Category</li>
<li>Second Category</li>
<li>Third Category</li>
<li>Fourth Category</li>
<li>Fifth Category</li>
</ul>
CSS
.two-col-special {
border: 1px dotted blue;
overflow: auto;
margin: 0;
padding: 0;
}
.two-col-special li {
display: inline-block;
width: 45%;
margin: 0;
padding: 0;
vertical-align: top; /* In case multi-word categories form two lines */
}
.two-col-special li:before {
content: '+';
padding: 5px;
margin-right: 5px; /* you can tweak the gap */
color: orange;
background-color: white; /* in case you want a color... */
display: inline-block;
}
Here's an example using display: flex and flex-direction: row to change the ordering from columns to rows:
#list-1 {
border: 3px solid red;
columns: 2;
column-gap: 5px;
width: 200px;
}
#list-2 {
border: 3px solid blue;
columns: 2;
display: flex;
flex-direction: row;
flex-wrap: wrap;
height: auto; /* can change this */
width: 200px;
}
#list-2 li {
width: 100px;
height: auto;
}
<ul id="list-1">
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
</ul>
<ul id="list-2">
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
</ul>
I think the most easies and proper way {OL tag especially} would be:
<ul>
<div class="row">
<div class="col-6">
<li>One</li>
<li>Two</li>
<li>Three</li>
</div>
<div class="col-6">
<li>Four</li>
<li>Five</li>
<li>Six</li>
</div>
</div>
</ul>

Resources