We're going to build a social network for App Academy! A mock-up, that is.
Often when working as a front-end developer you'll be collaborating with a designer. Most likely they will provide you with a sequence of screenshots and specifications for you to convert into neat, maintainable HTML and CSS.
Check out today's end goal. With some clear specifications, a bunch of screenshots, and some hints broken down in 12 phases, you will make a pixel perfect mock-up in code in no time.
- Make sure to keep the specs at your side at all times.
- Open the screenshots in Apple's Preview to study them. You get a nice crosshair to select and measure elements. You can also zoom.
- Use Chrome and the inspector tools. Make sure not to accidentally be zoomed in on your page. The screenshots and browser ratio should be 1:1.
- You will be writing your HTML in the
friends.html
file in the skeleton folder. - Each phase corresponds to a numbered CSS file you should use.
- Always use semantic tags when writing HTML. Avoid using
<div>
and<span>
tags, they should only be used as a last resort and are frowned upon. - Indent and space out your HTML cleanly. That is the only way to maintainable code.
- Always validate your HTML. It's easy for subtle layout bugs to creep in because of invalidly nested or unclosed tags.
- Double quote your attributes:
<nav class="header-nav">
. - Use descriptive classes. Convention is to make them all lowercase,
using dashes. I like to use dashes to note nesting. I may have a
parent
.header
element, with children named.header-nav
and a.header-list
. - Keep your selectors shallow. Nesting increases specificity, which in turn increases precedence. Use this calculator to untangle.
- Prefer less specific selectors like
.header-nav
instead ofnav.header-nav
. - Never use IDs as selectors.
- Finally, enjoy the beauty in the details. A designer's favorite game is Spot The Difference. So-so approximations never suffice, and they will kindly let you know.
- You can do it!
- Clear your floats. Always add a clearfix class to the parent of floated elements.
- When positioning something absolute, make sure what coordinate system
you are working in. Most likely you will want to set the parent
container to be
relative
, if it isn't already positioned. - Pseudo content is injected inside the selected element, as an inline element.
- If your CSS rules look right, but are not showing up, pull up the browser inspector and see if you have conflicting previous rules with more specific selectors. Chrome will show your properties with a strike-through, to show which rules apply, and which are overridden.
Topics: Reset, Appearance, Clearfix, Box-model, Box-sizing, Cursor
Let's start with a clean slate, by writing a reset in
./css/00-reset.css
. To speed you up, we provided some tag selectors to
get you started. Be wise about which properties to inherit, and which to
hard-code. Besides the regular, I'd like you to set the box-sizing
property to inherit, to have all elements behave the same, which is
content-box, by default.
Let's make all images block
elements, have them expand to the full
100%
width of their parent container, and have their height grow
auto
, which means proportionally.
Remove the bullets from list items, strip the default styling from form input elements by setting their appearance to none (see here), and show the little pointer hand on buttons to make it obvious you can click. Finally include the clearfix in your code. We'll be using it a lot!
Topics: Webfonts, Font-weight, Block, Float, Clearfix, Border
Let's study the first real set of screenshots and make a plan of attack.
Typography is always the best place to start. Pull up the specs. The
first thing you'll notice is a font family that most computers do not
have installed. Fortunately, Google provides it to us for free as a
hosted webfont. Find it on Google Fonts, select the
appropriate font-weights, and include the provided <link>
tag right
before the other <link>
tags in the <head>
.
In ./css/01-header.css
set the default font weight, family and size on
the body
tag. If you set up your reset correctly, these styles will
nicely trickle down to all child elements going forward.
The next step is to analyze the screenshots. You want to start thinking of everything as being contained in boxes. We see an outer red box that expands to the full width, with inside it a fixed width box. On the left you see the "App Academy Friends" logo heading, and on the right a list of links. How would you express these meanings using semantic tags?
Let's look at this list of tags. I'd suggest using the
<header>
, <nav>
, <h1>
, <ul>
and <li>
tags to express our
structure. Go ahead and write the skeleton in HTML.
Now add text and links. As you'll be adding dummy links throughout this
project, I recommend using a pound sign as the href: <a href="#">
.
That will prevent a page reload.
Now that we have some structured markup in place, let's add some nice
classes as hooks to select. Start by adding an outer .header
class,
for the full bar. Then add a .header-nav
class for the fixed width
container inside. I'd also suggest using a .header-logo
and
.header-list
class on the <h1>
and <ul>
elements, as this will
keep our selectors nice and shallow. I'd avoid adding classes to the
individual <li>
s, as we can select them by their parent.
With these classes in your HTML, jump to the ./css/01-header.css
file
and make an outline of all the classes you added as selectors. Now go
fill them out with actual styles. Make small changes, immediately
refreshing in your browser to see the changes. Your understanding will
grow by experimenting!
To center a smaller block element inside a larger block element, you'll
want to set its left and right margins to auto
. Since block elements
cannot sit next to each other normally, you're going to need floats.
Whenever you float, you will need to clearfix. It's OK to float things
inside of floated things.
You'll want to float your logo <h1>
to the left, and the <ul>
list
of links to the right. To get the individual <li>
next to each other
you'll want to float those left.
It can be helpful to give elements a temporary background color, to see their appearance while debugging.
As you put paddings in place, remember that usability is important. We
want large click targets. Make your links block
elements and add
padding to them. Also do not forget the hover states, this is important
and gratifying feedback for the user.
Pixel perfect? Do not move on before calling over a TA to check your work!
Topics: Border-radius, Positioning, Overflow, Display, White-space, Z-index
We're adding notifications! Add an inline badge, inside the
notifications <a>
tag. Give it the reusable .badge
class and style
it round as a circle. You'll want to tweak the padding to get it just
right.
For the dropdown, start by nesting a new list of notification list
elements inside of the original notification list element. Add it right
below the <a>
tag. You'll see how it stretches the whole header bar
down. It sort of looks right, if only we could lift it out of the
document flow, and have it not stretch its parent. Aha, you say!
Positioning! Remember to create a coordinate system you control, by
setting its parent to relative
position.
The trick to hiding and showing the dropdown is combining the :hover
selector and the display property. How would you select the dropdown
when someone hovers over the parent notification list item?
If you'd like a hint at this point, check out this amazing cat with glasses demo.
To keep the notification text on one line you may use the white-space
property.
As you add borders to everything, make sure to nudge the dropdown to
line up nicely with vertical lines in the navigation bar. Finally, you
may have issues with a list item poking through the bottom rounded
edges. Fix this using the overflow
property.
Before moving on to Phase 3, add a z-index
of 1
to the whole header
bar. In order to do this, you will also have to set the position
property to relative
, as z-index
does not work on static,
non-positioned, elements. This should not change anything visually
as-is, but will ensure that our header dropdown will stay on top as we
move on and add more to the page.
Pat yourself on the back, you've earned it! By now we've covered the core concepts of CSS. Things will just get easier and way more fun!
Show off your dropdown to a TA.
Topics: Float, Clearfix, Pseudo-content, Positioning
Make a .content
container, with a .content-sidebar
section and a
.content-main
section in it. Give them widths and paddings and float
them next to each other. As they do not have content yet, set a
min-height
property to 200px
to ensure they have some height, even
when empty. Set temporary background colors on the elements to verify
that they are properly next to each other and the correct size.
Often there are many ways you can create whitespace using CSS. You have
a choice of margin
and padding
and there are usually various
elements you could pick to add these to, in order to end up with the
same, correct appearance. In this case, if we look ahead a
bit, we see that inside the .content-sidebar
and .content-main
there's white space all around, inside these sections. Nowhere are the
edges/borders touched, save the big profile image, which is a special
case. When that is the case, it makes sense to pick the most DRY
solution, and add padding to these sections, rather than the child
elements inside.
Since there might be cases where either the sidebar or the main
container could be longer, we cannot simply add a border to one of their
sides to create the divider line in the middle. We want the line always
to be the full height of parent .content
container. We're going to
flex our CSS muscles and combine pseudo-content with absolute
positioning to accomplish this.
Use :before
pseudo-content to inject an element inside the .content
container. Make it a block
element and position
it absolute
. Give
it a width
of 1px
, set the left
coordinate appropriately, but set
the top
and bottom
simultaneously to 0
. This will nicely stretch
out the element to the top and bottom. Don't forget the gray background
color. Voila!
Hint: Anytime we position something, we need to be mindful of what
coordinate system we are working in. We like to control the coordinate
system by setting a parent element to relative
, if it is not already
positioned. In our case of injected pseudo-content, what is the parent?
Topics: Float, Clearfix, Border-radius
Add the footer to the bottom of the document. It does not need to be
nested inside the .content
container, but may be top level. You should
be getting the hang of this by now! Floats in floats. Pay close
attention to colors and typography.
Topics: Background-size, Positioning, Text-shadow
Create a .content-header
section and put it at the top inside of the
.content
container, above the sidebar and main section. Give it a
height and use the supplied ./shared/img/cats.jpg
image as a
background. Make sure the background image covers the full section.
Add a heading and button and position them absolute at the bottom. To
keep the heading legible on a varied background, use the text-shadow
property to increase contrast.
For headings with a large font-size
that do not wrap multiple lines,
we like to decrease the line-height
as it will add a decent chunk of
additional space above and below the words, which is only needed if we
have multiple lines. Let's get rid of that space by setting
line-height
to 1
on our header.
Topics: Positioning, Pseudo-selectors
Divide the sidebar up into three sections: .profile-picture
,
.profile-info
, and .profile-nav
.
Have the .profile-picture
be a link that contains an image tag with
the provided ./shared/img/cat.jpg
picture. Make the link a block
element and style it. Thanks to your earlier reset, the image will now
expand to fill the full width of the link.
To pull the .profile-picture
partly out of its sidebar section, use a
negative margin-top
. This is better than positioning, as it is still
in the document flow, and won't leave a gap, but pull everything up with
it.
To make sure it is in front of the .content-header
section, you will
have to position it relative
. You do not need to nudge it (we used
margin-top
to do that) or give it a z-index. As they're now both
relative
, order of appearance on the page dictates the stacking order.
This is in our favor, as .profile-picture
is declared later.
To get the divider lines between all the .profile-nav
list elements,
but also at the top and bottom, you'll want to use a pseudo selector
like :first-child
, :last-child
, or :nth-child()
.
Topics: Positioning, Overflow, Transform, Letter-spacing, Text-transform, Box-shadow
Celebrate being online with a a nice ribbon! Put an .online
element
inside of the .profile-picture
link. Position it absolute to be on top
of the image. Then go bonkers styling it using fancy transform
properties like rotate()
and translateX()
. Pay attention to
typography and don't forget to add a tiny box-shadow
.
Ask a TA to high-five you for your CSS mastery and give you a review of everything so far!
Topics: Float, Clearfix, Border-radius, Pseudo-content, Positioning, Transform, Triangles
A grid of friends! Use a list and float every <li>
! Spacing them
out properly will be tricky. You will need to use :nth-child()
pseudo-selectors to add some left and right margin to the middle of
every three <li>
s.
Create a .thumb
class to style the links that contain the thumbnails.
You can use the same ./shared/img/cat.jpg
picture for the <img>
tag.
We will want to reuse this .thumb
class later. Note that we're not
using this .thumb
class to float or space the grid, that task is left
to the <li>
s.
Add title
attributes containing friend names to the link tags. You
should have something like:
<a href="#" class="thumb" title="Jonathan">
. Then use :before
pseudo-content to grab this title and inject it into the link. Style
this to make it a tool tip, making it a block
element and position it
absolute.
To position an absolute
element in the center relative to its parent,
use a combination of left: 50%
and transform: translateX(-50%)
. The
left
percentage is relative to its parent, and will set the current
element's left most pixel to half its parent width. Since this is too
far to the left, we have to adjust this by subtracting half our own
width. The translateX()
value takes a percentage relative to itself,
which is exactly what we need.
To create a little triangle below the tooltip, we'll need to inject more
pseudo-content. Fortunately, we have two injection points, :before
and
:after
. Since we used :before
, we will now use :after
. Look at
this demo how you can make a triangle out of borders.
If you'd like an additional hint, check out this tool tip demo. But give it a shot yourself first!
Topics: Float, Clearfix, Border-radius, Pseudo-selectors, Box-shadow, Border-radius, Calc
Reuse your .thumb
class. Float the thumbnail and the form next to each
other. Wrap your inputs and labels in container elements with an
.input
class. Wrap the button in a .submit
container. Style them so
you can reuse them. Pay special attention to the :focus
and ':active'
pseudo-classes.
When you float a block element its width will be determined by its
content, it will take up the minimal space necessary. In our case, when
we float the thumbnail and the form next to each other, the form most
likely will not fill out the full width of the parent container. To fix
this you will want to set a manual width
on the element. You'll have
to do a little math to get this right.
Bonus: CSS can do math too! Though not required today, you may use the
calc()
function. It can be especially nice to do math with combined
units. For instance, you can easily subtract 100px off of a 100%
width, by setting width: calc(100% - 100px)
. You can do addition,
subtraction, multiplication, and division. You can even use
parentheses to denote order.
Topics: Float, Clearfix, Pseudo-content, Calc
Crush this using semantic tags and your floating skills. How about using
pseudo-content to inject little bullets ·
in between the list items?
Topics: Pseudo-selectors, Background-size, Background-position, Overflow
Icons make things look so good! And lucky you, we're going to use a technique called a sprite. This is one image file that contains many smaller images. We combine them to dry up our CSS, but most importantly, to reduce HTTP request overload. We only have to fetch one image, instead of many. This makes things crazily snappy!
Check out our sprite. Then look at the specs.
We will create a slew of icon classes, one for each icon. We will prefix
each class with .icon-
. Let's start off with the post icons, create
classes for .icon-comment
, .icon-reblog
, and .icon-favorite
.
Add these classes to the <a>
tags you wrote in the previous phase.
Back in your CSS, you can select all of these classes using the
[class*="icon-"]
pseudo-selector. Let's first write some general rules
that apply to all icons. Set the supplied ./shared/img/sprite.png
image as the background image. You will want to set the
background-size
property to the specs' sprite size, as the sprite
image is in double resolution for retina screens.
Then set the display property of all icons to inline-block
. This
allows us to set a width and height. Set a width
and height
of
25px
as per the specs. Go look at the results. Notice the background
image with the text on top of it.
We want to get rid of the text, but we do not want to take it out of our
HTML, as it conveys meaning. Let's use CSS to push the text out of the
box! First add a overflow: hidden
rule. See how that clips off the
text at the sides?
Now let's push out the text completely. Remember how padding is part of
an element and shows the background image? Let's use a padding-top
that is equal to the height, and set the height
to 0
. This
effectively pushes the text outside the box, as it does not fit in a 0
height element. Our overflow settings then proceed to clip it off. Check
it out!
Next up, start showing the correct part of the sprite for each class we
wrote. In each individual icon class selector we will only have to set
the background-position
coordinates.
Once we have these in place, also create selectors with the :hover
state.
For the small icons we're going to use the .icon-small-
prefix. Go
ahead and flesh those out.
We can then select all of them with the [class*="icon-small-"]
selector. Notice how the general rules of our earlier selector will also
apply. We can override the width
and padding-top
for the small
icons.
When it comes to applying these icons to our HTML, we don't want these
smaller icons hiding the text of the links, rather we want them to be an
addition. For this we will repurpose the <i>
tag, which seems suitable
for an icon.
Go ahead and add empty <i>
tags with icons classes inside of links on
the page. You'd end up with something like this:
<a href="#"><i class="icon-small-wall"></i> Wall</a>
.
Topics: Positioning, Border-radius
Create a .modal
container at the bottom of the page, with <body>
as
its parent. Have it contain two sections: .modal-screen
and
.modal-form
.
Give .modal-screen
a fixed
position. By setting top
, bottom
,
left
, right
all to 0
, we will stretch it out to fill the entire
screen. Add a z-index
of 2
to have it sit in front of everything
else on the page. Give it a rgba(0, 0, 0, 0.8)
value for its
background
property. The 0.8
alpha will make it slightly
see-through.
Position the .modal-form
absolute, using the centering trick from
earlier. Style it reusing the .input
and .submit
classes you
created.
You may want to use the ×
HTML-entity as your x
closing
button.
Toggle the showing and hiding of the modal based on the presence of the
.is-open
class on the .modal
parent container. Use the display
property.
Use the following script to make the toggling work in your mockup. Add
the classes .js-modal-open
and .js-modal-close
to any elements you
want to add interactivity. Enjoy!
<script src="../shared/js/jquery.js"></script>
<script>
$(function(){
$("body").on("click", ".js-modal-open", function(event){
event.preventDefault();
$(".modal").addClass("is-open");
});
$("body").on("click", ".js-modal-close", function(event){
event.preventDefault();
$(".modal").removeClass("is-open");
});
});
</script>