geeky · non php code

Emulate Float Center

This entry talks about how to solve a common design scenario with different approaches. If you are not interested in the long explanation, you can just take a look the end result of my emulation.

Here’s the scenario. You have some menu items you wish to show to a user. Each item has an image and a text description. These items are shown based on the user’s role. Therefore one user may see two items while another may see ten of them.

Here’s a traditional way to handle it with table. Create a table and a table row and let the number of cells be dynamic. Add a cell if you need one.

<table width="80%" align="center">
	<tr>
	  <td align="center">
		<img src="images/viewUsers.gif"><br /><a href="#">View Users</a>
	  </td>
	  <td align="center">
		<img src="images/searchSurveys.gif"><br /><a href="#">Search Surveys</a>
	  </td>
	  <td align="center">
		<img src="images/editSurvey.gif"><br /><a href="#">Edit Survey</a>
	  </td>
	</tr>
  </table>

Here’s the outcome of this approach.

Here is a couple issues with this approach.

Because you are trying to fit all items into one line, the more items you could see, the narrower the space becomes for each item. On the resolution 1024×768 (the most common one now) you will see something like:
menuIssueTraditional.png
The items are squeezed and may be hard to read. More importantly if you keep adding more items, the table will run out of space and will have to increase its width and intrude into nearby UI elements.

The code:

<img src="images/editSurvey.gif"><br /><a href="#">Edit Survey</a>

used to link the menu item also poses other issues. First you are not linking the image thus if you user clicks on the image, nothing happens. The user will have to very accurately click on the text in order to get a response. You could do this:

<a href="#"><img src="images/editSurvey.gif"><br />Edit Survey</a>

But that’s not much better. This will force you to style how the image tag should look wrapped in anchors and show unnecessary white space to be linked.

There is another problem with displaying the image inline. You cannot replace it with CSS. If you style the anchor in such a way that it uses the image as a background image, then that image can be easily replaced by changing the definition of the CSS instead of the markup.

The second way to handle this is using float:left and CSS block elements. This is nothing new and is widely acceptable.

Here’s the markup (it’s much cleaner than the table approach)

 <ul class="mainMenu">
	<li class="viewUsers">
		<a href="#">View Users</a>
	</li>
	<li class="searchSurveys">
		<a href="#">Search Surveys</a>
	</li>
	<li class="editSurvey">
		<a href="#">Edit Survey</a>
	</li>
</ul>

Here’s the css

ul.mainMenu {
	margin: 0 auto;
	width: 80%;
}

ul.mainMenu li {
	float: left;
}

ul.mainMenu li a:active,
ul.mainMenu li a:link,
ul.mainMenu li a:visited {
	display: block;
	float: left;
	color: #000;
	text-decoration: none;
	padding: 40px 10px 10px 10px;
	text-align: center;
	white-space: nowrap;
}


ul.mainMenu li a:hover {
	text-decoration: underline;
}

ul.mainMenu li.viewUsers a {
	background: transparent url(images/viewUsers.gif) center top no-repeat;
}

ul.mainMenu li.searchSurveys a {
	background: transparent url(images/searchSurveys.gif) center top no-repeat;
}

ul.mainMenu li.vendorLists a {
	background: transparent url(images/vendorLists.gif) center top no-repeat;
}

ul.mainMenu li.editSurvey a {
	background: transparent url(images/editSurvey.gif) center top no-repeat;
}

ul.mainMenu li.report a {
	background: transparent url(images/report.gif) center top no-repeat;
}

ul.mainMenu li.editProfile a {
	background: transparent url(images/editProfile.gif) center top no-repeat;
}

ul.mainMenu li.vendorNotes a {
	background: transparent url(images/vendorNotes.gif) center top no-repeat;
}

ul.mainMenu li.upgrade a {
	background: transparent url(images/upgrade.gif) center top no-repeat;
}

ul.mainMenu li.lowYield a {
	background: transparent url(images/lowYield.gif) center top no-repeat;
}

ul.mainMenu li.config a {
	background: transparent url(images/config.gif) center top no-repeat;
}

ul.mainMenu li.faq a {
	background: transparent url(images/mainMenuFaq.gif) center top no-repeat;
}

ul.mainMenu li.returnToHome a {
	background: transparent url(images/home.gif) center top no-repeat;
}

ul.mainMenu li.logout a {
	background: transparent url(images/logout.gif) center top no-repeat;
}

Here’s the outcome.

menuIssueFloatLeft.png

