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>
Related
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
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>
Given mark-up similar to:
<h1 id="Menu1Title">Menu1</h1>
<nav id="Menu1">
<a>Item1-1</a>
<a>Item1-2</a>
<a>Item1-3</a>
</nav>
<h1 id="Menu2Title">Menu2</h1>
<nav id="Menu2">
<a>Item2-1</a>
<a>Item2-2</a>
<a>Item2-3</a>
</nav>
<h1 id="Menu3Title">Menu3</h1>
<nav id="Menu3">
<a>Item3-1</a>
<a>Item3-2</a>
<a>Item3-3</a>
</nav>
How can this presentation be achieved using CSS only?
Menu1 Menu2 Menu3
Item1-1
Item1-2
Item1-3
Item2-1
Item2-2
Item2-3
Item3-1
Item3-2
Item3-3
ULs can also be used as long as they are three separate elements and not sub-lists of one another. I'd prefer not to use absolute positioning as there is other content below this that should flow around the mark-up above. I also have no need for old IE hacks; only supporting IE9 and modern browsers.
Is this even possible? Thanks!
Edit... The above formatting question is to style for mobile. Non-mobile is displayed as below which is why I was hoping for a CSS-only solution that didn't require mark-up changes.
Menu1
Item1-1
Item1-2
Item1-3
Menu2
Item2-1
Item2-2
Item2-3
Menu3
Item3-1
Item3-2
Item3-3
OK, if you really cant change mark up or use jQuery to alter the mark up then below is a CSS only solution:
http://jsfiddle.net/wSLEb/
You could absolutely position the headers and give the first ul margin top. Then using :nth-of-type pseudo class selector you could target individual headers and give them more left positioning to push them across the page and away from one another.
It's not very flexible as you have to hard code the left positioning so take into account how the width of the headers are rendered on a mobile screen.
Mark up would be:
<h1 id="Menu1Title" class="header">Menu1</h1>
<nav id="Menu1">
<ul class="first">
<li><a>Item1-1</a></li>
<li><a>Item1-2</a></li>
<li><a>Item1-3</a></li>
</ul>
</nav>
<h1 id="Menu2Title" class="header">Menu2</h1>
<nav id="Menu2">
<ul>
<li><a>Item2-1</a></li>
<li><a>Item2-2</a></li>
<li><a>Item2-3</a></li>
</ul>
</nav>
<h1 id="Menu3Title" class="header">Menu3</h1>
<nav id="Menu3">
<ul>
<li><a>Item3-1</a></li>
<li><a>Item3-2</a></li>
<li><a>Item3-3</a></li>
</ul>
</nav>
and CSS would be:
.header {
position: absolute;
top: 0;
left:0;
}
.header:nth-of-type(2) {
left:50px;
}
.header:nth-of-type(3) {
left:100px;
}
ul {
list-style: none;
margin:0;
padding:0;
}
ul.first {
margin-top: 20px;
}
You can read more about pseudo class selectors on Chris Coyier's site here: http://css-tricks.com/pseudo-class-selectors/
Good luck
To start your lists should be in uls.
if you can't use absolute positioning then you need to change your mark up to achieve that kind of styling. The headers should appear after one another in the html. If you can't change your mark up at the source then you will have to use jQuery to reorder the mark up on page load.
in your jQuery I would target all of the headers and then remove all of them except for the first and then insert these removed headers after the first one, and then place a clearing div after the last header.
See this or the code below: http://jsfiddle.net/wSLEb/
Your mark up would become like so:
<h1 id="Menu1Title" class="header">Menu1</h1>
<h1 id="Menu2Title" class="header">Menu2</h1>
<h1 id="Menu3Title" class="header">Menu3</h1>
<div class="clear"></div> <!--clearing div added to move first ul under the headers-->
<nav id="Menu1">
<ul>
<li><a>Item1-1</a></li>
<li><a>Item1-2</a></li>
<li><a>Item1-3</a></li>
</ul>
</nav>
<nav id="Menu2">
<ul>
<li><a>Item2-1</a></li>
<li><a>Item2-2</a></li>
<li><a>Item2-3</a></li>
</ul>
</nav>
<nav id="Menu3">
<ul>
<li><a>Item3-1</a></li>
<li><a>Item3-2</a></li>
<li><a>Item3-3</a></li>
</ul>
</nav>
The styling would then be like so:
.header {
float: left;
margin-right: 10px;
}
ul {
list-style: none;
margin:0;
padding:0;
}
.clear {
clear: both;
}
I would like the navigation links on this page to each appear on their own line:
A. Without using "display:block" - as that makes the hover animation take up the full width of the container, not just the <a> element.
B. Without using <br> tags, as I am eventually looking to create a responsive site with a horizontal navigation on smaller screens.
Thanks for your help.
Have you tried float:left; clear:left ?
wrap you navigation in ul, li:
<ul>
<li>Link 1</li>
<li>Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
css:
ul {list-style: none} li {display: block}
This lets you style your anchors accordingly while forcing them to break lines.
You can wrap the <a>'s in <div>'s and apply CSS to the div's to float:left, clear:left;
div.anchorContainer
{
float:left;
clear:left;
}
<div class="anchorContainer">
text
</div>
<div class="anchorContainer">
text
</div>
<div class="anchorContainer">
text
</div>
You can just apply word-break: break-all;
.parent-block {
max-width: 250px;
width: 100%;
border: solid 1px black;
}
.long-link {
word-break: break-all;
}
<div class="parent-block">
<a class="long-link">https://stackoverflow.com/questions/10000674/make-an-a-tag-move-onto-a-new-line-without-using-displayblock</a>
</div>
I'll ask the basic question first and then go into excruciating detail as to why I'm asking. I have a bunch of similar floated block elements inside a <div> and I've set overflow:auto on the <div> so that its height expands to properly contain all of the elements inside it.
Is there any way, using CSS and HTML only, to set only the first floated element to the full height of the div?
Just to be clear: I want to grow the contained element to the height of the container, not the other way around.
I tried adding
height: 100%
to the first floated element's CSS, but that has no effect.
On to the excruciating detail. And if a better overall approach comes to mind, which would eliminate this particular problem, I'm all ears.
I'm simulating a table with a bunch of floated <ul> elements inside a <div>. Each list is a column in the "table" and the first list is the row-label column. So, to render the following:
col A col B
row 1 foo baz
row 2 bar bat
I use this markup:
<div>
<ul class='row-label'>
<li> </li> *
<li>row 1</li>
<li>row 2</li>
</ul>
<ul class='data-col'>
<li class='data-header'>col A</li>
<li>foo</li>
<li>bar</li>
</ul>
<ul class='data-col'>
<li class='data-header'>col B</li>
<li>baz</li>
<li>bat</li>
</ul>
</div>
* there's supposed to be a non-breaking space in the first item of the 'row-label' list but I can't get SO to show
Attentive readers may be wondering "Huh? Why not use a real table?" Two answers:
My fake-table approach is much more appropriate, semantically, for my data. The data is more closely related within each "column" than within each "row", but HTML tables assume the opposite. So I would need more complex PHP on the backend to convert the data into HTML tables, and the result wouldn't make as much sense. The "table" here really is more of a visual/presentation effect than anything.
I wanted to leave open the ability to manipulate individual columns in JavaScript (show them and hide them in response to user action, with transition effects). From what I could tell when I was researching it, there's no straightforward way to do this in a standard HTML table -- precisely because the row, not the column, is the basic unit of the HTML table. Please shoot me a counter-example if I'm wrong.
The CSS, simplified, looks like this:
div {
overflow: auto;
}
div ul {
float: left;
list-style-type: none;
padding: 0;
margin: 0 0.5em;
}
A problem arises when a row has more columns than will fit in the width of the browser window. The columns wrap to the next line and I get this sloppy result:
col A col B col C
row 1 foo baz bar
col D col E
zab oof
Ultimately I have a better solution in mind but the simplest immediate fix is to give the row-label column enough height to push those wrapped columns into line. If I do something like this:
ul.row-label {
height: [lots of ems]
}
Then I get this result:
col A col B col C
row 1 foo baz bar
col D col E
zab oof
But since there can be more of these simulated tables below the first one, and since there can be any number of rows in each "table", I can't rely on an absolute height.
Make sure you set display: block on your the LI elements inside of your UL. You should also give your UL display: block, overflow: hidden and height: 100% as well. By default list items are inline-block, which will ignore your height settings.
Here is a proof of concept:
<html>
<head>
<style type="text/css">
* { border: solid 1px black; }
div { overflow: auto; }
div ul
{
display: block;
height: 100%;
overflow: hidden;
float: left;
}
div ul li { display: block; }
</style>
</head>
<body>
<div>
<ul class='row-label'>
<li> </li>
<li>row 1</li>
<li>row 2</li>
</ul>
<ul class='data-col'>
<li class='data-header'>col A</li>
<li>foo</li>
<li>bar</li>
</ul>
<ul class='data-col'>
<li class='data-header'>col B</li>
<li>baz</li>
<li>bat</li>
</ul>
</div>
</body>
</html>
Rendered example http://img526.imageshack.us/img526/9444/tablewithlists.png
Firstly, and as you pointed out, your REALLY SHOULD be using tables for tabular data. You can perform exactly the same manipulations on the elements in a table as you can anywhere else.
I dont know why you would want to do such a crazy thing, but your best bet is to just put the .data-col elements in a separate div, add a left margin, and position them to the left:
EDIT: code added for my sanity
ul, li {
display: block;
margin: 0px;
padding: 0px;
}
ul {
float: left;
margin: 0px 5px;
}
li {
height: 20px;
}
.data-cols {
left: 0px;
margin-left: 50px;
overflow: hidden;
}
<div>
<ul class='row-label'>
<li> </li>
<li>row 1</li>
<li>row 2</li>
</ul>
<div class="data-cols">
<ul class='data-col'>
<li class='data-header'>col A</li>
<li>foo</li>
<li>bar</li>
</ul>
<ul class='data-col'>
<li class='data-header'>col B</li>
<li>baz</li>
<li>bat</li>
</ul>
</div>
</div>
May be this would help with ideas? I just found this css framework myself:
http://www.blueprintcss.org/