Archive for the ‘Nerd Matrix’ Category
Top 3 Things That PHP 5.3 Brings to the Table
PHP 5.3 is out and is moving from “a nice toy to play with” release into a production ready version of PHP. I for one am ready for this to happen. PHP 5.3 has some really great improvements that will empower programmers to do rock-star level stuff. Here are three things that I’m itching to use.
Name Spaces
I can’t think of a more wonderful thing to come to PHP. Right now I have to create class names that look more like paragraphs than anything else. Here’s a little (fake) example.
LB_ContentManagement_Helper_Validation_SpecialCharacters::ReplaceAmpersand($content);
In order to have an __autoload() function we need to have class names that also represent where the file is found. It makes for all kinds of goofy class names. I’m looking forward to the day when I can just state the namespaces I’m using and then call the class like this
SpecialCharacters::ReplaceAmpersand($content);
Late Static Binding
This is a complex issue with many implications. One of those implications is that you can now call a static method from a variable like so.
$className = "Users";
$methodName = "Login";
$className::$methodName("bob@domain.com","password");
Prior to PHP 5.3, this wasn’t possible. You had to instantiate the class, then call a public method to do the same thing. Now you can call a method outside of the context of strict inheritance. In the above example you could set a different method for different types of logins, such as an admin login vs. a site user. Not the most practical example, but it gives you an idea of what you can do.
Anonymous Functons
Anyone who has done anything with JavaScript will know the power of anonymous functions. They empower the programmer to create a function that can be used as a callback. Here’s an example.
function doStuff($arg1, $arg2, $callback)
{
// do something with the arguments
$callback();
}
doStuff("1", "2", function() { echo "we just did a callback"; });
In the above example, the call to the function “doStuff” contained an anonymous function. This was then called within “doStuff” when all the processing of $arg1 and $arg2 was finished. This methodology has been a life saver in JavaScript, especially with jQuery, and I’m glad to see its arrival in PHP.
These and other features are moving PHP forward. I can’t wait until PHP 5.3 is adopted as the standard so that these new features can be turned into great applications.
Schema Busters – Part 3: Tricks & Tweaks
More minute methods to further improve your database performance
“Schema Busters” is a multipart technical overview of Database Design elements that you can implement when designing and accessing your database implementation. In this third section we will discuss several tricks and tweaks to consider when constructing your database schema and queries. While some of the proposed methods are fundamental and globally applicable, others are subject to a lot of debate since they are highly situational. Take the application logic into careful consideration before utilizing these methods since some of the proposed methods can actually work to the detriment of your system. The examples below are intended for a MySql implementation, but I am confident that similar issues can be resolved in a similar fashion for other database engines. With that said let’s begin with an extremely MySql specific concern.
MySql Storage Engines and the COUNT Function
While administering your database you may have noticed that MySql has two primary storage engines: MyISAM, which is good for read-heavy applications, and InnoDB, which is good for write-heavy applications. In general the two have similar performances with the one exception being how they handle the COUNT function. Before I begin discussing the benefits of using MyISAM’s meta-data collection, I would like to remind readers that InnoDB has considerable benefits when creating an insert/update heavy application which is common in several company intranet applications. Since a large majority of lifeBLUE’s projects involve front-facing websites wrapped around a back-end management utility, we frequently utilize the MyISAM engine over InnoDB.
MyISAM keeps an internal cache of table meta-data whereas InnoDB keeps no such cache. One of the values found in this table meta-data is the number of rows, which in turn means any COUNT(*) call has the potential of having minimal costs. InnoDB, on the other hand, has to read every entry row present in a table to evaluate a COUNT(*) call (which is about as effective as calling SELECT(*) on the table). The major drawback to utilizing MyISAM is the loss of InnoDB-specific functionality such as stored procedures.
Subqueries vs. Joins
For those who are unfamiliar with the terminology, Subqueries involve the embedding of queries in another query, most commonly in the form of SELECT statements, while a JOIN operation creates a temporary table that holds results from two different tables linked by an identical value in both tables. Two example queries with the same results are provided below:
- Subquery:
SELECT d.Id, (SELECT alias FROM resources r WHERE r.Id = d.Id) AS alias FROM document d - Join:
SELECT d.Id, r.alias FROM resources r INNER JOIN document d ON (r.Id = d.Id) GROUP BY r.Id
A general rule of thumb is to replace correlated subqueries with joins. A correlation occurs when the subquery references a table from the outer query. In our example, the subquery can be considered correlated since it references the d.Id property from the document table which is contained in the outer query. It is also important to point out that implied JOIN operations are not as efficient as explicit JOIN operations since the join condition is not specified immediately resulting in larger table reads. Above we utilized an explicit JOIN operation and below we show an example of an implicit JOIN operation:
- SELECT d.Id, r.alias FROM resources r, document d WHERE r.Id = d.Id
If you want to take it a step further, really crack down on the type of joins being utilized to reduce the size of returned datasets (types of JOIN operations explained here).
Table Partitioning
This practice requires a strong understanding of the application logic, and should be evaluated from both a usability and development standpoint. There are two approaches to table partitioning: read-optimization and write-optimization. Let’s start with read-optimization:
The idea is to simply maintain a smaller dataset of frequently accessed data and another table to hold infrequently accessed data. Imagine that you have an extremely generic content management system where each page contains an alias, description, url, and html body with the following table layout:
CONTENT
| contentId | alias | description | url | HTML |
The alias and description are simply to give a name and summary of the content and the url is obviously the page location. The HTML body will most likely only be accessed when the page is called directly, whereas the alias, description, and url may be displayed in search results and recent item listings. Our resultant tables would look like this:
CONTENT_FREQUENT
| contentId | alias | description | url |
CONTENT_INFREQUENT
| contentId | HTML |
For write-optimization we are implementing the same exact practice, just with the understanding that we are separating the frequently updated values of a table from the infrequently updated values.
Data Types & Size Constraints
There are several ways to tighten up your data usage by manipulating size constraints and data types. I will provide a few examples and leave the rest to the imagination. By now you should understand that VARCHARs maintain a variable length byte to keep track of how many characters are contained in the VARCHAR entry. If we are handling data entries that have a known fixed size, such as zipcodes, it is beneficial to use the CHAR data type as opposed to a VARCHAR since we are eliminating the need of the length determining byte. This may seem small at first, but after a thousand entries we are effectively eliminating a kilobyte of additional data. The worst memory hits come in the form of redundant data entries. It is important to implement proper database normalization to reduce redundant entries as well as other undesirable attributes. See my first Schema Busters entry for more information on database normalization.
Conclusion
If you have been following along from the first entry in this series you should now have enough information to crank out an extremely clean and efficient database design. If there are areas that still remain grey, I highly recommend picking up a textbook on database systems such as the Fundamentals of Database Systems by Elmasri & Navanthe. Also be sure to check back for future entries on improving database and application efficiency. From this point on we will be moving into application-level concepts to improve efficiency and promote usability. Any additional related database entries can be expected in the form of an addendum.
Schema Busters - Part 2: Indexing
The importance of Database Indexing and its effects on efficiency.
“Schema Busters” is a multipart technical overview of Database Design elements that you can implement when designing and accessing your database implementation. In this second section we will discuss the importance of Indexing database columns to speed up data accesses. We will discuss the pros and cons of indexing, and describe the logic behind Indexes.
What is an Index?
Think of database indexes like you would an index in a library book. When you go into the library and need to find a book of a particular genre, you usually head straight to the genre’s section. This is similar to performing Select statements on non-indexed tables. You might be looking at the right shelves but you don’t necessarily know where to start looking. Indexes help to more quickly identify the location of a book, or in the case of databases a record.
How do Indexes work?
Take our library example from above. What would be an efficient and simple solution to help speed up the time it takes to locate a particular book? Sorting! Let’s sort all of the books by their title, and now anybody who knows the title of their book can quickly slim their search down to a significantly smaller number of books. Database indexes work in the same exact way. Indexes keep track of a sorted set of values with an associated row number that allows them to point back to the original record containing the sought index value.
Creating an Index
You can create an index on a table column either at table creation or by using the CREATE INDEX syntax. Listed below are examples of both of these approaches on the same table with the same results:
-
CREATE TABLE Settings
(
settingId INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
settingName VARCHAR(128) NOT NULL,
settingDescription VARCHAR(512) NOT NULL,
settingGroup VARCHAR(256) NOT NULL,
settingValue VARCHAR(512) NOT NULL,
INDEX(settingName),
INDEX(settingGroup)
); -
CREATE TABLE Settings
(
settingId INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
settingName VARCHAR(128) NOT NULL,
settingDescription VARCHAR(512) NOT NULL,
settingGroup VARCHAR(256) NOT NULL,
settingValue VARCHAR(512) NOT NULL,
);
CREATE INDEX indexSettingName ON Settings (settingName);
CREATE INDEX indexSettingGroup ON Settings (settingGroup);
Efficiency Comparisons
Indexes manipulate the fact that they are looking through sorted records in order to refine their search scopes to specific regions by doing simple comparisons. While the method that indexes refine their search scopes is dependent upon the DBMS and the type of Index being created, we can still show a generic example of efficiency improvements due to indexing based on the concept of binary searching. Keep in mind that this is a rudimentary example of indexing logic and is simply an estimate of efficiency gains. Again we will refer to our library example when determining efficiency gains. Let’s assume that the number of books contained in this non-indexed library is N, where N is any real whole number greater than 0.
Imagine that you are looking for a particular book in a non-indexed library. Where do you start? Best case scenario is you will pick up the book you want first, however in the worst case scenario you could end up looking at every single book before finding the one you want. This yields a best case of 1 comparison versus a worst case of N comparisons.
Now imagine that you are looking for the same book in an indexed library sorted by book title. We can now logically eliminate half of the books to look through simply by comparing the middle book title with our sought after title. In one row comparison we have halved our search time, and the greatest part is this process can be applied recursively! This yields a best case of 1 comparison versus a worst case of log2(N) comparisons. The logarithmic base of 2 comes from our division into two subsets equivalent in size.
First let’s note that in the best case we gain nothing, however efficiency is better evaluated in the worst case or in an aggregate of the two. In the worst case we considerably reduce the amount of books we will have to look through. If you are familiar with Big-O Notation you will notice this difference immediately. If you’re not familiar with Big-O Notation, try substituting 1,000 for N. Our non-indexed library has a worst case of 1,000 searches whereas our indexed library has a worst case of approximately 10 searches. It takes 1% of the time to find the book we want in the non-indexed library (if we’re considering the worst case scenario)!
Side Note
If you have been using databases for a decent amount of time you have probably already come across indexes but may not be immediately aware of it. Primary Keys and Unique constraints are actually forms of indexing. By default these indexes are clustered, but you can specify otherwise when creating the constraint. This is important to note when deciding how to define primary keys for your tables.
Index Issues To Consider
Indexing is only beneficial to access queries, so before you go and add indexes to all of your tables on every column possible know that indexing can have a negative effect on your database performance. Indexing columns will increase the time it takes to perform INSERT, UPDATE, and DELETE commands since the index will also need to be modified appropriately to reflect changes. Always ask yourself “Will the majority of activity on this table be SELECT statements?” and “Where do I want to see stronger performance?” before adding indexes to a table.
It is also necessary to consider which columns you wish to index. Take our library example again: If we knew the author’s name but not the book title, then we would gain no benefit from an index on book titles. We would need to add an index on the author attribute instead of the book title column. In all reality you would probably benefit from an index on both attributes, but it is hard to understand multiple indexes with our library example since we cannot sort books by author and title separately due to physical limitations of the books. Fortunately there are no physical limitations with database data so it is entirely plausible to have two separate and distinct indexes. Choosing which columns to index is highly dependent upon project and client specifications. If you are having trouble identifying where you need to insert indexes consider using a database analyzer that can track where you are experiencing the most transaction traffic and provide suggestions that may benefit your database design.
Conclusion
Almost every project you come across can benefit from indexing database tables. Learning how to properly create indexes and utilize them to your advantage can further increase their usability, and the best part is they are relatively simple to understand and implement. Indexing is one of the primary means of boosting application speed, especially with a database-heavy application. For more information on indexing consider picking up Fundamentals of Database Systems by Elmasri & Navanthe or another database schema textbook.
Simple jQuery Tool Uncovered
It’s no secret we love jQuery here at lifeBLUE. It’s made our life easier and our applications better. One task I find myself frequently doing is finding something nested within the tag or element I’m working with. For example.
<div id="iKnowAboutThis" >
<div class="one" >One</div>
<div class="two" >Two</div>
<div class="iWantThis" >Three</div>
</div>
I know all about the div element with the id of “iKnowAboutThis”. I can get at that with a simple:
var iGotIt = $("#iKnowAboutThis");
I can use the jQuery object to do whatever I want. But what if I need to get at the element with the class “iWantThis” that is nested within “iKnowAboutThis”. If I have more than one on the page then I can’t just do this:
var iGotThis = $(".iWantThis");
If I do the above, I’ll get all of the elements with that class. All I want is the one nested within “iKnowAboutThis”. Fortunately, jQuery has a very powerful tool to help me.
By using the context option within the jQuery selector I am able to get at any nested item I want like this.
var iGotIt = $("#iKnowAboutThis");
var iWantThis = $(".iWantThis", iGotIt);
With that little snippet, my search for elements with the selector I specify stays within the context I set for it.
There you go, simple!
Schema Busters - Part 1: Normalization
The importance of Database Relations Normalization and its effects on efficiency.
“Schema Busters” is a multipart technical overview of Database Design elements that you can implement when designing and accessing your database implementation. In this first section we will discuss the importance of a concept titled Normalization which aims to eliminate a number of undesirable attributes that a database relation may contain. Initially we will discuss these undesirable attributes and then describe a number of popular methods, called Normalizations, to remove any undesirable attributes and convert an existing database relation into what is known as a Higher Normal Form Relation. In each section we will also provide real world examples where such normalizations improve the quality of relations and query efficiency.
Undesirable #1: Non-atomic field values
Storing atomic (or indivisible) values in a field makes accessing data simpler and reduces redundancy. Atomicity can be obtained by disallowing the direct storage of multiple values in a single attribute field. That is, a single field contains at most a single element of the attribute domain associated with this field. Take for example a CAR relation with a Color attribute. Even though a single car may come in several colors, we would not want to store a list of colors in a single field since it makes accessing a single color element indirect and complicated (shown in figure 1).
CAR
| Car_Id | Name | Color |
|---|---|---|
| 001 | Honda Civic | {Black} |
| 002 | Toyota Camry | {Red,White,Blue} |
Figure 1 – Non-atomic attribute Color
To resolve this issue we need to convert our CAR relation into what is called a First Normal Form relation. There are different ways of achieving this, some more efficient than others. Below is my recommended method:
- Remove the Color attribute from the CAR entity and place it into an associative table CAR_COLOR along with the primary key of CAR, Car_Id.
Pretty easy so far, right? These two tables are now considered to be in First Normal Form. We are now able to read in single car-to-color associations without the need of value parsing.
Undesirable #2: Non-Full Functional Dependency
Enforcing full functional dependency more accurately and properly associates relational data together. For example, a table may have a composite primary key with different elements being functionally dependent on pieces of the composite key. Full functional dependency separates data relations into intuitive dependency sets and allows for further database normalization. Take for example the following CAR_SHOP, which refers to a shop that works on cars, relation and functional dependencies (denoted FD):
CAR_SHOP
| Car_Id | Shop_Id | Driver | Owner | Price |
|---|
- FD1: Car_Id, Shop_Id >> Price
- FD2: Car_Id >> Driver
- FD3: Shop_Id >> Owner
The functional dependencies describe relations between data. FD1 simply states that for a given car at a given shop the price can be evaluated, FD2 states that a given car has a given driver, and FD3 states that a given shop has a given owner. We can break up the CAR_SHOP entity to be simpler and more descriptive by performing the following manipulations:
- Create a CAR entity that associates Car_Id and Driver.
- Create a SHOP entity that associates Shop_Id and Owner.
- Modify the CAR_SHOP entity that associates Car_Id, Shop_Id, and Price.
As you can see, this simply reflects the FDs described for our original CAR_SHOP entity. These three new entities are considered to be in Second Normal Form.
Undesirable #3: Transitive Dependencies
Transitive dependencies exist when a non-key attribute of an entity is found on both the left and right-hand side of a known functional dependency. This can lead to attributes being functionally dependent to non-key attributes. Take for example a modified version of the CAR entity we described in the previous section:
CAR
| Car_Id | VIN | OWNER | DL_NUMBER | SSN |
|---|
Notice that we can derive the following functional dependency Car_Id >> DL_Number, SSN by the transitive property as shown below:
- Car_Id >> Owner >> DL_Number, SSN
Since it is relatively safe to assume that a single Owner can have more than one car, we can easily see that having two entries in the CAR relation would generate repetitious data. In order to simplify our entity we can take the following steps:
- Modify the CAR entity and associates Car_Id, VIN, and Owner.
- Create an OWNER entity that associates Owner, DL_Number, and SSN.
We can verify that these manipulations are valid by double checking that the original functional dependencies still hold on our new relations, CAR and OWNER. FD1 now holds on the modified CAR entity and FD2 holds strictly on the OWNER entity.
Conclusion (for now)
While there are more normalizations we can consider, several have limited practicality in real-world environments and can be made unnecessary if a database is designed carefully. I say this not to belittle their importance, but to recognize the matter of pertinence in our discussion. If your projects are requiring you to perform additional normalizations, you may consider picking up Fundamentals of Database Systems by Elmasri & Navanthe or another database schema textbook and doing some independent studies. Hopefully by now you have gained a general understanding of the importance of database relation normalization and how it can improve your database schema. Look for my next entry in this series where we will discuss additional database schema concepts and practices.
.blogtable { width:100%; border:solid 1px #333333; color:White; } .blogtable th { background-color:#555555; color:White; } .blogtable td { background-color:#aaaaaa; color:White; padding:5px; }
4G and The Web World
Not to long from now 4G wireless coverage is going to change how the mobile device world works. No longer will high speed internet be relegated to a 100 yard radius around your home. It will extend out beyond your home, office, and internet cafe into every corner of whatever major city you live in.
Things are going to change.
Things are going to change a lot.
As the internet world truly integrates with the mobile world, internet marketing will change drastically. Gone are the days where gaudy banner ads are the way to go. Those lovely little text ads will change forever. Our social media outlets will no longer be tied to a desk. To reach the masses, creativity will be required.
Typically, the strongest part of any marketing campaign has been the “art” side of creative marketing. That is also changing. While graphic art is and always will be just as important to any marketing endeavor, the user interface has now risen to meet it in importance. Here are a few reasons why.
Technology is no longer a spectator sport.
People want to interact with things on a tactile level. Even with television, which is largely a spectator oriented technology, people gravitate to the content they can interact with. Shows such as “Dancing With The Stars”, “American Idol”, and others have proven this for years now. People like to contribute to their entertainment.
In the web world the sites that are used the most are sites that involve two things. First a simple, usable interface that lets users do what they want without reading a manual. Second, visitors can put their two cents in. This is why Facebook has taken the world by storm. People can use it without a Masters degree in computer science and it’s all about them.
People want to know and they want to know now.
People know that information is out there and they want it quickly and in a simple way. If you don’t provide that they will find it elsewhere. There are so many sites out there that do the same thing and 90% of the time the most successful site has three basic elements: clean design, relevant information, and most importantly it’s fun to use. The site that does these three things (plus some good marketing) has the best chance to be a success.
Brand is no longer just about a logo.
Brand loyalty is now built by usability as well as visual appeal. Take Google, they don’t have the greatest logo, a stunning visual design, or little pretties everywhere. In fact, they do quite the opposite. There is one woman who has been there since nearly the beginning who’s job it is to ensure that the user interface remains clean. She is paid huge sums of cash to tell the designers to keep it simple. People love Google not because it has a “WOW Wee” design, but because it is easy to use.
None of this negates good design. In fact, it helps define it. Good web design is defined by how the user will react AND interact with it. If a design is good looking and hard to use, it is still bad design. If a design is both then magic happens.
Now that the web is everywhere, user interface is everything. Design, development, and implementation of a marketing campaign deeply depends on how a user feels about using that marketing. It’s a good day for the internet because the user is finally the primary consideration.
Power to the users!
Three Misconceptions About jQuery
jQuery does produce a buzz. Some people love it, some people… not so much Many more just don’t get it. We at lifeBLUE love it to death, and with good reason. We spend more time creating great interactive applications and less time trying to make those applications work across all browsers. It’s a win-win for our customers and our developers.
However, there are the detractors. While some of them dislike jQuery from a purely philosophical standpoint, most just don’t truly understand it. These misconceptions fall into three categories. Let’s take a look.
“jQuery isn’t JavaScript”
Yep, your right! It’s not JavaScript. That may just be because NOTHING is JavaScript JavaScript does not truly exist. JavaScript is a technology recommendation that nobody really follows. EVERY browser vendor changes how they implement JavaScript every major version change (be it ever so small). In fact, it’s EXACTLY like the “Code” in the “Pirates of the Caribbean” movies; it’s more of a suggestion and can change whenever the browser vendor decides it’s going to change.
So… jQuery is no more or no less JavaScript than anything else written by any other developer anywhere. In fact, one of its stated purposes is to bridge the gap between the various browser’s implementations of JavaScript. jQuery does not require any special technology a browser doesn’t already implement. It does not require any special configuration changes to a server. It’s as “plug and play” as JavaScript gets.
“jQuery is cheating”
Whenthe “rules” of JavaScript really don’t exist you can’t cheat, can you? In fact, to use jQuery, you have to follow standards. jQuery has been around long enough to have a mature feature set and API. It stands worlds above any JavaScript standard in terms of consistency and predictability. If anything, jQuery levels the playing field so that you don’t have to cheat. You can use the same code for every browser, no hacks required.
“jQuery has to much overhead”
Of all the arguments against jQuery, this one has the most validity. jQuery does use memory, bandwidth, and processor power. This point is conceded. However, so does any other piece of JavaScript ever written. The total download size of the jQuery library (in the minimized version) is about the size of a small logo (around 55k), so it does not take much bandwidth. As far as processor power, it does not take very much more or less than any other JavaScript doing the same operation. So while jQuery does take up some resources, it will only really be an issue on really old computers with really slow connections.
In short, jQuery is a great option for most everyday JavaScript tasks. You can produce clean, lightweight, effective code simply. What’s not to like?
<li> + navigation = great combination
For the first time here at the LB, I’ve decided to write a blog directly reflecting my role. Sure we all write about industry related topics, as a team, we all basically perform any and all duties we can to build a website. Whether it’s designing, coding, coming up with a domain name, or talking search engine strategies, we’re all in this together.
Allow me to introduce myself (better late then never, right)… I’m Shauna, our Front End Developer. For the non-nerdy type, that basically means I turn an image into a website, for the somewhat-nerdy, I take the completed design and build the “front end” of what soon becomes a functional website, and for the super-nerdy, I’m responsible for the HTML/CSS side of things.
As with most things, we all have our “style”, “habits” or “the way we think it should be done”. In coding, here at lifeBLUE, you can look at code and immediately know who did it. One of the things that I prefer to do, that can be done probably 20 different ways, is do all navigation in a “list” format. Again, super nerds let me speak your language, <li>’s. It doesn’t matter how simple or complicated a navigation is, whether its live text or images, horizontal or vertical, jpg’s or png’s, whatever the situation may be, I promise you, you can build it in a list. (subliminal message: feel free to prove me wrong, in which I will then show you how it can actually be done).
Why? Several reasons. The OCD in me says do it this way because aesthetically it’s cleaner code (oh, how pretty it looks), but the technical side screams for the search engine aspect as well. Search engines prioritize lists and recognize lists as being a navigational element. So we should take advantage of this and use it properly. It also allows us to associate text with what could essentially be image-based only nav, where you would then lose out on this important feature. It’s also easy for editing, all controlled by the CSS, allowing for simple additions, deletions, and complete makeovers.
So here we go, my time to prove I may know what I’m talking about…
So we start simple… live text only:
CSS:
.nav {width:500px; height:50px; background:#e00260; font-family:Verdana, Arial, Helvetica, sans-serif;}
.nav ul {margin:0 0 0 18px; padding:0;}
.nav li {margin:0; padding:0; list-style:none; float:left; font-size:18px; line-height:50px; text-transform:uppercase; color:#CCC;}
.nav a {color:#FFF; font-weight:bold; text-decoration:none; padding:0 12px;}
.nav a:hover {background:#c80055; color:#FFF; font-weight:bold; text-decoration:none; padding:14px 12px;}
HTML:
<div class=”nav”>
<ul>
<li><a href=”#”>Home</a>|</li>
<li><a href=”#”>About</a>|</li>
<li><a href=”#”>Portfolio</a>|</li>
<li><a href=”#”>Contact</a></li>
</ul>
</div>
Now, image background with live text:
CSS:
.nav2 {width:500px; height:50px; background:#9101b0; font-family:Verdana, Arial, Helvetica, sans-serif;}
.nav2 ul {margin:0; padding:0;}
.nav2 li {margin:0; padding:0; list-style:none; float:left; font-size:15px; line-height:50px; text-transform:uppercase; letter-spacing:-.5px;}
.nav2 a {color:#FFF; font-weight:bold; text-decoration:none; width:125px; height:50px; background:url(nav2_bg.jpg); display:block; text-align:center;}
.nav2 a:hover {color:#FFF; font-weight:bold; text-decoration:none; background:url(nav2_bg_over.jpg);}
HTML:
<div class=”nav2″>
<ul>
<li><a href=”#”>Home</a></li>
<li><a href=”#”>About</a></li>
<li><a href=”#”>Portfolio</a></li>
<li><a href=”#”>Contact</a></li>
</ul>
</div>
And last, images only:
CSS:
.nav3 {width:500px; height:50px;}
.nav3 ul {margin:0; padding:0;}
.nav3 li {margin:0; padding:0; list-style:none; float:left;}
.nav3 a {width:125px; height:50px; display:block;}
.nav3 span {display:none;}.nav3 li.home a {background:url(nav3_home.jpg);}
.nav3 li.home a:hover {background:url(nav3_home_over.jpg);}
.nav3 li.about a {background:url(nav3_about.jpg);}
.nav3 li.about a:hover {background:url(nav3_about_over.jpg);}
.nav3 li.portfolio a {background:url(nav3_portfolio.jpg);}
.nav3 li.portfolio a:hover {background:url(nav3_portfolio_over.jpg);}
.nav3 li.contact a {background:url(nav3_contact.jpg);}
.nav3 li.contact a:hover {background:url(nav3_contact_over.jpg);}
HTML:
<div class=”nav3″>
<ul>
<li class=”home”><a href=”#”><span>Home</span></a></li>
<li class=”about”><a href=”#”><span>About</span></a></li>
<li class=”portfolio”><a href=”#”><span>Portfolio</span></a></li>
<li class=”contact”><a href=”#”><span>Contact</span></a></li>
</ul>
</div>
What navigation styles do you use?


RSS Feed
Atom Feed