A Frontend Development Process
A Frontend Development Process
You know the basics of HTML, and you know a similar amount of CSS, but how do you turn that into a working web page? Simply knowing all the HTML tags and all the CSS attributes isn't enough. You need something called a "process" that will guide you in your first web pages. A process is something artists use to remove a lot of the cognitive overload involved in creating complex visual experiences. By following a process as a beginner you can focus on applying what you know without also trying to figure out what to do next.
I like to call these "personal processes" or "creative processes" so that they aren't confused with the team oriented processes you find in software. The team processes are things like Scrum, Agile Development, XP, and other techniques for managing a large group of people. A personal process is one you can follow on your own to get your idea out of your head, which is also why I could call them a "creative process." Let's just call these "Personal Creative Processes" or PCP for short.
Everyone Has a Process, Except for You
An established artist, writer, musician, or programmer will most likely have a process that works for them. This process is something they've built up--either intentionally or accidentally--over years of working. For some people the process is very important and they're also very conscious of it. Other people just simply "go for it" and think they don't have a process, but if you were to film them working for a few days you'd easily find they do have one.
You, however, probably don't have one because you're a beginner and not that experienced. Or, maybe you've been programming for a while, but you're not as experienced in frontend development. I'd say you're still a beginner, so you don't really know what your process is yet.
I've created a process that works well for beginners for that very reason. If you follow it you'll increase your probability that what you make mostly works. As you work this process and practice it you'll eventually develop your own way of working, or just be fine with this one, but eventually the process should disappear. The goal isn't to chain you to something like a set of rules, but to set you up with a guide that helps you internalize the steps needed to create something. Once those steps are internalized you'll be able to think about more important things rather than, "Should I put images on now or later?"
What Makes a Good Process?
One way to understand Personal Creative Processes (PCP) is to see how other creative people do their thing. I can't speak for other people, but I am a painter, writer, and programmer so I can talk about my own processes. Even though I'm describing my personal process, I've found that there's four general features to all creative processes people use:
- Rough, loose, general, and "chunky" starts. It's easier to change or restart when you keep things loose. Big general structure in the beginning is also easier to manipulate because it's simpler.
- Avoiding details for as long as possible. Details are important but also very difficult to change. They're also difficult to get right if the underlying structure isn't solid enough to hold the details. Details also distract from the more important elements like composition, structure, plot, or logic.
- Tolerant of mistakes by making them easy to identify and fix in each stage. Mistakes are inevitable, so a good process makes them easy to correct and detect as you work. No point in making mistakes easy to fix if you can't even find them.
- Everything "works" as you progress, even if everything is not "exact." A rough sketch can be close enough that people will recognize the subject, even if it's not totally accurate. This means it "works", even if it's not photo realistic.
If a process can give you these four things then it will help, but for a beginner there's a few more things to consider:
- It has to be simple enough that you can remember it and follow it.
- It has to use a structure that focuses on one or two concepts at each stage.
- It can't be so rigid it kills all risk and experimentation, but still needs to teach "trusting the process."
- It has to allow for frequent rapid repetition while also being methodical enough to allow for study and contemplation.
What would a good process look like then? "Good" is subjective, but since you're just starting out I propose this process:
- Big Block Layout Layout the big blocks for the page, usually 3-7 blocks, or a big "example" block for each element you'll need.
- Refine Fake Content Fill in the big blocks with fake text, placeholder images, and other "content" to work out more refined positioning and proportions.
- Replace and Refine More Replace the block structure with semantic HTML tags and use CSS to correct placement, improve visuals, and add more details.
- Turn the Lights On Finally, add in the color schemes, fonts, images, and real text and then use that to continually refine the details even more. Your goal here is to not only make each element nice, but to make sure it fits with the whole visual experience, aka the "gestalt."
You can usually do step 1 and 2 on each big element of a large UI. For example, a landing page is a long list of big user interfaces. Each section has its own layout and design, so it makes more sense to do steps 1 (big block layout) and 2 (fake content) for each big element, treating them like one "UI." However, if you're doing a single page UI then you would do these steps in order.
You'll see what I mean in the demos in Exercises 9 and 10 when I recreate a landing page using this process, and also in the livestreams I did while figuring the process out.
Getting Practical with blockstart.css
Great, I've talked on and on about high minded ideas like "fill out the big blocks first" and "refine with medium details" but what does that mean in practical CSS and HTML? To help understand this I created blockstart.css which is a very simple tiny CSS file that lets you do stage 1 and 2 of the process. You use blockstart.css
like this:
- Use
<block>
,<grid>
, and<content>
tags to create containers for the "big blocks." Use classes and variables insidestyle=""
to change the configuration of these tags. This means you don't have to work in 2 places at once. You just work this simple HTML. - Fill in these
<block>
tags with fake text, formatting tags like<h1>
, and use<shape>
to create image placeholders. As you do this you can adjust the blocks to work with the content and get closer to your desired layout. - Replace each
<block>
tag with a named tag. If you are working on the hero of a landing page, then you change<block>
to<hero>
. You then copy that block's settings up to your CSS and start working the CSS to recreate the block. Now you have an HTML and CSS structure you can refine, and you've removed the majority of theblockstart.css
content. - "Turn the lights on" by going back through each of these new tags and add in the color, fonts, real text, images, videos, and further refinement. It's at this stage that you could then keep working on this page forever (or until you give up and rewrite it).
Sometimes I'll combine stage 1 and stage 2 if I need things to space out or fill blocks before they work. Otherwise I'll follow this process fairly closely, creating the blocks and slowly building them up with details until they're what I want. The end result of this process isn't so much a "finished work in 4 easy steps" but more of a "get a first rendition you can develop after 4 easy steps."
Reviewing the blockstart.css
To use this process you'll need understand what's in the blockstart.css file, so let's go through the major rules in the blockstart.css file and explain what they're doing before you watch the video demonstrating how to use it.
At the top of the file we have variables that are used to set different values and simple display features. The --value[0-9]
are nothing more than simple gray colors in an even distribution of light to dark. This helps you create the page without color.
:root {
--color-border: hsl(0, 0%, 50%);
--border-radius: 5px;
--value0: hsl(0, 0%, 0%);
--value1: hsl(0, 0%, 11%);
--value2: hsl(0, 0%, 22%);
--value3: hsl(0, 0%, 33%);
--value4: hsl(0, 0%, 44%);
--value5: hsl(0, 0%, 55%);
--value6: hsl(0, 0%, 66%);
--value7: hsl(0, 0%, 77%);
--value8: hsl(0, 0%, 88%);
--value9: hsl(0, 0%, 100%);
--text: 0;
}
The body
tag is then set to display flex
, it's given a simple text value, and all the padding is removed. This gives a quick reset of the body and makes it easier to work with flex-box later.
body {
color: hsl(0, 0%, calc(var(--text) * 11%));
display: flex;
flex-direction: column;
justify-content: flex-start;
padding: 0px;
margin: 0px;
}
A content
tag is a simple handy container for those situations where you need to wrap some content but don't want to use a more complex block. It's mostly only set to flex.
content {
display: flex;
flex-direction: column;
}
Next we fix links to have no color:
a {
color: hsl(0, 0%, calc(var(--text) * 11%));
}
Now we are finally at the block
tag, the meat of the whole blockstart.css
file. This sets the color using a variable, displays flex
style, and uses a variable --spacing
so you can change the spacing in the block
tag. If you want flex-end
you just write style="--spacing: flex-end"
.
block {
color: hsl(0, 0%, calc(var(--text) * 11%));
display: flex;
--spacing: space-evenly;
justify-content: var(--spacing);
flex-direction: column;
}
One thing we don't want is a ton of block
tags everywhere or else they'll be a pain to replace. This rule says that all of the first children will be set to display flex
, plus a few other settings that make them work better inside the block
tag. They should stretch
to fill the block, have a small margin, use the --text
variable like block
and body
, and flex equally and automatically. This makes it easy to throw any tags inside a block
, have them behave like a block, but not require anymore CSS.
block > * {
color: hsl(0, 0%, calc(var(--text) * 11%));
display: flex;
flex: 1 1 auto;
--spacing: flex-start;
justify-content: var(--spacing);
align-self: stretch;
flex-direction: column;
margin: 2px;
}
During this initial stage of development you usually want everything to behave like a block
, but sometimes you have to switch the tag back to being normal. For example, if you want a button to not expand to fill the block. The no-flex
class simply undoes most of the settings from the previous rule.
.no-flex {
display: block;
flex: unset;
flex-direction: unset;
align-self: unset;
}
Centering things is weirdly too hard in web development, but these three classes will help. You can tag most things with class="center"
and it will center itself and its contents...mostly. You still need to add a center-text
class if you also want the text centered. If you want a block to center itself, but not center its contents, then use center-self
.
.center {
justify-content: center;
align-items: center;
align-self: center;
}
.center-text > * {
text-align: center;
}
.center-self {
align-self: center;
}
The default orientation for display: flex
is horizontal (row), which is stupid. Everything in the web normally goes vertically by default, and 90% of the contents you'll work with are vertical, so we default to vertical (column). If you want horizontal then use class="horizontal"
.
.vertical {
flex-direction: column;
}
.horizontal {
flex-direction: row;
}
The grid
is so useful I may just keep it in my results. Grids don't show up in designs too often, and usually if you tried to remove this grid
tag to be "semantic" you'd end up with some other word for a grid. That's why I'm finding just leaving the grid
tags there works fine.
grid {
--cols: 1fr 1fr;
--rows: auto;
--gap: 0.5rem;
color: hsl(0, 0%, calc(var(--text) * 11%));
display: grid;
grid-gap: var(--gap);
grid-template-columns: var(--cols);
grid-template-rows: var(--rows);
}
There's rare occasions--especially in the final stage when you're introducing images--where you need to "stack" multiple elements. This CSS uses a feature of CSS grids to stack layers more easily than previous methods. If you need to overlay some text on an image than this is your best friend.
stack {
color: hsl(0, 0%, calc(var(--text) * 11%));
display: grid;
grid-template-rows: 1fr;
grid-template-columns: 1fr;
grid-template-areas: "cover";
}
stack > * {
color: hsl(0, 0%, calc(var(--text) * 11%));
width: 100%;
height: 100%;
position: relative;
grid-area: cover;
}
stack > .top {
z-index: 1000;
}
Many times you quickly need a spacer to separate elements, so we just use an invisible hr
to get it done.
hr {
--height: 1rem;
min-height: var(--height);
visibility: hidden;
}
hr.huge {
--height: 3rem;
}
Placeholder images are fine, but they take a long time to find, download, and link. This rule makes a simple shape
tag that can take a h1
label (or anything) inside and a value. You can use the style="--w: WIDTH; --h: HEIGHT;"
variables to set its size, and --value: VALUE; --text: VALUE;"
to set its value for background and text. For example, if you want a 300px by 300px square that's black with white text you use style="--w: 300px; --h: 300px; --value: 0; --text: 9"
.
shape {
--w: 100%;
--h: 100%;
--value: 4;
color: hsl(0, 0%, calc(var(--text) * 11%));
background-color: hsl(0, 0%, calc(var(--value) * 11%));
display: flex;
width: var(--w);
min-width: var(--w);
max-width: var(--w);
height: var(--h);
min-height: var(--h);
max-height: var(--h);
text-align: center;
justify-content: center;
align-items: center;
align-self: center;
}
It's tough to figure out what is really happening to the blocks, so the debug
class will add a red border around the outer block, and then blue borders on the first child blocks. It's very handy.
.debug {
border: 1px solid red;
}
.debug > * {
border: 1px solid blue;
}
You always need some quick padding and to set specific sizes of things, so the pad
and sized
classes do that.
.pad {
--pad: 1rem;
padding: var(--pad);
}
.sized {
--w: 100%;
--h: 100%;
width: var(--w);
min-width: var(--w);
max-width: var(--w);
height: var(--h);
min-height: var(--h);
max-height: var(--h);
}
Finally, you can set a border with the border
class and set a block to be "solid" with the solid
class. The solid
class uses the typical --value
variable to set it's background. If you wanted a black background you'd write class="solid" style="--value: 0"
.
.border {
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
}
.solid {
--value: 8;
background-color: hsl(0, 0%, calc(var(--value) * 11%));
}
The Challenge
You have short descriptions of these rules, you know HTML, and you know CSS. Your challenge for this exercise is two tasks:
- Study this CSS and make sure you know what everything does. Do you know what's going on in
hsl(0, 0%, calc(var(--value) * 11%))
? Why am I putting variables inside CSS rules instead of in the:root
? If there's something I'm doing that you don't know then study it. - Create your own
.html
file that demonstrates each of the rules in your own words. You can refer to the blockstart.css docs if you get stuck. - Using the
blockstart.css
file, take one of the blockstart.css demos and replicate it. You should only do stages 1 and 2. - Take what you've learned and find a different landing page in the real world to replicate. Remember to only do stages 1 and 2.
The Video
The video for this exercise shows me doing the challenge, so only watch it if you are stuck. You should also watch it if you're unclear about the process, then simply pick a different demo to do than the one I do in the video.
More from Learn Code the Hard Way
Rogue is the Best Project
My pitch for Rogue being the best for both beginners and old crusty coders like me.
Very Deep Not Boring Beginner Projects
A list of projects that anyone with basic programming knowledge can do in any language, but have a lot of depth and aren't boring to do.
C++ Is An Absolute Blast
Where I try to explain why I feel like C\+\+ is so much fun, and to correct some misinformation.
Just Use MSYS2 You Say?
Debunking idiots on HackerNews who think a total beginner can just 'Use MSYS2' on Windows.