Collapsing Menu

I’m finding it a puzzle to make a collapsing horizintal top menu using table-cell display type. It has six items, but at a certain width I want it to fold from 1 row of 6 to 2 rows of 3.
I have managed to make this work using % widths rather than table-cell. But table cell makes more efficient use of space, sizing cells according to content size, that way I should not have to fold as soon, or go another step to 3 rows of 2.
I tried wrapping the first 3 and last 3 menu items in separate spans, then making the spans display as table-row at a 600px media query. That works < 600px but breaks the display > 600px. The spans break the hierarchy of the table, with the anchors not being direct children of nav (table).
In the example I commented out the spans to show how the full width should work. Removing the comments will show the small version working but the wide not.

body{
    background: #666;
    font-family: Verdana, sans-serif ;
    letter-spacing: -1px;
    font-size: 14px;
    padding: 0;
}
#main   {
    background: #fff;
    margin: 0 auto;
    width: 80%;
}
h1  {
    background: #c00;
    color: #fff;
    text-align: center;
    padding: 0.2em;
}
nav {
    display: table;
    width: 100%;
}
nav span    {
    display: inline;
}
nav  a  {
    display: table-cell;
    background: #c00;
    border: solid 2px #dc0;
    border-radius: 5px;
    box-sizing: border-box;
    color: #fff;
    font-size: 1.2em;
    font-weight: bold;
    text-decoration: none;
    text-align: center;
    padding: 0.3em;
}
p {
    padding: 0.5em;
}
@media screen and (max-width: 600px) {
    #main  {
        width: 90% ;
    }
    nav span    {
        display: table-row;
    }
} 


<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name=viewport content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" type="text/css" href="menu.css" />
        <title>Menu</title>
    </head>
    <body>
        <div id="main">
            <h1>This is The Page Title</h1>
            <nav>
                <!--<span>-->
                    <a href="#">Home</a>
                    <a href="#">A Page</a>
                    <a href="#">Page Three</a>
                <!--</span>
                <span>-->
                    <a href="#">Four</a>
                    <a href="#">Contact</a>
                    <a href="#">About</a>
                <!--</span>-->
            </nav>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
            Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        </div>
    </body>
</html>

Would you be open to using flexbox? This might be the most appropriate use of flexbox, if I’ve ever seen one :slight_smile: .

I only recently read about flexbox, have yet to get my head around it. Does it have good support yet?

If you add in Tweener syntax for IE10, it has decent support. Depends on what you need.

So basically if you need IE9 and down…

I will look into it.
I suppose doing it with table display is difficult.

I haven’t seen your HTML, but I assume it’s like a normal table/table-cell approach. That’s not a good way to handle collapsing.

Table/table-cell is good for going from like…3 columns to stacking 1 columns. Most easily achieved (in that example) by changing the display types to block. Unless you switched to floats/inline-block for the 2x3, it’s not the best for having it be fully responsive and going from 6, to 2x3, to 1x6.

Tables love to keep their cells in one single row. Not spread out over multiple rows (unless the HTML is made that way.) No point fighting and pulling teeth with this :slight_smile: .

For a simple menu this should work.

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name=viewport content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="menu.css" />
<title>Menu</title>
<style>
body {
	background: #666;
	font-family: Verdana, sans-serif;
	letter-spacing: -1px;
	font-size: 14px;
	padding: 0;
}
#main {
	background: #fff;
	margin: 0 auto;
	width: 80%;
}
h1 {
	background: #c00;
	color: #fff;
	text-align: center;
	padding: 0.2em;
}
nav {
	display: table;
	width: 100%;
}
nav span {
	display:inline-table;
	width:50%;
	height:100%;
}
nav a {
	display: table-cell;
	background: #c00;
	border: solid 2px #dc0;
	border-radius: 5px;
	box-sizing: border-box;
	color: #fff;
	font-size: 1.2em;
	font-weight: bold;
	text-decoration: none;
	text-align: center;
	padding: 0.3em;
}
p {
	padding: 0.5em;
}
@media screen and (max-width: 600px) {
#main {
	width: 90%;
}
nav span {
	display: table-row;
}
}
</style>
</head>
<body>
<div id="main">
		<h1>This is The Page Title</h1>
		<nav> 
				<span> 
				<a href="#">Home</a> <a href="#">A Page</a> <a href="#">Page Three</a> 
				</span>
        <span> 
				<a href="#">Four</a> <a href="#">Contact</a> <a href="#">About</a> 
				</span> 
		</nav>
		<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
				Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
				Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
				Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</body>
