Code a Stylish Portfolio Site Design in HTML & CSS

Read the full post

Add to Flipboard Magazine.

Last week we went through the step by step process of building a simple yet stylish single page portfolio site concept in Photoshop. This week we’re going to code up the design into a complete working HTML and CSS website and add the finishing touches in the form of super duper jQuery effects.

The design concept

View the portfolio concept

In case you missed it, here’s the design we’re working towards from last week’s Photoshop tutorial. It’s a simple single page website that is made up of basic header with a short introductory sentence, a series of portfolio items each with a title and description, then the page ends with a stylish contact form in the footer. The idea for the portfolio items is to show the letterbox style thumbnail, then use some jQuery magic on the finished site to expand the letterbox to show the whole graphic.

View the portfolio website demo

Exporting the image files

The first stage of the website build is to export the individual graphics from the design concept so they can be used as CSS background images on the various HTML elements. A square selection of the background pattern can be set to repeat so it fills the whole page.

Images such as the title graphic need exporting as PNG-24 graphics so they can be overlaid onto the background seamlessly with the PNG’s alpha transparency.

The design itself doesn’t require many image files. The images folder includes the background texture, a repeating background for the form elements, the various portfolio pieces, a background ribbon graphic for headers, a small star to sit in the footer, a submit button for the form and the main title graphic.

The HTML markup

View code in full size

The HTML structure begins with a basic page layout. We’ll be keeping everything in check with a Strict XHTML Doctype. A descriptive title is added to the page and the stylesheet is referenced in the <head>.

View code in full size

A container div then houses all the following content, which will keep the site centred up on the page. The item that best defines the page content is the main title, so this is placed inside a <h1> element. The sub-heading follows this as a <h2>, with a line break splitting the sentences to match the text flow in the design concept.
Each portfolio piece is contained within a div with a class of portfolio, then each portfolio image is contained within a div with the class of piece to allow the expanding motion later. The next level heading is <h3>, so this is used to title each portfolio item.
A short description of the portfolio piece is added as a paragraph element, then the details are listed out as a definition list.

View code in full size

At the bottom of the page the contact area is contained within a div with the id of contact. The same font styling as the sub-heading is used in the design concept, so a <h2> will recreate this in the coded version. The contact form is then laid out as a <form> element. A <fieldset> surrounds all the form fields to adhere to the standards of the Strict doctype, then additional divs are used to split the fields so they can be later styled to sit side by side with CSS.
Each input field should have a unique ID, which is linked to using the for attribute on the <label> elements. This associates the two elements with each other, and allows users to click the label to select the appropriate field.
The submit button is created using the type=submit attribute, while the value attribute specifies the text used on the button. We’ll be styling the button graphic ourselves, so a class of submit will allow us to easily target this particular input tag.

The entire HTML markup

For reference, here’s the entire HTML markup all in one. The portfolio div is repeating twice more to include two more portfolio items.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "">
<html xmlns="">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>The Portfolio of Chris Spooner</title>

<link href="style.css" rel="stylesheet" type="text/css" media="screen" />


	<div id="container">
		<h1>The portfolio of Chris Spooner</h1>
		<h2>I'm a designer, blogger and all round creative nut.<br /> Here's a few examples of my recent work.</h2>
		<div class="portfolio">
			<div class="piece">
				<img src="images/snowboard-design.jpg" alt="Vector snowboard design" />
			<h3>Snowboard Design</h3>
			<p>Snowboard design created with an array of bright shapes, trendy lines and patterns to produce a bright and funky vector composition.</p>
		<div class="portfolio">
			<div class="piece">
				<img src="images/heraldic-design.jpg" alt="Ornate heraldic emblem style design" />
			<h3>Photo Manipulation</h3>
			<p>Ornate and detailed heralidic emblem style design featuring a range of flowing ornamental elements that surround a mean looking steer skull.</p>
		<div class="portfolio">
			<div class="piece">
				<img src="images/skull-design.jpg" alt="Vector sugar skull illustion" />
			<h3>Vector Illustration</h3>
			<p>A vector sugar skull illustration skull design that pays homage to the Mexican Dia de los Muertos tradition, created with a range of detailed and ornate vector elements.</p>
	<div id="contact">
		<h2>Like my work? I’d love to hear from you.</h2>
		<form action="" method="post">
					<label for="name">Name:</label>
					<input type="text" id="name" />
					<label for="email">Email:</label>
					<input type="text" id="email" />
					<label for="website">Website:</label>
					<input type="text" id="website" />
					<label for="message">Message:</label>
					<textarea id="message" rows="" cols=""></textarea>
				<input type="submit" value="Send Message" class="submit" />