This approach basically solves all the issues posed by the table. It makes sure the menu item text is not forced into two lines. The menu item images are defined in the CSS instead of the markup. Also if you hover over the links, you can get a response in the close vicinity of the menu item instead of having to accurately click on the text or the image. Most of the people are probably pretty happy with it. I was too until I realized it CANNOT establish something that the original table approach had. That is to center all the menu items. Because we use float:left, I’ve researched many places to find a way to center the items but have come up empty handed. Only if there is a float:center than we would have no problem. Since there isn’t one, I’ve decided to emulate one.

The way I emulate is by completely dropping the float:left CSS definition and use inline instead of block elements for the menu item. This requires both CSS and markup changes. This is by no means the best way to do it but it’s the only way I know that will accomplish all what I look for. I still do not know the browser compatibility of this approach (only tested in IE 6 and FF 2 at this point). If you are not an advanced CSS designer, please stick with the float:left approach.

The inspiration for this approach comes from a fix for a IE bug. Inline elements DO NOT understand width, height or margin. So in order to accomplish the block element look, I have to rely on padding and line-height. Line-height is used to emulate margin.

The markup will become something like this:

<div class="mainMenuWrapper">
	<a href="#"><span class="viewUsers">View Users</span></a>
	<a href="#"><span class="searchSurveys">Search Vendors</span></a>
	<a href="#"><span class="vendorLists">Vendor lists</span></a>
	<a href="#"><span class="editProfile">Edit My Account</span></a>
	<a href="#"><span class="vendorNotes">View All Notes</span></a>
	<a href="#"><span class="lowYield">Low Return Search Results</span></a>
	<a href="#"><span class="config">Configuration</span></a>
	<a href="#"><span class="faq">FAQ</a></span></a>
</div>

The CSS has the infamous * html IE hack to make the output look the same in IE and Firefox. I will not go into the detail explaining it. Hopefully if you are looking to do this you understand enough about CSS to figure it out on your own.

div.mainMenuWrapper { 
	text-align: center;
	padding: 17px 0 0 0;
	margin: 0;
	line-height: 80px;
}
* html div.mainMenuWrapper {
	padding: 10px 0 0 0;
}
div.mainMenuWrapper span { 
	padding: 40px 15px 0 15px;
	white-space: nowrap;
}
* html div.mainMenuWrapper span {
	padding: 10px 15px 0 15px;
}
div.mainMenuWrapper a,
div.mainMenuWrapper a:link,
div.mainMenuWrapper a:active,
div.mainMenuWrapper a:visited {
	cursor: pointer;
	text-decoration: none;
	color: #000;
	font-weight: bold;
}
html div.mainMenuWrapper a:hover {
	text-decoration: underline;
}
div.mainMenuWrapper span { 
	display: inline-block;
}

div.mainMenuWrapper span.viewUsers {
	background: transparent url(../images/viewUsers.gif) center top no-repeat;
}

div.mainMenuWrapper span.searchSurveys {
	background: transparent url(../images/searchSurveys.gif) center top no-repeat;
}

div.mainMenuWrapper span.vendorLists {
	background: transparent url(../images/vendorLists.gif) center top no-repeat;
}

div.mainMenuWrapper span.editSurvey {
	background: transparent url(../images/editSurvey.gif) center top no-repeat;
}

div.mainMenuWrapper span.report {
	background: transparent url(../images/report.gif) center top no-repeat;
}

div.mainMenuWrapper span.editProfile {
	background: transparent url(../images/editProfile.gif) center top no-repeat;
}

div.mainMenuWrapper span.vendorNotes {
	background: transparent url(../images/vendorNotes.gif) center top no-repeat;
}

div.mainMenuWrapper span.upgrade {
	background: transparent url(../images/upgrade.gif) center top no-repeat;
}

div.mainMenuWrapper span.lowYield {
	background: transparent url(../images/lowYield.gif) center top no-repeat;
}

div.mainMenuWrapper span.config {
	background: transparent url(../images/config.gif) center top no-repeat;
}

div.mainMenuWrapper span.faq {
	background: transparent url(../images/mainMenuFaq.gif) center top no-repeat;
}

div.mainMenuWrapper span.returnToHome {
	background: transparent url(../images/home.gif) center top no-repeat;
}

div.mainMenuWrapper span.logout {
	background: transparent url(../images/logout.gif) center top no-repeat;
}

Here’s outcome along with some additional styling and context.

One thought on “Emulate Float Center

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s