</html>

EDIT
Spoke too soon. Firefox needs the inline table to be 49.5% which spoils the effect.

It almost works.
I’m thinking to do it with table display, it would need nested tables, 2 tables in table cells of a table.

The html is there, it ended up in one block with the css. Obviously just a simplified example for testing.

Ah - missed that. Saw the CSS and figured it was just a CSS block.

It could certainly be done in table/table-cell if you wish; is flexbox support not something you’re comfortable with?

This works better in Firefox but Chrome loses the height so I added nowrap.

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name=viewport content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="menu.css" />
<title>Menu</title>
<style>
*, *:before, *:after {
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
}

body {
	background: #666;
	font-family: Verdana, sans-serif;
	letter-spacing: -1px;
	font-size: 14px;
	padding: 0;
}
#main {
	background: #fff;
	margin: 0 auto;
	width: 80%;
}
h1 {
	background: #c00;
	color: #fff;
	text-align: center;
	padding: 0.2em;
}
nav {
	display: table;
	width: 100%;
	height:100%;
	text-align:left;
	border-collapse:collapse;
}
nav span {
	display:table;
	width:50%;
	height:100%;
	float:left;
	vertical-align:middle;
	border-collapse:collapse;
}

nav a {
	display: table-cell;
	vertical-align:middle;
	background: #c00;
	border: solid 2px #dc0;
	border-radius: 5px;
	box-sizing: border-box;
	color: #fff;
	font-size: 1.2em;
	font-weight: bold;
	text-decoration: none;
	text-align: center;
	padding: 0.3em;
	height:100%;	
	white-space:nowrap;
}
p {
	padding: 0.5em;
}
@media screen and (max-width: 650px) {
#main {
	width: 90%;
}
nav span {
	display: table-row;
	float:none;
}
}
</style>
</head>
<body>
<div id="main">
		<h1>This is The Page Title</h1>
		<nav> 
				<span> 
				<a href="#">Home</a> <a href="#">A Page</a> <a href="#">Page Three</a> 
				</span>
       <span>
				<a href="#">Four</a> <a href="#">Contact</a> <a href="#">About</a> 
			</span>
		</nav>
		<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
				Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
				Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
				Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</body>
</html>

You could probably just use this solution for IE9/10 and use flexbox for modern browsers (probably would work in ie8 but untested).

This works in a way
css:-

body{
    background: #666;
    font-family: Verdana, sans-serif ;
    letter-spacing: -1px;
    font-size: 14px;
    padding: 0;
}
#main   {
    background: #fff;
    margin: 0 auto;
    width: 80%;
}
h1  {
    background: #c00;
    color: #fff;
    text-align: center;
    padding: 0.2em;
}
nav {
    display: table;
    width: 100%;
}
nav span {
    display: table-cell;
}
nav span .row   {
    display: table;
    width: 100%;
}
nav  a  {
    display: table-cell;
    background: #c00;
    border: solid 2px #dc0;
    border-radius: 5px;
    box-sizing: border-box;
    color: #fff;
    font-size: 1.2em;
    font-weight: bold;
    text-decoration: none;
    text-align: center;
    padding: 0.3em;
}
p {
    padding: 0.5em;
}
@media screen and (max-width: 600px) {
    #main  {
        width: 90% ;
    }
    nav span    {
        display: table-row;
    }
}

html:-

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name=viewport content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" type="text/css" href="menu.css" />
        <title>Menu</title>
    </head>
    <body>
        <div id="main">
            <h1>This is The Page Title</h1>
            <nav>
                <span>
                    <span class="row">
                        <a href="#">Home</a>
                        <a href="#">A Page</a>
                        <a href="#">Page Three</a>
                    </span>
                </span>
                <span>
                    <span class="row">
                        <a href="#">Four</a>
                        <a href="#">Contact</a>
                        <a href="#">About</a>
                    </span>
                </span>
            </nav>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
            Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        </div>
    </body>