The CSS styling

View code in full size

Now the HTMl structure is in place, the CSS styling can be written to match the plain code to the visual design concept. The first step with any stylesheet is to reset any browser defaults, then the body can be given some global styling such as a background image and overall font styling for the website.
The #container div is given a specific width of 760px, then the margin moves it into place 60px from the top and centrally on the page. The first elements to appear in the markup are the h1 and h2, these are both styled up to match the design concept. The h1 uses an image replacement technique to show a background image in place of the default text, whereas the h2 is styled so the actual text matches the design concept in size and colour. A CSS3 text-shadow will even match the subtle shading for those with modern browsers, but it’s a feature that won’t be missed on older browsers.

View code in full size

The h3 heading uses a mix of image and font styling. A background image is added to display the ribbon graphic, but the text is also styled and moved into place with padding. Each portfolio div is simply given some bottom margin to space out the design, then the actual .piece div is clipped to the letterbox size using a specific height of 230px and the overflow: hidden; property. When the div is hovered with the mouse, this is changed to height: auto; using the :hover pseudo selector. This crude hover effect is in place as a fallback if the user doesn’t have Javascript enabled, when we code the jQuery we’ll reset this effect then add a more super duper hover effect.

View code in full size

The #contact div at the bottom of the page is given the star background image and some top padding to match the spacing from the design concept. All the form elements are then moved into place with CSS. The divs that split the fields are floated side by side with float: left;, then the input and textarea elements are styled with various properties. Padding on both elements moves the text into place away from the edges of the fields, while margin spaces out the actual elements. All the fields are given a background image that repeats along the x-axis to recreate the subtle shading and texture from the design concept.
It’s a good idea to provide visual feedback on form fields, so the :focus pseudo selector is used to change the colour of the border.
The submit input field is given individual styling to display the button style background image, although some styling that is pulled through from the general input elements needs removing – border: none; and padding: 0; removes the CSS that was required on the general input fields, but not on this input with the submit class.

The entire CSS styling