</html>

Only; because its two separate tables it does not go into columns. More space efficient, but not very neat. Getting close.
I will read more about flex box and see it I like that method.

That’s better.

On the real sites I tend to use PHP includes for things like menus, so they could go in if IE tags without too much clutter.

Well IE9 and down are the only IE versions that support conditonal comments.

I disagree with Paul (only slightly here) - if you use Tweener syntax (coupled with -ms- prefix that IE10 needs), you can easily get IE10 working. Just a bit more flexbox code, but I’d leave Pauls solution for IE9 and down. Let IE10 get flexbox. This works perfectly due to the support conditional comments has.

Now I have something that works without flexbox, it may be time to go away and learn how flexbox works. Thank you both.

Here is an attempt with flex and no media queries. It behaves to some extent like my last table example, collapsing to 2 rows of 3 with uneven columns.
I re-added the spans to control the wrapping. I did not want to go from straight 6 to 5 & 1, then 4 & 2, then 3 & 3. I want to go straight to even 3 & 3 rows. I don’t know if there is a better way to control this, and constrain to even columns in a table-like way.
When it collapses to 3 rows it goes 2 & 1 & 3, rather than an even 2 & 2 & 2.
Am I being picky wanting an even grid-like layout? It just seems messy to me.

body{
    background: #666;
    font-family: Verdana, sans-serif ;
    letter-spacing: -1px;
    font-size: 14px;
    padding: 0;
}
#main   {
    background: #fff;
    margin: 0 auto;
    width: 80%;
}
h1  {
    background: #c00;
    color: #fff;
    text-align: center;
    padding: 0.2em;
}
nav {
    display: flex;
    width: 100%;
    flex-wrap: wrap;
    justify-content: space-between;
}
nav span    {
    flex-grow: 1;
}
nav span .row   {
    display: flex;
    width: 100%;
    flex-wrap: wrap;
    justify-content: space-between;
}
nav  a  {
    background: #c00;
    border: solid 2px #dc0;
    border-radius: 5px;
    box-sizing: border-box;
    color: #fff;
    font-size: 1.2em;
    font-weight: bold;
    text-decoration: none;
    text-align: center;
    padding: 0.3em;
    flex-grow: 1;
}
p {
    padding: 0.5em;
}

html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name=viewport content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" type="text/css" href="flmenu.css" />
        <title>Menu</title>
    </head>
    <body>
        <div id="main">
            <h1>This is The Page Title</h1>
            <nav>
                <span>
                    <span class="row">
                        <a href="#">Home</a>
                        <a href="#">A Page</a>
                        <a href="#">Page Three</a>
                    </span>
                </span>
                <span>
                    <span class="row">
                        <a href="#">Four</a>
                        <a href="#">Contact</a>
                        <a href="#">About</a>
                    </span>
                </span>
            </nav>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
            Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
            Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        </div>
    </body>
</html>

Hmm…I’m having trouble getting it like I have on my website. It always seems to wrap. Which, flexbox is built for.

If you want preset columns, perhaps inline-block might be best? Or floats?

Unless Paul can manage to get this working. I don’t see a way unless you mess with media queries (maybe), but if we are going to force the issue like this, then perhaps flexbox isn’t the best option after all.

It does wrap, I suppose I wanted more control over how it does that, keeping even rows and columns like a table layout. Starting wide at 1 x 6, then 2 x 3, 3 x 2 and 6 x 1. the last two are probably not needed.
I can do that easy with % widths, but they are all the same set width. I like how table cell and flex adapt the with.
I could use percent and set each item’s % width explicitly, but wondered if there was a smarter way.
Paul’s example was quite close to what I’m after.
Still, I see the potential in flexbox now.

Yes, I don’t think that flexbox can maintain columns when it wraps items of unequal width.It just stretches the rows to fit the space available.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.