body, div, h1, h2, h3, h4, h5, h6, p, ul, ol, li, dl, dt, dd, img, form, input, textarea, fieldset, blockquote {
	margin: 0; padding: 0; border: 0;

body {
	background: #7f9aae url(images/bg-texture.png);
	font: 16px/24px Helvetica, Arial, Sans-Serif; color: #fff;

#container {
	width: 760px; margin: 60px auto;

	h1 {
		width: 760px; height: 157px; margin: 0 0 15px 0;
		background: url(images/title-graphic.png); text-indent: -9999px;
	h2 {
		font: 27px/40px Helvetica, Arial, Sans-Serif; letter-spacing: 1px; text-align: center;
		text-shadow: 0px 2px 3px #546a7e; margin: 0 0 40px 0;
	h3 {
		width: 338px; height: 46px; padding: 11px 0 0 22px;
		background: url(images/portfolio-header.png) no-repeat;	
		font: 27px/24px Helvetica, Arial, Sans-Serif; letter-spacing: 1px;
	.portfolio {
		margin: 0 0 45px 0; 
		.portfolio .piece {
			height: 230px; overflow: hidden; margin: 0 0 24px 0;
			.portfolio .piece:hover {
				height: auto;

	dl {
		overflow: hidden;
		dt { 
			float: left; margin: 0 10px 0 0;
		dd {
			float: left; margin: 0 24px 0 0;

	#contact {
		background: url(images/star.png) center top no-repeat;
		padding: 90px 0 0 0; overflow: hidden;
	form div {
		float: left; 

	label {
		display: block; margin: 0 0 5px 0;
	input {
		width: 330px; height: 43px; padding: 5px 15px 5px 15px; margin: 0 16px 17px 0;
		background: #738ea0 url(images/form-bg.png) repeat-x;
		border: 1px solid #668094;
		font: 16px Helvetica, Arial, Sans-Serif; color: #fff;
		input:focus {
			border: 1px solid #93b9b0;
	textarea {
		width: 350px; height: 223px; padding: 16px 15px; 
		background: #738ea0 url(images/form-bg.png) repeat-x;
		border: 1px solid #668094;
		font: 16px/24px Helvetica, Arial, Sans-Serif; color: #fff;
		textarea:focus {
			border: 1px solid #93b9b0;
	input.submit {
		width: 196px; height: 49px; float: right; 
		background: url(images/submit.png); 
		font: 22px Helvetica, Arial, Sans-Serif; letter-spacing: 1px;
		border: none; padding: 0; cursor: pointer;

Adding the jQuery effects

<script src="" type="text/javascript"></script>
<script src="js/scripts.js" type="text/javascript"></script>

Now the site has taken shape and works perfectly as a plain old HTML and CSS build, it can be enhanced with a touch of jQuery. The first step is to reference your Javascript files in the HTML document. First we need the jQuery library, followed by our own scripts.js file where we’ll add some Javascript code of our own.

View code in full size

We coded the design to crudely work with a basic CSS hover effect, but we need to reset this if the user has Javascript enabled. We’ll tell jQuery to add a class named ‘js’ to the portfolio div, so if this class is present the CSS will use the default 230px height on the portfolio div, instead of the ‘auto’ value.

View code in full size

In the scripts.js file the jQuery effects are written out. First the js class is added to the portfolio div using the .addClass() function. The actual hover effect is created with the .hover() function, which tells the piece div to animate to the height of the image then back to the default 230px. A variable is used to fetch the height attribute of the image that is within the piece div (.children('img').attr('height')), then this variable is used inside the animation function.

Quickly fixing IE6

A swift test in all the popular browsers shows a consistent layout, even in IE6. IE6 does have one problem though, as it doesn’t support PNG transparency.

<!--[if IE 6]>
<link href="css/ie6fix.css" rel="stylesheet" type="text/css" media="screen" />
<script src="js/ie6fix.js" type="text/javascript"></script>

Luckily the Belated PNG Fix will quickly fix the transparency issues, but in turn this breaks the margin at on the container div, so a IE6 only stylesheet is added along with the IE6fix Javascript file in the <head> of the HTML document. In the Javascript file, the line DD_belatedPNG.fix('h1,h3,#contact,.submit'); lists out all the elements that have a PNG background image and applies the fix to them all. In the IE6 only CSS file the only addition is 60px top padding to the #container div.

The final portfolio site demo

View the portfolio concept

The entire portfolio site is now complete with valid code, progressively enhanced effects and cross browser consistency. View the demo to see it in all its animated glory.

View the portfolio website demo

  • 187
100 HD Blurred Backgrounds

Join the mailing list to have new content delivered straight to your email inbox. Every subscriber gets a free pack of 100 HD Blurred Backgrounds + bonus 10 realistic web shadows.

100 HD Blurred Backgrounds

Written by Iggy

Iggy is a designer who loves experimenting with new web design techniques collating creative website designs. You can follow Iggy on Twitter.


  1. Ross Macks says:

    Hi Chris, Great follow up tutorial. Really liked the JQuery effects.

    I would love to see you create a tutorial on a contact form build mainly on the backend and validation as this is one of the areas of web design/development I struggle with most. :)

  2. Michael Pitt says:

    Very Nice Chris! I found myself playing with the jquery effect, haha..

  3. Marc says:

    Great tutorial, very useful.

  4. esranull says:

    very very nice work thanks a lot

  5. Hadabo says:

    Thanks very much ;)

  6. This is Phenomenal Chris. It's simple clean, stylish, and all mixed with the latest trends. Is this your alter ego of your personal site?

    • Thanks Jose. For me these kind of tutorials give me an outlet to play around with such styles and 'trends'.
      I don't think I'll ever find a use for the design other than for tutorial purposes but I hope others find it useful.

  7. Great tutorial, written and illustrated in a very easy to understand way… thanks!

  8. Markus says:

    very cool. love the look of the whole page.

  9. Tina Ta says:

    Hi Chris,

    Thanks for the great tutorial! I've always learnt a lot from you.

    I'm just asking if you can write a tutorial for the contact form as well, because it is very complicated. I've try to create a email form in my website:

    but the link doesn't work. In the contact page I edited some template called sendaile.php but it has some error when I sent the message. If you can show us how to create a simple and practical contact form, I would appreciate very much, there's no good online tutorial about that topic, as I've been searching…

    • Thanks Tina, I've just added a response to Ross' comment above too – I tend to use WuFoo for my online forms, it takes out all the hard work and even leaves you with nicely formatted emails.

  10. Sean says:

    I have been waiting on this, great!

  11. verpacodesign says:

    fantastic chris!!!
    it's beautiful and original!

  12. Jarret Minkler says:

    Great article and tutorial, is there a trackback link?

  13. chris says:


    awesome tutorial again! you've been a big help in wordpress theme development for me. keep it up!

  14. Eric says:

    Great tutorial! How do you know what it looks like in IE6, as you use apple products? Do you have a separate windows PC, or in case you use browser testing software, which one?

  15. I absolutely learn a lot from your tutorials. I do have a question though. Do you ever run the firebug analysis on your sites? No matter how well I think I have coded my css and html, the program always tells me to cleanup my code.

    • I haven't used the Analysis option in particular (will have to check it out!) but Firebug itself is a super useful tool when building sites.
      I often move things into position using Firebug, then copy the CSS back over to the stylesheet.

  16. Beautiful design, I am a huge fan of clean one page portfolios like this.

  17. 9swords says:

    Lot's of fun and looks great!

  18. Mark says:

    Great post again Chris! love it. big help thanks.


  19. Tutorial Lounge says:

    excellent helping tips you sharing. thanks

  20. Very nice and detailed tutorial Chris.

  21. Fun tutorial and a good simple way to start my day. Keep up the good work!

  22. saurabh shah says:

    nice tutorial… loved it !

  23. Josh says:

    This is pretty snazzy, as always great tutorial. Can i throw in a tidbit to help the jquery code though?

    The animation will keep firing if you move over the areas and move out fast. So if you add a .stop(true, true) before the .hover it should stop this from happening.

    $('.portfolio.js .piece').stop(true,true).hover(function()

  24. Beben Koben says:

    i like the a:hover trick on image…
    but, we can used pure with CSS for hover attribute, but no smooth LoL
    thanks for tutor \m/

  25. stephen says:

    Really nice clean tutorial. Keep them coming :)

  26. John says:

    Great tutorial! I agree with a couple of the requests for a video demo of each of the steps.. that'd be awesome.

    Great info regardless.

  27. RKS News says:

    Up to date world wide news, fashion and showbiz, technology and health and beauty tips at <a href="">RKS News</a>

  28. Danae says:

    Nice design! Simple, usable, effective. I love the jquery expanding effect: also simple, yet I prefer it to Lightbox.

  29. Kiran K. says:

    Amazing design always ! Like the grid pattern you've created . Will start working on my portfolio on similar lines :) Thanks

  30. ben says:

    Thanks for the tutorial. As a programmer I only take care of the jquery and the server side scripts. But it is nice to know how the whole thing works to understand my designer better :-)

  31. rmaenza says:

    Great designs, you are headed in the right direction. Love the tutorial also.

  32. This is really great. I always love your little written comments for the CSS code. It really helps to figure out what and why it's there for.

  33. John says:

    Or just use wordpress.. a few plugins.. half the time :)

  34. helgaindra says:

    great tutorial!

    thanks a lot

  35. Ben Giordano says:

    Amazing tutorial. Def going to be using this as guide while I attempt my first few mark ups. Thanks so much for not being scared to put great info like this out there!

  36. Stephen says:

    Thanks for the tutorial! Had been using WordPress until now but I think I can try make a portfolio myself now!

  37. Bruce says:

    Awesome tutorial, very detailed. It helps a beginner like me a lot.

  38. anehra63 says:

    very good tutorial thanks for posting

Leave a response